mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-30 02:02:43 +00:00
The big one (#5346)
This commit is contained in:
@@ -6,6 +6,10 @@ if [ "$remote" = "enterprise" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$remote" = "ent" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -f version/version_ent.go ]; then
|
||||
echo "Found enterprise version file while pushing to oss remote"
|
||||
exit 1
|
||||
|
||||
8
Makefile
8
Makefile
@@ -143,18 +143,20 @@ proto:
|
||||
protoc helper/forwarding/types.proto --go_out=plugins=grpc:../../..
|
||||
protoc logical/*.proto --go_out=plugins=grpc:../../..
|
||||
protoc physical/types.proto --go_out=plugins=grpc:../../..
|
||||
protoc helper/identity/mfa/types.proto --go_out=plugins=grpc:../../..
|
||||
protoc helper/identity/types.proto --go_out=plugins=grpc:../../..
|
||||
protoc builtin/logical/database/dbplugin/*.proto --go_out=plugins=grpc:../../..
|
||||
protoc logical/plugin/pb/*.proto --go_out=plugins=grpc:../../..
|
||||
sed -i -e 's/Idp/IDP/' -e 's/Url/URL/' -e 's/Id/ID/' -e 's/EntityId/EntityID/' -e 's/Api/API/' -e 's/Qr/QR/' -e 's/protobuf:"/sentinel:"" protobuf:"/' helper/identity/types.pb.go helper/storagepacker/types.pb.go logical/plugin/pb/backend.pb.go
|
||||
sed -i -e 's/Idp/IDP/' -e 's/Url/URL/' -e 's/Id/ID/' -e 's/EntityId/EntityID/' -e 's/Api/API/' -e 's/Qr/QR/' -e 's/Totp/TOTP/' -e 's/Mfa/MFA/' -e 's/Pingid/PingID/' -e 's/protobuf:"/sentinel:"" protobuf:"/' -e 's/namespaceId/namespaceID/' -e 's/Ttl/TTL/' helper/identity/types.pb.go helper/storagepacker/types.pb.go logical/plugin/pb/backend.pb.go logical/identity.pb.go
|
||||
sed -i '1s;^;// +build !enterprise\n;' physical/types.pb.go
|
||||
sed -i '1s;^;// +build !enterprise\n;' helper/identity/mfa/types.pb.go
|
||||
|
||||
fmtcheck:
|
||||
@true
|
||||
#@sh -c "'$(CURDIR)/scripts/gofmtcheck.sh'"
|
||||
|
||||
fmt:
|
||||
@true
|
||||
#gofmt -w $(GOFMT_FILES)
|
||||
gofmt -w $(GOFMT_FILES)
|
||||
|
||||
spellcheck:
|
||||
@echo "==> Spell checking website..."
|
||||
|
||||
125
audit/format.go
125
audit/format.go
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/SermoDigital/jose/jws"
|
||||
"github.com/hashicorp/errwrap"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/helper/salt"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/mitchellh/copystructure"
|
||||
@@ -113,20 +114,26 @@ func (f *AuditFormatter) FormatRequest(ctx context.Context, w io.Writer, config
|
||||
errString = in.OuterErr.Error()
|
||||
}
|
||||
|
||||
ns, err := namespace.FromContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
reqEntry := &AuditRequestEntry{
|
||||
Type: "request",
|
||||
Error: errString,
|
||||
|
||||
Auth: AuditAuth{
|
||||
ClientToken: auth.ClientToken,
|
||||
Accessor: auth.Accessor,
|
||||
DisplayName: auth.DisplayName,
|
||||
Policies: auth.Policies,
|
||||
TokenPolicies: auth.TokenPolicies,
|
||||
IdentityPolicies: auth.IdentityPolicies,
|
||||
Metadata: auth.Metadata,
|
||||
EntityID: auth.EntityID,
|
||||
RemainingUses: req.ClientTokenRemainingUses,
|
||||
ClientToken: auth.ClientToken,
|
||||
Accessor: auth.Accessor,
|
||||
DisplayName: auth.DisplayName,
|
||||
Policies: auth.Policies,
|
||||
TokenPolicies: auth.TokenPolicies,
|
||||
IdentityPolicies: auth.IdentityPolicies,
|
||||
ExternalNamespacePolicies: auth.ExternalNamespacePolicies,
|
||||
Metadata: auth.Metadata,
|
||||
EntityID: auth.EntityID,
|
||||
RemainingUses: req.ClientTokenRemainingUses,
|
||||
},
|
||||
|
||||
Request: AuditRequest{
|
||||
@@ -134,12 +141,16 @@ func (f *AuditFormatter) FormatRequest(ctx context.Context, w io.Writer, config
|
||||
ClientToken: req.ClientToken,
|
||||
ClientTokenAccessor: req.ClientTokenAccessor,
|
||||
Operation: req.Operation,
|
||||
Path: req.Path,
|
||||
Data: req.Data,
|
||||
PolicyOverride: req.PolicyOverride,
|
||||
RemoteAddr: getRemoteAddr(req),
|
||||
ReplicationCluster: req.ReplicationCluster,
|
||||
Headers: req.Headers,
|
||||
Namespace: AuditNamespace{
|
||||
ID: ns.ID,
|
||||
Path: ns.Path,
|
||||
},
|
||||
Path: req.Path,
|
||||
Data: req.Data,
|
||||
PolicyOverride: req.PolicyOverride,
|
||||
RemoteAddr: getRemoteAddr(req),
|
||||
ReplicationCluster: req.ReplicationCluster,
|
||||
Headers: req.Headers,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -276,17 +287,23 @@ func (f *AuditFormatter) FormatResponse(ctx context.Context, w io.Writer, config
|
||||
errString = in.OuterErr.Error()
|
||||
}
|
||||
|
||||
ns, err := namespace.FromContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var respAuth *AuditAuth
|
||||
if resp.Auth != nil {
|
||||
respAuth = &AuditAuth{
|
||||
ClientToken: resp.Auth.ClientToken,
|
||||
Accessor: resp.Auth.Accessor,
|
||||
DisplayName: resp.Auth.DisplayName,
|
||||
Policies: resp.Auth.Policies,
|
||||
TokenPolicies: resp.Auth.TokenPolicies,
|
||||
IdentityPolicies: resp.Auth.IdentityPolicies,
|
||||
Metadata: resp.Auth.Metadata,
|
||||
NumUses: resp.Auth.NumUses,
|
||||
ClientToken: resp.Auth.ClientToken,
|
||||
Accessor: resp.Auth.Accessor,
|
||||
DisplayName: resp.Auth.DisplayName,
|
||||
Policies: resp.Auth.Policies,
|
||||
TokenPolicies: resp.Auth.TokenPolicies,
|
||||
IdentityPolicies: resp.Auth.IdentityPolicies,
|
||||
ExternalNamespacePolicies: resp.Auth.ExternalNamespacePolicies,
|
||||
Metadata: resp.Auth.Metadata,
|
||||
NumUses: resp.Auth.NumUses,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,15 +334,16 @@ func (f *AuditFormatter) FormatResponse(ctx context.Context, w io.Writer, config
|
||||
Type: "response",
|
||||
Error: errString,
|
||||
Auth: AuditAuth{
|
||||
DisplayName: auth.DisplayName,
|
||||
Policies: auth.Policies,
|
||||
TokenPolicies: auth.TokenPolicies,
|
||||
IdentityPolicies: auth.IdentityPolicies,
|
||||
Metadata: auth.Metadata,
|
||||
ClientToken: auth.ClientToken,
|
||||
Accessor: auth.Accessor,
|
||||
RemainingUses: req.ClientTokenRemainingUses,
|
||||
EntityID: auth.EntityID,
|
||||
DisplayName: auth.DisplayName,
|
||||
Policies: auth.Policies,
|
||||
TokenPolicies: auth.TokenPolicies,
|
||||
IdentityPolicies: auth.IdentityPolicies,
|
||||
ExternalNamespacePolicies: auth.ExternalNamespacePolicies,
|
||||
Metadata: auth.Metadata,
|
||||
ClientToken: auth.ClientToken,
|
||||
Accessor: auth.Accessor,
|
||||
RemainingUses: req.ClientTokenRemainingUses,
|
||||
EntityID: auth.EntityID,
|
||||
},
|
||||
|
||||
Request: AuditRequest{
|
||||
@@ -333,12 +351,16 @@ func (f *AuditFormatter) FormatResponse(ctx context.Context, w io.Writer, config
|
||||
ClientToken: req.ClientToken,
|
||||
ClientTokenAccessor: req.ClientTokenAccessor,
|
||||
Operation: req.Operation,
|
||||
Path: req.Path,
|
||||
Data: req.Data,
|
||||
PolicyOverride: req.PolicyOverride,
|
||||
RemoteAddr: getRemoteAddr(req),
|
||||
ReplicationCluster: req.ReplicationCluster,
|
||||
Headers: req.Headers,
|
||||
Namespace: AuditNamespace{
|
||||
ID: ns.ID,
|
||||
Path: ns.Path,
|
||||
},
|
||||
Path: req.Path,
|
||||
Data: req.Data,
|
||||
PolicyOverride: req.PolicyOverride,
|
||||
RemoteAddr: getRemoteAddr(req),
|
||||
ReplicationCluster: req.ReplicationCluster,
|
||||
Headers: req.Headers,
|
||||
},
|
||||
|
||||
Response: AuditResponse{
|
||||
@@ -386,6 +408,7 @@ type AuditRequest struct {
|
||||
Operation logical.Operation `json:"operation"`
|
||||
ClientToken string `json:"client_token"`
|
||||
ClientTokenAccessor string `json:"client_token_accessor"`
|
||||
Namespace AuditNamespace `json:"namespace"`
|
||||
Path string `json:"path"`
|
||||
Data map[string]interface{} `json:"data"`
|
||||
PolicyOverride bool `json:"policy_override"`
|
||||
@@ -403,16 +426,17 @@ type AuditResponse struct {
|
||||
}
|
||||
|
||||
type AuditAuth struct {
|
||||
ClientToken string `json:"client_token"`
|
||||
Accessor string `json:"accessor"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Policies []string `json:"policies"`
|
||||
TokenPolicies []string `json:"token_policies,omitempty"`
|
||||
IdentityPolicies []string `json:"identity_policies,omitempty"`
|
||||
Metadata map[string]string `json:"metadata"`
|
||||
NumUses int `json:"num_uses,omitempty"`
|
||||
RemainingUses int `json:"remaining_uses,omitempty"`
|
||||
EntityID string `json:"entity_id"`
|
||||
ClientToken string `json:"client_token"`
|
||||
Accessor string `json:"accessor"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Policies []string `json:"policies"`
|
||||
TokenPolicies []string `json:"token_policies,omitempty"`
|
||||
IdentityPolicies []string `json:"identity_policies,omitempty"`
|
||||
ExternalNamespacePolicies map[string][]string `json:"external_namespace_policies,omitempty"`
|
||||
Metadata map[string]string `json:"metadata"`
|
||||
NumUses int `json:"num_uses,omitempty"`
|
||||
RemainingUses int `json:"remaining_uses,omitempty"`
|
||||
EntityID string `json:"entity_id"`
|
||||
}
|
||||
|
||||
type AuditSecret struct {
|
||||
@@ -428,6 +452,11 @@ type AuditResponseWrapInfo struct {
|
||||
WrappedAccessor string `json:"wrapped_accessor,omitempty"`
|
||||
}
|
||||
|
||||
type AuditNamespace struct {
|
||||
ID string `json:"id"`
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
// getRemoteAddr safely gets the remote address avoiding a nil pointer
|
||||
func getRemoteAddr(req *logical.Request) string {
|
||||
if req != nil && req.Connection != nil {
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/vault/helper/jsonutil"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/helper/salt"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
)
|
||||
@@ -91,7 +92,7 @@ func TestFormatJSON_formatRequest(t *testing.T) {
|
||||
Request: tc.Req,
|
||||
OuterErr: tc.Err,
|
||||
}
|
||||
if err := formatter.FormatRequest(context.Background(), &buf, config, in); err != nil {
|
||||
if err := formatter.FormatRequest(namespace.RootContext(nil), &buf, config, in); err != nil {
|
||||
t.Fatalf("bad: %s\nerr: %s", name, err)
|
||||
}
|
||||
|
||||
@@ -104,6 +105,7 @@ func TestFormatJSON_formatRequest(t *testing.T) {
|
||||
if err := jsonutil.DecodeJSON([]byte(expectedResultStr), &expectedjson); err != nil {
|
||||
t.Fatalf("bad json: %s", err)
|
||||
}
|
||||
expectedjson.Request.Namespace = AuditNamespace{ID: "root"}
|
||||
|
||||
var actualjson = new(AuditRequestEntry)
|
||||
if err := jsonutil.DecodeJSON([]byte(buf.String())[len(tc.Prefix):], &actualjson); err != nil {
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/helper/salt"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
)
|
||||
@@ -52,7 +53,7 @@ func TestFormatJSONx_formatRequest(t *testing.T) {
|
||||
errors.New("this is an error"),
|
||||
"",
|
||||
"",
|
||||
fmt.Sprintf(`<json:object name="auth"><json:string name="accessor">bar</json:string><json:string name="client_token">%s</json:string><json:string name="display_name">testtoken</json:string><json:string name="entity_id"></json:string><json:null name="metadata" /><json:array name="policies"><json:string>root</json:string></json:array></json:object><json:string name="error">this is an error</json:string><json:object name="request"><json:string name="client_token"></json:string><json:string name="client_token_accessor"></json:string><json:null name="data" /><json:object name="headers"><json:array name="foo"><json:string>bar</json:string></json:array></json:object><json:string name="id"></json:string><json:string name="operation">update</json:string><json:string name="path">/foo</json:string><json:boolean name="policy_override">false</json:boolean><json:string name="remote_address">127.0.0.1</json:string><json:number name="wrap_ttl">60</json:number></json:object><json:string name="type">request</json:string>`,
|
||||
fmt.Sprintf(`<json:object name="auth"><json:string name="accessor">bar</json:string><json:string name="client_token">%s</json:string><json:string name="display_name">testtoken</json:string><json:string name="entity_id"></json:string><json:null name="metadata" /><json:array name="policies"><json:string>root</json:string></json:array></json:object><json:string name="error">this is an error</json:string><json:object name="request"><json:string name="client_token"></json:string><json:string name="client_token_accessor"></json:string><json:null name="data" /><json:object name="headers"><json:array name="foo"><json:string>bar</json:string></json:array></json:object><json:string name="id"></json:string><json:object name="namespace"><json:string name="id">root</json:string><json:string name="path"></json:string></json:object><json:string name="operation">update</json:string><json:string name="path">/foo</json:string><json:boolean name="policy_override">false</json:boolean><json:string name="remote_address">127.0.0.1</json:string><json:number name="wrap_ttl">60</json:number></json:object><json:string name="type">request</json:string>`,
|
||||
fooSalted),
|
||||
},
|
||||
"auth, request with prefix": {
|
||||
@@ -73,7 +74,7 @@ func TestFormatJSONx_formatRequest(t *testing.T) {
|
||||
errors.New("this is an error"),
|
||||
"",
|
||||
"@cee: ",
|
||||
fmt.Sprintf(`<json:object name="auth"><json:string name="accessor">bar</json:string><json:string name="client_token">%s</json:string><json:string name="display_name">testtoken</json:string><json:string name="entity_id"></json:string><json:null name="metadata" /><json:array name="policies"><json:string>root</json:string></json:array></json:object><json:string name="error">this is an error</json:string><json:object name="request"><json:string name="client_token"></json:string><json:string name="client_token_accessor"></json:string><json:null name="data" /><json:object name="headers"><json:array name="foo"><json:string>bar</json:string></json:array></json:object><json:string name="id"></json:string><json:string name="operation">update</json:string><json:string name="path">/foo</json:string><json:boolean name="policy_override">false</json:boolean><json:string name="remote_address">127.0.0.1</json:string><json:number name="wrap_ttl">60</json:number></json:object><json:string name="type">request</json:string>`,
|
||||
fmt.Sprintf(`<json:object name="auth"><json:string name="accessor">bar</json:string><json:string name="client_token">%s</json:string><json:string name="display_name">testtoken</json:string><json:string name="entity_id"></json:string><json:null name="metadata" /><json:array name="policies"><json:string>root</json:string></json:array></json:object><json:string name="error">this is an error</json:string><json:object name="request"><json:string name="client_token"></json:string><json:string name="client_token_accessor"></json:string><json:null name="data" /><json:object name="headers"><json:array name="foo"><json:string>bar</json:string></json:array></json:object><json:string name="id"></json:string><json:object name="namespace"><json:string name="id">root</json:string><json:string name="path"></json:string></json:object><json:string name="operation">update</json:string><json:string name="path">/foo</json:string><json:boolean name="policy_override">false</json:boolean><json:string name="remote_address">127.0.0.1</json:string><json:number name="wrap_ttl">60</json:number></json:object><json:string name="type">request</json:string>`,
|
||||
fooSalted),
|
||||
},
|
||||
}
|
||||
@@ -95,7 +96,7 @@ func TestFormatJSONx_formatRequest(t *testing.T) {
|
||||
Request: tc.Req,
|
||||
OuterErr: tc.Err,
|
||||
}
|
||||
if err := formatter.FormatRequest(context.Background(), &buf, config, in); err != nil {
|
||||
if err := formatter.FormatRequest(namespace.RootContext(nil), &buf, config, in); err != nil {
|
||||
t.Fatalf("bad: %s\nerr: %s", name, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
|
||||
"github.com/go-test/deep"
|
||||
"github.com/hashicorp/vault/builtin/logical/database/dbplugin"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/helper/pluginutil"
|
||||
vaulthttp "github.com/hashicorp/vault/http"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
@@ -58,7 +59,7 @@ func preparePostgresTestContainer(t *testing.T, s logical.Storage, b logical.Bac
|
||||
// exponential backoff-retry
|
||||
if err = pool.Retry(func() error {
|
||||
// This will cause a validation to run
|
||||
resp, err := b.HandleRequest(context.Background(), &logical.Request{
|
||||
resp, err := b.HandleRequest(namespace.TestContext(), &logical.Request{
|
||||
Storage: s,
|
||||
Operation: logical.UpdateOperation,
|
||||
Path: "config/postgresql",
|
||||
@@ -227,7 +228,7 @@ func TestBackend_config_connection(t *testing.T) {
|
||||
t.Fatal("expected not exists")
|
||||
}
|
||||
|
||||
resp, err = b.HandleRequest(context.Background(), configReq)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), configReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -242,7 +243,7 @@ func TestBackend_config_connection(t *testing.T) {
|
||||
"root_credentials_rotate_statements": []string{},
|
||||
}
|
||||
configReq.Operation = logical.ReadOperation
|
||||
resp, err = b.HandleRequest(context.Background(), configReq)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), configReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -279,7 +280,7 @@ func TestBackend_config_connection(t *testing.T) {
|
||||
t.Fatal("expected exists")
|
||||
}
|
||||
|
||||
resp, err = b.HandleRequest(context.Background(), configReq)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), configReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -294,7 +295,7 @@ func TestBackend_config_connection(t *testing.T) {
|
||||
"root_credentials_rotate_statements": []string{},
|
||||
}
|
||||
configReq.Operation = logical.ReadOperation
|
||||
resp, err = b.HandleRequest(context.Background(), configReq)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), configReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -320,7 +321,7 @@ func TestBackend_config_connection(t *testing.T) {
|
||||
Data: configData,
|
||||
}
|
||||
|
||||
resp, err = b.HandleRequest(context.Background(), configReq)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), configReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -335,7 +336,7 @@ func TestBackend_config_connection(t *testing.T) {
|
||||
"root_credentials_rotate_statements": []string{},
|
||||
}
|
||||
configReq.Operation = logical.ReadOperation
|
||||
resp, err = b.HandleRequest(context.Background(), configReq)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), configReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -351,7 +352,7 @@ func TestBackend_config_connection(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Path: "config/",
|
||||
}
|
||||
resp, err = b.HandleRequest(context.Background(), req)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -381,7 +382,7 @@ func TestBackend_BadConnectionString(t *testing.T) {
|
||||
|
||||
respCheck := func(req *logical.Request) {
|
||||
t.Helper()
|
||||
resp, err := b.HandleRequest(context.Background(), req)
|
||||
resp, err := b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -440,7 +441,7 @@ func TestBackend_basic(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err := b.HandleRequest(context.Background(), req)
|
||||
resp, err := b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -457,7 +458,7 @@ func TestBackend_basic(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err = b.HandleRequest(context.Background(), req)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -469,7 +470,7 @@ func TestBackend_basic(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
credsResp, err := b.HandleRequest(context.Background(), req)
|
||||
credsResp, err := b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (credsResp != nil && credsResp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, credsResp)
|
||||
}
|
||||
@@ -486,7 +487,7 @@ func TestBackend_basic(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err = b.HandleRequest(context.Background(), req)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -498,7 +499,7 @@ func TestBackend_basic(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
credsResp, err = b.HandleRequest(context.Background(), req)
|
||||
credsResp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (credsResp != nil && credsResp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, credsResp)
|
||||
}
|
||||
@@ -519,7 +520,7 @@ func TestBackend_basic(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err = b.HandleRequest(context.Background(), req)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -533,7 +534,7 @@ func TestBackend_basic(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
credsResp, err = b.HandleRequest(context.Background(), req)
|
||||
credsResp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (credsResp != nil && credsResp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, credsResp)
|
||||
}
|
||||
@@ -546,7 +547,7 @@ func TestBackend_basic(t *testing.T) {
|
||||
}
|
||||
|
||||
// Revoke creds
|
||||
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), &logical.Request{
|
||||
Operation: logical.RevokeOperation,
|
||||
Storage: config.StorageView,
|
||||
Secret: &logical.Secret{
|
||||
@@ -575,7 +576,7 @@ func TestBackend_basic(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
credsResp, err = b.HandleRequest(context.Background(), req)
|
||||
credsResp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (credsResp != nil && credsResp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, credsResp)
|
||||
}
|
||||
@@ -589,13 +590,13 @@ func TestBackend_basic(t *testing.T) {
|
||||
Path: "roles/plugin-role-test",
|
||||
Storage: config.StorageView,
|
||||
}
|
||||
resp, err = b.HandleRequest(context.Background(), req)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
|
||||
// Revoke creds
|
||||
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), &logical.Request{
|
||||
Operation: logical.RevokeOperation,
|
||||
Storage: config.StorageView,
|
||||
Secret: &logical.Secret{
|
||||
@@ -647,7 +648,7 @@ func TestBackend_connectionCrud(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err := b.HandleRequest(context.Background(), req)
|
||||
resp, err := b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -666,7 +667,7 @@ func TestBackend_connectionCrud(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err = b.HandleRequest(context.Background(), req)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -685,7 +686,7 @@ func TestBackend_connectionCrud(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err = b.HandleRequest(context.Background(), req)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -694,7 +695,7 @@ func TestBackend_connectionCrud(t *testing.T) {
|
||||
}
|
||||
|
||||
req.Operation = logical.ReadOperation
|
||||
resp, err = b.HandleRequest(context.Background(), req)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -706,7 +707,7 @@ func TestBackend_connectionCrud(t *testing.T) {
|
||||
req.Operation = logical.UpdateOperation
|
||||
connURL = strings.Replace(connURL, "postgres:secret", "{{username}}:{{password}}", -1)
|
||||
data["connection_url"] = connURL
|
||||
resp, err = b.HandleRequest(context.Background(), req)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -722,7 +723,7 @@ func TestBackend_connectionCrud(t *testing.T) {
|
||||
"root_credentials_rotate_statements": []string(nil),
|
||||
}
|
||||
req.Operation = logical.ReadOperation
|
||||
resp, err = b.HandleRequest(context.Background(), req)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -740,7 +741,7 @@ func TestBackend_connectionCrud(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err = b.HandleRequest(context.Background(), req)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -753,7 +754,7 @@ func TestBackend_connectionCrud(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
credsResp, err := b.HandleRequest(context.Background(), req)
|
||||
credsResp, err := b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (credsResp != nil && credsResp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, credsResp)
|
||||
}
|
||||
@@ -774,14 +775,14 @@ func TestBackend_connectionCrud(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err = b.HandleRequest(context.Background(), req)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
|
||||
// Read connection
|
||||
req.Operation = logical.ReadOperation
|
||||
resp, err = b.HandleRequest(context.Background(), req)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -824,7 +825,7 @@ func TestBackend_roleCrud(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err := b.HandleRequest(context.Background(), req)
|
||||
resp, err := b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -844,7 +845,7 @@ func TestBackend_roleCrud(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err = b.HandleRequest(context.Background(), req)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -868,7 +869,7 @@ func TestBackend_roleCrud(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err = b.HandleRequest(context.Background(), req)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -912,7 +913,7 @@ func TestBackend_roleCrud(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err = b.HandleRequest(context.Background(), req)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -936,7 +937,7 @@ func TestBackend_roleCrud(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err = b.HandleRequest(context.Background(), req)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -1050,7 +1051,7 @@ func TestBackend_roleCrud(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err = b.HandleRequest(context.Background(), req)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -1063,7 +1064,7 @@ func TestBackend_roleCrud(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err = b.HandleRequest(context.Background(), req)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -1101,7 +1102,7 @@ func TestBackend_allowedRoles(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err := b.HandleRequest(context.Background(), req)
|
||||
resp, err := b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -1119,7 +1120,7 @@ func TestBackend_allowedRoles(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err = b.HandleRequest(context.Background(), req)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -1136,7 +1137,7 @@ func TestBackend_allowedRoles(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err = b.HandleRequest(context.Background(), req)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -1149,7 +1150,7 @@ func TestBackend_allowedRoles(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
credsResp, err := b.HandleRequest(context.Background(), req)
|
||||
credsResp, err := b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != logical.ErrPermissionDenied {
|
||||
t.Fatalf("expected error to be:%s got:%#v\n", logical.ErrPermissionDenied, err)
|
||||
}
|
||||
@@ -1166,7 +1167,7 @@ func TestBackend_allowedRoles(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err = b.HandleRequest(context.Background(), req)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -1179,7 +1180,7 @@ func TestBackend_allowedRoles(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
credsResp, err = b.HandleRequest(context.Background(), req)
|
||||
credsResp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (credsResp != nil && credsResp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, credsResp)
|
||||
}
|
||||
@@ -1200,7 +1201,7 @@ func TestBackend_allowedRoles(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err = b.HandleRequest(context.Background(), req)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -1213,7 +1214,7 @@ func TestBackend_allowedRoles(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
credsResp, err = b.HandleRequest(context.Background(), req)
|
||||
credsResp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (credsResp != nil && credsResp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, credsResp)
|
||||
}
|
||||
@@ -1234,7 +1235,7 @@ func TestBackend_allowedRoles(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err = b.HandleRequest(context.Background(), req)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -1247,7 +1248,7 @@ func TestBackend_allowedRoles(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
credsResp, err = b.HandleRequest(context.Background(), req)
|
||||
credsResp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != logical.ErrPermissionDenied {
|
||||
t.Fatalf("expected error to be:%s got:%#v\n", logical.ErrPermissionDenied, err)
|
||||
}
|
||||
@@ -1260,7 +1261,7 @@ func TestBackend_allowedRoles(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
credsResp, err = b.HandleRequest(context.Background(), req)
|
||||
credsResp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (credsResp != nil && credsResp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, credsResp)
|
||||
}
|
||||
@@ -1303,7 +1304,7 @@ func TestBackend_RotateRootCredentials(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err := b.HandleRequest(context.Background(), req)
|
||||
resp, err := b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -1320,7 +1321,7 @@ func TestBackend_RotateRootCredentials(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err = b.HandleRequest(context.Background(), req)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
@@ -1332,7 +1333,7 @@ func TestBackend_RotateRootCredentials(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
credsResp, err := b.HandleRequest(context.Background(), req)
|
||||
credsResp, err := b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (credsResp != nil && credsResp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, credsResp)
|
||||
}
|
||||
@@ -1344,7 +1345,7 @@ func TestBackend_RotateRootCredentials(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err = b.HandleRequest(context.Background(), req)
|
||||
resp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (credsResp != nil && credsResp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, credsResp)
|
||||
}
|
||||
@@ -1365,7 +1366,7 @@ func TestBackend_RotateRootCredentials(t *testing.T) {
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
credsResp, err = b.HandleRequest(context.Background(), req)
|
||||
credsResp, err = b.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil || (credsResp != nil && credsResp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, credsResp)
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
log "github.com/hashicorp/go-hclog"
|
||||
plugin "github.com/hashicorp/go-plugin"
|
||||
"github.com/hashicorp/vault/builtin/logical/database/dbplugin"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/helper/pluginutil"
|
||||
vaulthttp "github.com/hashicorp/vault/http"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
@@ -147,7 +148,7 @@ func TestPlugin_Init(t *testing.T) {
|
||||
cluster, sys := getCluster(t)
|
||||
defer cluster.Cleanup()
|
||||
|
||||
dbRaw, err := dbplugin.PluginFactory(context.Background(), "test-plugin", sys, log.NewNullLogger())
|
||||
dbRaw, err := dbplugin.PluginFactory(namespace.TestContext(), "test-plugin", sys, log.NewNullLogger())
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
@@ -171,7 +172,7 @@ func TestPlugin_CreateUser(t *testing.T) {
|
||||
cluster, sys := getCluster(t)
|
||||
defer cluster.Cleanup()
|
||||
|
||||
db, err := dbplugin.PluginFactory(context.Background(), "test-plugin", sys, log.NewNullLogger())
|
||||
db, err := dbplugin.PluginFactory(namespace.TestContext(), "test-plugin", sys, log.NewNullLogger())
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
@@ -211,7 +212,7 @@ func TestPlugin_RenewUser(t *testing.T) {
|
||||
cluster, sys := getCluster(t)
|
||||
defer cluster.Cleanup()
|
||||
|
||||
db, err := dbplugin.PluginFactory(context.Background(), "test-plugin", sys, log.NewNullLogger())
|
||||
db, err := dbplugin.PluginFactory(namespace.TestContext(), "test-plugin", sys, log.NewNullLogger())
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
@@ -245,7 +246,7 @@ func TestPlugin_RevokeUser(t *testing.T) {
|
||||
cluster, sys := getCluster(t)
|
||||
defer cluster.Cleanup()
|
||||
|
||||
db, err := dbplugin.PluginFactory(context.Background(), "test-plugin", sys, log.NewNullLogger())
|
||||
db, err := dbplugin.PluginFactory(namespace.TestContext(), "test-plugin", sys, log.NewNullLogger())
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
@@ -287,7 +288,7 @@ func TestPlugin_NetRPC_Init(t *testing.T) {
|
||||
cluster, sys := getCluster(t)
|
||||
defer cluster.Cleanup()
|
||||
|
||||
dbRaw, err := dbplugin.PluginFactory(context.Background(), "test-plugin-netRPC", sys, log.NewNullLogger())
|
||||
dbRaw, err := dbplugin.PluginFactory(namespace.TestContext(), "test-plugin-netRPC", sys, log.NewNullLogger())
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
@@ -311,7 +312,7 @@ func TestPlugin_NetRPC_CreateUser(t *testing.T) {
|
||||
cluster, sys := getCluster(t)
|
||||
defer cluster.Cleanup()
|
||||
|
||||
db, err := dbplugin.PluginFactory(context.Background(), "test-plugin-netRPC", sys, log.NewNullLogger())
|
||||
db, err := dbplugin.PluginFactory(namespace.TestContext(), "test-plugin-netRPC", sys, log.NewNullLogger())
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
@@ -351,7 +352,7 @@ func TestPlugin_NetRPC_RenewUser(t *testing.T) {
|
||||
cluster, sys := getCluster(t)
|
||||
defer cluster.Cleanup()
|
||||
|
||||
db, err := dbplugin.PluginFactory(context.Background(), "test-plugin-netRPC", sys, log.NewNullLogger())
|
||||
db, err := dbplugin.PluginFactory(namespace.TestContext(), "test-plugin-netRPC", sys, log.NewNullLogger())
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
@@ -385,7 +386,7 @@ func TestPlugin_NetRPC_RevokeUser(t *testing.T) {
|
||||
cluster, sys := getCluster(t)
|
||||
defer cluster.Cleanup()
|
||||
|
||||
db, err := dbplugin.PluginFactory(context.Background(), "test-plugin-netRPC", sys, log.NewNullLogger())
|
||||
db, err := dbplugin.PluginFactory(namespace.TestContext(), "test-plugin-netRPC", sys, log.NewNullLogger())
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
@@ -101,8 +101,8 @@ func TestAWSEndToEnd(t *testing.T) {
|
||||
Logger: logger.Named("auth.aws"),
|
||||
MountPath: "auth/aws",
|
||||
Config: map[string]interface{}{
|
||||
"role": "test",
|
||||
"type": "iam",
|
||||
"role": "test",
|
||||
"type": "iam",
|
||||
"credential_poll_interval": 1,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
credToken "github.com/hashicorp/vault/builtin/credential/token"
|
||||
credUserpass "github.com/hashicorp/vault/builtin/credential/userpass"
|
||||
"github.com/hashicorp/vault/command/token"
|
||||
"github.com/hashicorp/vault/vault"
|
||||
)
|
||||
|
||||
func testLoginCommand(tb testing.TB) (*cli.MockUi, *LoginCommand) {
|
||||
@@ -78,7 +79,7 @@ func TestLoginCommand_Run(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if l, exp := len(storedToken), 36; l != exp {
|
||||
if l, exp := len(storedToken), vault.TokenLength; l != exp {
|
||||
t.Errorf("expected token to be %d characters, was %d: %q", exp, l, storedToken)
|
||||
}
|
||||
})
|
||||
@@ -205,7 +206,7 @@ func TestLoginCommand_Run(t *testing.T) {
|
||||
|
||||
// Verify only the token was printed
|
||||
token := ui.OutputWriter.String()
|
||||
if l, exp := len(token), 36; l != exp {
|
||||
if l, exp := len(token), vault.TokenLength; l != exp {
|
||||
t.Errorf("expected token to be %d characters, was %d: %q", exp, l, token)
|
||||
}
|
||||
|
||||
|
||||
@@ -3,14 +3,15 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"io"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
uuid "github.com/hashicorp/go-uuid"
|
||||
"github.com/hashicorp/vault/helper/xor"
|
||||
"github.com/hashicorp/vault/vault"
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
@@ -40,7 +41,7 @@ func TestOperatorGenerateRootCommand_Run(t *testing.T) {
|
||||
"-init",
|
||||
"-otp", "not-a-valid-otp",
|
||||
},
|
||||
"illegal base64 data at input",
|
||||
"OTP string is wrong length",
|
||||
2,
|
||||
},
|
||||
{
|
||||
@@ -122,8 +123,8 @@ func TestOperatorGenerateRootCommand_Run(t *testing.T) {
|
||||
t.Run("decode", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
encoded := "L9MaZ/4mQanpOV6QeWd84g=="
|
||||
otp := "dIeeezkjpDUv3fy7MYPOLQ=="
|
||||
encoded := "Bxg9JQQqOCNKBRICNwMIRzo2J3cWCBRi"
|
||||
otp := "3JhHkONiyiaNYj14nnD9xZQS"
|
||||
|
||||
client, closer := testVaultServer(t)
|
||||
defer closer()
|
||||
@@ -150,7 +151,7 @@ func TestOperatorGenerateRootCommand_Run(t *testing.T) {
|
||||
w.Close()
|
||||
os.Stdout = old
|
||||
|
||||
expected := "5b54841c-c705-e59c-c6e4-a22b48e4b2cf"
|
||||
expected := "4RUmoevJ3lsLni9sTXcNnRE1"
|
||||
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
|
||||
if combined != expected {
|
||||
t.Errorf("expected %q to be %q", combined, expected)
|
||||
@@ -160,7 +161,7 @@ func TestOperatorGenerateRootCommand_Run(t *testing.T) {
|
||||
t.Run("cancel", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
otp := "dIeeezkjpDUv3fy7MYPOLQ=="
|
||||
otp := "3JhHkONiyiaNYj14nnD9xZQS"
|
||||
|
||||
client, closer := testVaultServer(t)
|
||||
defer closer()
|
||||
@@ -199,7 +200,7 @@ func TestOperatorGenerateRootCommand_Run(t *testing.T) {
|
||||
t.Run("init_otp", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
otp := "dIeeezkjpDUv3fy7MYPOLQ=="
|
||||
otp := "3JhHkONiyiaNYj14nnD9xZQS"
|
||||
|
||||
client, closer := testVaultServer(t)
|
||||
defer closer()
|
||||
@@ -296,17 +297,16 @@ func TestOperatorGenerateRootCommand_Run(t *testing.T) {
|
||||
t.Run("provide_arg", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
otp := "dIeeezkjpDUv3fy7MYPOLQ=="
|
||||
|
||||
client, keys, closer := testVaultServerUnseal(t)
|
||||
defer closer()
|
||||
|
||||
// Initialize a generation
|
||||
status, err := client.Sys().GenerateRootInit(otp, "")
|
||||
status, err := client.Sys().GenerateRootInit("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
nonce := status.Nonce
|
||||
otp := status.OTP
|
||||
|
||||
// Supply the first n-1 unseal keys
|
||||
for _, key := range keys[:len(keys)-1] {
|
||||
@@ -340,16 +340,17 @@ func TestOperatorGenerateRootCommand_Run(t *testing.T) {
|
||||
t.Fatalf("no match: %#v", match)
|
||||
}
|
||||
|
||||
tokenBytes, err := xor.XORBase64(match[0][1], otp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
token, err := uuid.FormatUUID(tokenBytes)
|
||||
tokenBytes, err := base64.RawStdEncoding.DecodeString(match[0][1])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if l, exp := len(token), 36; l != exp {
|
||||
token, err := xor.XORBytes(tokenBytes, []byte(otp))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if l, exp := len(token), vault.TokenLength; l != exp {
|
||||
t.Errorf("expected %d to be %d: %s", l, exp, token)
|
||||
}
|
||||
})
|
||||
@@ -357,17 +358,16 @@ func TestOperatorGenerateRootCommand_Run(t *testing.T) {
|
||||
t.Run("provide_stdin", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
otp := "dIeeezkjpDUv3fy7MYPOLQ=="
|
||||
|
||||
client, keys, closer := testVaultServerUnseal(t)
|
||||
defer closer()
|
||||
|
||||
// Initialize a generation
|
||||
status, err := client.Sys().GenerateRootInit(otp, "")
|
||||
status, err := client.Sys().GenerateRootInit("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
nonce := status.Nonce
|
||||
otp := status.OTP
|
||||
|
||||
// Supply the first n-1 unseal keys
|
||||
for _, key := range keys[:len(keys)-1] {
|
||||
@@ -415,16 +415,28 @@ func TestOperatorGenerateRootCommand_Run(t *testing.T) {
|
||||
t.Fatalf("no match: %#v", match)
|
||||
}
|
||||
|
||||
tokenBytes, err := xor.XORBase64(match[0][1], otp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
token, err := uuid.FormatUUID(tokenBytes)
|
||||
// encodedOTP := base64.RawStdEncoding.EncodeToString([]byte(otp))
|
||||
|
||||
// tokenBytes, err := xor.XORBase64(match[0][1], encodedOTP)
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// token, err := uuid.FormatUUID(tokenBytes)
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
|
||||
tokenBytes, err := base64.RawStdEncoding.DecodeString(match[0][1])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if l, exp := len(token), 36; l != exp {
|
||||
token, err := xor.XORBytes(tokenBytes, []byte(otp))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if l, exp := len(token), vault.TokenLength; l != exp {
|
||||
t.Errorf("expected %d to be %d: %s", l, exp, token)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
|
||||
"github.com/hashicorp/vault/api"
|
||||
"github.com/hashicorp/vault/helper/pgpkeys"
|
||||
"github.com/hashicorp/vault/vault"
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
@@ -332,7 +333,7 @@ func TestOperatorInitCommand_Run(t *testing.T) {
|
||||
root := match[0][1]
|
||||
decryptedRoot := testPGPDecrypt(t, pgpkeys.TestPrivKey1, root)
|
||||
|
||||
if l, exp := len(decryptedRoot), 36; l != exp {
|
||||
if l, exp := len(decryptedRoot), vault.TokenLength; l != exp {
|
||||
t.Errorf("expected %d to be %d", l, exp)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/hcl/hcl/printer"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/vault"
|
||||
"github.com/mitchellh/cli"
|
||||
homedir "github.com/mitchellh/go-homedir"
|
||||
@@ -85,8 +86,9 @@ func (c *PolicyFmtCommand) Run(args []string) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
// Actually parse the policy
|
||||
if _, err := vault.ParseACLPolicy(string(b)); err != nil {
|
||||
// Actually parse the policy. We always use the root namespace here because
|
||||
// we don't want to modify the results.
|
||||
if _, err := vault.ParseACLPolicy(namespace.RootNamespace, string(b)); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
@@ -35,9 +35,11 @@ import (
|
||||
sockaddr "github.com/hashicorp/go-sockaddr"
|
||||
"github.com/hashicorp/vault/audit"
|
||||
"github.com/hashicorp/vault/command/server"
|
||||
serverseal "github.com/hashicorp/vault/command/server/seal"
|
||||
"github.com/hashicorp/vault/helper/gated-writer"
|
||||
"github.com/hashicorp/vault/helper/logging"
|
||||
"github.com/hashicorp/vault/helper/mlock"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/helper/parseutil"
|
||||
"github.com/hashicorp/vault/helper/reload"
|
||||
vaulthttp "github.com/hashicorp/vault/http"
|
||||
@@ -463,7 +465,25 @@ func (c *ServerCommand) Run(args []string) int {
|
||||
info["log level"] = c.flagLogLevel
|
||||
infoKeys = append(infoKeys, "log level")
|
||||
|
||||
var seal vault.Seal = vault.NewDefaultSeal()
|
||||
sealType := "shamir"
|
||||
if config.Seal != nil || os.Getenv("VAULT_SEAL_TYPE") != "" {
|
||||
if config.Seal == nil {
|
||||
sealType = os.Getenv("VAULT_SEAL_TYPE")
|
||||
} else {
|
||||
sealType = config.Seal.Type
|
||||
}
|
||||
}
|
||||
|
||||
sealLogger := c.logger.Named(sealType)
|
||||
allLoggers = append(allLoggers, sealLogger)
|
||||
seal, sealConfigError := serverseal.ConfigureSeal(config, &infoKeys, &info, sealLogger, vault.NewDefaultSeal())
|
||||
if sealConfigError != nil {
|
||||
if !errwrap.ContainsType(sealConfigError, new(logical.KeyNotFoundError)) {
|
||||
c.UI.Error(fmt.Sprintf(
|
||||
"Error parsing Seal configuration: %s", sealConfigError))
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the seal finalizer is called, even if using verify-only
|
||||
defer func() {
|
||||
@@ -481,24 +501,26 @@ func (c *ServerCommand) Run(args []string) int {
|
||||
}
|
||||
|
||||
coreConfig := &vault.CoreConfig{
|
||||
Physical: backend,
|
||||
RedirectAddr: config.Storage.RedirectAddr,
|
||||
HAPhysical: nil,
|
||||
Seal: seal,
|
||||
AuditBackends: c.AuditBackends,
|
||||
CredentialBackends: c.CredentialBackends,
|
||||
LogicalBackends: c.LogicalBackends,
|
||||
Logger: c.logger,
|
||||
DisableCache: config.DisableCache,
|
||||
DisableMlock: config.DisableMlock,
|
||||
MaxLeaseTTL: config.MaxLeaseTTL,
|
||||
DefaultLeaseTTL: config.DefaultLeaseTTL,
|
||||
ClusterName: config.ClusterName,
|
||||
CacheSize: config.CacheSize,
|
||||
PluginDirectory: config.PluginDirectory,
|
||||
EnableUI: config.EnableUI,
|
||||
EnableRaw: config.EnableRawEndpoint,
|
||||
AllLoggers: allLoggers,
|
||||
Physical: backend,
|
||||
RedirectAddr: config.Storage.RedirectAddr,
|
||||
HAPhysical: nil,
|
||||
Seal: seal,
|
||||
AuditBackends: c.AuditBackends,
|
||||
CredentialBackends: c.CredentialBackends,
|
||||
LogicalBackends: c.LogicalBackends,
|
||||
Logger: c.logger,
|
||||
DisableCache: config.DisableCache,
|
||||
DisableMlock: config.DisableMlock,
|
||||
MaxLeaseTTL: config.MaxLeaseTTL,
|
||||
DefaultLeaseTTL: config.DefaultLeaseTTL,
|
||||
ClusterName: config.ClusterName,
|
||||
CacheSize: config.CacheSize,
|
||||
PluginDirectory: config.PluginDirectory,
|
||||
EnableUI: config.EnableUI,
|
||||
EnableRaw: config.EnableRawEndpoint,
|
||||
DisableSealWrap: config.DisableSealWrap,
|
||||
DisablePerformanceStandby: config.DisablePerformanceStandby,
|
||||
AllLoggers: allLoggers,
|
||||
}
|
||||
if c.flagDev {
|
||||
coreConfig.DevToken = c.flagDevRootTokenID
|
||||
@@ -522,6 +544,10 @@ func (c *ServerCommand) Run(args []string) int {
|
||||
return c.enableThreeNodeDevCluster(coreConfig, info, infoKeys, c.flagDevListenAddr, os.Getenv("VAULT_DEV_TEMP_DIR"))
|
||||
}
|
||||
|
||||
if c.flagDevFourCluster {
|
||||
return c.enableFourClusterDev(coreConfig, info, infoKeys, c.flagDevListenAddr, os.Getenv("VAULT_DEV_TEMP_DIR"))
|
||||
}
|
||||
|
||||
var disableClustering bool
|
||||
|
||||
// Initialize the separate HA storage backend, if it exists
|
||||
@@ -887,7 +913,7 @@ CLUSTER_SYNTHESIS_COMPLETE:
|
||||
return false
|
||||
}
|
||||
|
||||
if err := sd.RunServiceDiscovery(c.WaitGroup, c.ShutdownCh, coreConfig.RedirectAddr, activeFunc, core.Sealed); err != nil {
|
||||
if err := sd.RunServiceDiscovery(c.WaitGroup, c.ShutdownCh, coreConfig.RedirectAddr, activeFunc, core.Sealed, core.PerfStandby); err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error initializing service discovery: %v", err))
|
||||
return 1
|
||||
}
|
||||
@@ -1014,6 +1040,18 @@ CLUSTER_SYNTHESIS_COMPLETE:
|
||||
go server.Serve(ln.Listener)
|
||||
}
|
||||
|
||||
if sealConfigError != nil {
|
||||
init, err := core.Initialized(context.Background())
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error checking if core is initialized: %v", err))
|
||||
return 1
|
||||
}
|
||||
if init {
|
||||
c.UI.Error("Vault is initialized but no Seal key could be loaded")
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
if newCoreError != nil {
|
||||
c.UI.Warn(wrapAtLength(
|
||||
"WARNING! A non-fatal error occurred during initialization. Please " +
|
||||
@@ -1126,6 +1164,8 @@ CLUSTER_SYNTHESIS_COMPLETE:
|
||||
}
|
||||
|
||||
func (c *ServerCommand) enableDev(core *vault.Core, coreConfig *vault.CoreConfig) (*vault.InitResult, error) {
|
||||
ctx := namespace.ContextWithNamespace(context.Background(), namespace.RootNamespace)
|
||||
|
||||
var recoveryConfig *vault.SealConfig
|
||||
barrierConfig := &vault.SealConfig{
|
||||
SecretShares: 1,
|
||||
@@ -1143,8 +1183,6 @@ func (c *ServerCommand) enableDev(core *vault.Core, coreConfig *vault.CoreConfig
|
||||
barrierConfig.StoredShares = 1
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Initialize it with a basic single key
|
||||
init, err := core.Initialize(ctx, &vault.InitParams{
|
||||
BarrierConfig: barrierConfig,
|
||||
@@ -1210,7 +1248,7 @@ func (c *ServerCommand) enableDev(core *vault.Core, coreConfig *vault.CoreConfig
|
||||
"no_default_policy": true,
|
||||
},
|
||||
}
|
||||
resp, err := core.HandleRequest(context.Background(), req)
|
||||
resp, err := core.HandleRequest(ctx, req)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf(fmt.Sprintf("failed to create root token with ID %q: {{err}}", coreConfig.DevToken), err)
|
||||
}
|
||||
@@ -1226,7 +1264,7 @@ func (c *ServerCommand) enableDev(core *vault.Core, coreConfig *vault.CoreConfig
|
||||
req.ID = "dev-revoke-init-root"
|
||||
req.Path = "auth/token/revoke-self"
|
||||
req.Data = nil
|
||||
resp, err = core.HandleRequest(context.Background(), req)
|
||||
resp, err = core.HandleRequest(ctx, req)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("failed to revoke initial root token: {{err}}", err)
|
||||
}
|
||||
@@ -1253,7 +1291,7 @@ func (c *ServerCommand) enableDev(core *vault.Core, coreConfig *vault.CoreConfig
|
||||
},
|
||||
},
|
||||
}
|
||||
resp, err := core.HandleRequest(context.Background(), req)
|
||||
resp, err := core.HandleRequest(ctx, req)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("error upgrading default K/V store: {{err}}", err)
|
||||
}
|
||||
@@ -1317,6 +1355,8 @@ func (c *ServerCommand) enableThreeNodeDevCluster(base *vault.CoreConfig, info m
|
||||
|
||||
testCluster.Start()
|
||||
|
||||
ctx := namespace.ContextWithNamespace(context.Background(), namespace.RootNamespace)
|
||||
|
||||
if base.DevToken != "" {
|
||||
req := &logical.Request{
|
||||
ID: "dev-gen-root",
|
||||
@@ -1330,7 +1370,7 @@ func (c *ServerCommand) enableThreeNodeDevCluster(base *vault.CoreConfig, info m
|
||||
"no_default_policy": true,
|
||||
},
|
||||
}
|
||||
resp, err := testCluster.Cores[0].HandleRequest(context.Background(), req)
|
||||
resp, err := testCluster.Cores[0].HandleRequest(ctx, req)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Sprintf("failed to create root token with ID %s: %s", base.DevToken, err))
|
||||
return 1
|
||||
@@ -1349,7 +1389,7 @@ func (c *ServerCommand) enableThreeNodeDevCluster(base *vault.CoreConfig, info m
|
||||
req.ID = "dev-revoke-init-root"
|
||||
req.Path = "auth/token/revoke-self"
|
||||
req.Data = nil
|
||||
resp, err = testCluster.Cores[0].HandleRequest(context.Background(), req)
|
||||
resp, err = testCluster.Cores[0].HandleRequest(ctx, req)
|
||||
if err != nil {
|
||||
c.UI.Output(fmt.Sprintf("failed to revoke initial root token: %s", err))
|
||||
return 1
|
||||
@@ -1482,7 +1522,8 @@ func (c *ServerCommand) addPlugin(path, token string, core *vault.Core) error {
|
||||
"command": name,
|
||||
},
|
||||
}
|
||||
if _, err := core.HandleRequest(context.Background(), req); err != nil {
|
||||
ctx := namespace.ContextWithNamespace(context.Background(), namespace.RootNamespace)
|
||||
if _, err := core.HandleRequest(ctx, req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
15
command/server/seal/server_seal.go
Normal file
15
command/server/seal/server_seal.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package seal
|
||||
|
||||
import (
|
||||
log "github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/vault/command/server"
|
||||
"github.com/hashicorp/vault/vault"
|
||||
)
|
||||
|
||||
var (
|
||||
ConfigureSeal func(*server.Config, *[]string, *map[string]string, log.Logger, vault.Seal) (vault.Seal, error) = configureSeal
|
||||
)
|
||||
|
||||
func configureSeal(config *server.Config, infoKeys *[]string, info *map[string]string, logger log.Logger, inseal vault.Seal) (seal vault.Seal, err error) {
|
||||
return inseal, nil
|
||||
}
|
||||
313
command/server_devfourcluster.go
Normal file
313
command/server_devfourcluster.go
Normal file
@@ -0,0 +1,313 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
mathrand "math/rand"
|
||||
"net"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/helper/testhelpers"
|
||||
vaulthttp "github.com/hashicorp/vault/http"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/vault"
|
||||
"github.com/hashicorp/vault/version"
|
||||
testing "github.com/mitchellh/go-testing-interface"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (c *ServerCommand) enableFourClusterDev(base *vault.CoreConfig, info map[string]string, infoKeys []string, devListenAddress, tempDir string) int {
|
||||
var err error
|
||||
ctx := namespace.RootContext(nil)
|
||||
clusters := map[string]*vault.TestCluster{}
|
||||
|
||||
if base.DevToken == "" {
|
||||
base.DevToken = "root"
|
||||
}
|
||||
base.EnableRaw = true
|
||||
|
||||
// Without setting something in the future we get bombarded with warnings which are quite annoying during testing
|
||||
base.DevLicenseDuration = 6 * time.Hour
|
||||
|
||||
// Set a base temp dir
|
||||
if tempDir == "" {
|
||||
tempDir, err = ioutil.TempDir("", "vault-test-cluster-")
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Sprintf("failed to create top-level temp dir: %s", err))
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
caKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Failed to generate CA key: %s", err))
|
||||
return 1
|
||||
}
|
||||
certIPs := []net.IP{
|
||||
net.IPv6loopback,
|
||||
net.ParseIP("127.0.0.1"),
|
||||
}
|
||||
caCertTemplate := &x509.Certificate{
|
||||
Subject: pkix.Name{
|
||||
CommonName: "localhost",
|
||||
},
|
||||
DNSNames: []string{"localhost"},
|
||||
IPAddresses: certIPs,
|
||||
KeyUsage: x509.KeyUsage(x509.KeyUsageCertSign | x509.KeyUsageCRLSign),
|
||||
SerialNumber: big.NewInt(mathrand.Int63()),
|
||||
NotBefore: time.Now().Add(-30 * time.Second),
|
||||
NotAfter: time.Now().Add(262980 * time.Hour),
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: true,
|
||||
}
|
||||
caBytes, err := x509.CreateCertificate(rand.Reader, caCertTemplate, caCertTemplate, caKey.Public(), caKey)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Failed to generate certificate: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
getCluster := func(name string) error {
|
||||
factory := c.PhysicalBackends["inmem_transactional_ha"]
|
||||
backend, err := factory(nil, c.logger)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error initializing storage of type %s: %s", "inmem_transactional_ha", err))
|
||||
return errors.New("")
|
||||
}
|
||||
base.Physical = backend
|
||||
base.Seal = vault.NewDefaultSeal()
|
||||
|
||||
testCluster := vault.NewTestCluster(&testing.RuntimeT{}, base, &vault.TestClusterOptions{
|
||||
HandlerFunc: vaulthttp.Handler,
|
||||
//BaseListenAddress: c.flagDevListenAddr,
|
||||
Logger: c.logger.Named(name),
|
||||
TempDir: fmt.Sprintf("%s/%s", tempDir, name),
|
||||
CAKey: caKey,
|
||||
CACert: caBytes,
|
||||
})
|
||||
|
||||
clusters[name] = testCluster
|
||||
|
||||
for i, core := range testCluster.Cores {
|
||||
info[fmt.Sprintf("%s node %d redirect address", name, i)] = fmt.Sprintf("https://%s", core.Listeners[0].Address.String())
|
||||
infoKeys = append(infoKeys, fmt.Sprintf("%s node %d redirect address", name, i))
|
||||
core.Server.Handler = vaulthttp.Handler(&vault.HandlerProperties{
|
||||
Core: core.Core,
|
||||
})
|
||||
core.SetClusterHandler(core.Server.Handler)
|
||||
}
|
||||
|
||||
testCluster.Start()
|
||||
|
||||
req := &logical.Request{
|
||||
ID: "dev-gen-root",
|
||||
Operation: logical.UpdateOperation,
|
||||
ClientToken: testCluster.RootToken,
|
||||
Path: "auth/token/create",
|
||||
Data: map[string]interface{}{
|
||||
"id": base.DevToken,
|
||||
"policies": []string{"root"},
|
||||
"no_parent": true,
|
||||
"no_default_policy": true,
|
||||
},
|
||||
}
|
||||
resp, err := testCluster.Cores[0].HandleRequest(ctx, req)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Sprintf("failed to create root token with ID %s: %s", base.DevToken, err))
|
||||
return errors.New("")
|
||||
}
|
||||
if resp == nil {
|
||||
c.UI.Error(fmt.Sprintf("nil response when creating root token with ID %s", base.DevToken))
|
||||
return errors.New("")
|
||||
}
|
||||
if resp.Auth == nil {
|
||||
c.UI.Error(fmt.Sprintf("nil auth when creating root token with ID %s", base.DevToken))
|
||||
return errors.New("")
|
||||
}
|
||||
|
||||
testCluster.RootToken = resp.Auth.ClientToken
|
||||
|
||||
req.ID = "dev-revoke-init-root"
|
||||
req.Path = "auth/token/revoke-self"
|
||||
req.Data = nil
|
||||
resp, err = testCluster.Cores[0].HandleRequest(ctx, req)
|
||||
if err != nil {
|
||||
c.UI.Output(fmt.Sprintf("failed to revoke initial root token: %s", err))
|
||||
return errors.New("")
|
||||
}
|
||||
|
||||
for _, core := range testCluster.Cores {
|
||||
core.Client.SetToken(base.DevToken)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
err = getCluster("perf-pri")
|
||||
if err != nil {
|
||||
return 1
|
||||
}
|
||||
err = getCluster("perf-pri-dr")
|
||||
if err != nil {
|
||||
return 1
|
||||
}
|
||||
err = getCluster("perf-sec")
|
||||
if err != nil {
|
||||
return 1
|
||||
}
|
||||
err = getCluster("perf-sec-dr")
|
||||
if err != nil {
|
||||
return 1
|
||||
}
|
||||
|
||||
clusterCleanup := func() {
|
||||
for name, cluster := range clusters {
|
||||
cluster.Cleanup()
|
||||
|
||||
// Shutdown will wait until after Vault is sealed, which means the
|
||||
// request forwarding listeners will also be closed (and also
|
||||
// waited for).
|
||||
for _, core := range cluster.Cores {
|
||||
if err := core.Shutdown(); err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error with cluster %s core shutdown: %s", name, err))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defer c.cleanupGuard.Do(clusterCleanup)
|
||||
|
||||
info["cluster parameters path"] = tempDir
|
||||
infoKeys = append(infoKeys, "cluster parameters path")
|
||||
|
||||
verInfo := version.GetVersion()
|
||||
info["version"] = verInfo.FullVersionNumber(false)
|
||||
infoKeys = append(infoKeys, "version")
|
||||
if verInfo.Revision != "" {
|
||||
info["version sha"] = strings.Trim(verInfo.Revision, "'")
|
||||
infoKeys = append(infoKeys, "version sha")
|
||||
}
|
||||
infoKeys = append(infoKeys, "cgo")
|
||||
info["cgo"] = "disabled"
|
||||
if version.CgoEnabled {
|
||||
info["cgo"] = "enabled"
|
||||
}
|
||||
|
||||
// Server configuration output
|
||||
padding := 40
|
||||
sort.Strings(infoKeys)
|
||||
c.UI.Output("==> Vault server configuration:\n")
|
||||
for _, k := range infoKeys {
|
||||
c.UI.Output(fmt.Sprintf(
|
||||
"%s%s: %s",
|
||||
strings.Repeat(" ", padding-len(k)),
|
||||
strings.Title(k),
|
||||
info[k]))
|
||||
}
|
||||
c.UI.Output("")
|
||||
|
||||
// Set the token
|
||||
tokenHelper, err := c.TokenHelper()
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error getting token helper: %s", err))
|
||||
return 1
|
||||
}
|
||||
if err := tokenHelper.Store(base.DevToken); err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error storing in token helper: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(filepath.Join(tempDir, "root_token"), []byte(base.DevToken), 0755); err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error writing token to tempfile: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
c.UI.Output(fmt.Sprintf(
|
||||
"\nRoot Token: %s\n", base.DevToken,
|
||||
))
|
||||
|
||||
for i, key := range clusters["perf-pri"].BarrierKeys {
|
||||
c.UI.Output(fmt.Sprintf(
|
||||
"Unseal Key %d: %s",
|
||||
i+1, base64.StdEncoding.EncodeToString(key),
|
||||
))
|
||||
}
|
||||
|
||||
c.UI.Output(fmt.Sprintf(
|
||||
"\nUseful env vars:\n"+
|
||||
"export VAULT_TOKEN=%s\n"+
|
||||
"export VAULT_CACERT=%s/perf-pri/ca_cert.pem\n",
|
||||
base.DevToken,
|
||||
tempDir,
|
||||
))
|
||||
c.UI.Output(fmt.Sprintf("Addresses of initial active nodes:"))
|
||||
clusterNames := []string{}
|
||||
for name := range clusters {
|
||||
clusterNames = append(clusterNames, name)
|
||||
}
|
||||
sort.Strings(clusterNames)
|
||||
for _, name := range clusterNames {
|
||||
c.UI.Output(fmt.Sprintf(
|
||||
"%s:\n"+
|
||||
"export VAULT_ADDR=%s\n",
|
||||
name,
|
||||
clusters[name].Cores[0].Client.Address(),
|
||||
))
|
||||
}
|
||||
|
||||
// Output the header that the server has started
|
||||
c.UI.Output("==> Vault clusters started! Log data will stream in below:\n")
|
||||
|
||||
// Inform any tests that the server is ready
|
||||
select {
|
||||
case c.startedCh <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
|
||||
// Release the log gate.
|
||||
c.logGate.Flush()
|
||||
|
||||
testhelpers.SetupFourClusterReplication(&testing.RuntimeT{},
|
||||
clusters["perf-pri"],
|
||||
clusters["perf-sec"],
|
||||
clusters["perf-pri-dr"],
|
||||
clusters["perf-sec-dr"],
|
||||
)
|
||||
|
||||
// Wait for shutdown
|
||||
shutdownTriggered := false
|
||||
|
||||
for !shutdownTriggered {
|
||||
select {
|
||||
case <-c.ShutdownCh:
|
||||
c.UI.Output("==> Vault shutdown triggered")
|
||||
|
||||
// Stop the listners so that we don't process further client requests.
|
||||
c.cleanupGuard.Do(clusterCleanup)
|
||||
|
||||
shutdownTriggered = true
|
||||
|
||||
case <-c.SighupCh:
|
||||
c.UI.Output("==> Vault reload triggered")
|
||||
for name, cluster := range clusters {
|
||||
for _, core := range cluster.Cores {
|
||||
if err := c.Reload(core.ReloadFuncsLock, core.ReloadFuncs, nil); err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error(s) were encountered during reload of cluster %s cores: %s", name, err))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
@@ -38,7 +38,7 @@ func (m *Request) Reset() { *m = Request{} }
|
||||
func (m *Request) String() string { return proto.CompactTextString(m) }
|
||||
func (*Request) ProtoMessage() {}
|
||||
func (*Request) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_types_7ccf0973261c4726, []int{0}
|
||||
return fileDescriptor_types_9f616cf8b37ed00d, []int{0}
|
||||
}
|
||||
func (m *Request) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Request.Unmarshal(m, b)
|
||||
@@ -129,7 +129,7 @@ func (m *URL) Reset() { *m = URL{} }
|
||||
func (m *URL) String() string { return proto.CompactTextString(m) }
|
||||
func (*URL) ProtoMessage() {}
|
||||
func (*URL) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_types_7ccf0973261c4726, []int{1}
|
||||
return fileDescriptor_types_9f616cf8b37ed00d, []int{1}
|
||||
}
|
||||
func (m *URL) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_URL.Unmarshal(m, b)
|
||||
@@ -209,7 +209,7 @@ func (m *HeaderEntry) Reset() { *m = HeaderEntry{} }
|
||||
func (m *HeaderEntry) String() string { return proto.CompactTextString(m) }
|
||||
func (*HeaderEntry) ProtoMessage() {}
|
||||
func (*HeaderEntry) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_types_7ccf0973261c4726, []int{2}
|
||||
return fileDescriptor_types_9f616cf8b37ed00d, []int{2}
|
||||
}
|
||||
func (m *HeaderEntry) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_HeaderEntry.Unmarshal(m, b)
|
||||
@@ -245,6 +245,7 @@ type Response struct {
|
||||
// Added in 0.6.2 to ensure that the content-type is set appropriately, as
|
||||
// well as any other information
|
||||
HeaderEntries map[string]*HeaderEntry `protobuf:"bytes,4,rep,name=header_entries,json=headerEntries,proto3" json:"header_entries,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
LastRemoteWal uint64 `protobuf:"varint,5,opt,name=last_remote_wal,json=lastRemoteWal,proto3" json:"last_remote_wal,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
@@ -254,7 +255,7 @@ func (m *Response) Reset() { *m = Response{} }
|
||||
func (m *Response) String() string { return proto.CompactTextString(m) }
|
||||
func (*Response) ProtoMessage() {}
|
||||
func (*Response) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_types_7ccf0973261c4726, []int{3}
|
||||
return fileDescriptor_types_9f616cf8b37ed00d, []int{3}
|
||||
}
|
||||
func (m *Response) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Response.Unmarshal(m, b)
|
||||
@@ -295,6 +296,13 @@ func (m *Response) GetHeaderEntries() map[string]*HeaderEntry {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Response) GetLastRemoteWal() uint64 {
|
||||
if m != nil {
|
||||
return m.LastRemoteWal
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Request)(nil), "forwarding.Request")
|
||||
proto.RegisterMapType((map[string]*HeaderEntry)(nil), "forwarding.Request.HeaderEntriesEntry")
|
||||
@@ -305,39 +313,41 @@ func init() {
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("helper/forwarding/types.proto", fileDescriptor_types_7ccf0973261c4726)
|
||||
proto.RegisterFile("helper/forwarding/types.proto", fileDescriptor_types_9f616cf8b37ed00d)
|
||||
}
|
||||
|
||||
var fileDescriptor_types_7ccf0973261c4726 = []byte{
|
||||
// 475 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x53, 0x4f, 0x8f, 0xd3, 0x3e,
|
||||
0x10, 0x55, 0x9a, 0x6e, 0xff, 0x4c, 0x77, 0x7f, 0xbf, 0xc5, 0x07, 0x30, 0x8b, 0x10, 0xa1, 0x12,
|
||||
0x10, 0x09, 0x48, 0xa4, 0x72, 0x41, 0xdc, 0x60, 0x85, 0xc4, 0x61, 0x41, 0x60, 0x69, 0x0f, 0x70,
|
||||
0x89, 0xdc, 0x78, 0x5a, 0x47, 0x34, 0x75, 0x6a, 0x3b, 0x5b, 0xe5, 0x63, 0xf1, 0x9d, 0x38, 0xf1,
|
||||
0x29, 0x90, 0x9d, 0xb0, 0x0d, 0x5a, 0x21, 0x4e, 0x9c, 0x32, 0xef, 0xbd, 0xc9, 0x78, 0xde, 0x8c,
|
||||
0x0d, 0xf7, 0x25, 0x6e, 0x2a, 0xd4, 0xe9, 0x4a, 0xe9, 0x3d, 0xd7, 0xa2, 0xd8, 0xae, 0x53, 0xdb,
|
||||
0x54, 0x68, 0x92, 0x4a, 0x2b, 0xab, 0x08, 0x1c, 0xf8, 0xf9, 0xf7, 0x01, 0x8c, 0x19, 0xee, 0x6a,
|
||||
0x34, 0x96, 0xdc, 0x86, 0x51, 0x89, 0x56, 0x2a, 0x41, 0x07, 0x51, 0x10, 0x4f, 0x59, 0x87, 0xc8,
|
||||
0x43, 0x08, 0x6b, 0xbd, 0xa1, 0x61, 0x14, 0xc4, 0xb3, 0xc5, 0xff, 0xc9, 0xe1, 0xef, 0xe4, 0x92,
|
||||
0x5d, 0x30, 0xa7, 0x91, 0xf7, 0xf0, 0x9f, 0x44, 0x2e, 0x50, 0x67, 0xb8, 0xb5, 0xba, 0x40, 0x43,
|
||||
0x87, 0x51, 0x18, 0xcf, 0x16, 0x8f, 0xfb, 0xd9, 0xdd, 0x39, 0xc9, 0x3b, 0x9f, 0xf9, 0xb6, 0x4d,
|
||||
0x74, 0x9f, 0x86, 0x9d, 0xc8, 0x3e, 0x47, 0x08, 0x0c, 0x97, 0x4a, 0x34, 0xf4, 0x28, 0x0a, 0xe2,
|
||||
0x63, 0xe6, 0x63, 0xc7, 0x49, 0x65, 0x2c, 0x1d, 0xf9, 0xde, 0x7c, 0x4c, 0x1e, 0xc0, 0x4c, 0x63,
|
||||
0xa9, 0x2c, 0x66, 0x5c, 0x08, 0x4d, 0xc7, 0x5e, 0x82, 0x96, 0x7a, 0x2d, 0x84, 0x26, 0x4f, 0xe1,
|
||||
0x56, 0x85, 0xa8, 0xb3, 0x1c, 0xb5, 0x2d, 0x56, 0x45, 0xce, 0x2d, 0x1a, 0x3a, 0x89, 0xc2, 0xf8,
|
||||
0x98, 0x9d, 0x3a, 0xe1, 0xbc, 0xc7, 0x9f, 0x7d, 0x06, 0x72, 0xb3, 0x35, 0x72, 0x0a, 0xe1, 0x57,
|
||||
0x6c, 0x68, 0xe0, 0x6b, 0xbb, 0x90, 0x3c, 0x87, 0xa3, 0x2b, 0xbe, 0xa9, 0xd1, 0x8f, 0x69, 0xb6,
|
||||
0xb8, 0xd3, 0xf7, 0x78, 0x28, 0xd0, 0xb0, 0x36, 0xeb, 0xd5, 0xe0, 0x65, 0x30, 0xff, 0x16, 0x40,
|
||||
0x78, 0xc9, 0x2e, 0xdc, 0x88, 0x4d, 0x2e, 0xb1, 0xc4, 0xae, 0x5e, 0x87, 0x1c, 0xaf, 0x2a, 0xbe,
|
||||
0xeb, 0x6a, 0x4e, 0x59, 0x87, 0xae, 0x4d, 0x0f, 0x7b, 0xa6, 0x09, 0x0c, 0x2b, 0x6e, 0xa5, 0x1f,
|
||||
0xce, 0x94, 0xf9, 0x98, 0xdc, 0x85, 0x89, 0xe6, 0xfb, 0xcc, 0xf3, 0xed, 0x80, 0xc6, 0x9a, 0xef,
|
||||
0x3f, 0x3a, 0xe9, 0x1e, 0x4c, 0x9d, 0xb4, 0xab, 0x51, 0x37, 0x74, 0xe2, 0x35, 0x97, 0xfb, 0xc9,
|
||||
0x61, 0x72, 0x06, 0x93, 0x95, 0xe6, 0xeb, 0x12, 0xb7, 0x96, 0x4e, 0x5b, 0xed, 0x17, 0x9e, 0x3f,
|
||||
0x82, 0x59, 0xcf, 0x8d, 0x6b, 0xd1, 0xfb, 0x31, 0x34, 0x88, 0x42, 0xd7, 0x62, 0x8b, 0xe6, 0x3f,
|
||||
0x02, 0x98, 0x30, 0x34, 0x95, 0xda, 0x1a, 0x74, 0x0b, 0x31, 0x96, 0xdb, 0xda, 0x64, 0xb9, 0x12,
|
||||
0xad, 0x99, 0x13, 0x06, 0x2d, 0x75, 0xae, 0x04, 0x5e, 0x6f, 0x36, 0xec, 0x6d, 0xf6, 0xc3, 0x1f,
|
||||
0x2e, 0xcf, 0x93, 0xdf, 0x2f, 0x4f, 0x7b, 0xc4, 0xdf, 0x6f, 0xcf, 0x3f, 0xdc, 0xe3, 0x9b, 0xe4,
|
||||
0xcb, 0xb3, 0x75, 0x61, 0x65, 0xbd, 0x4c, 0x72, 0x55, 0xa6, 0x92, 0x1b, 0x59, 0xe4, 0x4a, 0x57,
|
||||
0xe9, 0x15, 0xaf, 0x37, 0x36, 0xbd, 0xf1, 0xec, 0x96, 0x23, 0xff, 0xe2, 0x5e, 0xfc, 0x0c, 0x00,
|
||||
0x00, 0xff, 0xff, 0x03, 0xfa, 0xd9, 0x51, 0x92, 0x03, 0x00, 0x00,
|
||||
var fileDescriptor_types_9f616cf8b37ed00d = []byte{
|
||||
// 497 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x53, 0xc1, 0x6e, 0xd3, 0x40,
|
||||
0x10, 0x95, 0xe3, 0xb4, 0x49, 0x26, 0x0d, 0x2d, 0x7b, 0x80, 0xa5, 0x08, 0x61, 0x22, 0x51, 0x22,
|
||||
0x01, 0x8e, 0x14, 0x2e, 0x88, 0x1b, 0x54, 0x48, 0x1c, 0x0a, 0x82, 0x95, 0x2a, 0x04, 0x17, 0x6b,
|
||||
0xe3, 0x9d, 0x64, 0x2d, 0xec, 0xac, 0xb3, 0xbb, 0x6e, 0xe4, 0xdf, 0xe0, 0x4f, 0xf8, 0x27, 0x3e,
|
||||
0x04, 0xed, 0xda, 0x34, 0x46, 0x15, 0x12, 0x17, 0x4e, 0x99, 0xf7, 0xde, 0x64, 0x3c, 0x6f, 0x66,
|
||||
0x16, 0x1e, 0x48, 0xcc, 0x4b, 0xd4, 0xf3, 0x95, 0xd2, 0x3b, 0xae, 0x45, 0xb6, 0x59, 0xcf, 0x6d,
|
||||
0x5d, 0xa2, 0x89, 0x4b, 0xad, 0xac, 0x22, 0xb0, 0xe7, 0xa7, 0x3f, 0x7b, 0x30, 0x60, 0xb8, 0xad,
|
||||
0xd0, 0x58, 0x72, 0x07, 0x0e, 0x0b, 0xb4, 0x52, 0x09, 0xda, 0x8b, 0x82, 0xd9, 0x88, 0xb5, 0x88,
|
||||
0x3c, 0x82, 0xb0, 0xd2, 0x39, 0x0d, 0xa3, 0x60, 0x36, 0x5e, 0x1c, 0xc7, 0xfb, 0x7f, 0xc7, 0x97,
|
||||
0xec, 0x82, 0x39, 0x8d, 0xbc, 0x87, 0x5b, 0x12, 0xb9, 0x40, 0x9d, 0xe0, 0xc6, 0xea, 0x0c, 0x0d,
|
||||
0xed, 0x47, 0xe1, 0x6c, 0xbc, 0x38, 0xeb, 0x66, 0xb7, 0xdf, 0x89, 0xdf, 0xf9, 0xcc, 0xb7, 0x4d,
|
||||
0xa2, 0xfb, 0xa9, 0xd9, 0x44, 0x76, 0x39, 0x42, 0xa0, 0xbf, 0x54, 0xa2, 0xa6, 0x07, 0x51, 0x30,
|
||||
0x3b, 0x62, 0x3e, 0x76, 0x9c, 0x54, 0xc6, 0xd2, 0x43, 0xdf, 0x9b, 0x8f, 0xc9, 0x43, 0x18, 0x6b,
|
||||
0x2c, 0x94, 0xc5, 0x84, 0x0b, 0xa1, 0xe9, 0xc0, 0x4b, 0xd0, 0x50, 0xaf, 0x85, 0xd0, 0xe4, 0x29,
|
||||
0xdc, 0x2e, 0x11, 0x75, 0x92, 0xa2, 0xb6, 0xd9, 0x2a, 0x4b, 0xb9, 0x45, 0x43, 0x87, 0x51, 0x38,
|
||||
0x3b, 0x62, 0x27, 0x4e, 0x38, 0xef, 0xf0, 0xa7, 0x5f, 0x80, 0xdc, 0x6c, 0x8d, 0x9c, 0x40, 0xf8,
|
||||
0x0d, 0x6b, 0x1a, 0xf8, 0xda, 0x2e, 0x24, 0xcf, 0xe1, 0xe0, 0x8a, 0xe7, 0x15, 0xfa, 0x31, 0x8d,
|
||||
0x17, 0x77, 0xbb, 0x1e, 0xf7, 0x05, 0x6a, 0xd6, 0x64, 0xbd, 0xea, 0xbd, 0x0c, 0xa6, 0x3f, 0x02,
|
||||
0x08, 0x2f, 0xd9, 0x85, 0x1b, 0xb1, 0x49, 0x25, 0x16, 0xd8, 0xd6, 0x6b, 0x91, 0xe3, 0x55, 0xc9,
|
||||
0xb7, 0x6d, 0xcd, 0x11, 0x6b, 0xd1, 0xb5, 0xe9, 0x7e, 0xc7, 0x34, 0x81, 0x7e, 0xc9, 0xad, 0xf4,
|
||||
0xc3, 0x19, 0x31, 0x1f, 0x93, 0x7b, 0x30, 0xd4, 0x7c, 0x97, 0x78, 0xbe, 0x19, 0xd0, 0x40, 0xf3,
|
||||
0xdd, 0x47, 0x27, 0xdd, 0x87, 0x91, 0x93, 0xb6, 0x15, 0xea, 0x9a, 0x0e, 0xbd, 0xe6, 0x72, 0x3f,
|
||||
0x39, 0x4c, 0x4e, 0x61, 0xb8, 0xd2, 0x7c, 0x5d, 0xe0, 0xc6, 0xd2, 0x51, 0xa3, 0xfd, 0xc6, 0xd3,
|
||||
0xc7, 0x30, 0xee, 0xb8, 0x71, 0x2d, 0x7a, 0x3f, 0x86, 0x06, 0x51, 0xe8, 0x5a, 0x6c, 0xd0, 0xf4,
|
||||
0x7b, 0x0f, 0x86, 0x0c, 0x4d, 0xa9, 0x36, 0x06, 0xdd, 0x42, 0x8c, 0xe5, 0xb6, 0x32, 0x49, 0xaa,
|
||||
0x44, 0x63, 0x66, 0xc2, 0xa0, 0xa1, 0xce, 0x95, 0xc0, 0xeb, 0xcd, 0x86, 0x9d, 0xcd, 0x7e, 0xf8,
|
||||
0xcb, 0xf1, 0x3c, 0xf9, 0xf3, 0x78, 0x9a, 0x4f, 0xfc, 0xc3, 0xf5, 0x9c, 0xc1, 0x71, 0xce, 0x8d,
|
||||
0x4d, 0xda, 0xd3, 0xd8, 0xf1, 0xdc, 0xcf, 0xaa, 0xcf, 0x26, 0x8e, 0x66, 0x9e, 0xfd, 0xcc, 0xf3,
|
||||
0xff, 0xb8, 0xef, 0x37, 0xf1, 0xd7, 0x67, 0xeb, 0xcc, 0xca, 0x6a, 0x19, 0xa7, 0xaa, 0x98, 0x4b,
|
||||
0x6e, 0x64, 0x96, 0x2a, 0x5d, 0xce, 0xaf, 0x78, 0x95, 0xdb, 0xf9, 0x8d, 0xe7, 0xb9, 0x3c, 0xf4,
|
||||
0x2f, 0xf3, 0xc5, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xfd, 0xbd, 0xb1, 0xfc, 0xba, 0x03, 0x00,
|
||||
0x00,
|
||||
}
|
||||
|
||||
@@ -45,4 +45,5 @@ message Response {
|
||||
// Added in 0.6.2 to ensure that the content-type is set appropriately, as
|
||||
// well as any other information
|
||||
map<string, HeaderEntry> header_entries = 4;
|
||||
uint64 last_remote_wal = 5;
|
||||
}
|
||||
|
||||
69
helper/identity/mfa/types.pb.go
Normal file
69
helper/identity/mfa/types.pb.go
Normal file
@@ -0,0 +1,69 @@
|
||||
// +build !enterprise
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: helper/identity/mfa/types.proto
|
||||
|
||||
package mfa // import "github.com/hashicorp/vault/helper/identity/mfa"
|
||||
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
type Secret struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Secret) Reset() { *m = Secret{} }
|
||||
func (m *Secret) String() string { return proto.CompactTextString(m) }
|
||||
func (*Secret) ProtoMessage() {}
|
||||
func (*Secret) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_types_13bac6e8bbc072d1, []int{0}
|
||||
}
|
||||
func (m *Secret) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Secret.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Secret) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Secret.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (dst *Secret) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Secret.Merge(dst, src)
|
||||
}
|
||||
func (m *Secret) XXX_Size() int {
|
||||
return xxx_messageInfo_Secret.Size(m)
|
||||
}
|
||||
func (m *Secret) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Secret.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Secret proto.InternalMessageInfo
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Secret)(nil), "mfa.Secret")
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("helper/identity/mfa/types.proto", fileDescriptor_types_13bac6e8bbc072d1)
|
||||
}
|
||||
|
||||
var fileDescriptor_types_13bac6e8bbc072d1 = []byte{
|
||||
// 111 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xcf, 0x48, 0xcd, 0x29,
|
||||
0x48, 0x2d, 0xd2, 0xcf, 0x4c, 0x49, 0xcd, 0x2b, 0xc9, 0x2c, 0xa9, 0xd4, 0xcf, 0x4d, 0x4b, 0xd4,
|
||||
0x2f, 0xa9, 0x2c, 0x48, 0x2d, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0xce, 0x4d, 0x4b,
|
||||
0x54, 0xe2, 0xe0, 0x62, 0x0b, 0x4e, 0x4d, 0x2e, 0x4a, 0x2d, 0x71, 0x32, 0x88, 0xd2, 0x4b, 0xcf,
|
||||
0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0xcf, 0x48, 0x2c, 0xce, 0xc8, 0x4c, 0xce,
|
||||
0x2f, 0x2a, 0xd0, 0x2f, 0x4b, 0x2c, 0xcd, 0x29, 0xd1, 0xc7, 0x62, 0x58, 0x12, 0x1b, 0xd8, 0x1c,
|
||||
0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xc9, 0x73, 0x5e, 0x6a, 0x00, 0x00, 0x00,
|
||||
}
|
||||
7
helper/identity/mfa/types.proto
Normal file
7
helper/identity/mfa/types.proto
Normal file
@@ -0,0 +1,7 @@
|
||||
syntax = "proto3";
|
||||
|
||||
option go_package = "github.com/hashicorp/vault/helper/identity/mfa";
|
||||
|
||||
package mfa;
|
||||
|
||||
message Secret {}
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -18,6 +20,7 @@ type PopulateStringInput struct {
|
||||
String string
|
||||
Entity *Entity
|
||||
Groups []*Group
|
||||
Namespace *namespace.Namespace
|
||||
}
|
||||
|
||||
func PopulateString(p *PopulateStringInput) (bool, string, error) {
|
||||
@@ -58,7 +61,7 @@ func PopulateString(p *PopulateStringInput) (bool, string, error) {
|
||||
case 2:
|
||||
subst = true
|
||||
if !p.ValidityCheckOnly {
|
||||
tmplStr, err := performTemplating(strings.TrimSpace(splitPiece[0]), p.Entity, p.Groups)
|
||||
tmplStr, err := performTemplating(p.Namespace, strings.TrimSpace(splitPiece[0]), p.Entity, p.Groups)
|
||||
if err != nil {
|
||||
return false, "", err
|
||||
}
|
||||
@@ -73,7 +76,7 @@ func PopulateString(p *PopulateStringInput) (bool, string, error) {
|
||||
return subst, b.String(), nil
|
||||
}
|
||||
|
||||
func performTemplating(input string, entity *Entity, groups []*Group) (string, error) {
|
||||
func performTemplating(ns *namespace.Namespace, input string, entity *Entity, groups []*Group) (string, error) {
|
||||
performAliasTemplating := func(trimmed string, alias *Alias) (string, error) {
|
||||
switch {
|
||||
case trimmed == "id":
|
||||
@@ -151,9 +154,15 @@ func performTemplating(input string, entity *Entity, groups []*Group) (string, e
|
||||
}
|
||||
var found *Group
|
||||
for _, group := range groups {
|
||||
compare := group.Name
|
||||
var compare string
|
||||
if ids {
|
||||
compare = group.ID
|
||||
} else {
|
||||
if ns != nil && group.NamespaceID == ns.ID {
|
||||
compare = group.Name
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if compare == accessorSplit[0] {
|
||||
|
||||
@@ -3,6 +3,8 @@ package identity
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
)
|
||||
|
||||
func TestPopulate_Basic(t *testing.T) {
|
||||
@@ -165,9 +167,10 @@ func TestPopulate_Basic(t *testing.T) {
|
||||
var groups []*Group
|
||||
if test.groupName != "" {
|
||||
groups = append(groups, &Group{
|
||||
ID: "groupID",
|
||||
Name: test.groupName,
|
||||
Metadata: test.groupMetadata,
|
||||
ID: "groupID",
|
||||
Name: test.groupName,
|
||||
Metadata: test.groupMetadata,
|
||||
NamespaceID: namespace.RootNamespace.ID,
|
||||
})
|
||||
}
|
||||
subst, out, err := PopulateString(&PopulateStringInput{
|
||||
@@ -175,6 +178,7 @@ func TestPopulate_Basic(t *testing.T) {
|
||||
String: test.input,
|
||||
Entity: entity,
|
||||
Groups: groups,
|
||||
Namespace: namespace.RootNamespace,
|
||||
})
|
||||
if err != nil {
|
||||
if test.err == nil {
|
||||
|
||||
@@ -7,6 +7,7 @@ import proto "github.com/golang/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
import timestamp "github.com/golang/protobuf/ptypes/timestamp"
|
||||
import mfa "github.com/hashicorp/vault/helper/identity/mfa"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
@@ -56,7 +57,11 @@ type Group struct {
|
||||
// Memberships of the internal groups can be managed over the API whereas
|
||||
// the memberships on the external group --for which a corresponding alias
|
||||
// will be set-- will be managed automatically.
|
||||
Type string `sentinel:"" protobuf:"bytes,12,opt,name=type,proto3" json:"type,omitempty"`
|
||||
Type string `sentinel:"" protobuf:"bytes,12,opt,name=type,proto3" json:"type,omitempty"`
|
||||
// NamespaceID is the identifier of the namespace to which this group
|
||||
// belongs to. Do not return this value over the API when reading the
|
||||
// group.
|
||||
NamespaceID string `sentinel:"" protobuf:"bytes,13,opt,name=namespace_id,json=namespaceID,proto3" json:"namespace_id,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
@@ -66,7 +71,7 @@ func (m *Group) Reset() { *m = Group{} }
|
||||
func (m *Group) String() string { return proto.CompactTextString(m) }
|
||||
func (*Group) ProtoMessage() {}
|
||||
func (*Group) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_types_0360db4a8e77dd9b, []int{0}
|
||||
return fileDescriptor_types_7c8884717ecd36e8, []int{0}
|
||||
}
|
||||
func (m *Group) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Group.Unmarshal(m, b)
|
||||
@@ -170,6 +175,13 @@ func (m *Group) GetType() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Group) GetNamespaceID() string {
|
||||
if m != nil {
|
||||
return m.NamespaceID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Entity represents an entity that gets persisted and indexed.
|
||||
// Entity is fundamentally composed of zero or many aliases.
|
||||
type Entity struct {
|
||||
@@ -211,9 +223,16 @@ type Entity struct {
|
||||
// the entities belonging to a particular bucket during invalidation of the
|
||||
// storage key.
|
||||
BucketKeyHash string `sentinel:"" protobuf:"bytes,9,opt,name=bucket_key_hash,json=bucketKeyHash,proto3" json:"bucket_key_hash,omitempty"`
|
||||
// MFASecrets holds the MFA secrets indexed by the identifier of the MFA
|
||||
// method configuration.
|
||||
MFASecrets map[string]*mfa.Secret `sentinel:"" protobuf:"bytes,10,rep,name=mfa_secrets,json=mfaSecrets,proto3" json:"mfa_secrets,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
// Disabled indicates whether tokens associated with the account should not
|
||||
// be able to be used
|
||||
Disabled bool `sentinel:"" protobuf:"varint,11,opt,name=disabled,proto3" json:"disabled,omitempty"`
|
||||
Disabled bool `sentinel:"" protobuf:"varint,11,opt,name=disabled,proto3" json:"disabled,omitempty"`
|
||||
// NamespaceID is the identifier of the namespace to which this entity
|
||||
// belongs to. Do not return this value over the API when reading the
|
||||
// entity.
|
||||
NamespaceID string `sentinel:"" protobuf:"bytes,12,opt,name=namespace_id,json=namespaceID,proto3" json:"namespace_id,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
@@ -223,7 +242,7 @@ func (m *Entity) Reset() { *m = Entity{} }
|
||||
func (m *Entity) String() string { return proto.CompactTextString(m) }
|
||||
func (*Entity) ProtoMessage() {}
|
||||
func (*Entity) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_types_0360db4a8e77dd9b, []int{1}
|
||||
return fileDescriptor_types_7c8884717ecd36e8, []int{1}
|
||||
}
|
||||
func (m *Entity) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Entity.Unmarshal(m, b)
|
||||
@@ -306,6 +325,13 @@ func (m *Entity) GetBucketKeyHash() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Entity) GetMFASecrets() map[string]*mfa.Secret {
|
||||
if m != nil {
|
||||
return m.MFASecrets
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Entity) GetDisabled() bool {
|
||||
if m != nil {
|
||||
return m.Disabled
|
||||
@@ -313,6 +339,13 @@ func (m *Entity) GetDisabled() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *Entity) GetNamespaceID() string {
|
||||
if m != nil {
|
||||
return m.NamespaceID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Alias represents the alias that gets stored inside of the
|
||||
// entity object in storage and also represents in an in-memory index of an
|
||||
// alias object.
|
||||
@@ -349,16 +382,19 @@ type Alias struct {
|
||||
LastUpdateTime *timestamp.Timestamp `sentinel:"" protobuf:"bytes,9,opt,name=last_update_time,json=lastUpdateTime,proto3" json:"last_update_time,omitempty"`
|
||||
// MergedFromCanonicalIDs is the FIFO history of merging activity
|
||||
MergedFromCanonicalIDs []string `sentinel:"" protobuf:"bytes,10,rep,name=merged_from_canonical_ids,json=mergedFromCanonicalIds,proto3" json:"merged_from_canonical_ids,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
// NamespaceID is the identifier of the namespace to which this alias
|
||||
// belongs.
|
||||
NamespaceID string `sentinel:"" protobuf:"bytes,11,opt,name=namespace_id,json=namespaceID,proto3" json:"namespace_id,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Alias) Reset() { *m = Alias{} }
|
||||
func (m *Alias) String() string { return proto.CompactTextString(m) }
|
||||
func (*Alias) ProtoMessage() {}
|
||||
func (*Alias) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_types_0360db4a8e77dd9b, []int{2}
|
||||
return fileDescriptor_types_7c8884717ecd36e8, []int{2}
|
||||
}
|
||||
func (m *Alias) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Alias.Unmarshal(m, b)
|
||||
@@ -448,58 +484,306 @@ func (m *Alias) GetMergedFromCanonicalIDs() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Alias) GetNamespaceID() string {
|
||||
if m != nil {
|
||||
return m.NamespaceID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Deprecated. Retained for backwards compatibility.
|
||||
type EntityStorageEntry struct {
|
||||
Personas []*PersonaIndexEntry `sentinel:"" protobuf:"bytes,1,rep,name=personas,proto3" json:"personas,omitempty"`
|
||||
ID string `sentinel:"" protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Name string `sentinel:"" protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Metadata map[string]string `sentinel:"" protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
CreationTime *timestamp.Timestamp `sentinel:"" protobuf:"bytes,5,opt,name=creation_time,json=creationTime,proto3" json:"creation_time,omitempty"`
|
||||
LastUpdateTime *timestamp.Timestamp `sentinel:"" protobuf:"bytes,6,opt,name=last_update_time,json=lastUpdateTime,proto3" json:"last_update_time,omitempty"`
|
||||
MergedEntityIDs []string `sentinel:"" protobuf:"bytes,7,rep,name=merged_entity_ids,json=mergedEntityIDs,proto3" json:"merged_entity_ids,omitempty"`
|
||||
Policies []string `sentinel:"" protobuf:"bytes,8,rep,name=policies,proto3" json:"policies,omitempty"`
|
||||
BucketKeyHash string `sentinel:"" protobuf:"bytes,9,opt,name=bucket_key_hash,json=bucketKeyHash,proto3" json:"bucket_key_hash,omitempty"`
|
||||
MFASecrets map[string]*mfa.Secret `sentinel:"" protobuf:"bytes,10,rep,name=mfa_secrets,json=mfaSecrets,proto3" json:"mfa_secrets,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *EntityStorageEntry) Reset() { *m = EntityStorageEntry{} }
|
||||
func (m *EntityStorageEntry) String() string { return proto.CompactTextString(m) }
|
||||
func (*EntityStorageEntry) ProtoMessage() {}
|
||||
func (*EntityStorageEntry) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_types_7c8884717ecd36e8, []int{3}
|
||||
}
|
||||
func (m *EntityStorageEntry) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_EntityStorageEntry.Unmarshal(m, b)
|
||||
}
|
||||
func (m *EntityStorageEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_EntityStorageEntry.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (dst *EntityStorageEntry) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_EntityStorageEntry.Merge(dst, src)
|
||||
}
|
||||
func (m *EntityStorageEntry) XXX_Size() int {
|
||||
return xxx_messageInfo_EntityStorageEntry.Size(m)
|
||||
}
|
||||
func (m *EntityStorageEntry) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_EntityStorageEntry.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_EntityStorageEntry proto.InternalMessageInfo
|
||||
|
||||
func (m *EntityStorageEntry) GetPersonas() []*PersonaIndexEntry {
|
||||
if m != nil {
|
||||
return m.Personas
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *EntityStorageEntry) GetID() string {
|
||||
if m != nil {
|
||||
return m.ID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *EntityStorageEntry) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *EntityStorageEntry) GetMetadata() map[string]string {
|
||||
if m != nil {
|
||||
return m.Metadata
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *EntityStorageEntry) GetCreationTime() *timestamp.Timestamp {
|
||||
if m != nil {
|
||||
return m.CreationTime
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *EntityStorageEntry) GetLastUpdateTime() *timestamp.Timestamp {
|
||||
if m != nil {
|
||||
return m.LastUpdateTime
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *EntityStorageEntry) GetMergedEntityIDs() []string {
|
||||
if m != nil {
|
||||
return m.MergedEntityIDs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *EntityStorageEntry) GetPolicies() []string {
|
||||
if m != nil {
|
||||
return m.Policies
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *EntityStorageEntry) GetBucketKeyHash() string {
|
||||
if m != nil {
|
||||
return m.BucketKeyHash
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *EntityStorageEntry) GetMFASecrets() map[string]*mfa.Secret {
|
||||
if m != nil {
|
||||
return m.MFASecrets
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Deprecated. Retained for backwards compatibility.
|
||||
type PersonaIndexEntry struct {
|
||||
ID string `sentinel:"" protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
EntityID string `sentinel:"" protobuf:"bytes,2,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"`
|
||||
MountType string `sentinel:"" protobuf:"bytes,3,opt,name=mount_type,json=mountType,proto3" json:"mount_type,omitempty"`
|
||||
MountAccessor string `sentinel:"" protobuf:"bytes,4,opt,name=mount_accessor,json=mountAccessor,proto3" json:"mount_accessor,omitempty"`
|
||||
MountPath string `sentinel:"" protobuf:"bytes,5,opt,name=mount_path,json=mountPath,proto3" json:"mount_path,omitempty"`
|
||||
Metadata map[string]string `sentinel:"" protobuf:"bytes,6,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
Name string `sentinel:"" protobuf:"bytes,7,opt,name=name,proto3" json:"name,omitempty"`
|
||||
CreationTime *timestamp.Timestamp `sentinel:"" protobuf:"bytes,8,opt,name=creation_time,json=creationTime,proto3" json:"creation_time,omitempty"`
|
||||
LastUpdateTime *timestamp.Timestamp `sentinel:"" protobuf:"bytes,9,opt,name=last_update_time,json=lastUpdateTime,proto3" json:"last_update_time,omitempty"`
|
||||
MergedFromEntityIDs []string `sentinel:"" protobuf:"bytes,10,rep,name=merged_from_entity_ids,json=mergedFromEntityIDs,proto3" json:"merged_from_entity_ids,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *PersonaIndexEntry) Reset() { *m = PersonaIndexEntry{} }
|
||||
func (m *PersonaIndexEntry) String() string { return proto.CompactTextString(m) }
|
||||
func (*PersonaIndexEntry) ProtoMessage() {}
|
||||
func (*PersonaIndexEntry) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_types_7c8884717ecd36e8, []int{4}
|
||||
}
|
||||
func (m *PersonaIndexEntry) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_PersonaIndexEntry.Unmarshal(m, b)
|
||||
}
|
||||
func (m *PersonaIndexEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_PersonaIndexEntry.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (dst *PersonaIndexEntry) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_PersonaIndexEntry.Merge(dst, src)
|
||||
}
|
||||
func (m *PersonaIndexEntry) XXX_Size() int {
|
||||
return xxx_messageInfo_PersonaIndexEntry.Size(m)
|
||||
}
|
||||
func (m *PersonaIndexEntry) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_PersonaIndexEntry.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_PersonaIndexEntry proto.InternalMessageInfo
|
||||
|
||||
func (m *PersonaIndexEntry) GetID() string {
|
||||
if m != nil {
|
||||
return m.ID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *PersonaIndexEntry) GetEntityID() string {
|
||||
if m != nil {
|
||||
return m.EntityID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *PersonaIndexEntry) GetMountType() string {
|
||||
if m != nil {
|
||||
return m.MountType
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *PersonaIndexEntry) GetMountAccessor() string {
|
||||
if m != nil {
|
||||
return m.MountAccessor
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *PersonaIndexEntry) GetMountPath() string {
|
||||
if m != nil {
|
||||
return m.MountPath
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *PersonaIndexEntry) GetMetadata() map[string]string {
|
||||
if m != nil {
|
||||
return m.Metadata
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *PersonaIndexEntry) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *PersonaIndexEntry) GetCreationTime() *timestamp.Timestamp {
|
||||
if m != nil {
|
||||
return m.CreationTime
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *PersonaIndexEntry) GetLastUpdateTime() *timestamp.Timestamp {
|
||||
if m != nil {
|
||||
return m.LastUpdateTime
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *PersonaIndexEntry) GetMergedFromEntityIDs() []string {
|
||||
if m != nil {
|
||||
return m.MergedFromEntityIDs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Group)(nil), "identity.Group")
|
||||
proto.RegisterMapType((map[string]string)(nil), "identity.Group.MetadataEntry")
|
||||
proto.RegisterType((*Entity)(nil), "identity.Entity")
|
||||
proto.RegisterMapType((map[string]string)(nil), "identity.Entity.MetadataEntry")
|
||||
proto.RegisterMapType((map[string]*mfa.Secret)(nil), "identity.Entity.MFASecretsEntry")
|
||||
proto.RegisterType((*Alias)(nil), "identity.Alias")
|
||||
proto.RegisterMapType((map[string]string)(nil), "identity.Alias.MetadataEntry")
|
||||
proto.RegisterType((*EntityStorageEntry)(nil), "identity.EntityStorageEntry")
|
||||
proto.RegisterMapType((map[string]string)(nil), "identity.EntityStorageEntry.MetadataEntry")
|
||||
proto.RegisterMapType((map[string]*mfa.Secret)(nil), "identity.EntityStorageEntry.MFASecretsEntry")
|
||||
proto.RegisterType((*PersonaIndexEntry)(nil), "identity.PersonaIndexEntry")
|
||||
proto.RegisterMapType((map[string]string)(nil), "identity.PersonaIndexEntry.MetadataEntry")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("helper/identity/types.proto", fileDescriptor_types_0360db4a8e77dd9b) }
|
||||
func init() { proto.RegisterFile("helper/identity/types.proto", fileDescriptor_types_7c8884717ecd36e8) }
|
||||
|
||||
var fileDescriptor_types_0360db4a8e77dd9b = []byte{
|
||||
// 656 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x95, 0x5d, 0x6f, 0xd3, 0x3c,
|
||||
0x14, 0xc7, 0xd5, 0xa6, 0x2f, 0xe9, 0x69, 0xd7, 0xed, 0xb1, 0x1e, 0xa1, 0x50, 0x34, 0xe8, 0x26,
|
||||
0x0d, 0x95, 0x09, 0x25, 0xd2, 0xb8, 0x61, 0xe3, 0x02, 0x0d, 0x18, 0x30, 0x21, 0x24, 0x14, 0x8d,
|
||||
0x1b, 0x6e, 0x22, 0x37, 0xf1, 0x1a, 0x6b, 0x49, 0x1c, 0xc5, 0xce, 0x44, 0xbe, 0x0e, 0x5f, 0x8d,
|
||||
0x6b, 0xbe, 0x03, 0xf2, 0x71, 0xd3, 0x96, 0x75, 0xbc, 0x4c, 0xdb, 0x9d, 0xfd, 0x3f, 0xc7, 0xc7,
|
||||
0xf6, 0xf9, 0xff, 0xe2, 0xc0, 0x83, 0x98, 0x25, 0x39, 0x2b, 0x3c, 0x1e, 0xb1, 0x4c, 0x71, 0x55,
|
||||
0x79, 0xaa, 0xca, 0x99, 0x74, 0xf3, 0x42, 0x28, 0x41, 0xec, 0x5a, 0x1d, 0x3d, 0x9a, 0x09, 0x31,
|
||||
0x4b, 0x98, 0x87, 0xfa, 0xb4, 0x3c, 0xf7, 0x14, 0x4f, 0x99, 0x54, 0x34, 0xcd, 0x4d, 0xea, 0xee,
|
||||
0xb7, 0x16, 0xb4, 0xdf, 0x15, 0xa2, 0xcc, 0xc9, 0x10, 0x9a, 0x3c, 0x72, 0x1a, 0xe3, 0xc6, 0xa4,
|
||||
0xe7, 0x37, 0x79, 0x44, 0x08, 0xb4, 0x32, 0x9a, 0x32, 0xa7, 0x89, 0x0a, 0x8e, 0xc9, 0x08, 0xec,
|
||||
0x5c, 0x24, 0x3c, 0xe4, 0x4c, 0x3a, 0xd6, 0xd8, 0x9a, 0xf4, 0xfc, 0xc5, 0x9c, 0x4c, 0x60, 0x2b,
|
||||
0xa7, 0x05, 0xcb, 0x54, 0x30, 0xd3, 0xf5, 0x02, 0x1e, 0x49, 0xa7, 0x85, 0x39, 0x43, 0xa3, 0xe3,
|
||||
0x36, 0xa7, 0x91, 0x24, 0xfb, 0xf0, 0x5f, 0xca, 0xd2, 0x29, 0x2b, 0x02, 0x73, 0x4a, 0x4c, 0x6d,
|
||||
0x63, 0xea, 0xa6, 0x09, 0x9c, 0xa0, 0xae, 0x73, 0x0f, 0xc1, 0x4e, 0x99, 0xa2, 0x11, 0x55, 0xd4,
|
||||
0xe9, 0x8c, 0xad, 0x49, 0xff, 0x60, 0xdb, 0xad, 0x6f, 0xe7, 0x62, 0x45, 0xf7, 0xe3, 0x3c, 0x7e,
|
||||
0x92, 0xa9, 0xa2, 0xf2, 0x17, 0xe9, 0xe4, 0x25, 0x6c, 0x84, 0x05, 0xa3, 0x8a, 0x8b, 0x2c, 0xd0,
|
||||
0xd7, 0x76, 0xba, 0xe3, 0xc6, 0xa4, 0x7f, 0x30, 0x72, 0x4d, 0x4f, 0xdc, 0xba, 0x27, 0xee, 0x59,
|
||||
0xdd, 0x13, 0x7f, 0x50, 0x2f, 0xd0, 0x12, 0x79, 0x03, 0x5b, 0x09, 0x95, 0x2a, 0x28, 0xf3, 0x88,
|
||||
0x2a, 0x66, 0x6a, 0xd8, 0x7f, 0xad, 0x31, 0xd4, 0x6b, 0x3e, 0xe3, 0x12, 0xac, 0xb2, 0x03, 0x83,
|
||||
0x54, 0x44, 0xfc, 0xbc, 0x0a, 0x78, 0x16, 0xb1, 0xaf, 0x4e, 0x6f, 0xdc, 0x98, 0xb4, 0xfc, 0xbe,
|
||||
0xd1, 0x4e, 0xb5, 0x44, 0x1e, 0xc3, 0xe6, 0xb4, 0x0c, 0x2f, 0x98, 0x0a, 0x2e, 0x58, 0x15, 0xc4,
|
||||
0x54, 0xc6, 0x0e, 0x60, 0xd7, 0x37, 0x8c, 0xfc, 0x81, 0x55, 0xef, 0xa9, 0x8c, 0xc9, 0x1e, 0xb4,
|
||||
0x69, 0xc2, 0xa9, 0x74, 0xfa, 0x78, 0x8a, 0xcd, 0x65, 0x27, 0x8e, 0xb5, 0xec, 0x9b, 0xa8, 0x76,
|
||||
0x4e, 0xd3, 0xe0, 0x0c, 0x8c, 0x73, 0x7a, 0x3c, 0x7a, 0x01, 0x1b, 0xbf, 0xf4, 0x89, 0x6c, 0x81,
|
||||
0x75, 0xc1, 0xaa, 0xb9, 0xdf, 0x7a, 0x48, 0xfe, 0x87, 0xf6, 0x25, 0x4d, 0xca, 0xda, 0x71, 0x33,
|
||||
0x39, 0x6a, 0x3e, 0x6f, 0xec, 0x7e, 0xb7, 0xa0, 0x63, 0x2c, 0x21, 0x4f, 0xa0, 0x8b, 0x9b, 0x30,
|
||||
0xe9, 0x34, 0xd0, 0x8e, 0xb5, 0x43, 0xd4, 0xf1, 0x39, 0x50, 0xcd, 0x35, 0xa0, 0xac, 0x15, 0xa0,
|
||||
0x8e, 0x56, 0xec, 0x6d, 0x61, 0xbd, 0x87, 0xcb, 0x7a, 0x66, 0xcb, 0x7f, 0xf7, 0xb7, 0x7d, 0x07,
|
||||
0xfe, 0x76, 0x6e, 0xec, 0x2f, 0xd2, 0x5c, 0xcc, 0x58, 0xb4, 0x4a, 0x73, 0xb7, 0xa6, 0x59, 0x07,
|
||||
0x96, 0x34, 0xaf, 0x7e, 0x3f, 0xf6, 0x95, 0xef, 0xe7, 0x1a, 0x08, 0x7a, 0xd7, 0x41, 0x30, 0x02,
|
||||
0x3b, 0xe2, 0x92, 0x4e, 0x13, 0x16, 0x21, 0x07, 0xb6, 0xbf, 0x98, 0xdf, 0xce, 0xe5, 0x1f, 0x16,
|
||||
0xb4, 0xd1, 0xc2, 0xb5, 0xa7, 0x60, 0x07, 0x06, 0x21, 0xcd, 0x44, 0xc6, 0x43, 0x9a, 0x04, 0x0b,
|
||||
0x4f, 0xfb, 0x0b, 0xed, 0x34, 0x22, 0xdb, 0x00, 0xa9, 0x28, 0x33, 0x15, 0x20, 0x79, 0xc6, 0xe2,
|
||||
0x1e, 0x2a, 0x67, 0x55, 0xce, 0xc8, 0x1e, 0x0c, 0x4d, 0x98, 0x86, 0x21, 0x93, 0x52, 0x14, 0x4e,
|
||||
0xcb, 0xdc, 0x0d, 0xd5, 0xe3, 0xb9, 0xb8, 0xac, 0x92, 0x53, 0x15, 0xa3, 0x9f, 0x75, 0x95, 0x4f,
|
||||
0x54, 0xc5, 0x7f, 0x7e, 0x0c, 0xf0, 0xe8, 0xbf, 0x85, 0xa5, 0x86, 0xaf, 0xbb, 0x02, 0xdf, 0x1a,
|
||||
0x40, 0xf6, 0x1d, 0x00, 0xd4, 0xbb, 0x31, 0x40, 0x87, 0x70, 0x7f, 0x0e, 0xd0, 0x79, 0x21, 0xd2,
|
||||
0x60, 0xb5, 0xd3, 0xd2, 0x01, 0xa4, 0xe4, 0x9e, 0x49, 0x78, 0x5b, 0x88, 0xf4, 0xf5, 0xb2, 0xe9,
|
||||
0xf2, 0x56, 0x7e, 0xbf, 0x7a, 0xfa, 0x65, 0x7f, 0xc6, 0x55, 0x5c, 0x4e, 0xdd, 0x50, 0xa4, 0x9e,
|
||||
0x06, 0x8e, 0x87, 0xa2, 0xc8, 0xbd, 0x4b, 0x5a, 0x26, 0xca, 0xbb, 0xf2, 0x7f, 0x99, 0x76, 0xf0,
|
||||
0x26, 0xcf, 0x7e, 0x06, 0x00, 0x00, 0xff, 0xff, 0xf6, 0x89, 0x41, 0x55, 0x79, 0x06, 0x00, 0x00,
|
||||
var fileDescriptor_types_7c8884717ecd36e8 = []byte{
|
||||
// 861 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x96, 0xcf, 0x8f, 0xdb, 0x44,
|
||||
0x14, 0xc7, 0x95, 0x1f, 0x4e, 0xec, 0xe7, 0xfc, 0xd8, 0x0e, 0xa8, 0x32, 0x59, 0x95, 0x66, 0x2b,
|
||||
0x15, 0xa5, 0xab, 0xca, 0x91, 0xb6, 0x07, 0x68, 0x39, 0xa0, 0x05, 0xb6, 0x10, 0x50, 0xa5, 0xca,
|
||||
0x2d, 0x17, 0x2e, 0xd6, 0xc4, 0x9e, 0x24, 0xa3, 0xb5, 0x3d, 0x96, 0x67, 0x5c, 0x91, 0xff, 0x80,
|
||||
0x23, 0x17, 0xfe, 0x24, 0xfe, 0x28, 0x6e, 0x68, 0x66, 0x6c, 0xc7, 0x8d, 0xd3, 0xa5, 0x2b, 0x22,
|
||||
0x04, 0x52, 0x6f, 0xf6, 0x77, 0xde, 0xbc, 0x3c, 0xbf, 0xf7, 0x79, 0x5f, 0x05, 0x4e, 0x37, 0x24,
|
||||
0x4a, 0x49, 0x36, 0xa7, 0x21, 0x49, 0x04, 0x15, 0xdb, 0xb9, 0xd8, 0xa6, 0x84, 0xbb, 0x69, 0xc6,
|
||||
0x04, 0x43, 0x66, 0xa9, 0x4e, 0xee, 0xaf, 0x19, 0x5b, 0x47, 0x64, 0xae, 0xf4, 0x65, 0xbe, 0x9a,
|
||||
0x0b, 0x1a, 0x13, 0x2e, 0x70, 0x9c, 0xea, 0xd0, 0xc9, 0xfd, 0xfd, 0x3c, 0xf1, 0x0a, 0xd7, 0x73,
|
||||
0x3d, 0xf8, 0xa3, 0x0b, 0xc6, 0x77, 0x19, 0xcb, 0x53, 0x34, 0x82, 0x36, 0x0d, 0x9d, 0xd6, 0xb4,
|
||||
0x35, 0xb3, 0xbc, 0x36, 0x0d, 0x11, 0x82, 0x6e, 0x82, 0x63, 0xe2, 0xb4, 0x95, 0xa2, 0x9e, 0xd1,
|
||||
0x04, 0xcc, 0x94, 0x45, 0x34, 0xa0, 0x84, 0x3b, 0x9d, 0x69, 0x67, 0x66, 0x79, 0xd5, 0x3b, 0x9a,
|
||||
0xc1, 0x49, 0x8a, 0x33, 0x92, 0x08, 0x7f, 0x2d, 0xf3, 0xf9, 0x34, 0xe4, 0x4e, 0x57, 0xc5, 0x8c,
|
||||
0xb4, 0xae, 0x7e, 0x66, 0x11, 0x72, 0x74, 0x0e, 0x77, 0x62, 0x12, 0x2f, 0x49, 0xe6, 0xeb, 0xa2,
|
||||
0x54, 0xa8, 0xa1, 0x42, 0xc7, 0xfa, 0xe0, 0x4a, 0xe9, 0x32, 0xf6, 0x29, 0x98, 0x31, 0x11, 0x38,
|
||||
0xc4, 0x02, 0x3b, 0xbd, 0x69, 0x67, 0x66, 0x5f, 0xdc, 0x73, 0xcb, 0x8f, 0x71, 0x55, 0x46, 0xf7,
|
||||
0x45, 0x71, 0x7e, 0x95, 0x88, 0x6c, 0xeb, 0x55, 0xe1, 0xe8, 0x2b, 0x18, 0x06, 0x19, 0xc1, 0x82,
|
||||
0xb2, 0xc4, 0x97, 0x7d, 0x71, 0xfa, 0xd3, 0xd6, 0xcc, 0xbe, 0x98, 0xb8, 0xba, 0x69, 0x6e, 0xd9,
|
||||
0x34, 0xf7, 0x75, 0xd9, 0x34, 0x6f, 0x50, 0x5e, 0x90, 0x12, 0xfa, 0x16, 0x4e, 0x22, 0xcc, 0x85,
|
||||
0x9f, 0xa7, 0x21, 0x16, 0x44, 0xe7, 0x30, 0xff, 0x36, 0xc7, 0x48, 0xde, 0xf9, 0x49, 0x5d, 0x51,
|
||||
0x59, 0xce, 0x60, 0x10, 0xb3, 0x90, 0xae, 0xb6, 0x3e, 0x4d, 0x42, 0xf2, 0x8b, 0x63, 0x4d, 0x5b,
|
||||
0xb3, 0xae, 0x67, 0x6b, 0x6d, 0x21, 0x25, 0xf4, 0x19, 0x8c, 0x97, 0x79, 0x70, 0x4d, 0x84, 0x7f,
|
||||
0x4d, 0xb6, 0xfe, 0x06, 0xf3, 0x8d, 0x03, 0xaa, 0xeb, 0x43, 0x2d, 0xff, 0x48, 0xb6, 0xdf, 0x63,
|
||||
0xbe, 0x41, 0x0f, 0xc1, 0xc0, 0x11, 0xc5, 0xdc, 0xb1, 0x55, 0x15, 0xe3, 0x5d, 0x27, 0x2e, 0xa5,
|
||||
0xec, 0xe9, 0x53, 0x39, 0x39, 0x39, 0x62, 0x67, 0xa0, 0x27, 0x27, 0x9f, 0x65, 0x15, 0x72, 0x82,
|
||||
0x3c, 0xc5, 0x01, 0xf1, 0x69, 0xe8, 0x0c, 0xd5, 0x99, 0x5d, 0x69, 0x8b, 0x70, 0xf2, 0x25, 0x0c,
|
||||
0xdf, 0x6a, 0x25, 0x3a, 0x81, 0xce, 0x35, 0xd9, 0x16, 0x48, 0xc8, 0x47, 0xf4, 0x31, 0x18, 0x6f,
|
||||
0x70, 0x94, 0x97, 0x50, 0xe8, 0x97, 0x67, 0xed, 0x2f, 0x5a, 0x0f, 0x7e, 0x37, 0xa0, 0xa7, 0xa7,
|
||||
0x86, 0x1e, 0x41, 0x5f, 0xd5, 0x41, 0xb8, 0xd3, 0x52, 0x13, 0x6b, 0xd4, 0x59, 0x9e, 0x17, 0xcc,
|
||||
0xb5, 0x1b, 0xcc, 0x75, 0x6a, 0xcc, 0x3d, 0xab, 0x11, 0xd0, 0x55, 0xf9, 0x3e, 0xdd, 0xe5, 0xd3,
|
||||
0x3f, 0xf9, 0xfe, 0x08, 0x18, 0x47, 0x40, 0xa0, 0x77, 0x6b, 0x04, 0x14, 0xf0, 0xd9, 0x9a, 0x84,
|
||||
0x75, 0xe0, 0xfb, 0x25, 0xf0, 0xf2, 0x60, 0x07, 0x7c, 0x7d, 0xc5, 0xcc, 0xbd, 0x15, 0x3b, 0xc0,
|
||||
0x89, 0x75, 0x88, 0x93, 0x4b, 0xb0, 0xe3, 0x15, 0xf6, 0x39, 0x09, 0x32, 0x22, 0xb8, 0x03, 0xaa,
|
||||
0x6b, 0xd3, 0x66, 0xd7, 0x56, 0xf8, 0x95, 0x0e, 0xd1, 0x7d, 0x83, 0xb8, 0x12, 0x64, 0x19, 0x21,
|
||||
0xe5, 0x78, 0x19, 0x91, 0x50, 0xd1, 0x66, 0x7a, 0xd5, 0x7b, 0x83, 0xa5, 0xc1, 0x71, 0x59, 0x9a,
|
||||
0xfc, 0x00, 0xe3, 0xbd, 0xd2, 0x0e, 0x5c, 0x3f, 0xab, 0x5f, 0xb7, 0x2f, 0x6c, 0x37, 0x5e, 0x61,
|
||||
0x57, 0xdf, 0xa9, 0x73, 0xf9, 0x5b, 0x17, 0x0c, 0x05, 0x5d, 0xc3, 0xdf, 0xce, 0x60, 0x10, 0xe0,
|
||||
0x84, 0x25, 0x34, 0xc0, 0x91, 0x5f, 0x51, 0x68, 0x57, 0xda, 0x22, 0x44, 0xf7, 0x00, 0x62, 0x96,
|
||||
0x27, 0xc2, 0x57, 0xeb, 0xa4, 0xa1, 0xb4, 0x94, 0xf2, 0x5a, 0xee, 0xd4, 0x43, 0x18, 0xe9, 0x63,
|
||||
0x1c, 0x04, 0x84, 0x73, 0x96, 0x39, 0x5d, 0x3d, 0x0d, 0xa5, 0x5e, 0x16, 0xe2, 0x2e, 0x4b, 0x8a,
|
||||
0xc5, 0x46, 0x11, 0x58, 0x66, 0x79, 0x89, 0xc5, 0xe6, 0x66, 0x87, 0x53, 0xa5, 0xbf, 0x13, 0xef,
|
||||
0x72, 0x5d, 0xfa, 0xb5, 0x75, 0x69, 0x20, 0x6f, 0x1e, 0x01, 0x79, 0xeb, 0xd6, 0xc8, 0x3f, 0x85,
|
||||
0x4f, 0x0a, 0xe4, 0x57, 0x19, 0x8b, 0xfd, 0x7a, 0xa7, 0x35, 0x90, 0x96, 0x77, 0x57, 0x07, 0x3c,
|
||||
0xcf, 0x58, 0xfc, 0xcd, 0xae, 0xe9, 0xbc, 0x81, 0x97, 0x7d, 0x64, 0xab, 0xfa, 0xd5, 0x00, 0xa4,
|
||||
0x37, 0xe0, 0x95, 0x60, 0x19, 0x5e, 0x13, 0x9d, 0xe2, 0x73, 0x30, 0x53, 0x92, 0x71, 0x96, 0xe0,
|
||||
0xd2, 0xb7, 0x4e, 0x77, 0x73, 0x78, 0xa9, 0x4f, 0x94, 0x5d, 0x17, 0x53, 0x28, 0x83, 0xdf, 0xcb,
|
||||
0xc4, 0x9e, 0x37, 0x4c, 0xec, 0x7c, 0x7f, 0x1d, 0xeb, 0xc5, 0x7c, 0x30, 0xb4, 0xb7, 0x0d, 0xed,
|
||||
0xc5, 0x21, 0x43, 0x7b, 0x7c, 0x73, 0x07, 0xdf, 0x6d, 0x6e, 0xff, 0x1d, 0x77, 0xfa, 0xb3, 0x03,
|
||||
0x77, 0x1a, 0x68, 0x35, 0x9c, 0xea, 0x14, 0xac, 0xaa, 0xcd, 0x45, 0x3d, 0x26, 0x29, 0xfa, 0xfb,
|
||||
0xef, 0x78, 0xd4, 0x55, 0xc3, 0xa3, 0x1e, 0xdd, 0xb0, 0x1b, 0xff, 0x47, 0xbf, 0x7a, 0x02, 0x77,
|
||||
0xeb, 0x7e, 0x55, 0xc3, 0x5a, 0x9b, 0xd5, 0x47, 0x3b, 0xb3, 0xaa, 0xd0, 0xfe, 0x47, 0x1c, 0x7d,
|
||||
0xfd, 0xf8, 0xe7, 0xf3, 0x35, 0x15, 0x9b, 0x7c, 0xe9, 0x06, 0x2c, 0x9e, 0x4b, 0xf6, 0x69, 0xc0,
|
||||
0xb2, 0x74, 0xfe, 0x06, 0xe7, 0x91, 0x98, 0xef, 0xfd, 0x6f, 0x5f, 0xf6, 0xd4, 0x37, 0x3c, 0xf9,
|
||||
0x2b, 0x00, 0x00, 0xff, 0xff, 0x66, 0xa2, 0xa4, 0x7e, 0x19, 0x0c, 0x00, 0x00,
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ option go_package = "github.com/hashicorp/vault/helper/identity";
|
||||
package identity;
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "helper/identity/mfa/types.proto";
|
||||
|
||||
// Group represents an identity group.
|
||||
message Group {
|
||||
@@ -56,14 +57,12 @@ message Group {
|
||||
// will be set-- will be managed automatically.
|
||||
string type = 12;
|
||||
|
||||
// **Enterprise only**
|
||||
// NamespaceID is the identifier of the namespace to which this group
|
||||
// NamespaceID is the identifier of the namespace to which this group
|
||||
// belongs to. Do not return this value over the API when reading the
|
||||
// group.
|
||||
//string namespace_id = 13;
|
||||
string namespace_id = 13;
|
||||
}
|
||||
|
||||
|
||||
// Entity represents an entity that gets persisted and indexed.
|
||||
// Entity is fundamentally composed of zero or many aliases.
|
||||
message Entity {
|
||||
@@ -114,20 +113,18 @@ message Entity {
|
||||
// storage key.
|
||||
string bucket_key_hash = 9;
|
||||
|
||||
// **Enterprise only**
|
||||
// MFASecrets holds the MFA secrets indexed by the identifier of the MFA
|
||||
// method configuration.
|
||||
//map<string, mfa.Secret> mfa_secrets = 10;
|
||||
map<string, mfa.Secret> mfa_secrets = 10;
|
||||
|
||||
// Disabled indicates whether tokens associated with the account should not
|
||||
// be able to be used
|
||||
bool disabled = 11;
|
||||
|
||||
// **Enterprise only**
|
||||
// NamespaceID is the identifier of the namespace to which this entity
|
||||
// belongs to. Do not return this value over the API when reading the
|
||||
// entity.
|
||||
//string namespace_id = 12;
|
||||
string namespace_id = 12;
|
||||
}
|
||||
|
||||
// Alias represents the alias that gets stored inside of the
|
||||
@@ -175,4 +172,36 @@ message Alias {
|
||||
|
||||
// MergedFromCanonicalIDs is the FIFO history of merging activity
|
||||
repeated string merged_from_canonical_ids = 10;
|
||||
|
||||
// NamespaceID is the identifier of the namespace to which this alias
|
||||
// belongs.
|
||||
string namespace_id = 11;
|
||||
}
|
||||
|
||||
// Deprecated. Retained for backwards compatibility.
|
||||
message EntityStorageEntry {
|
||||
repeated PersonaIndexEntry personas = 1;
|
||||
string id = 2;
|
||||
string name = 3;
|
||||
map<string, string> metadata = 4;
|
||||
google.protobuf.Timestamp creation_time = 5;
|
||||
google.protobuf.Timestamp last_update_time= 6;
|
||||
repeated string merged_entity_ids = 7;
|
||||
repeated string policies = 8;
|
||||
string bucket_key_hash = 9;
|
||||
map<string, mfa.Secret> mfa_secrets = 10;
|
||||
}
|
||||
|
||||
// Deprecated. Retained for backwards compatibility.
|
||||
message PersonaIndexEntry {
|
||||
string id = 1;
|
||||
string entity_id = 2;
|
||||
string mount_type = 3;
|
||||
string mount_accessor = 4;
|
||||
string mount_path = 5;
|
||||
map<string, string> metadata = 6;
|
||||
string name = 7;
|
||||
google.protobuf.Timestamp creation_time = 8;
|
||||
google.protobuf.Timestamp last_update_time = 9;
|
||||
repeated string merged_from_entity_ids = 10;
|
||||
}
|
||||
|
||||
12
helper/license/feature.go
Normal file
12
helper/license/feature.go
Normal file
@@ -0,0 +1,12 @@
|
||||
// +build !enterprise
|
||||
|
||||
package license
|
||||
|
||||
// Features is a bitmask of feature flags
|
||||
type Features uint
|
||||
|
||||
const FeatureNone Features = 0
|
||||
|
||||
func (f Features) HasFeature(flag Features) bool {
|
||||
return false
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package namespace
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -27,10 +26,6 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
var AdjustRequest = func(r *http.Request) (*http.Request, int) {
|
||||
return r.WithContext(ContextWithNamespace(r.Context(), RootNamespace)), 0
|
||||
}
|
||||
|
||||
func (n *Namespace) HasParent(possibleParent *Namespace) bool {
|
||||
switch {
|
||||
case n.Path == "":
|
||||
@@ -105,3 +100,15 @@ func Canonicalize(nsPath string) string {
|
||||
|
||||
return nsPath
|
||||
}
|
||||
|
||||
func SplitIDFromString(input string) (string, string) {
|
||||
idx := strings.LastIndex(input, ".")
|
||||
if idx == -1 {
|
||||
return input, ""
|
||||
}
|
||||
if idx == len(input)-1 {
|
||||
return input, ""
|
||||
}
|
||||
|
||||
return input[:idx], input[idx+1:]
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
uuid "github.com/hashicorp/go-uuid"
|
||||
"github.com/hashicorp/vault/helper/consts"
|
||||
"github.com/hashicorp/vault/helper/xor"
|
||||
"github.com/hashicorp/vault/vault"
|
||||
"github.com/mitchellh/go-testing-interface"
|
||||
@@ -23,16 +23,6 @@ func GenerateRoot(t testing.T, cluster *vault.TestCluster, drToken bool) string
|
||||
}
|
||||
|
||||
func GenerateRootWithError(t testing.T, cluster *vault.TestCluster, drToken bool) (string, error) {
|
||||
buf := make([]byte, 16)
|
||||
readLen, err := rand.Read(buf)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if readLen != 16 {
|
||||
return "", fmt.Errorf("wrong readlen: %d", readLen)
|
||||
}
|
||||
otp := base64.StdEncoding.EncodeToString(buf)
|
||||
|
||||
// If recovery keys supported, use those to perform root token generation instead
|
||||
var keys [][]byte
|
||||
if cluster.Cores[0].SealAccess().RecoveryKeySupported() {
|
||||
@@ -46,7 +36,7 @@ func GenerateRootWithError(t testing.T, cluster *vault.TestCluster, drToken bool
|
||||
if drToken {
|
||||
f = client.Sys().GenerateDROperationTokenInit
|
||||
}
|
||||
status, err := f(otp, "")
|
||||
status, err := f("", "")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -55,6 +45,8 @@ func GenerateRootWithError(t testing.T, cluster *vault.TestCluster, drToken bool
|
||||
return "", fmt.Errorf("need more keys than have, need %d have %d", status.Required, len(keys))
|
||||
}
|
||||
|
||||
otp := status.OTP
|
||||
|
||||
for i, key := range keys {
|
||||
if i >= status.Required {
|
||||
break
|
||||
@@ -71,15 +63,16 @@ func GenerateRootWithError(t testing.T, cluster *vault.TestCluster, drToken bool
|
||||
if !status.Complete {
|
||||
return "", errors.New("generate root operation did not end successfully")
|
||||
}
|
||||
tokenBytes, err := xor.XORBase64(status.EncodedToken, otp)
|
||||
|
||||
tokenBytes, err := base64.RawStdEncoding.DecodeString(status.EncodedToken)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
token, err := uuid.FormatUUID(tokenBytes)
|
||||
tokenBytes, err = xor.XORBytes(tokenBytes, []byte(otp))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return token, nil
|
||||
return string(tokenBytes), nil
|
||||
}
|
||||
|
||||
// RandomWithPrefix is used to generate a unique name with a prefix, for
|
||||
@@ -87,3 +80,185 @@ func GenerateRootWithError(t testing.T, cluster *vault.TestCluster, drToken bool
|
||||
func RandomWithPrefix(name string) string {
|
||||
return fmt.Sprintf("%s-%d", name, rand.New(rand.NewSource(time.Now().UnixNano())).Int())
|
||||
}
|
||||
|
||||
func EnsureCoresUnsealed(t testing.T, c *vault.TestCluster) {
|
||||
t.Helper()
|
||||
for _, core := range c.Cores {
|
||||
if !core.Sealed() {
|
||||
continue
|
||||
}
|
||||
|
||||
client := core.Client
|
||||
client.Sys().ResetUnsealProcess()
|
||||
for j := 0; j < len(c.BarrierKeys); j++ {
|
||||
statusResp, err := client.Sys().Unseal(base64.StdEncoding.EncodeToString(c.BarrierKeys[j]))
|
||||
if err != nil {
|
||||
// Sometimes when we get here it's already unsealed on its own
|
||||
// and then this fails for DR secondaries so check again
|
||||
if core.Sealed() {
|
||||
t.Fatal(err)
|
||||
}
|
||||
break
|
||||
}
|
||||
if statusResp == nil {
|
||||
t.Fatal("nil status response during unseal")
|
||||
}
|
||||
if !statusResp.Sealed {
|
||||
break
|
||||
}
|
||||
}
|
||||
if core.Sealed() {
|
||||
t.Fatal("core is still sealed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func WaitForReplicationState(t testing.T, c *vault.Core, state consts.ReplicationState) {
|
||||
timeout := time.Now().Add(10 * time.Second)
|
||||
for {
|
||||
if time.Now().After(timeout) {
|
||||
t.Fatalf("timeout waiting for core to have state %d", uint32(state))
|
||||
}
|
||||
state := c.ReplicationState()
|
||||
if state.HasState(state) {
|
||||
break
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func SetupFourClusterReplication(t testing.T, perfPrimary, perfSecondary, perfDRSecondary, perfSecondaryDRSecondary *vault.TestCluster) {
|
||||
// Enable dr primary
|
||||
_, err := perfPrimary.Cores[0].Client.Logical().Write("sys/replication/dr/primary/enable", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
WaitForReplicationState(t, perfPrimary.Cores[0].Core, consts.ReplicationDRPrimary)
|
||||
|
||||
// Enable performance primary
|
||||
_, err = perfPrimary.Cores[0].Client.Logical().Write("sys/replication/primary/enable", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
WaitForReplicationState(t, perfPrimary.Cores[0].Core, consts.ReplicationPerformancePrimary)
|
||||
|
||||
// get dr token
|
||||
secret, err := perfPrimary.Cores[0].Client.Logical().Write("sys/replication/dr/primary/secondary-token", map[string]interface{}{
|
||||
"id": "1",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
token := secret.WrapInfo.Token
|
||||
|
||||
// enable dr secondary
|
||||
secret, err = perfDRSecondary.Cores[0].Client.Logical().Write("sys/replication/dr/secondary/enable", map[string]interface{}{
|
||||
"token": token,
|
||||
"ca_file": perfPrimary.CACertPEMFile,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
WaitForReplicationState(t, perfDRSecondary.Cores[0].Core, consts.ReplicationDRSecondary)
|
||||
perfDRSecondary.BarrierKeys = perfPrimary.BarrierKeys
|
||||
EnsureCoresUnsealed(t, perfDRSecondary)
|
||||
|
||||
// get performance token
|
||||
secret, err = perfPrimary.Cores[0].Client.Logical().Write("sys/replication/primary/secondary-token", map[string]interface{}{
|
||||
"id": "1",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
token = secret.WrapInfo.Token
|
||||
|
||||
// enable performace secondary
|
||||
secret, err = perfSecondary.Cores[0].Client.Logical().Write("sys/replication/secondary/enable", map[string]interface{}{
|
||||
"token": token,
|
||||
"ca_file": perfPrimary.CACertPEMFile,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
WaitForReplicationState(t, perfSecondary.Cores[0].Core, consts.ReplicationPerformanceSecondary)
|
||||
time.Sleep(time.Second * 3)
|
||||
perfSecondary.BarrierKeys = perfPrimary.BarrierKeys
|
||||
|
||||
EnsureCoresUnsealed(t, perfSecondary)
|
||||
rootToken := GenerateRoot(t, perfSecondary, false)
|
||||
perfSecondary.Cores[0].Client.SetToken(rootToken)
|
||||
|
||||
// Enable dr primary on perf secondary
|
||||
_, err = perfSecondary.Cores[0].Client.Logical().Write("sys/replication/dr/primary/enable", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
WaitForReplicationState(t, perfSecondary.Cores[0].Core, consts.ReplicationDRPrimary)
|
||||
|
||||
// get dr token from perf secondary
|
||||
secret, err = perfSecondary.Cores[0].Client.Logical().Write("sys/replication/dr/primary/secondary-token", map[string]interface{}{
|
||||
"id": "1",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
token = secret.WrapInfo.Token
|
||||
|
||||
// enable dr secondary
|
||||
secret, err = perfSecondaryDRSecondary.Cores[0].Client.Logical().Write("sys/replication/dr/secondary/enable", map[string]interface{}{
|
||||
"token": token,
|
||||
"ca_file": perfSecondary.CACertPEMFile,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
WaitForReplicationState(t, perfSecondaryDRSecondary.Cores[0].Core, consts.ReplicationDRSecondary)
|
||||
perfSecondaryDRSecondary.BarrierKeys = perfPrimary.BarrierKeys
|
||||
EnsureCoresUnsealed(t, perfSecondaryDRSecondary)
|
||||
|
||||
perfDRSecondary.Cores[0].Client.SetToken(perfPrimary.Cores[0].Client.Token())
|
||||
perfSecondaryDRSecondary.Cores[0].Client.SetToken(rootToken)
|
||||
}
|
||||
|
||||
func DeriveActiveCore(t testing.T, cluster *vault.TestCluster) *vault.TestClusterCore {
|
||||
for i := 0; i < 10; i++ {
|
||||
for _, core := range cluster.Cores {
|
||||
leaderResp, err := core.Client.Sys().Leader()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if leaderResp.IsSelf {
|
||||
return core
|
||||
}
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
t.Fatal("could not derive the active core")
|
||||
return nil
|
||||
}
|
||||
|
||||
func WaitForNCoresSealed(t testing.T, cluster *vault.TestCluster, n int) {
|
||||
for i := 0; i < 10; i++ {
|
||||
sealed := 0
|
||||
for _, core := range cluster.Cores {
|
||||
if core.Core.Sealed() {
|
||||
sealed++
|
||||
}
|
||||
}
|
||||
|
||||
if sealed >= n {
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
t.Fatalf("%d cores were not sealed", n)
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ func TestAuthTokenRenew(t *testing.T) {
|
||||
if err == nil {
|
||||
t.Fatal("should not be allowed to renew root token")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "lease is not renewable") {
|
||||
if !strings.Contains(err.Error(), "invalid lease ID") {
|
||||
t.Fatalf("wrong error; got %v", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
log "github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/vault/builtin/logical/transit"
|
||||
"github.com/hashicorp/vault/helper/consts"
|
||||
"github.com/hashicorp/vault/helper/forwarding"
|
||||
"github.com/hashicorp/vault/helper/logging"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
@@ -58,7 +59,7 @@ func BenchmarkHTTP_Forwarding_Stress(b *testing.B) {
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
req.Header.Set(AuthHeaderName, cluster.RootToken)
|
||||
req.Header.Set(consts.AuthHeaderName, cluster.RootToken)
|
||||
_, err = client.Do(req)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
@@ -71,7 +72,7 @@ func BenchmarkHTTP_Forwarding_Stress(b *testing.B) {
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
req.Header.Set(AuthHeaderName, cluster.RootToken)
|
||||
req.Header.Set(consts.AuthHeaderName, cluster.RootToken)
|
||||
w := forwarding.NewRPCResponseWriter()
|
||||
handler.ServeHTTP(w, req)
|
||||
switch w.StatusCode() {
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"github.com/hashicorp/vault/api"
|
||||
credCert "github.com/hashicorp/vault/builtin/credential/cert"
|
||||
"github.com/hashicorp/vault/builtin/logical/transit"
|
||||
"github.com/hashicorp/vault/helper/consts"
|
||||
"github.com/hashicorp/vault/helper/keysutil"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/vault"
|
||||
@@ -179,7 +180,7 @@ func testHTTP_Forwarding_Stress_Common(t *testing.T, parallel bool, num uint32)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
req.Header.Set(AuthHeaderName, cluster.RootToken)
|
||||
req.Header.Set(consts.AuthHeaderName, cluster.RootToken)
|
||||
_, err = client.Do(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -232,7 +233,7 @@ func testHTTP_Forwarding_Stress_Common(t *testing.T, parallel bool, num uint32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set(AuthHeaderName, cluster.RootToken)
|
||||
req.Header.Set(consts.AuthHeaderName, cluster.RootToken)
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -472,7 +473,7 @@ func TestHTTP_Forwarding_ClientTLS(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
req.Header.Set(AuthHeaderName, cluster.RootToken)
|
||||
req.Header.Set(consts.AuthHeaderName, cluster.RootToken)
|
||||
_, err = client.Do(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -494,7 +495,7 @@ func TestHTTP_Forwarding_ClientTLS(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
req.Header.Set(AuthHeaderName, cluster.RootToken)
|
||||
req.Header.Set(consts.AuthHeaderName, cluster.RootToken)
|
||||
_, err = client.Do(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
215
http/handler.go
215
http/handler.go
@@ -21,15 +21,14 @@ import (
|
||||
sockaddr "github.com/hashicorp/go-sockaddr"
|
||||
"github.com/hashicorp/vault/helper/consts"
|
||||
"github.com/hashicorp/vault/helper/jsonutil"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/helper/parseutil"
|
||||
"github.com/hashicorp/vault/helper/pathmanager"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/vault"
|
||||
)
|
||||
|
||||
const (
|
||||
// AuthHeaderName is the name of the header containing the token.
|
||||
AuthHeaderName = "X-Vault-Token"
|
||||
|
||||
// WrapTTLHeaderName is the name of the header containing a directive to
|
||||
// wrap the response
|
||||
WrapTTLHeaderName = "X-Vault-Wrap-TTL"
|
||||
@@ -62,11 +61,13 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
ReplicationStaleReadTimeout = 2 * time.Second
|
||||
|
||||
// Set to false by stub_asset if the ui build tag isn't enabled
|
||||
uiBuiltIn = true
|
||||
|
||||
// perfStandbyAlwaysForwardPaths is used to check a requested path against
|
||||
// the always forward list
|
||||
perfStandbyAlwaysForwardPaths = pathmanager.New()
|
||||
|
||||
injectDataIntoTopRoutes = []string{
|
||||
"/v1/sys/audit",
|
||||
"/v1/sys/audit/",
|
||||
@@ -114,14 +115,11 @@ func Handler(props *vault.HandlerProperties) http.Handler {
|
||||
mux.Handle("/v1/sys/rekey-recovery-key/init", handleRequestForwarding(core, handleSysRekeyInit(core, true)))
|
||||
mux.Handle("/v1/sys/rekey-recovery-key/update", handleRequestForwarding(core, handleSysRekeyUpdate(core, true)))
|
||||
mux.Handle("/v1/sys/rekey-recovery-key/verify", handleRequestForwarding(core, handleSysRekeyVerify(core, true)))
|
||||
mux.Handle("/v1/sys/wrapping/lookup", handleRequestForwarding(core, handleLogical(core, wrappingVerificationFunc)))
|
||||
mux.Handle("/v1/sys/wrapping/rewrap", handleRequestForwarding(core, handleLogical(core, wrappingVerificationFunc)))
|
||||
mux.Handle("/v1/sys/wrapping/unwrap", handleRequestForwarding(core, handleLogical(core, wrappingVerificationFunc)))
|
||||
for _, path := range injectDataIntoTopRoutes {
|
||||
mux.Handle(path, handleRequestForwarding(core, handleLogicalWithInjector(core, nil)))
|
||||
mux.Handle(path, handleRequestForwarding(core, handleLogicalWithInjector(core)))
|
||||
}
|
||||
mux.Handle("/v1/sys/", handleRequestForwarding(core, handleLogical(core, nil)))
|
||||
mux.Handle("/v1/", handleRequestForwarding(core, handleLogical(core, nil)))
|
||||
mux.Handle("/v1/sys/", handleRequestForwarding(core, handleLogical(core)))
|
||||
mux.Handle("/v1/", handleRequestForwarding(core, handleLogical(core)))
|
||||
if core.UIEnabled() == true {
|
||||
if uiBuiltIn {
|
||||
mux.Handle("/ui/", http.StripPrefix("/ui/", gziphandler.GzipHandler(handleUIHeaders(core, handleUI(http.FileServer(&UIAssetWrapper{FileSystem: assetFS()}))))))
|
||||
@@ -131,13 +129,13 @@ func Handler(props *vault.HandlerProperties) http.Handler {
|
||||
mux.Handle("/", handleRootRedirect())
|
||||
}
|
||||
|
||||
additionalRoutes(mux, core)
|
||||
|
||||
// Wrap the handler in another handler to trigger all help paths.
|
||||
helpWrappedHandler := wrapHelpHandler(mux, core)
|
||||
corsWrappedHandler := wrapCORSHandler(helpWrappedHandler, core)
|
||||
|
||||
// Wrap the help wrapped handler with another layer with a generic
|
||||
// handler
|
||||
genericWrappedHandler := wrapGenericHandler(corsWrappedHandler, props.MaxRequestSize, props.MaxRequestDuration)
|
||||
genericWrappedHandler := genericWrapping(core, corsWrappedHandler, props)
|
||||
|
||||
// Wrap the handler with PrintablePathCheckHandler to check for non-printable
|
||||
// characters in the request path.
|
||||
@@ -152,7 +150,7 @@ func Handler(props *vault.HandlerProperties) http.Handler {
|
||||
// wrapGenericHandler wraps the handler with an extra layer of handler where
|
||||
// tasks that should be commonly handled for all the requests and/or responses
|
||||
// are performed.
|
||||
func wrapGenericHandler(h http.Handler, maxRequestSize int64, maxRequestDuration time.Duration) http.Handler {
|
||||
func wrapGenericHandler(core *vault.Core, h http.Handler, maxRequestSize int64, maxRequestDuration time.Duration) http.Handler {
|
||||
if maxRequestDuration == 0 {
|
||||
maxRequestDuration = vault.DefaultMaxRequestDuration
|
||||
}
|
||||
@@ -170,7 +168,26 @@ func wrapGenericHandler(h http.Handler, maxRequestSize int64, maxRequestDuration
|
||||
if maxRequestSize > 0 {
|
||||
ctx = context.WithValue(ctx, "max_request_size", maxRequestSize)
|
||||
}
|
||||
ctx = context.WithValue(ctx, "original_request_path", r.URL.Path)
|
||||
r = r.WithContext(ctx)
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(r.URL.Path, "/v1/"):
|
||||
newR, status := adjustRequest(core, r)
|
||||
if status != 0 {
|
||||
respondError(w, status, nil)
|
||||
cancelFunc()
|
||||
return
|
||||
}
|
||||
r = newR
|
||||
|
||||
case strings.HasPrefix(r.URL.Path, "/ui/"), r.URL.Path == "/":
|
||||
default:
|
||||
respondError(w, http.StatusNotFound, nil)
|
||||
cancelFunc()
|
||||
return
|
||||
}
|
||||
|
||||
h.ServeHTTP(w, r)
|
||||
cancelFunc()
|
||||
return
|
||||
@@ -268,12 +285,12 @@ func WrapForwardedForHandler(h http.Handler, authorizedAddrs []*sockaddr.SockAdd
|
||||
// A lookup on a token that is about to expire returns nil, which means by the
|
||||
// time we can validate a wrapping token lookup will return nil since it will
|
||||
// be revoked after the call. So we have to do the validation here.
|
||||
func wrappingVerificationFunc(core *vault.Core, req *logical.Request) error {
|
||||
func wrappingVerificationFunc(ctx context.Context, core *vault.Core, req *logical.Request) error {
|
||||
if req == nil {
|
||||
return fmt.Errorf("invalid request")
|
||||
}
|
||||
|
||||
valid, err := core.ValidateWrappingToken(req)
|
||||
valid, err := core.ValidateWrappingToken(ctx, req)
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("error validating wrapping token: {{err}}", err)
|
||||
}
|
||||
@@ -396,16 +413,18 @@ func parseRequest(r *http.Request, w http.ResponseWriter, out interface{}) error
|
||||
// falling back on the older behavior of redirecting the client
|
||||
func handleRequestForwarding(core *vault.Core, handler http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Header.Get(vault.IntNoForwardingHeaderName) != "" {
|
||||
handler.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
if r.Header.Get(NoRequestForwardingHeaderName) != "" {
|
||||
// Forwarding explicitly disabled, fall back to previous behavior
|
||||
core.Logger().Debug("handleRequestForwarding: forwarding disabled by client request")
|
||||
handler.ServeHTTP(w, r)
|
||||
return
|
||||
// If we are a performance standby we can handle the request.
|
||||
if core.PerfStandby() {
|
||||
ns, err := namespace.FromContext(r.Context())
|
||||
if err != nil {
|
||||
respondError(w, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
path := ns.TrimmedPath(r.URL.Path[len("/v1/"):])
|
||||
if !perfStandbyAlwaysForwardPaths.HasPath(path) {
|
||||
handler.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Note: in an HA setup, this call will also ensure that connections to
|
||||
@@ -432,38 +451,60 @@ func handleRequestForwarding(core *vault.Core, handler http.Handler) http.Handle
|
||||
return
|
||||
}
|
||||
|
||||
// Attempt forwarding the request. If we cannot forward -- perhaps it's
|
||||
// been disabled on the active node -- this will return with an
|
||||
// ErrCannotForward and we simply fall back
|
||||
statusCode, header, retBytes, err := core.ForwardRequest(r)
|
||||
if err != nil {
|
||||
if err == vault.ErrCannotForward {
|
||||
core.Logger().Debug("handleRequestForwarding: cannot forward (possibly disabled on active node), falling back")
|
||||
} else {
|
||||
core.Logger().Error("handleRequestForwarding: error forwarding request", "error", err)
|
||||
}
|
||||
|
||||
// Fall back to redirection
|
||||
handler.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
if header != nil {
|
||||
for k, v := range header {
|
||||
w.Header()[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
w.WriteHeader(statusCode)
|
||||
w.Write(retBytes)
|
||||
forwardRequest(core, w, r)
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
func forwardRequest(core *vault.Core, w http.ResponseWriter, r *http.Request) {
|
||||
if r.Header.Get(vault.IntNoForwardingHeaderName) != "" {
|
||||
respondStandby(core, w, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
if r.Header.Get(NoRequestForwardingHeaderName) != "" {
|
||||
// Forwarding explicitly disabled, fall back to previous behavior
|
||||
core.Logger().Debug("handleRequestForwarding: forwarding disabled by client request")
|
||||
respondStandby(core, w, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
// Attempt forwarding the request. If we cannot forward -- perhaps it's
|
||||
// been disabled on the active node -- this will return with an
|
||||
// ErrCannotForward and we simply fall back
|
||||
statusCode, header, retBytes, err := core.ForwardRequest(r)
|
||||
if err != nil {
|
||||
if err == vault.ErrCannotForward {
|
||||
core.Logger().Debug("handleRequestForwarding: cannot forward (possibly disabled on active node), falling back")
|
||||
} else {
|
||||
core.Logger().Error("handleRequestForwarding: error forwarding request", "error", err)
|
||||
}
|
||||
|
||||
// Fall back to redirection
|
||||
respondStandby(core, w, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
if header != nil {
|
||||
for k, v := range header {
|
||||
w.Header()[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
w.WriteHeader(statusCode)
|
||||
w.Write(retBytes)
|
||||
}
|
||||
|
||||
// request is a helper to perform a request and properly exit in the
|
||||
// case of an error.
|
||||
func request(core *vault.Core, w http.ResponseWriter, rawReq *http.Request, r *logical.Request) (*logical.Response, bool) {
|
||||
resp, err := core.HandleRequest(rawReq.Context(), r)
|
||||
if r.LastRemoteWAL() > 0 && !vault.WaitUntilWALShipped(rawReq.Context(), core, r.LastRemoteWAL()) {
|
||||
if resp == nil {
|
||||
resp = &logical.Response{}
|
||||
}
|
||||
resp.AddWarning("Timeout hit while waiting for local replicated cluster to apply primary's write; this client may encounter stale reads of values written during this operation.")
|
||||
}
|
||||
if errwrap.Contains(err, consts.ErrStandby.Error()) {
|
||||
respondStandby(core, w, rawReq.URL)
|
||||
return resp, false
|
||||
@@ -526,16 +567,19 @@ func respondStandby(core *vault.Core, w http.ResponseWriter, reqURL *url.URL) {
|
||||
}
|
||||
|
||||
// requestAuth adds the token to the logical.Request if it exists.
|
||||
func requestAuth(core *vault.Core, r *http.Request, req *logical.Request) *logical.Request {
|
||||
func requestAuth(core *vault.Core, r *http.Request, req *logical.Request) (*logical.Request, error) {
|
||||
// Attach the header value if we have it
|
||||
if v := r.Header.Get(AuthHeaderName); v != "" {
|
||||
if v := r.Header.Get(consts.AuthHeaderName); v != "" {
|
||||
req.ClientToken = v
|
||||
|
||||
// Also attach the accessor if we have it. This doesn't fail if it
|
||||
// doesn't exist because the request may be to an unauthenticated
|
||||
// endpoint/login endpoint where a bad current token doesn't matter, or
|
||||
// a token from a Vault version pre-accessors.
|
||||
te, err := core.LookupToken(v)
|
||||
te, err := core.LookupToken(r.Context(), v)
|
||||
if err != nil && strings.Count(v, ".") != 2 {
|
||||
return req, err
|
||||
}
|
||||
if err == nil && te != nil {
|
||||
req.ClientTokenAccessor = te.Accessor
|
||||
req.ClientTokenRemainingUses = te.NumUses
|
||||
@@ -543,7 +587,22 @@ func requestAuth(core *vault.Core, r *http.Request, req *logical.Request) *logic
|
||||
}
|
||||
}
|
||||
|
||||
return req
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func requestPolicyOverride(r *http.Request, req *logical.Request) error {
|
||||
raw := r.Header.Get(PolicyOverrideHeaderName)
|
||||
if raw == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
override, err := parseutil.ParseBool(raw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.PolicyOverride = override
|
||||
return nil
|
||||
}
|
||||
|
||||
// requestWrapInfo adds the WrapInfo value to the logical.Request if wrap info exists
|
||||
@@ -576,6 +635,52 @@ func requestWrapInfo(r *http.Request, req *logical.Request) (*logical.Request, e
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// parseMFAHeader parses the MFAHeaderName in the request headers and organizes
|
||||
// them with MFA method name as the index.
|
||||
func parseMFAHeader(req *logical.Request) error {
|
||||
if req == nil {
|
||||
return fmt.Errorf("request is nil")
|
||||
}
|
||||
|
||||
if req.Headers == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Reset and initialize the credentials in the request
|
||||
req.MFACreds = make(map[string][]string)
|
||||
|
||||
for _, mfaHeaderValue := range req.Headers[canonicalMFAHeaderName] {
|
||||
// Skip the header with no value in it
|
||||
if mfaHeaderValue == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Handle the case where only method name is mentioned and no value
|
||||
// is supplied
|
||||
if !strings.Contains(mfaHeaderValue, ":") {
|
||||
// Mark the presense of method name, but set an empty set to it
|
||||
// indicating that there were no values supplied for the method
|
||||
if req.MFACreds[mfaHeaderValue] == nil {
|
||||
req.MFACreds[mfaHeaderValue] = []string{}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
shardSplits := strings.SplitN(mfaHeaderValue, ":", 2)
|
||||
if shardSplits[0] == "" {
|
||||
return fmt.Errorf("invalid data in header %q; missing method name", MFAHeaderName)
|
||||
}
|
||||
|
||||
if shardSplits[1] == "" {
|
||||
return fmt.Errorf("invalid data in header %q; missing method value", MFAHeaderName)
|
||||
}
|
||||
|
||||
req.MFACreds[shardSplits[0]] = append(req.MFACreds[shardSplits[0]], shardSplits[1])
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func respondError(w http.ResponseWriter, status int, err error) {
|
||||
logical.AdjustErrorStatusCode(&status, err)
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/textproto"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -16,6 +17,93 @@ import (
|
||||
"github.com/hashicorp/vault/vault"
|
||||
)
|
||||
|
||||
func TestHandler_parseMFAHandler(t *testing.T) {
|
||||
var err error
|
||||
var expectedMFACreds logical.MFACreds
|
||||
req := &logical.Request{
|
||||
Headers: make(map[string][]string),
|
||||
}
|
||||
|
||||
headerName := textproto.CanonicalMIMEHeaderKey(MFAHeaderName)
|
||||
|
||||
// Set TOTP passcode in the MFA header
|
||||
req.Headers[headerName] = []string{
|
||||
"my_totp:123456",
|
||||
"my_totp:111111",
|
||||
"my_second_mfa:hi=hello",
|
||||
"my_third_mfa",
|
||||
}
|
||||
err = parseMFAHeader(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Verify that it is being parsed properly
|
||||
expectedMFACreds = logical.MFACreds{
|
||||
"my_totp": []string{
|
||||
"123456",
|
||||
"111111",
|
||||
},
|
||||
"my_second_mfa": []string{
|
||||
"hi=hello",
|
||||
},
|
||||
"my_third_mfa": []string{},
|
||||
}
|
||||
if !reflect.DeepEqual(expectedMFACreds, req.MFACreds) {
|
||||
t.Fatalf("bad: parsed MFACreds; expected: %#v\n actual: %#v\n", expectedMFACreds, req.MFACreds)
|
||||
}
|
||||
|
||||
// Split the creds of a method type in different headers and check if they
|
||||
// all get merged together
|
||||
req.Headers[headerName] = []string{
|
||||
"my_mfa:passcode=123456",
|
||||
"my_mfa:month=july",
|
||||
"my_mfa:day=tuesday",
|
||||
}
|
||||
err = parseMFAHeader(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectedMFACreds = logical.MFACreds{
|
||||
"my_mfa": []string{
|
||||
"passcode=123456",
|
||||
"month=july",
|
||||
"day=tuesday",
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(expectedMFACreds, req.MFACreds) {
|
||||
t.Fatalf("bad: parsed MFACreds; expected: %#v\n actual: %#v\n", expectedMFACreds, req.MFACreds)
|
||||
}
|
||||
|
||||
// Header without method name should error out
|
||||
req.Headers[headerName] = []string{
|
||||
":passcode=123456",
|
||||
}
|
||||
err = parseMFAHeader(req)
|
||||
if err == nil {
|
||||
t.Fatalf("expected an error; actual: %#v\n", req.MFACreds)
|
||||
}
|
||||
|
||||
// Header without method name and method value should error out
|
||||
req.Headers[headerName] = []string{
|
||||
":",
|
||||
}
|
||||
err = parseMFAHeader(req)
|
||||
if err == nil {
|
||||
t.Fatalf("expected an error; actual: %#v\n", req.MFACreds)
|
||||
}
|
||||
|
||||
// Header without method name and method value should error out
|
||||
req.Headers[headerName] = []string{
|
||||
"my_totp:",
|
||||
}
|
||||
err = parseMFAHeader(req)
|
||||
if err == nil {
|
||||
t.Fatalf("expected an error; actual: %#v\n", req.MFACreds)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandler_cors(t *testing.T) {
|
||||
core, _, _ := vault.TestCoreUnsealed(t)
|
||||
ln, addr := TestServer(t, core)
|
||||
@@ -106,7 +194,7 @@ func TestHandler_CacheControlNoStore(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
req.Header.Set(AuthHeaderName, token)
|
||||
req.Header.Set(consts.AuthHeaderName, token)
|
||||
req.Header.Set(WrapTTLHeaderName, "60s")
|
||||
|
||||
client := cleanhttp.DefaultClient()
|
||||
@@ -139,7 +227,7 @@ func TestHandler_Accepted(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
req.Header.Set(AuthHeaderName, token)
|
||||
req.Header.Set(consts.AuthHeaderName, token)
|
||||
|
||||
client := cleanhttp.DefaultClient()
|
||||
resp, err := client.Do(req)
|
||||
@@ -160,7 +248,7 @@ func TestSysMounts_headerAuth(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
req.Header.Set(AuthHeaderName, token)
|
||||
req.Header.Set(consts.AuthHeaderName, token)
|
||||
|
||||
client := cleanhttp.DefaultClient()
|
||||
resp, err := client.Do(req)
|
||||
@@ -310,7 +398,7 @@ func TestSysMounts_headerAuth_Wrapped(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
req.Header.Set(AuthHeaderName, token)
|
||||
req.Header.Set(consts.AuthHeaderName, token)
|
||||
req.Header.Set(WrapTTLHeaderName, "60s")
|
||||
|
||||
client := cleanhttp.DefaultClient()
|
||||
@@ -379,6 +467,30 @@ func TestHandler_sealed(t *testing.T) {
|
||||
testResponseStatus(t, resp, 503)
|
||||
}
|
||||
|
||||
func TestHandler_ui_default(t *testing.T) {
|
||||
core := vault.TestCoreUI(t, false)
|
||||
ln, addr := TestServer(t, core)
|
||||
defer ln.Close()
|
||||
|
||||
resp, err := http.Get(addr + "/ui/")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
testResponseStatus(t, resp, 404)
|
||||
}
|
||||
|
||||
func TestHandler_ui_enabled(t *testing.T) {
|
||||
core := vault.TestCoreUI(t, true)
|
||||
ln, addr := TestServer(t, core)
|
||||
defer ln.Close()
|
||||
|
||||
resp, err := http.Get(addr + "/ui/")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
}
|
||||
|
||||
func TestHandler_error(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
@@ -429,7 +541,7 @@ func testNonPrintable(t *testing.T, disable bool) {
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
req.Header.Set(AuthHeaderName, token)
|
||||
req.Header.Set(consts.AuthHeaderName, token)
|
||||
|
||||
client := cleanhttp.DefaultClient()
|
||||
resp, err := client.Do(req)
|
||||
|
||||
35
http/help.go
35
http/help.go
@@ -3,6 +3,8 @@ package http
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/vault"
|
||||
)
|
||||
@@ -24,22 +26,31 @@ func wrapHelpHandler(h http.Handler, core *vault.Core) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
func handleHelp(core *vault.Core, w http.ResponseWriter, req *http.Request) {
|
||||
path, ok := stripPrefix("/v1/", req.URL.Path)
|
||||
if !ok {
|
||||
respondError(w, http.StatusNotFound, nil)
|
||||
func handleHelp(core *vault.Core, w http.ResponseWriter, r *http.Request) {
|
||||
ns, err := namespace.FromContext(r.Context())
|
||||
if err != nil {
|
||||
respondError(w, http.StatusBadRequest, nil)
|
||||
return
|
||||
}
|
||||
path := ns.TrimmedPath(r.URL.Path[len("/v1/"):])
|
||||
|
||||
req, err := requestAuth(core, r, &logical.Request{
|
||||
Operation: logical.HelpOperation,
|
||||
Path: path,
|
||||
Connection: getConnection(r),
|
||||
})
|
||||
if err != nil {
|
||||
if errwrap.Contains(err, logical.ErrPermissionDenied.Error()) {
|
||||
respondError(w, http.StatusForbidden, nil)
|
||||
return
|
||||
}
|
||||
respondError(w, http.StatusBadRequest, errwrap.Wrapf("error performing token check: {{err}}", err))
|
||||
return
|
||||
}
|
||||
|
||||
lreq := requestAuth(core, req, &logical.Request{
|
||||
Operation: logical.HelpOperation,
|
||||
Path: path,
|
||||
Connection: getConnection(req),
|
||||
})
|
||||
|
||||
resp, err := core.HandleRequest(req.Context(), lreq)
|
||||
resp, err := core.HandleRequest(r.Context(), req)
|
||||
if err != nil {
|
||||
respondErrorCommon(w, lreq, resp, err)
|
||||
respondErrorCommon(w, req, resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package http
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
@@ -12,21 +13,17 @@ import (
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
"github.com/hashicorp/go-uuid"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/vault"
|
||||
)
|
||||
|
||||
type PrepareRequestFunc func(*vault.Core, *logical.Request) error
|
||||
|
||||
func buildLogicalRequest(core *vault.Core, w http.ResponseWriter, r *http.Request) (*logical.Request, int, error) {
|
||||
// Determine the path...
|
||||
if !strings.HasPrefix(r.URL.Path, "/v1/") {
|
||||
return nil, http.StatusNotFound, nil
|
||||
}
|
||||
path := r.URL.Path[len("/v1/"):]
|
||||
if path == "" {
|
||||
return nil, http.StatusNotFound, nil
|
||||
ns, err := namespace.FromContext(r.Context())
|
||||
if err != nil {
|
||||
return nil, http.StatusBadRequest, nil
|
||||
}
|
||||
path := ns.TrimmedPath(r.URL.Path[len("/v1/"):])
|
||||
|
||||
var data map[string]interface{}
|
||||
|
||||
@@ -103,13 +100,12 @@ func buildLogicalRequest(core *vault.Core, w http.ResponseWriter, r *http.Reques
|
||||
return nil, http.StatusMethodNotAllowed, nil
|
||||
}
|
||||
|
||||
var err error
|
||||
request_id, err := uuid.GenerateUUID()
|
||||
if err != nil {
|
||||
return nil, http.StatusBadRequest, errwrap.Wrapf("failed to generate identifier for the request: {{err}}", err)
|
||||
}
|
||||
|
||||
req := requestAuth(core, r, &logical.Request{
|
||||
req, err := requestAuth(core, r, &logical.Request{
|
||||
ID: request_id,
|
||||
Operation: op,
|
||||
Path: path,
|
||||
@@ -117,24 +113,40 @@ func buildLogicalRequest(core *vault.Core, w http.ResponseWriter, r *http.Reques
|
||||
Connection: getConnection(r),
|
||||
Headers: r.Header,
|
||||
})
|
||||
if err != nil {
|
||||
if errwrap.Contains(err, logical.ErrPermissionDenied.Error()) {
|
||||
return nil, http.StatusForbidden, nil
|
||||
}
|
||||
return nil, http.StatusBadRequest, errwrap.Wrapf("error performing token check: {{err}}", err)
|
||||
}
|
||||
|
||||
req, err = requestWrapInfo(r, req)
|
||||
if err != nil {
|
||||
return nil, http.StatusBadRequest, errwrap.Wrapf("error parsing X-Vault-Wrap-TTL header: {{err}}", err)
|
||||
}
|
||||
|
||||
err = parseMFAHeader(req)
|
||||
if err != nil {
|
||||
return nil, http.StatusBadRequest, errwrap.Wrapf("failed to parse X-Vault-MFA header: {{err}}", err)
|
||||
}
|
||||
|
||||
err = requestPolicyOverride(r, req)
|
||||
if err != nil {
|
||||
return nil, http.StatusBadRequest, errwrap.Wrapf(fmt.Sprintf(`failed to parse %s header: {{err}}`, PolicyOverrideHeaderName), err)
|
||||
}
|
||||
|
||||
return req, 0, nil
|
||||
}
|
||||
|
||||
func handleLogical(core *vault.Core, prepareRequestCallback PrepareRequestFunc) http.Handler {
|
||||
return handleLogicalInternal(core, false, prepareRequestCallback)
|
||||
func handleLogical(core *vault.Core) http.Handler {
|
||||
return handleLogicalInternal(core, false)
|
||||
}
|
||||
|
||||
func handleLogicalWithInjector(core *vault.Core, prepareRequestCallback PrepareRequestFunc) http.Handler {
|
||||
return handleLogicalInternal(core, true, prepareRequestCallback)
|
||||
func handleLogicalWithInjector(core *vault.Core) http.Handler {
|
||||
return handleLogicalInternal(core, true)
|
||||
}
|
||||
|
||||
func handleLogicalInternal(core *vault.Core, injectDataIntoTopLevel bool, prepareRequestCallback PrepareRequestFunc) http.Handler {
|
||||
func handleLogicalInternal(core *vault.Core, injectDataIntoTopLevel bool) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
req, statusCode, err := buildLogicalRequest(core, w, r)
|
||||
if err != nil || statusCode != 0 {
|
||||
@@ -142,14 +154,53 @@ func handleLogicalInternal(core *vault.Core, injectDataIntoTopLevel bool, prepar
|
||||
return
|
||||
}
|
||||
|
||||
// Certain endpoints may require changes to the request object. They
|
||||
// will have a callback registered to do the needed operations, so
|
||||
// invoke it before proceeding.
|
||||
if prepareRequestCallback != nil {
|
||||
if err := prepareRequestCallback(core, req); err != nil {
|
||||
respondError(w, http.StatusBadRequest, err)
|
||||
// Always forward requests that are using a limited use count token
|
||||
if core.PerfStandby() && req.ClientTokenRemainingUses > 0 {
|
||||
forwardRequest(core, w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// req.Path will be relative by this point. The prefix check is first
|
||||
// to fail faster if we're not in this situation since it's a hot path
|
||||
switch {
|
||||
case strings.HasPrefix(req.Path, "sys/wrapping/"), strings.HasPrefix(req.Path, "auth/token/"):
|
||||
// Get the token ns info; if we match the paths below we want to
|
||||
// swap in the token context (but keep the relative path)
|
||||
if err != nil {
|
||||
core.Logger().Warn("error looking up just-set context", "error", err)
|
||||
respondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
te := req.TokenEntry()
|
||||
newCtx := r.Context()
|
||||
if te != nil {
|
||||
ns, err := vault.NamespaceByID(newCtx, te.NamespaceID, core)
|
||||
if err != nil {
|
||||
core.Logger().Warn("error looking up namespace from the token's namespace ID", "error", err)
|
||||
respondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
if ns != nil {
|
||||
newCtx = namespace.ContextWithNamespace(newCtx, ns)
|
||||
}
|
||||
}
|
||||
switch req.Path {
|
||||
case "sys/wrapping/lookup", "sys/wrapping/rewrap", "sys/wrapping/unwrap":
|
||||
r = r.WithContext(newCtx)
|
||||
if err := wrappingVerificationFunc(r.Context(), core, req); err != nil {
|
||||
if errwrap.Contains(err, logical.ErrPermissionDenied.Error()) {
|
||||
respondError(w, http.StatusForbidden, err)
|
||||
} else {
|
||||
respondError(w, http.StatusBadRequest, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// The -self paths have no meaning outside of the token NS, so
|
||||
// requests for these paths always go to the token NS
|
||||
case "auth/token/lookup-self", "auth/token/renew-self", "auth/token/revoke-self":
|
||||
r = r.WithContext(newCtx)
|
||||
}
|
||||
}
|
||||
|
||||
// Make the internal request. We attach the connection info
|
||||
|
||||
@@ -15,7 +15,9 @@ import (
|
||||
|
||||
log "github.com/hashicorp/go-hclog"
|
||||
|
||||
"github.com/hashicorp/vault/helper/consts"
|
||||
"github.com/hashicorp/vault/helper/logging"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/physical"
|
||||
"github.com/hashicorp/vault/physical/inmem"
|
||||
@@ -267,8 +269,10 @@ func TestLogical_RequestSizeLimit(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLogical_ListSuffix(t *testing.T) {
|
||||
core, _, _ := vault.TestCoreUnsealed(t)
|
||||
core, _, rootToken := vault.TestCoreUnsealed(t)
|
||||
req, _ := http.NewRequest("GET", "http://127.0.0.1:8200/v1/secret/foo", nil)
|
||||
req = req.WithContext(namespace.RootContext(nil))
|
||||
req.Header.Add(consts.AuthHeaderName, rootToken)
|
||||
lreq, status, err := buildLogicalRequest(core, nil, req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -281,6 +285,8 @@ func TestLogical_ListSuffix(t *testing.T) {
|
||||
}
|
||||
|
||||
req, _ = http.NewRequest("GET", "http://127.0.0.1:8200/v1/secret/foo?list=true", nil)
|
||||
req = req.WithContext(namespace.RootContext(nil))
|
||||
req.Header.Add(consts.AuthHeaderName, rootToken)
|
||||
lreq, status, err = buildLogicalRequest(core, nil, req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -293,6 +299,8 @@ func TestLogical_ListSuffix(t *testing.T) {
|
||||
}
|
||||
|
||||
req, _ = http.NewRequest("LIST", "http://127.0.0.1:8200/v1/secret/foo", nil)
|
||||
req = req.WithContext(namespace.RootContext(nil))
|
||||
req.Header.Add(consts.AuthHeaderName, rootToken)
|
||||
lreq, status, err = buildLogicalRequest(core, nil, req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -15,18 +15,24 @@ import (
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/logical/plugin"
|
||||
"github.com/hashicorp/vault/logical/plugin/mock"
|
||||
"github.com/hashicorp/vault/physical"
|
||||
"github.com/hashicorp/vault/physical/inmem"
|
||||
"github.com/hashicorp/vault/vault"
|
||||
)
|
||||
|
||||
func getPluginClusterAndCore(t testing.TB, logger log.Logger) (*vault.TestCluster, *vault.TestClusterCore) {
|
||||
inm, err := inmem.NewTransactionalInmem(nil, logger)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
inmha, err := inmem.NewInmemHA(nil, logger)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
coreConfig := &vault.CoreConfig{
|
||||
Physical: inmha,
|
||||
Physical: inm,
|
||||
HAPhysical: inmha.(physical.HABackend),
|
||||
LogicalBackends: map[string]logical.Factory{
|
||||
"plugin": bplugin.Factory,
|
||||
},
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/hashicorp/vault/helper/base62"
|
||||
"github.com/hashicorp/vault/vault"
|
||||
)
|
||||
|
||||
@@ -14,7 +15,7 @@ func handleSysGenerateRootAttempt(core *vault.Core, generateStrategy vault.Gener
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.Method {
|
||||
case "GET":
|
||||
handleSysGenerateRootAttemptGet(core, w, r)
|
||||
handleSysGenerateRootAttemptGet(core, w, r, "")
|
||||
case "POST", "PUT":
|
||||
handleSysGenerateRootAttemptPut(core, w, r, generateStrategy)
|
||||
case "DELETE":
|
||||
@@ -25,7 +26,7 @@ func handleSysGenerateRootAttempt(core *vault.Core, generateStrategy vault.Gener
|
||||
})
|
||||
}
|
||||
|
||||
func handleSysGenerateRootAttemptGet(core *vault.Core, w http.ResponseWriter, r *http.Request) {
|
||||
func handleSysGenerateRootAttemptGet(core *vault.Core, w http.ResponseWriter, r *http.Request, otp string) {
|
||||
ctx, cancel := core.GetContext()
|
||||
defer cancel()
|
||||
|
||||
@@ -65,10 +66,12 @@ func handleSysGenerateRootAttemptGet(core *vault.Core, w http.ResponseWriter, r
|
||||
|
||||
// Format the status
|
||||
status := &GenerateRootStatusResponse{
|
||||
Started: false,
|
||||
Progress: progress,
|
||||
Required: sealConfig.SecretThreshold,
|
||||
Complete: false,
|
||||
Started: false,
|
||||
Progress: progress,
|
||||
Required: sealConfig.SecretThreshold,
|
||||
Complete: false,
|
||||
OTPLength: vault.TokenLength,
|
||||
OTP: otp,
|
||||
}
|
||||
if generationConfig != nil {
|
||||
status.Nonce = generationConfig.Nonce
|
||||
@@ -87,19 +90,32 @@ func handleSysGenerateRootAttemptPut(core *vault.Core, w http.ResponseWriter, r
|
||||
return
|
||||
}
|
||||
|
||||
if len(req.OTP) > 0 && len(req.PGPKey) > 0 {
|
||||
respondError(w, http.StatusBadRequest, fmt.Errorf("only one of \"otp\" and \"pgp_key\" must be specified"))
|
||||
return
|
||||
var err error
|
||||
var genned bool
|
||||
|
||||
switch {
|
||||
case len(req.PGPKey) > 0, len(req.OTP) > 0:
|
||||
default:
|
||||
genned = true
|
||||
req.OTP, err = base62.Random(vault.TokenLength, true)
|
||||
if err != nil {
|
||||
respondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Attemptialize the generation
|
||||
err := core.GenerateRootInit(req.OTP, req.PGPKey, generateStrategy)
|
||||
if err != nil {
|
||||
if err := core.GenerateRootInit(req.OTP, req.PGPKey, generateStrategy); err != nil {
|
||||
respondError(w, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
|
||||
handleSysGenerateRootAttemptGet(core, w, r)
|
||||
if genned {
|
||||
handleSysGenerateRootAttemptGet(core, w, r, req.OTP)
|
||||
return
|
||||
}
|
||||
|
||||
handleSysGenerateRootAttemptGet(core, w, r, "")
|
||||
}
|
||||
|
||||
func handleSysGenerateRootAttemptDelete(core *vault.Core, w http.ResponseWriter, r *http.Request) {
|
||||
@@ -184,6 +200,8 @@ type GenerateRootStatusResponse struct {
|
||||
EncodedToken string `json:"encoded_token"`
|
||||
EncodedRootToken string `json:"encoded_root_token"`
|
||||
PGPFingerprint string `json:"pgp_fingerprint"`
|
||||
OTP string `json:"otp"`
|
||||
OTPLength int `json:"otp_length"`
|
||||
}
|
||||
|
||||
type GenerateRootUpdateRequest struct {
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/go-uuid"
|
||||
"github.com/hashicorp/vault/helper/pgpkeys"
|
||||
"github.com/hashicorp/vault/helper/xor"
|
||||
"github.com/hashicorp/vault/vault"
|
||||
@@ -36,6 +35,8 @@ func TestSysGenerateRootAttempt_Status(t *testing.T) {
|
||||
"encoded_root_token": "",
|
||||
"pgp_fingerprint": "",
|
||||
"nonce": "",
|
||||
"otp": "",
|
||||
"otp_length": json.Number("24"),
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
testResponseBody(t, resp, &actual)
|
||||
@@ -70,6 +71,8 @@ func TestSysGenerateRootAttempt_Setup_OTP(t *testing.T) {
|
||||
"encoded_token": "",
|
||||
"encoded_root_token": "",
|
||||
"pgp_fingerprint": "",
|
||||
"otp": "",
|
||||
"otp_length": json.Number("24"),
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
testResponseBody(t, resp, &actual)
|
||||
@@ -92,6 +95,8 @@ func TestSysGenerateRootAttempt_Setup_OTP(t *testing.T) {
|
||||
"encoded_token": "",
|
||||
"encoded_root_token": "",
|
||||
"pgp_fingerprint": "",
|
||||
"otp": "",
|
||||
"otp_length": json.Number("24"),
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
testResponseBody(t, resp, &actual)
|
||||
@@ -126,6 +131,8 @@ func TestSysGenerateRootAttempt_Setup_PGP(t *testing.T) {
|
||||
"encoded_token": "",
|
||||
"encoded_root_token": "",
|
||||
"pgp_fingerprint": "816938b8a29146fbe245dd29e7cbaf8e011db793",
|
||||
"otp": "",
|
||||
"otp_length": json.Number("24"),
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
testResponseBody(t, resp, &actual)
|
||||
@@ -163,6 +170,8 @@ func TestSysGenerateRootAttempt_Cancel(t *testing.T) {
|
||||
"encoded_token": "",
|
||||
"encoded_root_token": "",
|
||||
"pgp_fingerprint": "",
|
||||
"otp": "",
|
||||
"otp_length": json.Number("24"),
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
testResponseBody(t, resp, &actual)
|
||||
@@ -192,6 +201,8 @@ func TestSysGenerateRootAttempt_Cancel(t *testing.T) {
|
||||
"encoded_root_token": "",
|
||||
"pgp_fingerprint": "",
|
||||
"nonce": "",
|
||||
"otp": "",
|
||||
"otp_length": json.Number("24"),
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
testResponseBody(t, resp, &actual)
|
||||
@@ -251,18 +262,11 @@ func TestSysGenerateRoot_Update_OTP(t *testing.T) {
|
||||
defer ln.Close()
|
||||
TestServerAuth(t, addr, token)
|
||||
|
||||
otpBytes, err := vault.GenerateRandBytes(16)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
otp := base64.StdEncoding.EncodeToString(otpBytes)
|
||||
|
||||
resp := testHttpPut(t, token, addr+"/v1/sys/generate-root/attempt", map[string]interface{}{
|
||||
"otp": otp,
|
||||
})
|
||||
resp := testHttpPut(t, token, addr+"/v1/sys/generate-root/attempt", map[string]interface{}{})
|
||||
var rootGenerationStatus map[string]interface{}
|
||||
testResponseStatus(t, resp, 200)
|
||||
testResponseBody(t, resp, &rootGenerationStatus)
|
||||
otp := rootGenerationStatus["otp"].(string)
|
||||
|
||||
var actual map[string]interface{}
|
||||
var expected map[string]interface{}
|
||||
@@ -280,6 +284,8 @@ func TestSysGenerateRoot_Update_OTP(t *testing.T) {
|
||||
"required": json.Number(fmt.Sprintf("%d", len(keys))),
|
||||
"started": true,
|
||||
"pgp_fingerprint": "",
|
||||
"otp": "",
|
||||
"otp_length": json.Number("0"),
|
||||
}
|
||||
if i+1 == len(keys) {
|
||||
expected["complete"] = true
|
||||
@@ -296,19 +302,22 @@ func TestSysGenerateRoot_Update_OTP(t *testing.T) {
|
||||
}
|
||||
expected["encoded_token"] = actual["encoded_token"]
|
||||
expected["encoded_root_token"] = actual["encoded_root_token"]
|
||||
expected["encoded_token"] = actual["encoded_token"]
|
||||
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("\nexpected: %#v\nactual: %#v", expected, actual)
|
||||
}
|
||||
|
||||
decodedToken, err := xor.XORBase64(otp, actual["encoded_root_token"].(string))
|
||||
tokenBytes, err := base64.RawStdEncoding.DecodeString(expected["encoded_token"].(string))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newRootToken, err := uuid.FormatUUID(decodedToken)
|
||||
|
||||
tokenBytes, err = xor.XORBytes(tokenBytes, []byte(otp))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newRootToken := string(tokenBytes)
|
||||
|
||||
actual = map[string]interface{}{}
|
||||
expected = map[string]interface{}{
|
||||
@@ -374,6 +383,8 @@ func TestSysGenerateRoot_Update_PGP(t *testing.T) {
|
||||
"required": json.Number(fmt.Sprintf("%d", len(keys))),
|
||||
"started": true,
|
||||
"pgp_fingerprint": "816938b8a29146fbe245dd29e7cbaf8e011db793",
|
||||
"otp": "",
|
||||
"otp_length": json.Number("0"),
|
||||
}
|
||||
if i+1 == len(keys) {
|
||||
expected["complete"] = true
|
||||
@@ -390,12 +401,13 @@ func TestSysGenerateRoot_Update_PGP(t *testing.T) {
|
||||
}
|
||||
expected["encoded_token"] = actual["encoded_token"]
|
||||
expected["encoded_root_token"] = actual["encoded_root_token"]
|
||||
expected["encoded_token"] = actual["encoded_token"]
|
||||
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("\nexpected: %#v\nactual: %#v", expected, actual)
|
||||
}
|
||||
|
||||
decodedTokenBuf, err := pgpkeys.DecryptBytes(actual["encoded_root_token"].(string), pgpkeys.TestPrivKey1)
|
||||
decodedTokenBuf, err := pgpkeys.DecryptBytes(actual["encoded_token"].(string), pgpkeys.TestPrivKey1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -29,134 +29,140 @@ func TestSysRekey_Init_pgpKeysEntriesForRekey(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSysRekey_Init_Status(t *testing.T) {
|
||||
core, _, token := vault.TestCoreUnsealed(t)
|
||||
ln, addr := TestServer(t, core)
|
||||
defer ln.Close()
|
||||
TestServerAuth(t, addr, token)
|
||||
t.Run("status-barrier-default", func(t *testing.T) {
|
||||
core, _, token := vault.TestCoreUnsealed(t)
|
||||
ln, addr := TestServer(t, core)
|
||||
defer ln.Close()
|
||||
TestServerAuth(t, addr, token)
|
||||
|
||||
resp, err := http.Get(addr + "/v1/sys/rekey/init")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
resp, err := http.Get(addr + "/v1/sys/rekey/init")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
var actual map[string]interface{}
|
||||
expected := map[string]interface{}{
|
||||
"started": false,
|
||||
"t": json.Number("0"),
|
||||
"n": json.Number("0"),
|
||||
"progress": json.Number("0"),
|
||||
"required": json.Number("3"),
|
||||
"pgp_fingerprints": interface{}(nil),
|
||||
"backup": false,
|
||||
"nonce": "",
|
||||
"verification_required": false,
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
testResponseBody(t, resp, &actual)
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("\nexpected: %#v\nactual: %#v", expected, actual)
|
||||
}
|
||||
var actual map[string]interface{}
|
||||
expected := map[string]interface{}{
|
||||
"started": false,
|
||||
"t": json.Number("0"),
|
||||
"n": json.Number("0"),
|
||||
"progress": json.Number("0"),
|
||||
"required": json.Number("3"),
|
||||
"pgp_fingerprints": interface{}(nil),
|
||||
"backup": false,
|
||||
"nonce": "",
|
||||
"verification_required": false,
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
testResponseBody(t, resp, &actual)
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("\nexpected: %#v\nactual: %#v", expected, actual)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestSysRekey_Init_Setup(t *testing.T) {
|
||||
core, _, token := vault.TestCoreUnsealed(t)
|
||||
ln, addr := TestServer(t, core)
|
||||
defer ln.Close()
|
||||
TestServerAuth(t, addr, token)
|
||||
t.Run("init-barrier-barrier-key", func(t *testing.T) {
|
||||
core, _, token := vault.TestCoreUnsealed(t)
|
||||
ln, addr := TestServer(t, core)
|
||||
defer ln.Close()
|
||||
TestServerAuth(t, addr, token)
|
||||
|
||||
// Start rekey
|
||||
resp := testHttpPut(t, token, addr+"/v1/sys/rekey/init", map[string]interface{}{
|
||||
"secret_shares": 5,
|
||||
"secret_threshold": 3,
|
||||
// Start rekey
|
||||
resp := testHttpPut(t, token, addr+"/v1/sys/rekey/init", map[string]interface{}{
|
||||
"secret_shares": 5,
|
||||
"secret_threshold": 3,
|
||||
})
|
||||
testResponseStatus(t, resp, 200)
|
||||
|
||||
var actual map[string]interface{}
|
||||
expected := map[string]interface{}{
|
||||
"started": true,
|
||||
"t": json.Number("3"),
|
||||
"n": json.Number("5"),
|
||||
"progress": json.Number("0"),
|
||||
"required": json.Number("3"),
|
||||
"pgp_fingerprints": interface{}(nil),
|
||||
"backup": false,
|
||||
"verification_required": false,
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
testResponseBody(t, resp, &actual)
|
||||
if actual["nonce"].(string) == "" {
|
||||
t.Fatalf("nonce was empty")
|
||||
}
|
||||
expected["nonce"] = actual["nonce"]
|
||||
if diff := deep.Equal(actual, expected); diff != nil {
|
||||
t.Fatal(diff)
|
||||
}
|
||||
|
||||
// Get rekey status
|
||||
resp = testHttpGet(t, token, addr+"/v1/sys/rekey/init")
|
||||
|
||||
actual = map[string]interface{}{}
|
||||
expected = map[string]interface{}{
|
||||
"started": true,
|
||||
"t": json.Number("3"),
|
||||
"n": json.Number("5"),
|
||||
"progress": json.Number("0"),
|
||||
"required": json.Number("3"),
|
||||
"pgp_fingerprints": interface{}(nil),
|
||||
"backup": false,
|
||||
"verification_required": false,
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
testResponseBody(t, resp, &actual)
|
||||
if actual["nonce"].(string) == "" {
|
||||
t.Fatalf("nonce was empty")
|
||||
}
|
||||
if actual["nonce"].(string) == "" {
|
||||
t.Fatalf("nonce was empty")
|
||||
}
|
||||
expected["nonce"] = actual["nonce"]
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("\nexpected: %#v\nactual: %#v", expected, actual)
|
||||
}
|
||||
})
|
||||
testResponseStatus(t, resp, 200)
|
||||
|
||||
var actual map[string]interface{}
|
||||
expected := map[string]interface{}{
|
||||
"started": true,
|
||||
"t": json.Number("3"),
|
||||
"n": json.Number("5"),
|
||||
"progress": json.Number("0"),
|
||||
"required": json.Number("3"),
|
||||
"pgp_fingerprints": interface{}(nil),
|
||||
"backup": false,
|
||||
"verification_required": false,
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
testResponseBody(t, resp, &actual)
|
||||
if actual["nonce"].(string) == "" {
|
||||
t.Fatalf("nonce was empty")
|
||||
}
|
||||
expected["nonce"] = actual["nonce"]
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("\nexpected: %#v\nactual: %#v", expected, actual)
|
||||
}
|
||||
|
||||
// Get rekey status
|
||||
resp = testHttpGet(t, token, addr+"/v1/sys/rekey/init")
|
||||
|
||||
actual = map[string]interface{}{}
|
||||
expected = map[string]interface{}{
|
||||
"started": true,
|
||||
"t": json.Number("3"),
|
||||
"n": json.Number("5"),
|
||||
"progress": json.Number("0"),
|
||||
"required": json.Number("3"),
|
||||
"pgp_fingerprints": interface{}(nil),
|
||||
"backup": false,
|
||||
"verification_required": false,
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
testResponseBody(t, resp, &actual)
|
||||
if actual["nonce"].(string) == "" {
|
||||
t.Fatalf("nonce was empty")
|
||||
}
|
||||
if actual["nonce"].(string) == "" {
|
||||
t.Fatalf("nonce was empty")
|
||||
}
|
||||
expected["nonce"] = actual["nonce"]
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("\nexpected: %#v\nactual: %#v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSysRekey_Init_Cancel(t *testing.T) {
|
||||
core, _, token := vault.TestCoreUnsealed(t)
|
||||
ln, addr := TestServer(t, core)
|
||||
defer ln.Close()
|
||||
TestServerAuth(t, addr, token)
|
||||
t.Run("cancel-barrier-barrier-key", func(t *testing.T) {
|
||||
core, _, token := vault.TestCoreUnsealed(t)
|
||||
ln, addr := TestServer(t, core)
|
||||
defer ln.Close()
|
||||
TestServerAuth(t, addr, token)
|
||||
|
||||
resp := testHttpPut(t, token, addr+"/v1/sys/rekey/init", map[string]interface{}{
|
||||
"secret_shares": 5,
|
||||
"secret_threshold": 3,
|
||||
resp := testHttpPut(t, token, addr+"/v1/sys/rekey/init", map[string]interface{}{
|
||||
"secret_shares": 5,
|
||||
"secret_threshold": 3,
|
||||
})
|
||||
testResponseStatus(t, resp, 200)
|
||||
|
||||
resp = testHttpDelete(t, token, addr+"/v1/sys/rekey/init")
|
||||
testResponseStatus(t, resp, 204)
|
||||
|
||||
resp, err := http.Get(addr + "/v1/sys/rekey/init")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
var actual map[string]interface{}
|
||||
expected := map[string]interface{}{
|
||||
"started": false,
|
||||
"t": json.Number("0"),
|
||||
"n": json.Number("0"),
|
||||
"progress": json.Number("0"),
|
||||
"required": json.Number("3"),
|
||||
"pgp_fingerprints": interface{}(nil),
|
||||
"backup": false,
|
||||
"nonce": "",
|
||||
"verification_required": false,
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
testResponseBody(t, resp, &actual)
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("\nexpected: %#v\nactual: %#v", expected, actual)
|
||||
}
|
||||
})
|
||||
testResponseStatus(t, resp, 200)
|
||||
|
||||
resp = testHttpDelete(t, token, addr+"/v1/sys/rekey/init")
|
||||
testResponseStatus(t, resp, 204)
|
||||
|
||||
resp, err := http.Get(addr + "/v1/sys/rekey/init")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
var actual map[string]interface{}
|
||||
expected := map[string]interface{}{
|
||||
"started": false,
|
||||
"t": json.Number("0"),
|
||||
"n": json.Number("0"),
|
||||
"progress": json.Number("0"),
|
||||
"required": json.Number("3"),
|
||||
"pgp_fingerprints": interface{}(nil),
|
||||
"backup": false,
|
||||
"nonce": "",
|
||||
"verification_required": false,
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
testResponseBody(t, resp, &actual)
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("\nexpected: %#v\nactual: %#v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSysRekey_badKey(t *testing.T) {
|
||||
@@ -172,71 +178,73 @@ func TestSysRekey_badKey(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSysRekey_Update(t *testing.T) {
|
||||
core, keys, token := vault.TestCoreUnsealed(t)
|
||||
ln, addr := TestServer(t, core)
|
||||
defer ln.Close()
|
||||
TestServerAuth(t, addr, token)
|
||||
t.Run("rekey-barrier-barrier-key", func(t *testing.T) {
|
||||
core, keys, token := vault.TestCoreUnsealed(t)
|
||||
ln, addr := TestServer(t, core)
|
||||
defer ln.Close()
|
||||
TestServerAuth(t, addr, token)
|
||||
|
||||
resp := testHttpPut(t, token, addr+"/v1/sys/rekey/init", map[string]interface{}{
|
||||
"secret_shares": 5,
|
||||
"secret_threshold": 3,
|
||||
})
|
||||
var rekeyStatus map[string]interface{}
|
||||
testResponseStatus(t, resp, 200)
|
||||
testResponseBody(t, resp, &rekeyStatus)
|
||||
|
||||
var actual map[string]interface{}
|
||||
var expected map[string]interface{}
|
||||
|
||||
for i, key := range keys {
|
||||
resp = testHttpPut(t, token, addr+"/v1/sys/rekey/update", map[string]interface{}{
|
||||
"nonce": rekeyStatus["nonce"].(string),
|
||||
"key": hex.EncodeToString(key),
|
||||
resp := testHttpPut(t, token, addr+"/v1/sys/rekey/init", map[string]interface{}{
|
||||
"secret_shares": 5,
|
||||
"secret_threshold": 3,
|
||||
})
|
||||
|
||||
actual = map[string]interface{}{}
|
||||
expected = map[string]interface{}{
|
||||
"started": true,
|
||||
"nonce": rekeyStatus["nonce"].(string),
|
||||
"backup": false,
|
||||
"pgp_fingerprints": interface{}(nil),
|
||||
"required": json.Number("3"),
|
||||
"t": json.Number("3"),
|
||||
"n": json.Number("5"),
|
||||
"progress": json.Number(fmt.Sprintf("%d", i+1)),
|
||||
"verification_required": false,
|
||||
}
|
||||
var rekeyStatus map[string]interface{}
|
||||
testResponseStatus(t, resp, 200)
|
||||
testResponseBody(t, resp, &actual)
|
||||
testResponseBody(t, resp, &rekeyStatus)
|
||||
|
||||
if i+1 == len(keys) {
|
||||
delete(expected, "started")
|
||||
delete(expected, "required")
|
||||
delete(expected, "t")
|
||||
delete(expected, "n")
|
||||
delete(expected, "progress")
|
||||
expected["complete"] = true
|
||||
expected["keys"] = actual["keys"]
|
||||
expected["keys_base64"] = actual["keys_base64"]
|
||||
var actual map[string]interface{}
|
||||
var expected map[string]interface{}
|
||||
|
||||
for i, key := range keys {
|
||||
resp = testHttpPut(t, token, addr+"/v1/sys/rekey/update", map[string]interface{}{
|
||||
"nonce": rekeyStatus["nonce"].(string),
|
||||
"key": hex.EncodeToString(key),
|
||||
})
|
||||
|
||||
actual = map[string]interface{}{}
|
||||
expected = map[string]interface{}{
|
||||
"started": true,
|
||||
"nonce": rekeyStatus["nonce"].(string),
|
||||
"backup": false,
|
||||
"pgp_fingerprints": interface{}(nil),
|
||||
"required": json.Number("3"),
|
||||
"t": json.Number("3"),
|
||||
"n": json.Number("5"),
|
||||
"progress": json.Number(fmt.Sprintf("%d", i+1)),
|
||||
"verification_required": false,
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
testResponseBody(t, resp, &actual)
|
||||
|
||||
if i+1 == len(keys) {
|
||||
delete(expected, "started")
|
||||
delete(expected, "required")
|
||||
delete(expected, "t")
|
||||
delete(expected, "n")
|
||||
delete(expected, "progress")
|
||||
expected["complete"] = true
|
||||
expected["keys"] = actual["keys"]
|
||||
expected["keys_base64"] = actual["keys_base64"]
|
||||
}
|
||||
|
||||
if i+1 < len(keys) && (actual["nonce"] == nil || actual["nonce"].(string) == "") {
|
||||
t.Fatalf("expected a nonce, i is %d, actual is %#v", i, actual)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("\nexpected: \n%#v\nactual: \n%#v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
if i+1 < len(keys) && (actual["nonce"] == nil || actual["nonce"].(string) == "") {
|
||||
t.Fatalf("expected a nonce, i is %d, actual is %#v", i, actual)
|
||||
retKeys := actual["keys"].([]interface{})
|
||||
if len(retKeys) != 5 {
|
||||
t.Fatalf("bad: %#v", retKeys)
|
||||
}
|
||||
|
||||
if diff := deep.Equal(actual, expected); diff != nil {
|
||||
t.Fatal(diff)
|
||||
keysB64 := actual["keys_base64"].([]interface{})
|
||||
if len(keysB64) != 5 {
|
||||
t.Fatalf("bad: %#v", keysB64)
|
||||
}
|
||||
}
|
||||
|
||||
retKeys := actual["keys"].([]interface{})
|
||||
if len(retKeys) != 5 {
|
||||
t.Fatalf("bad: %#v", retKeys)
|
||||
}
|
||||
keysB64 := actual["keys_base64"].([]interface{})
|
||||
if len(keysB64) != 5 {
|
||||
t.Fatalf("bad: %#v", keysB64)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestSysRekey_ReInitUpdate(t *testing.T) {
|
||||
|
||||
@@ -36,10 +36,9 @@ func handleSysSeal(core *vault.Core) http.Handler {
|
||||
if errwrap.Contains(err, logical.ErrPermissionDenied.Error()) {
|
||||
respondError(w, http.StatusForbidden, err)
|
||||
return
|
||||
} else {
|
||||
respondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
respondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
respondOk(w, nil)
|
||||
@@ -63,6 +62,10 @@ func handleSysStepDown(core *vault.Core) http.Handler {
|
||||
|
||||
// Seal with the token above
|
||||
if err := core.StepDown(r.Context(), req); err != nil {
|
||||
if errwrap.Contains(err, logical.ErrPermissionDenied.Error()) {
|
||||
respondError(w, http.StatusForbidden, err)
|
||||
return
|
||||
}
|
||||
respondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
@@ -197,28 +200,30 @@ func handleSysSealStatusRaw(core *vault.Core, w http.ResponseWriter, r *http.Req
|
||||
progress, nonce := core.SecretProgress()
|
||||
|
||||
respondOk(w, &SealStatusResponse{
|
||||
Type: sealConfig.Type,
|
||||
Sealed: sealed,
|
||||
T: sealConfig.SecretThreshold,
|
||||
N: sealConfig.SecretShares,
|
||||
Progress: progress,
|
||||
Nonce: nonce,
|
||||
Version: version.GetVersion().VersionNumber(),
|
||||
ClusterName: clusterName,
|
||||
ClusterID: clusterID,
|
||||
Type: sealConfig.Type,
|
||||
Sealed: sealed,
|
||||
T: sealConfig.SecretThreshold,
|
||||
N: sealConfig.SecretShares,
|
||||
Progress: progress,
|
||||
Nonce: nonce,
|
||||
Version: version.GetVersion().VersionNumber(),
|
||||
ClusterName: clusterName,
|
||||
ClusterID: clusterID,
|
||||
RecoverySeal: core.SealAccess().RecoveryKeySupported(),
|
||||
})
|
||||
}
|
||||
|
||||
type SealStatusResponse struct {
|
||||
Type string `json:"type"`
|
||||
Sealed bool `json:"sealed"`
|
||||
T int `json:"t"`
|
||||
N int `json:"n"`
|
||||
Progress int `json:"progress"`
|
||||
Nonce string `json:"nonce"`
|
||||
Version string `json:"version"`
|
||||
ClusterName string `json:"cluster_name,omitempty"`
|
||||
ClusterID string `json:"cluster_id,omitempty"`
|
||||
Type string `json:"type"`
|
||||
Sealed bool `json:"sealed"`
|
||||
T int `json:"t"`
|
||||
N int `json:"n"`
|
||||
Progress int `json:"progress"`
|
||||
Nonce string `json:"nonce"`
|
||||
Version string `json:"version"`
|
||||
ClusterName string `json:"cluster_name,omitempty"`
|
||||
ClusterID string `json:"cluster_id,omitempty"`
|
||||
RecoverySeal bool `json:"recovery_seal"`
|
||||
}
|
||||
|
||||
type UnsealRequest struct {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -10,6 +9,7 @@ import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/vault"
|
||||
)
|
||||
@@ -27,12 +27,13 @@ func TestSysSealStatus(t *testing.T) {
|
||||
|
||||
var actual map[string]interface{}
|
||||
expected := map[string]interface{}{
|
||||
"sealed": true,
|
||||
"t": json.Number("3"),
|
||||
"n": json.Number("3"),
|
||||
"progress": json.Number("0"),
|
||||
"nonce": "",
|
||||
"type": "shamir",
|
||||
"sealed": true,
|
||||
"t": json.Number("3"),
|
||||
"n": json.Number("3"),
|
||||
"progress": json.Number("0"),
|
||||
"nonce": "",
|
||||
"type": "shamir",
|
||||
"recovery_seal": false,
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
testResponseBody(t, resp, &actual)
|
||||
@@ -108,12 +109,13 @@ func TestSysUnseal(t *testing.T) {
|
||||
|
||||
var actual map[string]interface{}
|
||||
expected := map[string]interface{}{
|
||||
"sealed": true,
|
||||
"t": json.Number("3"),
|
||||
"n": json.Number("3"),
|
||||
"progress": json.Number(fmt.Sprintf("%d", i+1)),
|
||||
"nonce": "",
|
||||
"type": "shamir",
|
||||
"sealed": true,
|
||||
"t": json.Number("3"),
|
||||
"n": json.Number("3"),
|
||||
"progress": json.Number(fmt.Sprintf("%d", i+1)),
|
||||
"nonce": "",
|
||||
"type": "shamir",
|
||||
"recovery_seal": false,
|
||||
}
|
||||
if i == len(keys)-1 {
|
||||
expected["sealed"] = false
|
||||
@@ -187,11 +189,12 @@ func TestSysUnseal_Reset(t *testing.T) {
|
||||
|
||||
var actual map[string]interface{}
|
||||
expected := map[string]interface{}{
|
||||
"sealed": true,
|
||||
"t": json.Number("3"),
|
||||
"n": json.Number("5"),
|
||||
"progress": json.Number(strconv.Itoa(i + 1)),
|
||||
"type": "shamir",
|
||||
"sealed": true,
|
||||
"t": json.Number("3"),
|
||||
"n": json.Number("5"),
|
||||
"progress": json.Number(strconv.Itoa(i + 1)),
|
||||
"type": "shamir",
|
||||
"recovery_seal": false,
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
testResponseBody(t, resp, &actual)
|
||||
@@ -224,11 +227,12 @@ func TestSysUnseal_Reset(t *testing.T) {
|
||||
|
||||
actual = map[string]interface{}{}
|
||||
expected := map[string]interface{}{
|
||||
"sealed": true,
|
||||
"t": json.Number("3"),
|
||||
"n": json.Number("5"),
|
||||
"progress": json.Number("0"),
|
||||
"type": "shamir",
|
||||
"sealed": true,
|
||||
"t": json.Number("3"),
|
||||
"n": json.Number("5"),
|
||||
"progress": json.Number("0"),
|
||||
"type": "shamir",
|
||||
"recovery_seal": false,
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
testResponseBody(t, resp, &actual)
|
||||
@@ -274,7 +278,7 @@ func TestSysSeal_Permissions(t *testing.T) {
|
||||
},
|
||||
ClientToken: root,
|
||||
}
|
||||
resp, err := core.HandleRequest(context.Background(), req)
|
||||
resp, err := core.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -289,7 +293,7 @@ func TestSysSeal_Permissions(t *testing.T) {
|
||||
"policies": []string{"test"},
|
||||
}
|
||||
|
||||
resp, err = core.HandleRequest(context.Background(), req)
|
||||
resp, err = core.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v %v", err, resp)
|
||||
}
|
||||
@@ -312,7 +316,7 @@ func TestSysSeal_Permissions(t *testing.T) {
|
||||
},
|
||||
ClientToken: root,
|
||||
}
|
||||
resp, err = core.HandleRequest(context.Background(), req)
|
||||
resp, err = core.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -333,7 +337,7 @@ func TestSysSeal_Permissions(t *testing.T) {
|
||||
},
|
||||
ClientToken: root,
|
||||
}
|
||||
resp, err = core.HandleRequest(context.Background(), req)
|
||||
resp, err = core.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -354,7 +358,7 @@ func TestSysSeal_Permissions(t *testing.T) {
|
||||
},
|
||||
ClientToken: root,
|
||||
}
|
||||
resp, err = core.HandleRequest(context.Background(), req)
|
||||
resp, err = core.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
22
http/util.go
Normal file
22
http/util.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/vault"
|
||||
)
|
||||
|
||||
var (
|
||||
adjustRequest = func(c *vault.Core, r *http.Request) (*http.Request, int) {
|
||||
return r.WithContext(namespace.ContextWithNamespace(r.Context(), namespace.RootNamespace)), 0
|
||||
}
|
||||
|
||||
genericWrapping = func(core *vault.Core, in http.Handler, props *vault.HandlerProperties) http.Handler {
|
||||
// Wrap the help wrapped handler with another layer with a generic
|
||||
// handler
|
||||
return wrapGenericHandler(core, in, props.MaxRequestSize, props.MaxRequestDuration)
|
||||
}
|
||||
|
||||
additionalRoutes = func(mux *http.ServeMux, core *vault.Core) {}
|
||||
)
|
||||
@@ -34,6 +34,10 @@ type Auth struct {
|
||||
TokenPolicies []string `json:"token_policies" mapstructure:"token_policies" structs:"token_policies"`
|
||||
IdentityPolicies []string `json:"identity_policies" mapstructure:"identity_policies" structs:"identity_policies"`
|
||||
|
||||
// ExternalNamespacePolicies represent the policies authorized from
|
||||
// different namespaces indexed by respective namespace identifiers
|
||||
ExternalNamespacePolicies map[string][]string `json:"external_namespace_policies" mapstructure:"external_namespace_policies" structs:"external_namespace_policies"`
|
||||
|
||||
// Metadata is used to attach arbitrary string-type metadata to
|
||||
// an authenticated user. This metadata will be outputted into the
|
||||
// audit log.
|
||||
|
||||
@@ -76,3 +76,15 @@ type ReplicationCodedError struct {
|
||||
func (r *ReplicationCodedError) Error() string {
|
||||
return r.Msg
|
||||
}
|
||||
|
||||
type KeyNotFoundError struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e *KeyNotFoundError) WrappedErrors() []error {
|
||||
return []error{e.Err}
|
||||
}
|
||||
|
||||
func (e *KeyNotFoundError) Error() string {
|
||||
return e.Err.Error()
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/hashicorp/vault/helper/errutil"
|
||||
"github.com/hashicorp/vault/helper/license"
|
||||
"github.com/hashicorp/vault/helper/logging"
|
||||
"github.com/hashicorp/vault/helper/parseutil"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
@@ -183,6 +184,14 @@ func (b *Backend) HandleRequest(ctx context.Context, req *logical.Request) (*log
|
||||
return nil, logical.ErrUnsupportedPath
|
||||
}
|
||||
|
||||
// Check if a feature is required and if the license has that feature
|
||||
if path.FeatureRequired != license.FeatureNone {
|
||||
hasFeature := b.system.HasFeature(path.FeatureRequired)
|
||||
if !hasFeature {
|
||||
return nil, logical.CodedError(401, "Feature Not Enabled")
|
||||
}
|
||||
}
|
||||
|
||||
// Build up the data for the route, with the URL taking priority
|
||||
// for the fields over the PUT data.
|
||||
raw := make(map[string]interface{}, len(path.Fields))
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
"github.com/hashicorp/vault/helper/license"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
)
|
||||
|
||||
@@ -69,6 +70,10 @@ type Path struct {
|
||||
// must have UpdateCapability on the path.
|
||||
ExistenceCheck ExistenceFunc
|
||||
|
||||
// FeatureRequired, if implemented, will validate if the given feature is
|
||||
// enabled for the set of paths
|
||||
FeatureRequired license.Features
|
||||
|
||||
// Help is text describing how to use this path. This will be used
|
||||
// to auto-generate the help operation. The Path will automatically
|
||||
// generate a parameter listing and URL structure based on the
|
||||
|
||||
@@ -20,13 +20,13 @@ const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
type Entity struct {
|
||||
// ID is the unique identifier for the entity
|
||||
ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
|
||||
ID string `sentinel:"" protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
|
||||
// Name is the human-friendly unique identifier for the entity
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Name string `sentinel:"" protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
// Aliases contains thhe alias mappings for the given entity
|
||||
Aliases []*Alias `protobuf:"bytes,3,rep,name=aliases,proto3" json:"aliases,omitempty"`
|
||||
Aliases []*Alias `sentinel:"" protobuf:"bytes,3,rep,name=aliases,proto3" json:"aliases,omitempty"`
|
||||
// Metadata represents the custom data tied to this entity
|
||||
Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
Metadata map[string]string `sentinel:"" protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
@@ -86,14 +86,14 @@ func (m *Entity) GetMetadata() map[string]string {
|
||||
|
||||
type Alias struct {
|
||||
// MountType is the backend mount's type to which this identity belongs
|
||||
MountType string `protobuf:"bytes,1,opt,name=mount_type,json=mountType,proto3" json:"mount_type,omitempty"`
|
||||
MountType string `sentinel:"" protobuf:"bytes,1,opt,name=mount_type,json=mountType,proto3" json:"mount_type,omitempty"`
|
||||
// MountAccessor is the identifier of the mount entry to which this
|
||||
// identity belongs
|
||||
MountAccessor string `protobuf:"bytes,2,opt,name=mount_accessor,json=mountAccessor,proto3" json:"mount_accessor,omitempty"`
|
||||
MountAccessor string `sentinel:"" protobuf:"bytes,2,opt,name=mount_accessor,json=mountAccessor,proto3" json:"mount_accessor,omitempty"`
|
||||
// Name is the identifier of this identity in its authentication source
|
||||
Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Name string `sentinel:"" protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
|
||||
// Metadata represents the custom data tied to this alias
|
||||
Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
Metadata map[string]string `sentinel:"" protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/vault/helper/consts"
|
||||
"github.com/hashicorp/vault/helper/license"
|
||||
"github.com/hashicorp/vault/helper/pluginutil"
|
||||
"github.com/hashicorp/vault/helper/wrapping"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
@@ -123,6 +124,11 @@ func (s *gRPCSystemViewClient) MlockEnabled() bool {
|
||||
return reply.Enabled
|
||||
}
|
||||
|
||||
func (s *gRPCSystemViewClient) HasFeature(feature license.Features) bool {
|
||||
// Not implemented
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *gRPCSystemViewClient) LocalMount() bool {
|
||||
reply, err := s.client.LocalMount(context.Background(), &pb.Empty{})
|
||||
if err != nil {
|
||||
|
||||
@@ -35,7 +35,7 @@ func (m *Empty) Reset() { *m = Empty{} }
|
||||
func (m *Empty) String() string { return proto.CompactTextString(m) }
|
||||
func (*Empty) ProtoMessage() {}
|
||||
func (*Empty) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{0}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{0}
|
||||
}
|
||||
func (m *Empty) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Empty.Unmarshal(m, b)
|
||||
@@ -66,7 +66,7 @@ func (m *Header) Reset() { *m = Header{} }
|
||||
func (m *Header) String() string { return proto.CompactTextString(m) }
|
||||
func (*Header) ProtoMessage() {}
|
||||
func (*Header) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{1}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{1}
|
||||
}
|
||||
func (m *Header) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Header.Unmarshal(m, b)
|
||||
@@ -117,7 +117,7 @@ func (m *ProtoError) Reset() { *m = ProtoError{} }
|
||||
func (m *ProtoError) String() string { return proto.CompactTextString(m) }
|
||||
func (*ProtoError) ProtoMessage() {}
|
||||
func (*ProtoError) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{2}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{2}
|
||||
}
|
||||
func (m *ProtoError) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ProtoError.Unmarshal(m, b)
|
||||
@@ -180,7 +180,7 @@ func (m *Paths) Reset() { *m = Paths{} }
|
||||
func (m *Paths) String() string { return proto.CompactTextString(m) }
|
||||
func (*Paths) ProtoMessage() {}
|
||||
func (*Paths) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{3}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{3}
|
||||
}
|
||||
func (m *Paths) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Paths.Unmarshal(m, b)
|
||||
@@ -304,7 +304,7 @@ func (m *Request) Reset() { *m = Request{} }
|
||||
func (m *Request) String() string { return proto.CompactTextString(m) }
|
||||
func (*Request) ProtoMessage() {}
|
||||
func (*Request) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{4}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{4}
|
||||
}
|
||||
func (m *Request) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Request.Unmarshal(m, b)
|
||||
@@ -513,7 +513,11 @@ type Auth struct {
|
||||
GroupAliases []*logical.Alias `sentinel:"" protobuf:"bytes,12,rep,name=group_aliases,json=groupAliases,proto3" json:"group_aliases,omitempty"`
|
||||
// If set, restricts usage of the certificates to client IPs falling within
|
||||
// the range of the specified CIDR(s).
|
||||
BoundCidrs []string `sentinel:"" protobuf:"bytes,13,rep,name=bound_cidrs,json=boundCidrs,proto3" json:"bound_cidrs,omitempty"`
|
||||
BoundCidrs []string `sentinel:"" protobuf:"bytes,13,rep,name=bound_cidrs,json=boundCidrs,proto3" json:"bound_cidrs,omitempty"`
|
||||
// TokenPolicies and IdentityPolicies break down the list in Policies to
|
||||
// help determine where a policy was sourced
|
||||
TokenPolicies []string `sentinel:"" protobuf:"bytes,14,rep,name=token_policies,json=tokenPolicies,proto3" json:"token_policies,omitempty"`
|
||||
IdentityPolicies []string `sentinel:"" protobuf:"bytes,15,rep,name=identity_policies,json=identityPolicies,proto3" json:"identity_policies,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
@@ -523,7 +527,7 @@ func (m *Auth) Reset() { *m = Auth{} }
|
||||
func (m *Auth) String() string { return proto.CompactTextString(m) }
|
||||
func (*Auth) ProtoMessage() {}
|
||||
func (*Auth) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{5}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{5}
|
||||
}
|
||||
func (m *Auth) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Auth.Unmarshal(m, b)
|
||||
@@ -634,6 +638,186 @@ func (m *Auth) GetBoundCidrs() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Auth) GetTokenPolicies() []string {
|
||||
if m != nil {
|
||||
return m.TokenPolicies
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Auth) GetIdentityPolicies() []string {
|
||||
if m != nil {
|
||||
return m.IdentityPolicies
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type TokenEntry struct {
|
||||
ID string `sentinel:"" protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Accessor string `sentinel:"" protobuf:"bytes,2,opt,name=accessor,proto3" json:"accessor,omitempty"`
|
||||
Parent string `sentinel:"" protobuf:"bytes,3,opt,name=parent,proto3" json:"parent,omitempty"`
|
||||
Policies []string `sentinel:"" protobuf:"bytes,4,rep,name=policies,proto3" json:"policies,omitempty"`
|
||||
Path string `sentinel:"" protobuf:"bytes,5,opt,name=path,proto3" json:"path,omitempty"`
|
||||
Meta map[string]string `sentinel:"" protobuf:"bytes,6,rep,name=meta,proto3" json:"meta,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
DisplayName string `sentinel:"" protobuf:"bytes,7,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"`
|
||||
NumUses int64 `sentinel:"" protobuf:"varint,8,opt,name=num_uses,json=numUses,proto3" json:"num_uses,omitempty"`
|
||||
CreationTime int64 `sentinel:"" protobuf:"varint,9,opt,name=creation_time,json=creationTime,proto3" json:"creation_time,omitempty"`
|
||||
TTL int64 `sentinel:"" protobuf:"varint,10,opt,name=ttl,proto3" json:"ttl,omitempty"`
|
||||
ExplicitMaxTTL int64 `sentinel:"" protobuf:"varint,11,opt,name=explicit_max_ttl,json=explicitMaxTtl,proto3" json:"explicit_max_ttl,omitempty"`
|
||||
Role string `sentinel:"" protobuf:"bytes,12,opt,name=role,proto3" json:"role,omitempty"`
|
||||
Period int64 `sentinel:"" protobuf:"varint,13,opt,name=period,proto3" json:"period,omitempty"`
|
||||
EntityID string `sentinel:"" protobuf:"bytes,14,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"`
|
||||
BoundCidrs []string `sentinel:"" protobuf:"bytes,15,rep,name=bound_cidrs,json=boundCidrs,proto3" json:"bound_cidrs,omitempty"`
|
||||
NamespaceID string `sentinel:"" protobuf:"bytes,16,opt,name=namespace_id,json=namespaceID,proto3" json:"namespace_id,omitempty"`
|
||||
CubbyholeID string `sentinel:"" protobuf:"bytes,17,opt,name=cubbyhole_id,json=cubbyholeId,proto3" json:"cubbyhole_id,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *TokenEntry) Reset() { *m = TokenEntry{} }
|
||||
func (m *TokenEntry) String() string { return proto.CompactTextString(m) }
|
||||
func (*TokenEntry) ProtoMessage() {}
|
||||
func (*TokenEntry) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{6}
|
||||
}
|
||||
func (m *TokenEntry) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_TokenEntry.Unmarshal(m, b)
|
||||
}
|
||||
func (m *TokenEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_TokenEntry.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (dst *TokenEntry) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_TokenEntry.Merge(dst, src)
|
||||
}
|
||||
func (m *TokenEntry) XXX_Size() int {
|
||||
return xxx_messageInfo_TokenEntry.Size(m)
|
||||
}
|
||||
func (m *TokenEntry) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_TokenEntry.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_TokenEntry proto.InternalMessageInfo
|
||||
|
||||
func (m *TokenEntry) GetID() string {
|
||||
if m != nil {
|
||||
return m.ID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *TokenEntry) GetAccessor() string {
|
||||
if m != nil {
|
||||
return m.Accessor
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *TokenEntry) GetParent() string {
|
||||
if m != nil {
|
||||
return m.Parent
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *TokenEntry) GetPolicies() []string {
|
||||
if m != nil {
|
||||
return m.Policies
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *TokenEntry) GetPath() string {
|
||||
if m != nil {
|
||||
return m.Path
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *TokenEntry) GetMeta() map[string]string {
|
||||
if m != nil {
|
||||
return m.Meta
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *TokenEntry) GetDisplayName() string {
|
||||
if m != nil {
|
||||
return m.DisplayName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *TokenEntry) GetNumUses() int64 {
|
||||
if m != nil {
|
||||
return m.NumUses
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *TokenEntry) GetCreationTime() int64 {
|
||||
if m != nil {
|
||||
return m.CreationTime
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *TokenEntry) GetTTL() int64 {
|
||||
if m != nil {
|
||||
return m.TTL
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *TokenEntry) GetExplicitMaxTTL() int64 {
|
||||
if m != nil {
|
||||
return m.ExplicitMaxTTL
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *TokenEntry) GetRole() string {
|
||||
if m != nil {
|
||||
return m.Role
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *TokenEntry) GetPeriod() int64 {
|
||||
if m != nil {
|
||||
return m.Period
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *TokenEntry) GetEntityID() string {
|
||||
if m != nil {
|
||||
return m.EntityID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *TokenEntry) GetBoundCidrs() []string {
|
||||
if m != nil {
|
||||
return m.BoundCidrs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *TokenEntry) GetNamespaceID() string {
|
||||
if m != nil {
|
||||
return m.NamespaceID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *TokenEntry) GetCubbyholeID() string {
|
||||
if m != nil {
|
||||
return m.CubbyholeID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type LeaseOptions struct {
|
||||
TTL int64 `sentinel:"" protobuf:"varint,1,opt,name=TTL,proto3" json:"TTL,omitempty"`
|
||||
Renewable bool `sentinel:"" protobuf:"varint,2,opt,name=renewable,proto3" json:"renewable,omitempty"`
|
||||
@@ -649,7 +833,7 @@ func (m *LeaseOptions) Reset() { *m = LeaseOptions{} }
|
||||
func (m *LeaseOptions) String() string { return proto.CompactTextString(m) }
|
||||
func (*LeaseOptions) ProtoMessage() {}
|
||||
func (*LeaseOptions) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{6}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{7}
|
||||
}
|
||||
func (m *LeaseOptions) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_LeaseOptions.Unmarshal(m, b)
|
||||
@@ -723,7 +907,7 @@ func (m *Secret) Reset() { *m = Secret{} }
|
||||
func (m *Secret) String() string { return proto.CompactTextString(m) }
|
||||
func (*Secret) ProtoMessage() {}
|
||||
func (*Secret) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{7}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{8}
|
||||
}
|
||||
func (m *Secret) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Secret.Unmarshal(m, b)
|
||||
@@ -794,7 +978,7 @@ func (m *Response) Reset() { *m = Response{} }
|
||||
func (m *Response) String() string { return proto.CompactTextString(m) }
|
||||
func (*Response) ProtoMessage() {}
|
||||
func (*Response) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{8}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{9}
|
||||
}
|
||||
func (m *Response) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Response.Unmarshal(m, b)
|
||||
@@ -889,7 +1073,7 @@ func (m *ResponseWrapInfo) Reset() { *m = ResponseWrapInfo{} }
|
||||
func (m *ResponseWrapInfo) String() string { return proto.CompactTextString(m) }
|
||||
func (*ResponseWrapInfo) ProtoMessage() {}
|
||||
func (*ResponseWrapInfo) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{9}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{10}
|
||||
}
|
||||
func (m *ResponseWrapInfo) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ResponseWrapInfo.Unmarshal(m, b)
|
||||
@@ -991,7 +1175,7 @@ func (m *RequestWrapInfo) Reset() { *m = RequestWrapInfo{} }
|
||||
func (m *RequestWrapInfo) String() string { return proto.CompactTextString(m) }
|
||||
func (*RequestWrapInfo) ProtoMessage() {}
|
||||
func (*RequestWrapInfo) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{10}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{11}
|
||||
}
|
||||
func (m *RequestWrapInfo) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_RequestWrapInfo.Unmarshal(m, b)
|
||||
@@ -1045,7 +1229,7 @@ func (m *HandleRequestArgs) Reset() { *m = HandleRequestArgs{} }
|
||||
func (m *HandleRequestArgs) String() string { return proto.CompactTextString(m) }
|
||||
func (*HandleRequestArgs) ProtoMessage() {}
|
||||
func (*HandleRequestArgs) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{11}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{12}
|
||||
}
|
||||
func (m *HandleRequestArgs) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_HandleRequestArgs.Unmarshal(m, b)
|
||||
@@ -1092,7 +1276,7 @@ func (m *HandleRequestReply) Reset() { *m = HandleRequestReply{} }
|
||||
func (m *HandleRequestReply) String() string { return proto.CompactTextString(m) }
|
||||
func (*HandleRequestReply) ProtoMessage() {}
|
||||
func (*HandleRequestReply) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{12}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{13}
|
||||
}
|
||||
func (m *HandleRequestReply) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_HandleRequestReply.Unmarshal(m, b)
|
||||
@@ -1138,7 +1322,7 @@ func (m *SpecialPathsReply) Reset() { *m = SpecialPathsReply{} }
|
||||
func (m *SpecialPathsReply) String() string { return proto.CompactTextString(m) }
|
||||
func (*SpecialPathsReply) ProtoMessage() {}
|
||||
func (*SpecialPathsReply) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{13}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{14}
|
||||
}
|
||||
func (m *SpecialPathsReply) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_SpecialPathsReply.Unmarshal(m, b)
|
||||
@@ -1178,7 +1362,7 @@ func (m *HandleExistenceCheckArgs) Reset() { *m = HandleExistenceCheckAr
|
||||
func (m *HandleExistenceCheckArgs) String() string { return proto.CompactTextString(m) }
|
||||
func (*HandleExistenceCheckArgs) ProtoMessage() {}
|
||||
func (*HandleExistenceCheckArgs) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{14}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{15}
|
||||
}
|
||||
func (m *HandleExistenceCheckArgs) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_HandleExistenceCheckArgs.Unmarshal(m, b)
|
||||
@@ -1226,7 +1410,7 @@ func (m *HandleExistenceCheckReply) Reset() { *m = HandleExistenceCheckR
|
||||
func (m *HandleExistenceCheckReply) String() string { return proto.CompactTextString(m) }
|
||||
func (*HandleExistenceCheckReply) ProtoMessage() {}
|
||||
func (*HandleExistenceCheckReply) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{15}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{16}
|
||||
}
|
||||
func (m *HandleExistenceCheckReply) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_HandleExistenceCheckReply.Unmarshal(m, b)
|
||||
@@ -1281,7 +1465,7 @@ func (m *SetupArgs) Reset() { *m = SetupArgs{} }
|
||||
func (m *SetupArgs) String() string { return proto.CompactTextString(m) }
|
||||
func (*SetupArgs) ProtoMessage() {}
|
||||
func (*SetupArgs) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{16}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{17}
|
||||
}
|
||||
func (m *SetupArgs) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_SetupArgs.Unmarshal(m, b)
|
||||
@@ -1334,7 +1518,7 @@ func (m *SetupReply) Reset() { *m = SetupReply{} }
|
||||
func (m *SetupReply) String() string { return proto.CompactTextString(m) }
|
||||
func (*SetupReply) ProtoMessage() {}
|
||||
func (*SetupReply) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{17}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{18}
|
||||
}
|
||||
func (m *SetupReply) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_SetupReply.Unmarshal(m, b)
|
||||
@@ -1373,7 +1557,7 @@ func (m *TypeReply) Reset() { *m = TypeReply{} }
|
||||
func (m *TypeReply) String() string { return proto.CompactTextString(m) }
|
||||
func (*TypeReply) ProtoMessage() {}
|
||||
func (*TypeReply) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{18}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{19}
|
||||
}
|
||||
func (m *TypeReply) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_TypeReply.Unmarshal(m, b)
|
||||
@@ -1411,7 +1595,7 @@ func (m *InvalidateKeyArgs) Reset() { *m = InvalidateKeyArgs{} }
|
||||
func (m *InvalidateKeyArgs) String() string { return proto.CompactTextString(m) }
|
||||
func (*InvalidateKeyArgs) ProtoMessage() {}
|
||||
func (*InvalidateKeyArgs) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{19}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{20}
|
||||
}
|
||||
func (m *InvalidateKeyArgs) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_InvalidateKeyArgs.Unmarshal(m, b)
|
||||
@@ -1451,7 +1635,7 @@ func (m *StorageEntry) Reset() { *m = StorageEntry{} }
|
||||
func (m *StorageEntry) String() string { return proto.CompactTextString(m) }
|
||||
func (*StorageEntry) ProtoMessage() {}
|
||||
func (*StorageEntry) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{20}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{21}
|
||||
}
|
||||
func (m *StorageEntry) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_StorageEntry.Unmarshal(m, b)
|
||||
@@ -1503,7 +1687,7 @@ func (m *StorageListArgs) Reset() { *m = StorageListArgs{} }
|
||||
func (m *StorageListArgs) String() string { return proto.CompactTextString(m) }
|
||||
func (*StorageListArgs) ProtoMessage() {}
|
||||
func (*StorageListArgs) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{21}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{22}
|
||||
}
|
||||
func (m *StorageListArgs) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_StorageListArgs.Unmarshal(m, b)
|
||||
@@ -1542,7 +1726,7 @@ func (m *StorageListReply) Reset() { *m = StorageListReply{} }
|
||||
func (m *StorageListReply) String() string { return proto.CompactTextString(m) }
|
||||
func (*StorageListReply) ProtoMessage() {}
|
||||
func (*StorageListReply) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{22}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{23}
|
||||
}
|
||||
func (m *StorageListReply) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_StorageListReply.Unmarshal(m, b)
|
||||
@@ -1587,7 +1771,7 @@ func (m *StorageGetArgs) Reset() { *m = StorageGetArgs{} }
|
||||
func (m *StorageGetArgs) String() string { return proto.CompactTextString(m) }
|
||||
func (*StorageGetArgs) ProtoMessage() {}
|
||||
func (*StorageGetArgs) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{23}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{24}
|
||||
}
|
||||
func (m *StorageGetArgs) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_StorageGetArgs.Unmarshal(m, b)
|
||||
@@ -1626,7 +1810,7 @@ func (m *StorageGetReply) Reset() { *m = StorageGetReply{} }
|
||||
func (m *StorageGetReply) String() string { return proto.CompactTextString(m) }
|
||||
func (*StorageGetReply) ProtoMessage() {}
|
||||
func (*StorageGetReply) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{24}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{25}
|
||||
}
|
||||
func (m *StorageGetReply) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_StorageGetReply.Unmarshal(m, b)
|
||||
@@ -1671,7 +1855,7 @@ func (m *StoragePutArgs) Reset() { *m = StoragePutArgs{} }
|
||||
func (m *StoragePutArgs) String() string { return proto.CompactTextString(m) }
|
||||
func (*StoragePutArgs) ProtoMessage() {}
|
||||
func (*StoragePutArgs) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{25}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{26}
|
||||
}
|
||||
func (m *StoragePutArgs) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_StoragePutArgs.Unmarshal(m, b)
|
||||
@@ -1709,7 +1893,7 @@ func (m *StoragePutReply) Reset() { *m = StoragePutReply{} }
|
||||
func (m *StoragePutReply) String() string { return proto.CompactTextString(m) }
|
||||
func (*StoragePutReply) ProtoMessage() {}
|
||||
func (*StoragePutReply) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{26}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{27}
|
||||
}
|
||||
func (m *StoragePutReply) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_StoragePutReply.Unmarshal(m, b)
|
||||
@@ -1747,7 +1931,7 @@ func (m *StorageDeleteArgs) Reset() { *m = StorageDeleteArgs{} }
|
||||
func (m *StorageDeleteArgs) String() string { return proto.CompactTextString(m) }
|
||||
func (*StorageDeleteArgs) ProtoMessage() {}
|
||||
func (*StorageDeleteArgs) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{27}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{28}
|
||||
}
|
||||
func (m *StorageDeleteArgs) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_StorageDeleteArgs.Unmarshal(m, b)
|
||||
@@ -1785,7 +1969,7 @@ func (m *StorageDeleteReply) Reset() { *m = StorageDeleteReply{} }
|
||||
func (m *StorageDeleteReply) String() string { return proto.CompactTextString(m) }
|
||||
func (*StorageDeleteReply) ProtoMessage() {}
|
||||
func (*StorageDeleteReply) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{28}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{29}
|
||||
}
|
||||
func (m *StorageDeleteReply) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_StorageDeleteReply.Unmarshal(m, b)
|
||||
@@ -1823,7 +2007,7 @@ func (m *TTLReply) Reset() { *m = TTLReply{} }
|
||||
func (m *TTLReply) String() string { return proto.CompactTextString(m) }
|
||||
func (*TTLReply) ProtoMessage() {}
|
||||
func (*TTLReply) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{29}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{30}
|
||||
}
|
||||
func (m *TTLReply) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_TTLReply.Unmarshal(m, b)
|
||||
@@ -1862,7 +2046,7 @@ func (m *SudoPrivilegeArgs) Reset() { *m = SudoPrivilegeArgs{} }
|
||||
func (m *SudoPrivilegeArgs) String() string { return proto.CompactTextString(m) }
|
||||
func (*SudoPrivilegeArgs) ProtoMessage() {}
|
||||
func (*SudoPrivilegeArgs) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{30}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{31}
|
||||
}
|
||||
func (m *SudoPrivilegeArgs) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_SudoPrivilegeArgs.Unmarshal(m, b)
|
||||
@@ -1907,7 +2091,7 @@ func (m *SudoPrivilegeReply) Reset() { *m = SudoPrivilegeReply{} }
|
||||
func (m *SudoPrivilegeReply) String() string { return proto.CompactTextString(m) }
|
||||
func (*SudoPrivilegeReply) ProtoMessage() {}
|
||||
func (*SudoPrivilegeReply) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{31}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{32}
|
||||
}
|
||||
func (m *SudoPrivilegeReply) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_SudoPrivilegeReply.Unmarshal(m, b)
|
||||
@@ -1945,7 +2129,7 @@ func (m *TaintedReply) Reset() { *m = TaintedReply{} }
|
||||
func (m *TaintedReply) String() string { return proto.CompactTextString(m) }
|
||||
func (*TaintedReply) ProtoMessage() {}
|
||||
func (*TaintedReply) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{32}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{33}
|
||||
}
|
||||
func (m *TaintedReply) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_TaintedReply.Unmarshal(m, b)
|
||||
@@ -1983,7 +2167,7 @@ func (m *CachingDisabledReply) Reset() { *m = CachingDisabledReply{} }
|
||||
func (m *CachingDisabledReply) String() string { return proto.CompactTextString(m) }
|
||||
func (*CachingDisabledReply) ProtoMessage() {}
|
||||
func (*CachingDisabledReply) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{33}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{34}
|
||||
}
|
||||
func (m *CachingDisabledReply) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_CachingDisabledReply.Unmarshal(m, b)
|
||||
@@ -2021,7 +2205,7 @@ func (m *ReplicationStateReply) Reset() { *m = ReplicationStateReply{} }
|
||||
func (m *ReplicationStateReply) String() string { return proto.CompactTextString(m) }
|
||||
func (*ReplicationStateReply) ProtoMessage() {}
|
||||
func (*ReplicationStateReply) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{34}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{35}
|
||||
}
|
||||
func (m *ReplicationStateReply) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ReplicationStateReply.Unmarshal(m, b)
|
||||
@@ -2061,7 +2245,7 @@ func (m *ResponseWrapDataArgs) Reset() { *m = ResponseWrapDataArgs{} }
|
||||
func (m *ResponseWrapDataArgs) String() string { return proto.CompactTextString(m) }
|
||||
func (*ResponseWrapDataArgs) ProtoMessage() {}
|
||||
func (*ResponseWrapDataArgs) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{35}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{36}
|
||||
}
|
||||
func (m *ResponseWrapDataArgs) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ResponseWrapDataArgs.Unmarshal(m, b)
|
||||
@@ -2114,7 +2298,7 @@ func (m *ResponseWrapDataReply) Reset() { *m = ResponseWrapDataReply{} }
|
||||
func (m *ResponseWrapDataReply) String() string { return proto.CompactTextString(m) }
|
||||
func (*ResponseWrapDataReply) ProtoMessage() {}
|
||||
func (*ResponseWrapDataReply) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{36}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{37}
|
||||
}
|
||||
func (m *ResponseWrapDataReply) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ResponseWrapDataReply.Unmarshal(m, b)
|
||||
@@ -2159,7 +2343,7 @@ func (m *MlockEnabledReply) Reset() { *m = MlockEnabledReply{} }
|
||||
func (m *MlockEnabledReply) String() string { return proto.CompactTextString(m) }
|
||||
func (*MlockEnabledReply) ProtoMessage() {}
|
||||
func (*MlockEnabledReply) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{37}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{38}
|
||||
}
|
||||
func (m *MlockEnabledReply) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_MlockEnabledReply.Unmarshal(m, b)
|
||||
@@ -2197,7 +2381,7 @@ func (m *LocalMountReply) Reset() { *m = LocalMountReply{} }
|
||||
func (m *LocalMountReply) String() string { return proto.CompactTextString(m) }
|
||||
func (*LocalMountReply) ProtoMessage() {}
|
||||
func (*LocalMountReply) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{38}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{39}
|
||||
}
|
||||
func (m *LocalMountReply) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_LocalMountReply.Unmarshal(m, b)
|
||||
@@ -2235,7 +2419,7 @@ func (m *EntityInfoArgs) Reset() { *m = EntityInfoArgs{} }
|
||||
func (m *EntityInfoArgs) String() string { return proto.CompactTextString(m) }
|
||||
func (*EntityInfoArgs) ProtoMessage() {}
|
||||
func (*EntityInfoArgs) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{39}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{40}
|
||||
}
|
||||
func (m *EntityInfoArgs) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_EntityInfoArgs.Unmarshal(m, b)
|
||||
@@ -2274,7 +2458,7 @@ func (m *EntityInfoReply) Reset() { *m = EntityInfoReply{} }
|
||||
func (m *EntityInfoReply) String() string { return proto.CompactTextString(m) }
|
||||
func (*EntityInfoReply) ProtoMessage() {}
|
||||
func (*EntityInfoReply) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{40}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{41}
|
||||
}
|
||||
func (m *EntityInfoReply) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_EntityInfoReply.Unmarshal(m, b)
|
||||
@@ -2320,7 +2504,7 @@ func (m *PluginEnvReply) Reset() { *m = PluginEnvReply{} }
|
||||
func (m *PluginEnvReply) String() string { return proto.CompactTextString(m) }
|
||||
func (*PluginEnvReply) ProtoMessage() {}
|
||||
func (*PluginEnvReply) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{41}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{42}
|
||||
}
|
||||
func (m *PluginEnvReply) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_PluginEnvReply.Unmarshal(m, b)
|
||||
@@ -2366,7 +2550,7 @@ func (m *Connection) Reset() { *m = Connection{} }
|
||||
func (m *Connection) String() string { return proto.CompactTextString(m) }
|
||||
func (*Connection) ProtoMessage() {}
|
||||
func (*Connection) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_backend_6306a5aa9d5ea026, []int{42}
|
||||
return fileDescriptor_backend_2aa165f9d8e053c1, []int{43}
|
||||
}
|
||||
func (m *Connection) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Connection.Unmarshal(m, b)
|
||||
@@ -2402,6 +2586,8 @@ func init() {
|
||||
proto.RegisterMapType((map[string]*Header)(nil), "pb.Request.HeadersEntry")
|
||||
proto.RegisterType((*Auth)(nil), "pb.Auth")
|
||||
proto.RegisterMapType((map[string]string)(nil), "pb.Auth.MetadataEntry")
|
||||
proto.RegisterType((*TokenEntry)(nil), "pb.TokenEntry")
|
||||
proto.RegisterMapType((map[string]string)(nil), "pb.TokenEntry.MetaEntry")
|
||||
proto.RegisterType((*LeaseOptions)(nil), "pb.LeaseOptions")
|
||||
proto.RegisterType((*Secret)(nil), "pb.Secret")
|
||||
proto.RegisterType((*Response)(nil), "pb.Response")
|
||||
@@ -3370,151 +3556,163 @@ var _SystemView_serviceDesc = grpc.ServiceDesc{
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("logical/plugin/pb/backend.proto", fileDescriptor_backend_6306a5aa9d5ea026)
|
||||
proto.RegisterFile("logical/plugin/pb/backend.proto", fileDescriptor_backend_2aa165f9d8e053c1)
|
||||
}
|
||||
|
||||
var fileDescriptor_backend_6306a5aa9d5ea026 = []byte{
|
||||
// 2258 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x5f, 0x73, 0xdb, 0xc6,
|
||||
0x11, 0x1f, 0x92, 0x22, 0x09, 0x2e, 0x49, 0x51, 0x3a, 0x2b, 0x2e, 0x4c, 0x3b, 0x35, 0x8b, 0xd4,
|
||||
0xb6, 0xe2, 0x89, 0x29, 0x9b, 0x69, 0x5a, 0xa7, 0x9d, 0xa4, 0xa3, 0xc8, 0x8a, 0xa3, 0x46, 0x4a,
|
||||
0x34, 0x90, 0xdc, 0xf4, 0xdf, 0x0c, 0x73, 0x02, 0x56, 0x24, 0x46, 0x20, 0x80, 0x1e, 0x0e, 0xb2,
|
||||
0xf9, 0xd4, 0x6f, 0xd1, 0xb7, 0x7e, 0x86, 0xbe, 0xf6, 0xad, 0x6f, 0x9d, 0xce, 0xf4, 0xb9, 0x5f,
|
||||
0xa3, 0x9f, 0xa1, 0x73, 0x7f, 0x00, 0x1e, 0x48, 0xaa, 0x71, 0x67, 0xda, 0xb7, 0xdb, 0x3f, 0xb7,
|
||||
0x77, 0xbb, 0xd8, 0xfd, 0xed, 0x1e, 0xe0, 0x7e, 0x18, 0x4f, 0x02, 0x8f, 0x86, 0x7b, 0x49, 0x98,
|
||||
0x4d, 0x82, 0x68, 0x2f, 0xb9, 0xd8, 0xbb, 0xa0, 0xde, 0x15, 0x46, 0xfe, 0x30, 0x61, 0x31, 0x8f,
|
||||
0x49, 0x35, 0xb9, 0xe8, 0xdf, 0x9f, 0xc4, 0xf1, 0x24, 0xc4, 0x3d, 0xc9, 0xb9, 0xc8, 0x2e, 0xf7,
|
||||
0x78, 0x30, 0xc3, 0x94, 0xd3, 0x59, 0xa2, 0x94, 0xfa, 0xb7, 0x73, 0x2b, 0x81, 0x8f, 0x11, 0x0f,
|
||||
0xf8, 0x5c, 0xf3, 0x77, 0xca, 0xd6, 0x15, 0xd7, 0x69, 0x42, 0xfd, 0x70, 0x96, 0xf0, 0xb9, 0x33,
|
||||
0x80, 0xc6, 0x17, 0x48, 0x7d, 0x64, 0xe4, 0x36, 0x34, 0xa6, 0x72, 0x65, 0x57, 0x06, 0xb5, 0xdd,
|
||||
0x96, 0xab, 0x29, 0xe7, 0xb7, 0x00, 0xa7, 0x62, 0xcf, 0x21, 0x63, 0x31, 0x23, 0x77, 0xc0, 0x42,
|
||||
0xc6, 0xc6, 0x7c, 0x9e, 0xa0, 0x5d, 0x19, 0x54, 0x76, 0xbb, 0x6e, 0x13, 0x19, 0x3b, 0x9f, 0x27,
|
||||
0x48, 0xbe, 0x07, 0x62, 0x39, 0x9e, 0xa5, 0x13, 0xbb, 0x3a, 0xa8, 0x08, 0x0b, 0xc8, 0xd8, 0x49,
|
||||
0x3a, 0xc9, 0xf7, 0x78, 0xb1, 0x8f, 0x76, 0x6d, 0x50, 0xd9, 0xad, 0xc9, 0x3d, 0x07, 0xb1, 0x8f,
|
||||
0xce, 0x1f, 0x2b, 0x50, 0x3f, 0xa5, 0x7c, 0x9a, 0x12, 0x02, 0x1b, 0x2c, 0x8e, 0xb9, 0x3e, 0x5c,
|
||||
0xae, 0xc9, 0x2e, 0xf4, 0xb2, 0x88, 0x66, 0x7c, 0x2a, 0x3c, 0xf2, 0x28, 0x47, 0xdf, 0xae, 0x4a,
|
||||
0xf1, 0x32, 0x9b, 0xbc, 0x07, 0xdd, 0x30, 0xf6, 0x68, 0x38, 0x4e, 0x79, 0xcc, 0xe8, 0x44, 0x9c,
|
||||
0x23, 0xf4, 0x3a, 0x92, 0x79, 0xa6, 0x78, 0xe4, 0x31, 0x6c, 0xa7, 0x48, 0xc3, 0xf1, 0x6b, 0x46,
|
||||
0x93, 0x42, 0x71, 0x43, 0x19, 0x14, 0x82, 0x6f, 0x18, 0x4d, 0xb4, 0xae, 0xf3, 0xd7, 0x06, 0x34,
|
||||
0x5d, 0xfc, 0x7d, 0x86, 0x29, 0x27, 0x9b, 0x50, 0x0d, 0x7c, 0xe9, 0x6d, 0xcb, 0xad, 0x06, 0x3e,
|
||||
0x19, 0x02, 0x71, 0x31, 0x09, 0xc5, 0xd1, 0x41, 0x1c, 0x1d, 0x84, 0x59, 0xca, 0x91, 0x69, 0x9f,
|
||||
0xd7, 0x48, 0xc8, 0x3d, 0x68, 0xc5, 0x09, 0x32, 0xc9, 0x93, 0x01, 0x68, 0xb9, 0x0b, 0x86, 0x70,
|
||||
0x3c, 0xa1, 0x7c, 0x6a, 0x6f, 0x48, 0x81, 0x5c, 0x0b, 0x9e, 0x4f, 0x39, 0xb5, 0xeb, 0x8a, 0x27,
|
||||
0xd6, 0xc4, 0x81, 0x46, 0x8a, 0x1e, 0x43, 0x6e, 0x37, 0x06, 0x95, 0xdd, 0xf6, 0x08, 0x86, 0xc9,
|
||||
0xc5, 0xf0, 0x4c, 0x72, 0x5c, 0x2d, 0x21, 0xf7, 0x60, 0x43, 0xc4, 0xc5, 0x6e, 0x4a, 0x0d, 0x4b,
|
||||
0x68, 0xec, 0x67, 0x7c, 0xea, 0x4a, 0x2e, 0x19, 0x41, 0x53, 0x7d, 0xd3, 0xd4, 0xb6, 0x06, 0xb5,
|
||||
0xdd, 0xf6, 0xc8, 0x16, 0x0a, 0xda, 0xcb, 0xa1, 0x4a, 0x83, 0xf4, 0x30, 0xe2, 0x6c, 0xee, 0xe6,
|
||||
0x8a, 0xe4, 0x07, 0xd0, 0xf1, 0xc2, 0x00, 0x23, 0x3e, 0xe6, 0xf1, 0x15, 0x46, 0x76, 0x4b, 0xde,
|
||||
0xa8, 0xad, 0x78, 0xe7, 0x82, 0x45, 0x46, 0xf0, 0x8e, 0xa9, 0x32, 0xa6, 0x9e, 0x87, 0x69, 0x1a,
|
||||
0x33, 0x1b, 0xa4, 0xee, 0x2d, 0x43, 0x77, 0x5f, 0x8b, 0x84, 0x59, 0x3f, 0x48, 0x93, 0x90, 0xce,
|
||||
0xc7, 0x11, 0x9d, 0xa1, 0xdd, 0x56, 0x66, 0x35, 0xef, 0x2b, 0x3a, 0x43, 0x72, 0x1f, 0xda, 0xb3,
|
||||
0x38, 0x8b, 0xf8, 0x38, 0x89, 0x83, 0x88, 0xdb, 0x1d, 0xa9, 0x01, 0x92, 0x75, 0x2a, 0x38, 0xe4,
|
||||
0x5d, 0x50, 0x94, 0x4a, 0xc6, 0xae, 0x8a, 0xab, 0xe4, 0xc8, 0x74, 0x7c, 0x00, 0x9b, 0x4a, 0x5c,
|
||||
0xdc, 0x67, 0x53, 0xaa, 0x74, 0x25, 0xb7, 0xb8, 0xc9, 0x53, 0x68, 0xc9, 0x7c, 0x08, 0xa2, 0xcb,
|
||||
0xd8, 0xee, 0xc9, 0xb8, 0xdd, 0x32, 0xc2, 0x22, 0x72, 0xe2, 0x28, 0xba, 0x8c, 0x5d, 0xeb, 0xb5,
|
||||
0x5e, 0x91, 0x4f, 0xe0, 0x6e, 0xc9, 0x5f, 0x86, 0x33, 0x1a, 0x44, 0x41, 0x34, 0x19, 0x67, 0x29,
|
||||
0xa6, 0xf6, 0x96, 0xcc, 0x70, 0xdb, 0xf0, 0xda, 0xcd, 0x15, 0x5e, 0xa5, 0x98, 0x92, 0xbb, 0xd0,
|
||||
0x52, 0x05, 0x3a, 0x0e, 0x7c, 0x7b, 0x5b, 0x5e, 0xc9, 0x52, 0x8c, 0x23, 0x9f, 0x3c, 0x82, 0x5e,
|
||||
0x12, 0x87, 0x81, 0x37, 0x1f, 0xc7, 0xd7, 0xc8, 0x58, 0xe0, 0xa3, 0x4d, 0x06, 0x95, 0x5d, 0xcb,
|
||||
0xdd, 0x54, 0xec, 0xaf, 0x35, 0x77, 0x5d, 0x69, 0xdc, 0x92, 0x8a, 0x2b, 0xa5, 0x31, 0x04, 0xf0,
|
||||
0xe2, 0x28, 0x42, 0x4f, 0xa6, 0xdf, 0x8e, 0xf4, 0x70, 0x53, 0x78, 0x78, 0x50, 0x70, 0x5d, 0x43,
|
||||
0xa3, 0xff, 0x39, 0x74, 0xcc, 0x54, 0x20, 0x5b, 0x50, 0xbb, 0xc2, 0xb9, 0x4e, 0x7f, 0xb1, 0x24,
|
||||
0x03, 0xa8, 0x5f, 0xd3, 0x30, 0x43, 0x99, 0xf2, 0x3a, 0x11, 0xd5, 0x16, 0x57, 0x09, 0x7e, 0x5a,
|
||||
0x7d, 0x5e, 0x71, 0xfe, 0xb4, 0x01, 0x1b, 0x22, 0xf9, 0xc8, 0x47, 0xd0, 0x0d, 0x91, 0xa6, 0x38,
|
||||
0x8e, 0x13, 0x71, 0x40, 0x2a, 0x4d, 0xb5, 0x47, 0x5b, 0x62, 0xdb, 0xb1, 0x10, 0x7c, 0xad, 0xf8,
|
||||
0x6e, 0x27, 0x34, 0x28, 0x51, 0xd2, 0x41, 0xc4, 0x91, 0x45, 0x34, 0x1c, 0xcb, 0x62, 0x50, 0x05,
|
||||
0xd6, 0xc9, 0x99, 0x2f, 0x44, 0x51, 0x2c, 0xe7, 0x51, 0x6d, 0x35, 0x8f, 0xfa, 0x60, 0xc9, 0xd8,
|
||||
0x05, 0x98, 0xea, 0x62, 0x2f, 0x68, 0x32, 0x02, 0x6b, 0x86, 0x9c, 0xea, 0x5a, 0x13, 0x25, 0x71,
|
||||
0x3b, 0xaf, 0x99, 0xe1, 0x89, 0x16, 0xa8, 0x82, 0x28, 0xf4, 0x56, 0x2a, 0xa2, 0xb1, 0x5a, 0x11,
|
||||
0x7d, 0xb0, 0x8a, 0xa4, 0x6b, 0xaa, 0x2f, 0x9c, 0xd3, 0x02, 0x66, 0x13, 0x64, 0x41, 0xec, 0xdb,
|
||||
0x96, 0x4c, 0x14, 0x4d, 0x09, 0x90, 0x8c, 0xb2, 0x99, 0x4a, 0xa1, 0x96, 0x02, 0xc9, 0x28, 0x9b,
|
||||
0xad, 0x66, 0x0c, 0x2c, 0x65, 0xcc, 0x0f, 0xa1, 0x4e, 0xc3, 0x80, 0xa6, 0xb2, 0x84, 0xc4, 0x97,
|
||||
0xd5, 0x78, 0x3f, 0xdc, 0x17, 0x5c, 0x57, 0x09, 0xc9, 0x87, 0xd0, 0x9d, 0xb0, 0x38, 0x4b, 0xc6,
|
||||
0x92, 0xc4, 0xd4, 0xee, 0x48, 0x6f, 0x97, 0xb5, 0x3b, 0x52, 0x69, 0x5f, 0xe9, 0x88, 0x0a, 0xbc,
|
||||
0x88, 0xb3, 0xc8, 0x1f, 0x7b, 0x81, 0xcf, 0x52, 0xbb, 0x2b, 0x83, 0x07, 0x92, 0x75, 0x20, 0x38,
|
||||
0xfd, 0x9f, 0x41, 0xb7, 0x14, 0xa5, 0x35, 0xb9, 0xb2, 0x63, 0xe6, 0x4a, 0xcb, 0xcc, 0x8f, 0x3f,
|
||||
0x57, 0xa0, 0x63, 0x7e, 0x7e, 0xb1, 0xf9, 0xfc, 0xfc, 0x58, 0x6e, 0xae, 0xb9, 0x62, 0x29, 0x80,
|
||||
0x93, 0x61, 0x84, 0xaf, 0xe9, 0x45, 0xa8, 0x0c, 0x58, 0xee, 0x82, 0x21, 0xa4, 0x41, 0xe4, 0x31,
|
||||
0x9c, 0x61, 0xc4, 0x75, 0x5f, 0x59, 0x30, 0xc8, 0xc7, 0x00, 0x41, 0x9a, 0x66, 0x38, 0x16, 0x8d,
|
||||
0x52, 0x82, 0x6b, 0x7b, 0xd4, 0x1f, 0xaa, 0x2e, 0x3a, 0xcc, 0xbb, 0xe8, 0xf0, 0x3c, 0xef, 0xa2,
|
||||
0x6e, 0x4b, 0x6a, 0x0b, 0x5a, 0x7c, 0xa2, 0x13, 0xfa, 0x46, 0xdc, 0xa5, 0xae, 0x3e, 0x91, 0xa2,
|
||||
0x9c, 0x3f, 0x40, 0x43, 0xe1, 0xed, 0xff, 0x35, 0xa5, 0xef, 0x80, 0xa5, 0x6c, 0x07, 0xbe, 0x4e,
|
||||
0xe7, 0xa6, 0xa4, 0x8f, 0x7c, 0xe7, 0x1f, 0x15, 0xb0, 0x5c, 0x4c, 0x93, 0x38, 0x4a, 0xd1, 0xe8,
|
||||
0x07, 0x95, 0xef, 0xec, 0x07, 0xd5, 0xb5, 0xfd, 0x20, 0xef, 0x32, 0x35, 0xa3, 0xcb, 0xf4, 0xc1,
|
||||
0x62, 0xe8, 0x07, 0x0c, 0x3d, 0xae, 0x3b, 0x52, 0x41, 0x0b, 0xd9, 0x6b, 0xca, 0x04, 0x90, 0xa5,
|
||||
0xb2, 0x5a, 0x5a, 0x6e, 0x41, 0x93, 0x67, 0x26, 0x8c, 0xaa, 0x06, 0xb5, 0xa3, 0x60, 0x54, 0x5d,
|
||||
0x77, 0x15, 0x47, 0x9d, 0xbf, 0x57, 0x61, 0x6b, 0x59, 0xbc, 0x26, 0x09, 0x76, 0xa0, 0xae, 0x0a,
|
||||
0x4d, 0x67, 0x10, 0x5f, 0x29, 0xb1, 0xda, 0x52, 0x89, 0xfd, 0x1c, 0xba, 0x1e, 0x43, 0xd9, 0x5d,
|
||||
0xdf, 0xf6, 0xeb, 0x77, 0xf2, 0x0d, 0x32, 0x01, 0xde, 0x87, 0x2d, 0x71, 0xcb, 0x04, 0xfd, 0x45,
|
||||
0xf3, 0x50, 0xad, 0xb8, 0xa7, 0xf9, 0x45, 0xfb, 0x78, 0x0c, 0xdb, 0xb9, 0xea, 0xa2, 0x46, 0x1b,
|
||||
0x25, 0xdd, 0xc3, 0xbc, 0x54, 0x6f, 0x43, 0xe3, 0x32, 0x66, 0x33, 0xca, 0x35, 0x28, 0x68, 0x4a,
|
||||
0xa4, 0x45, 0x71, 0x5f, 0x39, 0x0a, 0x58, 0x2a, 0x2d, 0x72, 0xa6, 0x18, 0x90, 0x04, 0x08, 0x14,
|
||||
0xc3, 0x8b, 0x04, 0x08, 0xcb, 0xb5, 0xf2, 0xa1, 0xc5, 0xf9, 0x15, 0xf4, 0x96, 0xfa, 0xd5, 0x9a,
|
||||
0x40, 0x2e, 0x8e, 0xaf, 0x96, 0x8e, 0x2f, 0x59, 0xae, 0x2d, 0x59, 0xfe, 0x35, 0x6c, 0x7f, 0x41,
|
||||
0x23, 0x3f, 0x44, 0x6d, 0x7f, 0x9f, 0x4d, 0x52, 0xd1, 0x79, 0xf5, 0xf8, 0x34, 0xd6, 0x83, 0x51,
|
||||
0xd7, 0x6d, 0x69, 0xce, 0x91, 0x4f, 0x1e, 0x40, 0x93, 0x29, 0x6d, 0x9d, 0x78, 0x6d, 0xa3, 0xa1,
|
||||
0xba, 0xb9, 0xcc, 0xf9, 0x16, 0x48, 0xc9, 0xb4, 0x98, 0x9c, 0xe6, 0x64, 0x57, 0x24, 0xa0, 0x4a,
|
||||
0x0a, 0x9d, 0xd8, 0x1d, 0x33, 0x8f, 0xdc, 0x42, 0x4a, 0x06, 0x50, 0x43, 0xc6, 0xf4, 0x11, 0xb2,
|
||||
0xa3, 0x2d, 0xe6, 0x54, 0x57, 0x88, 0x9c, 0x1f, 0xc1, 0xf6, 0x59, 0x82, 0x5e, 0x40, 0x43, 0x39,
|
||||
0x63, 0xaa, 0x03, 0xee, 0x43, 0x5d, 0x04, 0x39, 0xaf, 0xd9, 0x96, 0xdc, 0x28, 0xc5, 0x8a, 0xef,
|
||||
0x7c, 0x0b, 0xb6, 0xba, 0xd7, 0xe1, 0x9b, 0x20, 0xe5, 0x18, 0x79, 0x78, 0x30, 0x45, 0xef, 0xea,
|
||||
0x7f, 0xe8, 0xf9, 0x35, 0xdc, 0x59, 0x77, 0x42, 0x7e, 0xbf, 0xb6, 0x27, 0xa8, 0xf1, 0xa5, 0x00,
|
||||
0x5a, 0x79, 0x86, 0xe5, 0x82, 0x64, 0x7d, 0x2e, 0x38, 0xe2, 0x3b, 0xa2, 0xd8, 0x97, 0x6a, 0x48,
|
||||
0xd4, 0x54, 0x1e, 0x8f, 0xda, 0xcd, 0xf1, 0xf8, 0x4b, 0x05, 0x5a, 0x67, 0xc8, 0xb3, 0x44, 0xfa,
|
||||
0x72, 0x17, 0x5a, 0x17, 0x2c, 0xbe, 0x42, 0xb6, 0x70, 0xc5, 0x52, 0x8c, 0x23, 0x9f, 0x3c, 0x83,
|
||||
0xc6, 0x41, 0x1c, 0x5d, 0x06, 0x13, 0x39, 0x71, 0xb7, 0x47, 0x77, 0x14, 0xba, 0xe8, 0xbd, 0x43,
|
||||
0x25, 0x53, 0xad, 0x51, 0x2b, 0x92, 0x01, 0xb4, 0xf5, 0xbb, 0xe5, 0xd5, 0xab, 0xa3, 0x17, 0x79,
|
||||
0x2b, 0x36, 0x58, 0xfd, 0x8f, 0xa1, 0x6d, 0x6c, 0xfc, 0xaf, 0xba, 0xc5, 0xf7, 0x01, 0xe4, 0xe9,
|
||||
0x2a, 0x46, 0x5b, 0xca, 0x55, 0xbd, 0x53, 0xb8, 0x76, 0x1f, 0x5a, 0x62, 0xea, 0x53, 0x62, 0x02,
|
||||
0x1b, 0xc6, 0x03, 0x45, 0xae, 0x9d, 0x07, 0xb0, 0x7d, 0x14, 0x5d, 0xd3, 0x30, 0xf0, 0x29, 0xc7,
|
||||
0x2f, 0x71, 0x2e, 0x43, 0xb0, 0x72, 0x03, 0xe7, 0x0c, 0x3a, 0xfa, 0x09, 0xf0, 0x56, 0x77, 0xec,
|
||||
0xe8, 0x3b, 0xfe, 0xe7, 0x22, 0x7a, 0x1f, 0x7a, 0xda, 0xe8, 0x71, 0xa0, 0x4b, 0x48, 0x8c, 0x01,
|
||||
0x0c, 0x2f, 0x83, 0x37, 0xda, 0xb4, 0xa6, 0x9c, 0xe7, 0xb0, 0x65, 0xa8, 0x16, 0xee, 0x5c, 0xe1,
|
||||
0x3c, 0xcd, 0x9f, 0x46, 0x62, 0x9d, 0x47, 0xa0, 0xba, 0x88, 0x80, 0x03, 0x9b, 0x7a, 0xe7, 0x4b,
|
||||
0xe4, 0x37, 0x78, 0xf7, 0x65, 0x71, 0x91, 0x97, 0xa8, 0x8d, 0x3f, 0x84, 0x3a, 0x0a, 0x4f, 0xcd,
|
||||
0x16, 0x66, 0x46, 0xc0, 0x55, 0xe2, 0x35, 0x07, 0x3e, 0x2f, 0x0e, 0x3c, 0xcd, 0xd4, 0x81, 0x6f,
|
||||
0x69, 0xcb, 0x79, 0xaf, 0xb8, 0xc6, 0x69, 0xc6, 0x6f, 0xfa, 0xa2, 0x0f, 0x60, 0x5b, 0x2b, 0xbd,
|
||||
0xc0, 0x10, 0x39, 0xde, 0xe0, 0xd2, 0x43, 0x20, 0x25, 0xb5, 0x9b, 0xcc, 0xdd, 0x03, 0xeb, 0xfc,
|
||||
0xfc, 0xb8, 0x90, 0x96, 0xb1, 0xd1, 0xf9, 0x04, 0xb6, 0xcf, 0x32, 0x3f, 0x3e, 0x65, 0xc1, 0x75,
|
||||
0x10, 0xe2, 0x44, 0x1d, 0x96, 0xbf, 0xcc, 0x2a, 0xc6, 0xcb, 0x6c, 0x6d, 0x37, 0x72, 0x76, 0x81,
|
||||
0x94, 0xb6, 0x17, 0xdf, 0x2d, 0xcd, 0xfc, 0x58, 0x97, 0xb0, 0x5c, 0x3b, 0xbb, 0xd0, 0x39, 0xa7,
|
||||
0xa2, 0xdf, 0xfb, 0x4a, 0xc7, 0x86, 0x26, 0x57, 0xb4, 0x56, 0xcb, 0x49, 0x67, 0x04, 0x3b, 0x07,
|
||||
0xd4, 0x9b, 0x06, 0xd1, 0xe4, 0x45, 0x90, 0x8a, 0x81, 0x47, 0xef, 0xe8, 0x83, 0xe5, 0x6b, 0x86,
|
||||
0xde, 0x52, 0xd0, 0xce, 0x13, 0x78, 0xc7, 0x78, 0x7f, 0x9e, 0x71, 0x9a, 0xc7, 0x63, 0x07, 0xea,
|
||||
0xa9, 0xa0, 0xe4, 0x8e, 0xba, 0xab, 0x08, 0xe7, 0x2b, 0xd8, 0x31, 0x1b, 0xb0, 0x18, 0x3f, 0x72,
|
||||
0xc7, 0xe5, 0x60, 0x50, 0x31, 0x06, 0x03, 0x1d, 0xb3, 0xea, 0xa2, 0x9f, 0x6c, 0x41, 0xed, 0x17,
|
||||
0xdf, 0x9c, 0xeb, 0x64, 0x17, 0x4b, 0xe7, 0x77, 0xe2, 0xf8, 0xb2, 0x3d, 0x75, 0x7c, 0x69, 0x3a,
|
||||
0xa8, 0xbc, 0xcd, 0x74, 0xb0, 0x26, 0xdf, 0x9e, 0xc0, 0xf6, 0x49, 0x18, 0x7b, 0x57, 0x87, 0x91,
|
||||
0x11, 0x0d, 0x1b, 0x9a, 0x18, 0x99, 0xc1, 0xc8, 0x49, 0xe7, 0x11, 0xf4, 0x8e, 0xc5, 0xeb, 0xff,
|
||||
0x44, 0x3c, 0xf7, 0x8a, 0x28, 0xc8, 0x1f, 0x02, 0x5a, 0x55, 0x11, 0xce, 0x13, 0xd8, 0xd4, 0x2d,
|
||||
0x3a, 0xba, 0x8c, 0x73, 0x64, 0x5c, 0x34, 0xf3, 0x4a, 0x79, 0xe0, 0x76, 0x8e, 0xa1, 0xb7, 0x50,
|
||||
0x57, 0x76, 0x1f, 0x41, 0x43, 0x89, 0xb5, 0x6f, 0xbd, 0x62, 0xac, 0x56, 0x9a, 0xae, 0x16, 0xaf,
|
||||
0x71, 0x6a, 0x06, 0x9b, 0xa7, 0xf2, 0xc7, 0xcc, 0x61, 0x74, 0xad, 0x8c, 0x1d, 0x01, 0x51, 0xbf,
|
||||
0x6a, 0xc6, 0x18, 0x5d, 0x07, 0x2c, 0x8e, 0xe4, 0x7c, 0x5b, 0xd1, 0x23, 0x4c, 0x6e, 0xb8, 0xd8,
|
||||
0x94, 0x6b, 0xb8, 0xdb, 0xc9, 0x32, 0x6b, 0x6d, 0x0c, 0x61, 0xf1, 0xec, 0x13, 0xad, 0x86, 0xe1,
|
||||
0x2c, 0xe6, 0x38, 0xa6, 0xbe, 0x9f, 0x57, 0x0b, 0x28, 0xd6, 0xbe, 0xef, 0xb3, 0xd1, 0xbf, 0xaa,
|
||||
0xd0, 0xfc, 0x4c, 0x01, 0x38, 0xf9, 0x14, 0xba, 0xa5, 0x76, 0x4d, 0xde, 0x91, 0xef, 0xbe, 0xe5,
|
||||
0xe1, 0xa0, 0x7f, 0x7b, 0x85, 0xad, 0xfc, 0x7a, 0x0a, 0x1d, 0xb3, 0x19, 0x13, 0xd9, 0x78, 0xe5,
|
||||
0x4f, 0xa8, 0xbe, 0xb4, 0xb4, 0xda, 0xa9, 0xcf, 0x60, 0x67, 0x5d, 0x9b, 0x24, 0xf7, 0x16, 0x27,
|
||||
0xac, 0xb6, 0xe8, 0xfe, 0xbb, 0x37, 0x49, 0xf3, 0xf6, 0xda, 0x3c, 0x08, 0x91, 0x46, 0x59, 0x62,
|
||||
0xde, 0x60, 0xb1, 0x24, 0xcf, 0xa0, 0x5b, 0x6a, 0x14, 0xca, 0xcf, 0x95, 0xde, 0x61, 0x6e, 0x79,
|
||||
0x08, 0x75, 0xd9, 0x9c, 0x48, 0xb7, 0xd4, 0x25, 0xfb, 0x9b, 0x05, 0xa9, 0xce, 0x1e, 0xc0, 0x86,
|
||||
0xfc, 0x35, 0x61, 0x1c, 0x2c, 0x77, 0x14, 0x9d, 0x6b, 0xf4, 0xcf, 0x0a, 0x34, 0xf3, 0xdf, 0x55,
|
||||
0xcf, 0x60, 0x43, 0xf4, 0x00, 0x72, 0xcb, 0x80, 0xd1, 0xbc, 0x7f, 0xf4, 0x77, 0x96, 0x98, 0xea,
|
||||
0x80, 0x21, 0xd4, 0x5e, 0x22, 0x27, 0xc4, 0x10, 0xea, 0x66, 0xd0, 0xbf, 0x55, 0xe6, 0x15, 0xfa,
|
||||
0xa7, 0x59, 0x59, 0x5f, 0x63, 0x79, 0x49, 0xbf, 0x40, 0xe9, 0x9f, 0x40, 0x43, 0xa1, 0xac, 0x0a,
|
||||
0xca, 0x0a, 0x3e, 0xab, 0x8f, 0xbf, 0x8a, 0xc7, 0xa3, 0xbf, 0x6d, 0x00, 0x9c, 0xcd, 0x53, 0x8e,
|
||||
0xb3, 0x5f, 0x06, 0xf8, 0x9a, 0x3c, 0x86, 0xde, 0x0b, 0xbc, 0xa4, 0x59, 0xc8, 0xe5, 0x6b, 0x49,
|
||||
0xa0, 0x89, 0x11, 0x13, 0x39, 0xf0, 0x15, 0x60, 0xfd, 0x10, 0xda, 0x27, 0xf4, 0xcd, 0x77, 0xeb,
|
||||
0x7d, 0x0a, 0xdd, 0x12, 0x06, 0xeb, 0x2b, 0x2e, 0xa3, 0xba, 0xbe, 0xe2, 0x2a, 0x5a, 0x3f, 0x84,
|
||||
0xa6, 0x46, 0x66, 0xf3, 0x0c, 0xd9, 0xc3, 0x4a, 0x88, 0xfd, 0x63, 0xe8, 0x2d, 0xe1, 0xb2, 0xa9,
|
||||
0x2f, 0x7f, 0xa9, 0xad, 0xc5, 0xed, 0xe7, 0xe2, 0xb5, 0x53, 0xc6, 0x66, 0x73, 0xe3, 0x1d, 0x85,
|
||||
0x87, 0xeb, 0xc0, 0xfb, 0x65, 0xf9, 0x9d, 0x24, 0x5f, 0x89, 0xf6, 0x32, 0x7c, 0xe6, 0xe0, 0x9d,
|
||||
0x1b, 0x5a, 0x07, 0xc3, 0x4f, 0xa1, 0x63, 0x22, 0xe8, 0x4a, 0x09, 0xae, 0xc2, 0xeb, 0x07, 0x00,
|
||||
0x0b, 0x10, 0x35, 0xf5, 0x65, 0x7a, 0x2c, 0xe3, 0xeb, 0x47, 0x00, 0x0b, 0x68, 0x54, 0x59, 0x55,
|
||||
0x46, 0x56, 0xb5, 0x6d, 0x19, 0x3e, 0x1f, 0x43, 0xab, 0x80, 0x33, 0xf3, 0x0c, 0x69, 0xa0, 0x8c,
|
||||
0x8e, 0x9f, 0x0d, 0x7f, 0xf3, 0xc1, 0x24, 0xe0, 0xd3, 0xec, 0x62, 0xe8, 0xc5, 0xb3, 0xbd, 0x29,
|
||||
0x4d, 0xa7, 0x81, 0x17, 0xb3, 0x64, 0xef, 0x5a, 0x24, 0xd3, 0xde, 0xca, 0x9f, 0xf4, 0x8b, 0x86,
|
||||
0x7c, 0xec, 0x7d, 0xf8, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc6, 0x0c, 0x9b, 0x12, 0x65, 0x17,
|
||||
0x00, 0x00,
|
||||
var fileDescriptor_backend_2aa165f9d8e053c1 = []byte{
|
||||
// 2457 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x59, 0x5f, 0x73, 0xdb, 0xc6,
|
||||
0x11, 0x1f, 0xfe, 0x27, 0x97, 0xff, 0xa4, 0xb3, 0xa2, 0xc2, 0x8c, 0x53, 0x33, 0x48, 0x6d, 0x2b,
|
||||
0xae, 0x4d, 0xd9, 0x4a, 0xd3, 0x38, 0xed, 0x24, 0x1d, 0x45, 0x56, 0x1c, 0x35, 0x52, 0xa2, 0x81,
|
||||
0xe8, 0xa6, 0xff, 0x66, 0x90, 0x23, 0x70, 0xa2, 0x30, 0x02, 0x01, 0xf4, 0x70, 0x90, 0xc5, 0xa7,
|
||||
0x7e, 0x8b, 0x7e, 0x8d, 0xbe, 0x75, 0xfa, 0xd6, 0xb7, 0x4e, 0x67, 0xfa, 0xdc, 0xaf, 0xd1, 0x99,
|
||||
0x7e, 0x83, 0xce, 0xed, 0x1d, 0x40, 0x80, 0xa4, 0x62, 0x67, 0xa6, 0x7d, 0xbb, 0xdb, 0xdd, 0xdb,
|
||||
0xbb, 0x5b, 0xfc, 0xf6, 0xb7, 0x7b, 0x24, 0xdc, 0xf5, 0xc3, 0xa9, 0xe7, 0x50, 0x7f, 0x37, 0xf2,
|
||||
0x93, 0xa9, 0x17, 0xec, 0x46, 0x93, 0xdd, 0x09, 0x75, 0x2e, 0x59, 0xe0, 0x8e, 0x22, 0x1e, 0x8a,
|
||||
0x90, 0x94, 0xa3, 0xc9, 0xe0, 0xee, 0x34, 0x0c, 0xa7, 0x3e, 0xdb, 0x45, 0xc9, 0x24, 0x39, 0xdf,
|
||||
0x15, 0xde, 0x8c, 0xc5, 0x82, 0xce, 0x22, 0x65, 0x34, 0xd8, 0x4e, 0xbd, 0x78, 0x2e, 0x0b, 0x84,
|
||||
0x27, 0xe6, 0x5a, 0xbe, 0x55, 0xf4, 0xae, 0xa4, 0x66, 0x03, 0x6a, 0x87, 0xb3, 0x48, 0xcc, 0xcd,
|
||||
0x21, 0xd4, 0xbf, 0x60, 0xd4, 0x65, 0x9c, 0x6c, 0x43, 0xfd, 0x02, 0x47, 0x46, 0x69, 0x58, 0xd9,
|
||||
0x69, 0x59, 0x7a, 0x66, 0xfe, 0x0e, 0xe0, 0x54, 0xae, 0x39, 0xe4, 0x3c, 0xe4, 0xe4, 0x36, 0x34,
|
||||
0x19, 0xe7, 0xb6, 0x98, 0x47, 0xcc, 0x28, 0x0d, 0x4b, 0x3b, 0x5d, 0xab, 0xc1, 0x38, 0x1f, 0xcf,
|
||||
0x23, 0x46, 0x7e, 0x00, 0x72, 0x68, 0xcf, 0xe2, 0xa9, 0x51, 0x1e, 0x96, 0xa4, 0x07, 0xc6, 0xf9,
|
||||
0x49, 0x3c, 0x4d, 0xd7, 0x38, 0xa1, 0xcb, 0x8c, 0xca, 0xb0, 0xb4, 0x53, 0xc1, 0x35, 0x07, 0xa1,
|
||||
0xcb, 0xcc, 0x3f, 0x95, 0xa0, 0x76, 0x4a, 0xc5, 0x45, 0x4c, 0x08, 0x54, 0x79, 0x18, 0x0a, 0xbd,
|
||||
0x39, 0x8e, 0xc9, 0x0e, 0xf4, 0x93, 0x80, 0x26, 0xe2, 0x42, 0xde, 0xc8, 0xa1, 0x82, 0xb9, 0x46,
|
||||
0x19, 0xd5, 0xcb, 0x62, 0xf2, 0x1e, 0x74, 0xfd, 0xd0, 0xa1, 0xbe, 0x1d, 0x8b, 0x90, 0xd3, 0xa9,
|
||||
0xdc, 0x47, 0xda, 0x75, 0x50, 0x78, 0xa6, 0x64, 0xe4, 0x21, 0x6c, 0xc6, 0x8c, 0xfa, 0xf6, 0x2b,
|
||||
0x4e, 0xa3, 0xcc, 0xb0, 0xaa, 0x1c, 0x4a, 0xc5, 0x37, 0x9c, 0x46, 0xda, 0xd6, 0xfc, 0x5b, 0x1d,
|
||||
0x1a, 0x16, 0xfb, 0x43, 0xc2, 0x62, 0x41, 0x7a, 0x50, 0xf6, 0x5c, 0xbc, 0x6d, 0xcb, 0x2a, 0x7b,
|
||||
0x2e, 0x19, 0x01, 0xb1, 0x58, 0xe4, 0xcb, 0xad, 0xbd, 0x30, 0x38, 0xf0, 0x93, 0x58, 0x30, 0xae,
|
||||
0xef, 0xbc, 0x46, 0x43, 0xee, 0x40, 0x2b, 0x8c, 0x18, 0x47, 0x19, 0x06, 0xa0, 0x65, 0x2d, 0x04,
|
||||
0xf2, 0xe2, 0x11, 0x15, 0x17, 0x46, 0x15, 0x15, 0x38, 0x96, 0x32, 0x97, 0x0a, 0x6a, 0xd4, 0x94,
|
||||
0x4c, 0x8e, 0x89, 0x09, 0xf5, 0x98, 0x39, 0x9c, 0x09, 0xa3, 0x3e, 0x2c, 0xed, 0xb4, 0xf7, 0x60,
|
||||
0x14, 0x4d, 0x46, 0x67, 0x28, 0xb1, 0xb4, 0x86, 0xdc, 0x81, 0xaa, 0x8c, 0x8b, 0xd1, 0x40, 0x8b,
|
||||
0xa6, 0xb4, 0xd8, 0x4f, 0xc4, 0x85, 0x85, 0x52, 0xb2, 0x07, 0x0d, 0xf5, 0x4d, 0x63, 0xa3, 0x39,
|
||||
0xac, 0xec, 0xb4, 0xf7, 0x0c, 0x69, 0xa0, 0x6f, 0x39, 0x52, 0x30, 0x88, 0x0f, 0x03, 0xc1, 0xe7,
|
||||
0x56, 0x6a, 0x48, 0xde, 0x85, 0x8e, 0xe3, 0x7b, 0x2c, 0x10, 0xb6, 0x08, 0x2f, 0x59, 0x60, 0xb4,
|
||||
0xf0, 0x44, 0x6d, 0x25, 0x1b, 0x4b, 0x11, 0xd9, 0x83, 0xb7, 0xf2, 0x26, 0x36, 0x75, 0x1c, 0x16,
|
||||
0xc7, 0x21, 0x37, 0x00, 0x6d, 0x6f, 0xe5, 0x6c, 0xf7, 0xb5, 0x4a, 0xba, 0x75, 0xbd, 0x38, 0xf2,
|
||||
0xe9, 0xdc, 0x0e, 0xe8, 0x8c, 0x19, 0x6d, 0xe5, 0x56, 0xcb, 0xbe, 0xa2, 0x33, 0x46, 0xee, 0x42,
|
||||
0x7b, 0x16, 0x26, 0x81, 0xb0, 0xa3, 0xd0, 0x0b, 0x84, 0xd1, 0x41, 0x0b, 0x40, 0xd1, 0xa9, 0x94,
|
||||
0x90, 0x77, 0x40, 0xcd, 0x14, 0x18, 0xbb, 0x2a, 0xae, 0x28, 0x41, 0x38, 0xde, 0x83, 0x9e, 0x52,
|
||||
0x67, 0xe7, 0xe9, 0xa1, 0x49, 0x17, 0xa5, 0xd9, 0x49, 0x9e, 0x40, 0x0b, 0xf1, 0xe0, 0x05, 0xe7,
|
||||
0xa1, 0xd1, 0xc7, 0xb8, 0xdd, 0xca, 0x85, 0x45, 0x62, 0xe2, 0x28, 0x38, 0x0f, 0xad, 0xe6, 0x2b,
|
||||
0x3d, 0x22, 0x9f, 0xc0, 0xdb, 0x85, 0xfb, 0x72, 0x36, 0xa3, 0x5e, 0xe0, 0x05, 0x53, 0x3b, 0x89,
|
||||
0x59, 0x6c, 0x6c, 0x20, 0xc2, 0x8d, 0xdc, 0xad, 0xad, 0xd4, 0xe0, 0x65, 0xcc, 0x62, 0xf2, 0x36,
|
||||
0xb4, 0x54, 0x82, 0xda, 0x9e, 0x6b, 0x6c, 0xe2, 0x91, 0x9a, 0x4a, 0x70, 0xe4, 0x92, 0x07, 0xd0,
|
||||
0x8f, 0x42, 0xdf, 0x73, 0xe6, 0x76, 0x78, 0xc5, 0x38, 0xf7, 0x5c, 0x66, 0x90, 0x61, 0x69, 0xa7,
|
||||
0x69, 0xf5, 0x94, 0xf8, 0x6b, 0x2d, 0x5d, 0x97, 0x1a, 0xb7, 0xd0, 0x70, 0x25, 0x35, 0x46, 0x00,
|
||||
0x4e, 0x18, 0x04, 0xcc, 0x41, 0xf8, 0x6d, 0xe1, 0x0d, 0x7b, 0xf2, 0x86, 0x07, 0x99, 0xd4, 0xca,
|
||||
0x59, 0x0c, 0x3e, 0x87, 0x4e, 0x1e, 0x0a, 0x64, 0x03, 0x2a, 0x97, 0x6c, 0xae, 0xe1, 0x2f, 0x87,
|
||||
0x64, 0x08, 0xb5, 0x2b, 0xea, 0x27, 0x0c, 0x21, 0xaf, 0x81, 0xa8, 0x96, 0x58, 0x4a, 0xf1, 0xb3,
|
||||
0xf2, 0xb3, 0x92, 0xf9, 0x9f, 0x2a, 0x54, 0x25, 0xf8, 0xc8, 0x87, 0xd0, 0xf5, 0x19, 0x8d, 0x99,
|
||||
0x1d, 0x46, 0x72, 0x83, 0x18, 0x5d, 0xb5, 0xf7, 0x36, 0xe4, 0xb2, 0x63, 0xa9, 0xf8, 0x5a, 0xc9,
|
||||
0xad, 0x8e, 0x9f, 0x9b, 0xc9, 0x94, 0xf6, 0x02, 0xc1, 0x78, 0x40, 0x7d, 0x1b, 0x93, 0x41, 0x25,
|
||||
0x58, 0x27, 0x15, 0x3e, 0x97, 0x49, 0xb1, 0x8c, 0xa3, 0xca, 0x2a, 0x8e, 0x06, 0xd0, 0xc4, 0xd8,
|
||||
0x79, 0x2c, 0xd6, 0xc9, 0x9e, 0xcd, 0xc9, 0x1e, 0x34, 0x67, 0x4c, 0x50, 0x9d, 0x6b, 0x32, 0x25,
|
||||
0xb6, 0xd3, 0x9c, 0x19, 0x9d, 0x68, 0x85, 0x4a, 0x88, 0xcc, 0x6e, 0x25, 0x23, 0xea, 0xab, 0x19,
|
||||
0x31, 0x80, 0x66, 0x06, 0xba, 0x86, 0xfa, 0xc2, 0xe9, 0x5c, 0xd2, 0x6c, 0xc4, 0xb8, 0x17, 0xba,
|
||||
0x46, 0x13, 0x81, 0xa2, 0x67, 0x92, 0x24, 0x83, 0x64, 0xa6, 0x20, 0xd4, 0x52, 0x24, 0x19, 0x24,
|
||||
0xb3, 0x55, 0xc4, 0xc0, 0x12, 0x62, 0x7e, 0x04, 0x35, 0xea, 0x7b, 0x34, 0xc6, 0x14, 0x92, 0x5f,
|
||||
0x56, 0xf3, 0xfd, 0x68, 0x5f, 0x4a, 0x2d, 0xa5, 0x24, 0x1f, 0x40, 0x77, 0xca, 0xc3, 0x24, 0xb2,
|
||||
0x71, 0xca, 0x62, 0xa3, 0x83, 0xb7, 0x5d, 0xb6, 0xee, 0xa0, 0xd1, 0xbe, 0xb2, 0x91, 0x19, 0x38,
|
||||
0x09, 0x93, 0xc0, 0xb5, 0x1d, 0xcf, 0xe5, 0xb1, 0xd1, 0xc5, 0xe0, 0x01, 0x8a, 0x0e, 0xa4, 0x44,
|
||||
0xa6, 0x98, 0x4a, 0x81, 0x2c, 0xc0, 0x3d, 0xb4, 0xe9, 0xa2, 0xf4, 0x34, 0x8d, 0xf2, 0x8f, 0x61,
|
||||
0x33, 0x2d, 0x4a, 0x0b, 0xcb, 0x3e, 0x5a, 0x6e, 0xa4, 0x8a, 0xd4, 0x78, 0xf0, 0x73, 0xe8, 0x16,
|
||||
0x22, 0xbf, 0x06, 0x7f, 0x5b, 0x79, 0xfc, 0xb5, 0xf2, 0x98, 0xfb, 0x4b, 0x15, 0x00, 0x3f, 0x81,
|
||||
0x5a, 0xba, 0x4c, 0xdc, 0xf9, 0xef, 0x52, 0x5e, 0xf3, 0x5d, 0x28, 0x67, 0x81, 0xd0, 0x18, 0xd2,
|
||||
0xb3, 0xef, 0x84, 0x4f, 0x4a, 0xdd, 0xb5, 0x1c, 0x75, 0x3f, 0x82, 0xaa, 0x84, 0x8a, 0x51, 0x5f,
|
||||
0x30, 0xec, 0xe2, 0x44, 0x08, 0x2a, 0x05, 0x28, 0xb4, 0x5a, 0xc1, 0x6f, 0x63, 0x15, 0xbf, 0x79,
|
||||
0x60, 0x34, 0x8b, 0xc0, 0x78, 0x0f, 0xba, 0x0e, 0x67, 0x58, 0x46, 0x6c, 0xd9, 0x0f, 0x68, 0xe0,
|
||||
0x74, 0x52, 0xe1, 0xd8, 0x9b, 0x31, 0x19, 0x3f, 0x21, 0x7c, 0xc4, 0x4d, 0xc5, 0x92, 0x43, 0xb2,
|
||||
0x03, 0x1b, 0xec, 0x5a, 0x56, 0x29, 0x4f, 0xd8, 0x33, 0x7a, 0x6d, 0x4b, 0x75, 0x1b, 0xd5, 0xbd,
|
||||
0x54, 0x7e, 0x42, 0xaf, 0xc7, 0xc2, 0x57, 0x45, 0xd9, 0x67, 0x9a, 0x7c, 0x71, 0x9c, 0x03, 0x70,
|
||||
0xb7, 0x00, 0xe0, 0x02, 0x4a, 0x7b, 0x4b, 0x28, 0x5d, 0x82, 0x52, 0x7f, 0x05, 0x4a, 0xef, 0x42,
|
||||
0x47, 0x06, 0x20, 0x8e, 0xa8, 0xc3, 0xa4, 0x83, 0x0d, 0x15, 0x88, 0x4c, 0x76, 0xe4, 0x62, 0xe2,
|
||||
0x25, 0x93, 0xc9, 0xfc, 0x22, 0xf4, 0xd9, 0x82, 0x3b, 0xdb, 0x99, 0xec, 0xc8, 0x1d, 0x7c, 0x04,
|
||||
0xad, 0x2c, 0xc2, 0xdf, 0x0b, 0x38, 0x7f, 0x2e, 0x41, 0x27, 0xcf, 0x45, 0x72, 0xf1, 0x78, 0x7c,
|
||||
0x8c, 0x8b, 0x2b, 0x96, 0x1c, 0xca, 0x2a, 0xce, 0x59, 0xc0, 0x5e, 0xd1, 0x89, 0xaf, 0x1c, 0x34,
|
||||
0xad, 0x85, 0x40, 0x6a, 0xbd, 0xc0, 0xe1, 0x6c, 0x96, 0x22, 0xa8, 0x62, 0x2d, 0x04, 0xe4, 0x63,
|
||||
0x00, 0x2f, 0x8e, 0x13, 0xa6, 0xbe, 0x52, 0x15, 0x33, 0x75, 0x30, 0x52, 0x2d, 0xdd, 0x28, 0x6d,
|
||||
0xe9, 0x46, 0xe3, 0xb4, 0xa5, 0xb3, 0x5a, 0x68, 0x8d, 0x9f, 0x6f, 0x1b, 0xea, 0xf2, 0x63, 0x8c,
|
||||
0x8f, 0x11, 0x65, 0x15, 0x4b, 0xcf, 0xcc, 0x3f, 0x42, 0x5d, 0x15, 0xff, 0xff, 0x2b, 0xbf, 0xde,
|
||||
0x86, 0xa6, 0xf2, 0xed, 0xb9, 0x3a, 0x2f, 0x1a, 0x38, 0x3f, 0x72, 0xcd, 0x7f, 0x96, 0xa0, 0x69,
|
||||
0xb1, 0x38, 0x0a, 0x83, 0x98, 0xe5, 0x9a, 0x93, 0xd2, 0x6b, 0x9b, 0x93, 0xf2, 0xda, 0xe6, 0x24,
|
||||
0x6d, 0x79, 0x2a, 0xb9, 0x96, 0x67, 0x00, 0x4d, 0xce, 0x5c, 0x8f, 0x33, 0x47, 0xe8, 0xf6, 0x28,
|
||||
0x9b, 0x4b, 0xdd, 0x2b, 0xca, 0x65, 0x55, 0x8d, 0x91, 0xba, 0x5b, 0x56, 0x36, 0x27, 0x4f, 0xf3,
|
||||
0x35, 0x5d, 0x75, 0x4b, 0x5b, 0xaa, 0xa6, 0xab, 0xe3, 0xae, 0x16, 0x75, 0xf3, 0x1f, 0x65, 0xd8,
|
||||
0x58, 0x56, 0xaf, 0x01, 0xc1, 0x16, 0xd4, 0x14, 0xeb, 0x6b, 0x04, 0x89, 0x15, 0xbe, 0xaf, 0x2c,
|
||||
0xf1, 0xca, 0x2f, 0x96, 0x73, 0xf4, 0xf5, 0x5f, 0xbf, 0x98, 0xbf, 0xef, 0xc3, 0x86, 0x3c, 0x65,
|
||||
0xc4, 0xdc, 0x45, 0x27, 0xa3, 0x08, 0xa7, 0xaf, 0xe5, 0x59, 0x2f, 0xf3, 0x10, 0x36, 0x53, 0xd3,
|
||||
0x45, 0x2a, 0xd6, 0x0b, 0xb6, 0x87, 0x69, 0x46, 0x6e, 0x43, 0xfd, 0x3c, 0xe4, 0x33, 0x2a, 0x34,
|
||||
0xe7, 0xe8, 0x59, 0x81, 0x53, 0x90, 0xdc, 0x9a, 0x0a, 0x16, 0xa9, 0x50, 0x76, 0xeb, 0x32, 0xd7,
|
||||
0xb3, 0x4e, 0x1a, 0x49, 0xa7, 0x69, 0x35, 0xd3, 0x0e, 0xda, 0xfc, 0x35, 0xf4, 0x97, 0x9a, 0xa7,
|
||||
0x35, 0x81, 0x5c, 0x6c, 0x5f, 0x2e, 0x6c, 0x5f, 0xf0, 0x5c, 0x59, 0xf2, 0xfc, 0x1b, 0xd8, 0xfc,
|
||||
0x82, 0x06, 0xae, 0xcf, 0xb4, 0xff, 0x7d, 0x3e, 0x8d, 0x65, 0x1b, 0xa8, 0x7b, 0x79, 0x5b, 0x93,
|
||||
0x7d, 0xd7, 0x6a, 0x69, 0xc9, 0x91, 0x4b, 0xee, 0x41, 0x83, 0x2b, 0x6b, 0x0d, 0xbc, 0x76, 0xae,
|
||||
0xbb, 0xb3, 0x52, 0x9d, 0xf9, 0x2d, 0x90, 0x82, 0x6b, 0xd9, 0xc6, 0xcf, 0xc9, 0x8e, 0x04, 0xa0,
|
||||
0x02, 0x85, 0x06, 0x76, 0x27, 0x8f, 0x23, 0x2b, 0xd3, 0x92, 0x21, 0x54, 0x18, 0xe7, 0x7a, 0x0b,
|
||||
0x6c, 0xaf, 0x16, 0x8f, 0x26, 0x4b, 0xaa, 0xcc, 0x9f, 0xc0, 0xe6, 0x59, 0xc4, 0x1c, 0x8f, 0xfa,
|
||||
0xf8, 0xe0, 0x51, 0x1b, 0xdc, 0x85, 0x9a, 0x0c, 0x72, 0x9a, 0xb3, 0x2d, 0x5c, 0x88, 0x6a, 0x25,
|
||||
0x37, 0xbf, 0x05, 0x43, 0x9d, 0xeb, 0xf0, 0xda, 0x8b, 0x05, 0x0b, 0x1c, 0x76, 0x70, 0xc1, 0x9c,
|
||||
0xcb, 0xff, 0xe1, 0xcd, 0xaf, 0xe0, 0xf6, 0xba, 0x1d, 0xd2, 0xf3, 0xb5, 0x1d, 0x39, 0xb3, 0xcf,
|
||||
0x25, 0x55, 0xe3, 0x1e, 0x4d, 0x0b, 0x50, 0xf4, 0xb9, 0x94, 0xc8, 0xef, 0xc8, 0xe4, 0xba, 0x58,
|
||||
0x53, 0xa2, 0x9e, 0xa5, 0xf1, 0xa8, 0xdc, 0x1c, 0x8f, 0xbf, 0x96, 0xa0, 0x75, 0xc6, 0x44, 0x12,
|
||||
0xe1, 0x5d, 0xde, 0x86, 0xd6, 0x84, 0x87, 0x97, 0x8c, 0x2f, 0xae, 0xd2, 0x54, 0x82, 0x23, 0x97,
|
||||
0x3c, 0x85, 0xfa, 0x41, 0x18, 0x9c, 0x7b, 0x53, 0x7c, 0xfe, 0xb5, 0xf7, 0x6e, 0x2b, 0x76, 0xd1,
|
||||
0x6b, 0x47, 0x4a, 0xa7, 0xca, 0xaa, 0x36, 0x24, 0x43, 0x68, 0xeb, 0x47, 0xf4, 0xcb, 0x97, 0x47,
|
||||
0xcf, 0xd3, 0xbe, 0x30, 0x27, 0x1a, 0x7c, 0x0c, 0xed, 0xdc, 0xc2, 0xef, 0x55, 0x2d, 0x7e, 0x08,
|
||||
0x80, 0xbb, 0xab, 0x18, 0x6d, 0xa8, 0xab, 0xea, 0x95, 0xf2, 0x6a, 0x77, 0xa1, 0x25, 0x9f, 0x20,
|
||||
0x4a, 0x4d, 0xa0, 0x9a, 0x7b, 0x2d, 0xe3, 0xd8, 0xbc, 0x07, 0x9b, 0x47, 0xc1, 0x15, 0xf5, 0x3d,
|
||||
0x97, 0x0a, 0xf6, 0x25, 0x9b, 0x63, 0x08, 0x56, 0x4e, 0x60, 0x9e, 0x41, 0x47, 0xbf, 0x47, 0xdf,
|
||||
0xe8, 0x8c, 0x1d, 0x7d, 0xc6, 0xef, 0x4e, 0xa2, 0xf7, 0xa1, 0xaf, 0x9d, 0x1e, 0x7b, 0x3a, 0x85,
|
||||
0x64, 0x49, 0xe7, 0xec, 0xdc, 0xbb, 0xd6, 0xae, 0xf5, 0xcc, 0x7c, 0x06, 0x1b, 0x39, 0xd3, 0xec,
|
||||
0x3a, 0x97, 0x6c, 0x1e, 0xa7, 0xef, 0x74, 0x39, 0x4e, 0x23, 0x50, 0x5e, 0x44, 0xc0, 0x84, 0x9e,
|
||||
0x5e, 0xf9, 0x82, 0x89, 0x1b, 0x6e, 0xf7, 0x65, 0x76, 0x90, 0x17, 0x4c, 0x3b, 0xbf, 0x0f, 0x35,
|
||||
0x26, 0x6f, 0x9a, 0x2f, 0x61, 0xf9, 0x08, 0x58, 0x4a, 0xbd, 0x66, 0xc3, 0x67, 0xd9, 0x86, 0xa7,
|
||||
0x89, 0xda, 0xf0, 0x0d, 0x7d, 0x99, 0xef, 0x65, 0xc7, 0x38, 0x4d, 0xc4, 0x4d, 0x5f, 0xf4, 0x1e,
|
||||
0x6c, 0x6a, 0xa3, 0xe7, 0xcc, 0x67, 0x82, 0xdd, 0x70, 0xa5, 0xfb, 0x40, 0x0a, 0x66, 0x37, 0xb9,
|
||||
0xbb, 0x03, 0xcd, 0xf1, 0xf8, 0x38, 0xd3, 0x16, 0xb9, 0xd1, 0xfc, 0x04, 0x36, 0xcf, 0x12, 0x37,
|
||||
0x3c, 0xe5, 0xde, 0x95, 0xe7, 0xb3, 0xa9, 0xda, 0x2c, 0xed, 0x35, 0x4b, 0xb9, 0x5e, 0x73, 0x6d,
|
||||
0x35, 0x32, 0x77, 0x80, 0x14, 0x96, 0x67, 0xdf, 0x2d, 0x4e, 0xdc, 0x50, 0xa7, 0x30, 0x8e, 0xcd,
|
||||
0x1d, 0xe8, 0x8c, 0xa9, 0xac, 0xf7, 0xae, 0xb2, 0x31, 0xa0, 0x21, 0xd4, 0x5c, 0x9b, 0xa5, 0x53,
|
||||
0x73, 0x0f, 0xb6, 0x0e, 0xa8, 0x73, 0xe1, 0x05, 0xd3, 0xe7, 0x5e, 0x2c, 0x1b, 0x1e, 0xbd, 0x62,
|
||||
0x00, 0x4d, 0x57, 0x0b, 0xf4, 0x92, 0x6c, 0x6e, 0x3e, 0x86, 0xb7, 0x72, 0x3f, 0x86, 0x9c, 0x09,
|
||||
0x9a, 0xc6, 0x63, 0x0b, 0x6a, 0xb1, 0x9c, 0xe1, 0x8a, 0x9a, 0xa5, 0x26, 0xe6, 0x57, 0xb0, 0x95,
|
||||
0x2f, 0xc0, 0xb2, 0xfd, 0x48, 0x2f, 0x8e, 0x8d, 0x41, 0x29, 0xd7, 0x18, 0xe8, 0x98, 0x95, 0x17,
|
||||
0xf5, 0x64, 0x03, 0x2a, 0xbf, 0xfc, 0x66, 0xac, 0xc1, 0x2e, 0x87, 0xe6, 0xef, 0xe5, 0xf6, 0x45,
|
||||
0x7f, 0x6a, 0xfb, 0x42, 0x77, 0x50, 0x7a, 0x93, 0xee, 0x60, 0x0d, 0xde, 0x1e, 0xc3, 0xe6, 0x89,
|
||||
0x1f, 0x3a, 0x97, 0x87, 0x41, 0x2e, 0x1a, 0x06, 0x34, 0x58, 0x90, 0x0f, 0x46, 0x3a, 0x35, 0x1f,
|
||||
0x40, 0xff, 0x38, 0x74, 0xa8, 0x7f, 0x12, 0x26, 0x81, 0xc8, 0xa2, 0x80, 0xbf, 0x4e, 0x69, 0x53,
|
||||
0x35, 0x31, 0x1f, 0x43, 0x4f, 0x97, 0xe8, 0xe0, 0x3c, 0x4c, 0x99, 0x71, 0x51, 0xcc, 0x4b, 0xc5,
|
||||
0xbe, 0xda, 0x3c, 0x86, 0xfe, 0xc2, 0x5c, 0xf9, 0x7d, 0x00, 0x75, 0xa5, 0xd6, 0x77, 0xeb, 0x67,
|
||||
0x6f, 0x3c, 0x65, 0x69, 0x69, 0xf5, 0x9a, 0x4b, 0xcd, 0xa0, 0x77, 0x8a, 0xbf, 0x12, 0x1e, 0x06,
|
||||
0x57, 0xca, 0xd9, 0x11, 0x10, 0xf5, 0xbb, 0xa1, 0xcd, 0x82, 0x2b, 0x8f, 0x87, 0x01, 0xf6, 0xb7,
|
||||
0x25, 0xdd, 0xc2, 0xa4, 0x8e, 0xb3, 0x45, 0xa9, 0x85, 0xb5, 0x19, 0x2d, 0x8b, 0xd6, 0xc6, 0x10,
|
||||
0x16, 0xbf, 0x41, 0xc8, 0x52, 0xc3, 0xd9, 0x2c, 0x14, 0xcc, 0xa6, 0xae, 0x9b, 0x66, 0x0b, 0x28,
|
||||
0xd1, 0xbe, 0xeb, 0xf2, 0xbd, 0x7f, 0x97, 0xa1, 0xf1, 0x99, 0x22, 0x70, 0xf2, 0x29, 0x74, 0x0b,
|
||||
0xe5, 0x9a, 0xbc, 0x85, 0x3f, 0x42, 0x2c, 0x37, 0x07, 0x83, 0xed, 0x15, 0xb1, 0xba, 0xd7, 0x13,
|
||||
0xe8, 0xe4, 0x8b, 0x31, 0xc1, 0xc2, 0x8b, 0xbf, 0x88, 0x0e, 0xd0, 0xd3, 0x6a, 0xa5, 0x3e, 0x83,
|
||||
0xad, 0x75, 0x65, 0x92, 0xdc, 0x59, 0xec, 0xb0, 0x5a, 0xa2, 0x07, 0xef, 0xdc, 0xa4, 0x4d, 0xcb,
|
||||
0x6b, 0xe3, 0xc0, 0x67, 0x34, 0x48, 0xa2, 0xfc, 0x09, 0x16, 0x43, 0xf2, 0x14, 0xba, 0x85, 0x42,
|
||||
0xa1, 0xee, 0xb9, 0x52, 0x3b, 0xf2, 0x4b, 0xee, 0x43, 0x0d, 0x8b, 0x13, 0xe9, 0x16, 0xaa, 0xe4,
|
||||
0xa0, 0x97, 0x4d, 0xd5, 0xde, 0x43, 0xa8, 0xe2, 0xef, 0x64, 0xb9, 0x8d, 0x71, 0x45, 0x56, 0xb9,
|
||||
0xf6, 0xfe, 0x55, 0x82, 0x46, 0xfa, 0xdb, 0xe9, 0x53, 0xa8, 0xca, 0x1a, 0x40, 0x6e, 0xe5, 0x68,
|
||||
0x34, 0xad, 0x1f, 0x83, 0xad, 0x25, 0xa1, 0xda, 0x60, 0x04, 0x95, 0x17, 0x4c, 0x10, 0x92, 0x53,
|
||||
0xea, 0x62, 0x30, 0xb8, 0x55, 0x94, 0x65, 0xf6, 0xa7, 0x49, 0xd1, 0x5e, 0x73, 0x79, 0xc1, 0x3e,
|
||||
0x63, 0xe9, 0x8f, 0xa0, 0xae, 0x58, 0x56, 0x05, 0x65, 0x85, 0x9f, 0xd5, 0xc7, 0x5f, 0xe5, 0xe3,
|
||||
0xbd, 0xbf, 0x57, 0x01, 0xce, 0xe6, 0xb1, 0x60, 0xb3, 0x5f, 0x79, 0xec, 0x15, 0x79, 0x08, 0xfd,
|
||||
0xe7, 0xec, 0x9c, 0x26, 0xbe, 0xc0, 0xd7, 0x92, 0x64, 0x93, 0x5c, 0x4c, 0xb0, 0xe1, 0xcb, 0xc8,
|
||||
0xfa, 0x3e, 0xb4, 0x4f, 0xe8, 0xf5, 0xeb, 0xed, 0x3e, 0x85, 0x6e, 0x81, 0x83, 0xf5, 0x11, 0x97,
|
||||
0x59, 0x5d, 0x1f, 0x71, 0x95, 0xad, 0xef, 0x43, 0x43, 0x33, 0x73, 0x7e, 0x0f, 0xac, 0x61, 0x05,
|
||||
0xc6, 0xfe, 0x29, 0xf4, 0x97, 0x78, 0x39, 0x6f, 0x8f, 0xbf, 0x3e, 0xac, 0xe5, 0xed, 0x67, 0xf2,
|
||||
0xb5, 0x53, 0xe4, 0xe6, 0xfc, 0xc2, 0xdb, 0x8a, 0x0f, 0xd7, 0x91, 0xf7, 0x8b, 0xe2, 0x3b, 0x09,
|
||||
0x5f, 0x89, 0xc6, 0x32, 0x7d, 0xa6, 0xe4, 0x9d, 0x3a, 0x5a, 0x47, 0xc3, 0x4f, 0xa0, 0x93, 0x67,
|
||||
0xd0, 0x95, 0x14, 0x5c, 0xa5, 0xd7, 0x47, 0x00, 0x0b, 0x12, 0xcd, 0xdb, 0x23, 0x3c, 0x96, 0xf9,
|
||||
0xf5, 0x43, 0x80, 0x05, 0x35, 0x2a, 0x54, 0x15, 0x99, 0x55, 0x2d, 0x5b, 0xa6, 0xcf, 0x87, 0xd0,
|
||||
0xca, 0xe8, 0x2c, 0xbf, 0x07, 0x3a, 0x28, 0xb2, 0xe3, 0x67, 0xa3, 0xdf, 0x3e, 0x9a, 0x7a, 0xe2,
|
||||
0x22, 0x99, 0x8c, 0x9c, 0x70, 0xb6, 0x7b, 0x41, 0xe3, 0x0b, 0xcf, 0x09, 0x79, 0xb4, 0x7b, 0x25,
|
||||
0xc1, 0xb4, 0xbb, 0xf2, 0xb7, 0xce, 0xa4, 0x8e, 0x8f, 0xbd, 0x0f, 0xfe, 0x1b, 0x00, 0x00, 0xff,
|
||||
0xff, 0xf0, 0x04, 0x0e, 0x5a, 0xf2, 0x19, 0x00, 0x00,
|
||||
}
|
||||
|
||||
@@ -198,6 +198,31 @@ message Auth {
|
||||
// If set, restricts usage of the certificates to client IPs falling within
|
||||
// the range of the specified CIDR(s).
|
||||
repeated string bound_cidrs = 13;
|
||||
|
||||
// TokenPolicies and IdentityPolicies break down the list in Policies to
|
||||
// help determine where a policy was sourced
|
||||
repeated string token_policies = 14;
|
||||
repeated string identity_policies = 15;
|
||||
}
|
||||
|
||||
message TokenEntry {
|
||||
string id = 1;
|
||||
string accessor = 2;
|
||||
string parent = 3;
|
||||
repeated string policies = 4;
|
||||
string path = 5;
|
||||
map<string, string> meta = 6;
|
||||
string display_name = 7;
|
||||
int64 num_uses = 8;
|
||||
int64 creation_time = 9;
|
||||
int64 ttl = 10;
|
||||
int64 explicit_max_ttl = 11;
|
||||
string role = 12;
|
||||
int64 period = 13;
|
||||
string entity_id = 14;
|
||||
repeated string bound_cidrs = 15;
|
||||
string namespace_id = 16;
|
||||
string cubbyhole_id = 17;
|
||||
}
|
||||
|
||||
message LeaseOptions {
|
||||
|
||||
@@ -485,19 +485,21 @@ func LogicalAuthToProtoAuth(a *logical.Auth) (*Auth, error) {
|
||||
}
|
||||
|
||||
return &Auth{
|
||||
LeaseOptions: lo,
|
||||
InternalData: string(buf[:]),
|
||||
DisplayName: a.DisplayName,
|
||||
Policies: a.Policies,
|
||||
Metadata: a.Metadata,
|
||||
ClientToken: a.ClientToken,
|
||||
Accessor: a.Accessor,
|
||||
Period: int64(a.Period),
|
||||
NumUses: int64(a.NumUses),
|
||||
EntityID: a.EntityID,
|
||||
Alias: a.Alias,
|
||||
GroupAliases: a.GroupAliases,
|
||||
BoundCidrs: boundCIDRs,
|
||||
LeaseOptions: lo,
|
||||
InternalData: string(buf[:]),
|
||||
DisplayName: a.DisplayName,
|
||||
Policies: a.Policies,
|
||||
TokenPolicies: a.TokenPolicies,
|
||||
IdentityPolicies: a.IdentityPolicies,
|
||||
Metadata: a.Metadata,
|
||||
ClientToken: a.ClientToken,
|
||||
Accessor: a.Accessor,
|
||||
Period: int64(a.Period),
|
||||
NumUses: int64(a.NumUses),
|
||||
EntityID: a.EntityID,
|
||||
Alias: a.Alias,
|
||||
GroupAliases: a.GroupAliases,
|
||||
BoundCidrs: boundCIDRs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -528,18 +530,87 @@ func ProtoAuthToLogicalAuth(a *Auth) (*logical.Auth, error) {
|
||||
}
|
||||
|
||||
return &logical.Auth{
|
||||
LeaseOptions: lo,
|
||||
InternalData: data,
|
||||
DisplayName: a.DisplayName,
|
||||
Policies: a.Policies,
|
||||
Metadata: a.Metadata,
|
||||
ClientToken: a.ClientToken,
|
||||
Accessor: a.Accessor,
|
||||
Period: time.Duration(a.Period),
|
||||
NumUses: int(a.NumUses),
|
||||
EntityID: a.EntityID,
|
||||
Alias: a.Alias,
|
||||
GroupAliases: a.GroupAliases,
|
||||
BoundCIDRs: boundCIDRs,
|
||||
LeaseOptions: lo,
|
||||
InternalData: data,
|
||||
DisplayName: a.DisplayName,
|
||||
Policies: a.Policies,
|
||||
TokenPolicies: a.TokenPolicies,
|
||||
IdentityPolicies: a.IdentityPolicies,
|
||||
Metadata: a.Metadata,
|
||||
ClientToken: a.ClientToken,
|
||||
Accessor: a.Accessor,
|
||||
Period: time.Duration(a.Period),
|
||||
NumUses: int(a.NumUses),
|
||||
EntityID: a.EntityID,
|
||||
Alias: a.Alias,
|
||||
GroupAliases: a.GroupAliases,
|
||||
BoundCIDRs: boundCIDRs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func LogicalTokenEntryToProtoTokenEntry(t *logical.TokenEntry) *TokenEntry {
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
boundCIDRs := make([]string, len(t.BoundCIDRs))
|
||||
for i, cidr := range t.BoundCIDRs {
|
||||
boundCIDRs[i] = cidr.String()
|
||||
}
|
||||
|
||||
return &TokenEntry{
|
||||
ID: t.ID,
|
||||
Accessor: t.Accessor,
|
||||
Parent: t.Parent,
|
||||
Policies: t.Policies,
|
||||
Path: t.Path,
|
||||
Meta: t.Meta,
|
||||
DisplayName: t.DisplayName,
|
||||
NumUses: int64(t.NumUses),
|
||||
CreationTime: t.CreationTime,
|
||||
TTL: int64(t.TTL),
|
||||
ExplicitMaxTTL: int64(t.ExplicitMaxTTL),
|
||||
Role: t.Role,
|
||||
Period: int64(t.Period),
|
||||
EntityID: t.EntityID,
|
||||
BoundCidrs: boundCIDRs,
|
||||
NamespaceID: t.NamespaceID,
|
||||
CubbyholeID: t.CubbyholeID,
|
||||
}
|
||||
}
|
||||
|
||||
func ProtoTokenEntryToLogicalTokenEntry(t *TokenEntry) (*logical.TokenEntry, error) {
|
||||
if t == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
boundCIDRs, err := parseutil.ParseAddrs(t.BoundCidrs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(boundCIDRs) == 0 {
|
||||
// On inbound auths, if auth.BoundCIDRs is empty, it will be nil.
|
||||
// Let's match that behavior outbound.
|
||||
boundCIDRs = nil
|
||||
}
|
||||
|
||||
return &logical.TokenEntry{
|
||||
ID: t.ID,
|
||||
Accessor: t.Accessor,
|
||||
Parent: t.Parent,
|
||||
Policies: t.Policies,
|
||||
Path: t.Path,
|
||||
Meta: t.Meta,
|
||||
DisplayName: t.DisplayName,
|
||||
NumUses: int(t.NumUses),
|
||||
CreationTime: t.CreationTime,
|
||||
TTL: time.Duration(t.TTL),
|
||||
ExplicitMaxTTL: time.Duration(t.ExplicitMaxTTL),
|
||||
Role: t.Role,
|
||||
Period: time.Duration(t.Period),
|
||||
EntityID: t.EntityID,
|
||||
BoundCIDRs: boundCIDRs,
|
||||
NamespaceID: t.NamespaceID,
|
||||
CubbyholeID: t.CubbyholeID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/vault/helper/consts"
|
||||
"github.com/hashicorp/vault/helper/license"
|
||||
"github.com/hashicorp/vault/helper/pluginutil"
|
||||
"github.com/hashicorp/vault/helper/wrapping"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
@@ -109,6 +110,11 @@ func (s *SystemViewClient) LookupPlugin(ctx context.Context, name string) (*plug
|
||||
return nil, fmt.Errorf("cannot call LookupPlugin from a plugin backend")
|
||||
}
|
||||
|
||||
func (s *SystemViewClient) HasFeature(feature license.Features) bool {
|
||||
// Not implemented
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *SystemViewClient) MlockEnabled() bool {
|
||||
var reply MlockEnabledReply
|
||||
err := s.client.Call("Plugin.MlockEnabled", new(interface{}), &reply)
|
||||
|
||||
@@ -51,6 +51,8 @@ func (r *RequestWrapInfo) SentinelKeys() []string {
|
||||
// by the router after policy checks; the token namespace would be the right
|
||||
// place to access them via Sentinel
|
||||
type Request struct {
|
||||
entReq
|
||||
|
||||
// Id is the uuid associated with each request
|
||||
ID string `json:"id" structs:"id" mapstructure:"id" sentinel:""`
|
||||
|
||||
@@ -140,6 +142,10 @@ type Request struct {
|
||||
// accessible.
|
||||
Unauthenticated bool `json:"unauthenticated" structs:"unauthenticated" mapstructure:"unauthenticated"`
|
||||
|
||||
// MFACreds holds the parsed MFA information supplied over the API as part of
|
||||
// X-Vault-MFA header
|
||||
MFACreds MFACreds `json:"mfa_creds" structs:"mfa_creds" mapstructure:"mfa_creds" sentinel:""`
|
||||
|
||||
// Cached token entry. This avoids another lookup in request handling when
|
||||
// we've already looked it up at http handling time. Note that this token
|
||||
// has not been "used", as in it will not properly take into account use
|
||||
@@ -272,3 +278,5 @@ const (
|
||||
RenewOperation = "renew"
|
||||
RollbackOperation = "rollback"
|
||||
)
|
||||
|
||||
type MFACreds map[string][]string
|
||||
|
||||
14
logical/request_util.go
Normal file
14
logical/request_util.go
Normal file
@@ -0,0 +1,14 @@
|
||||
// +build !enterprise
|
||||
|
||||
package logical
|
||||
|
||||
type entReq struct {
|
||||
ControlGroup interface{}
|
||||
}
|
||||
|
||||
func (r *Request) EntReq() *entReq {
|
||||
return &entReq{}
|
||||
}
|
||||
|
||||
func (r *Request) SetEntReq(*entReq) {
|
||||
}
|
||||
@@ -70,11 +70,13 @@ func RespondErrorCommon(req *Request, resp *Response, err error) (int, error) {
|
||||
|
||||
if errwrap.ContainsType(err, new(ReplicationCodedError)) {
|
||||
var allErrors error
|
||||
codedErr := errwrap.GetType(err, new(ReplicationCodedError)).(*ReplicationCodedError)
|
||||
var codedErr *ReplicationCodedError
|
||||
errwrap.Walk(err, func(inErr error) {
|
||||
newErr, ok := inErr.(*ReplicationCodedError)
|
||||
if !ok {
|
||||
allErrors = multierror.Append(allErrors, newErr)
|
||||
if ok {
|
||||
codedErr = newErr
|
||||
} else {
|
||||
allErrors = multierror.Append(allErrors, inErr)
|
||||
}
|
||||
})
|
||||
if allErrors != nil {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/vault/helper/consts"
|
||||
"github.com/hashicorp/vault/helper/license"
|
||||
"github.com/hashicorp/vault/helper/pluginutil"
|
||||
"github.com/hashicorp/vault/helper/wrapping"
|
||||
)
|
||||
@@ -46,6 +47,9 @@ type SystemView interface {
|
||||
// ReplicationState indicates the state of cluster replication
|
||||
ReplicationState() consts.ReplicationState
|
||||
|
||||
// HasFeature returns true if the feature is currently enabled
|
||||
HasFeature(feature license.Features) bool
|
||||
|
||||
// ResponseWrapData wraps the given data in a cubbyhole and returns the
|
||||
// token used to unwrap.
|
||||
ResponseWrapData(ctx context.Context, data map[string]interface{}, ttl time.Duration, jwt bool) (*wrapping.ResponseWrapInfo, error)
|
||||
@@ -77,6 +81,7 @@ type StaticSystemView struct {
|
||||
LocalMountVal bool
|
||||
ReplicationStateVal consts.ReplicationState
|
||||
EntityVal *Entity
|
||||
Features license.Features
|
||||
VaultVersion string
|
||||
PluginEnvironment *PluginEnvironment
|
||||
}
|
||||
@@ -125,6 +130,10 @@ func (d StaticSystemView) EntityInfo(entityID string) (*Entity, error) {
|
||||
return d.EntityVal, nil
|
||||
}
|
||||
|
||||
func (d StaticSystemView) HasFeature(feature license.Features) bool {
|
||||
return d.Features.HasFeature(feature)
|
||||
}
|
||||
|
||||
func (d StaticSystemView) PluginEnv(_ context.Context) (*PluginEnvironment, error) {
|
||||
return d.PluginEnvironment, nil
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/hashicorp/errwrap"
|
||||
"github.com/hashicorp/vault/api"
|
||||
"github.com/hashicorp/vault/helper/logging"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/http"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/physical/inmem"
|
||||
@@ -249,7 +250,7 @@ func Test(tt TestT, c TestCase) {
|
||||
req.Path = fmt.Sprintf("%s/%s", prefix, req.Path)
|
||||
|
||||
// Make the request
|
||||
resp, err := core.HandleRequest(context.Background(), req)
|
||||
resp, err := core.HandleRequest(namespace.TestContext(), req)
|
||||
if resp != nil && resp.Secret != nil {
|
||||
// Revoke this secret later
|
||||
revoke = append(revoke, &logical.Request{
|
||||
@@ -303,7 +304,7 @@ func Test(tt TestT, c TestCase) {
|
||||
logger.Warn("Revoking secret", "secret", fmt.Sprintf("%#v", req))
|
||||
}
|
||||
req.ClientToken = client.Token()
|
||||
resp, err := core.HandleRequest(context.Background(), req)
|
||||
resp, err := core.HandleRequest(namespace.TestContext(), req)
|
||||
if err == nil && resp.IsError() {
|
||||
err = fmt.Errorf("erroneous response:\n\n%#v", resp)
|
||||
}
|
||||
@@ -320,7 +321,7 @@ func Test(tt TestT, c TestCase) {
|
||||
req := logical.RollbackRequest(prefix + "/")
|
||||
req.Data["immediate"] = true
|
||||
req.ClientToken = client.Token()
|
||||
resp, err := core.HandleRequest(context.Background(), req)
|
||||
resp, err := core.HandleRequest(namespace.TestContext(), req)
|
||||
if err == nil && resp.IsError() {
|
||||
err = fmt.Errorf("erroneous response:\n\n%#v", resp)
|
||||
}
|
||||
|
||||
@@ -65,6 +65,15 @@ type TokenEntry struct {
|
||||
|
||||
// The set of CIDRs that this token can be used with
|
||||
BoundCIDRs []*sockaddr.SockAddrMarshaler `json:"bound_cidrs"`
|
||||
|
||||
// NamespaceID is the identifier of the namespace to which this token is
|
||||
// confined to. Do not return this value over the API when the token is
|
||||
// being looked up.
|
||||
NamespaceID string `json:"namespace_id" mapstructure:"namespace_id" structs:"namespace_id" sentinel:""`
|
||||
|
||||
// CubbyholeID is the identifier of the cubbyhole storage belonging to this
|
||||
// token
|
||||
CubbyholeID string `json:"cubbyhole_id" mapstructure:"cubbyhole_id" structs:"cubbyhole_id" sentinel:""`
|
||||
}
|
||||
|
||||
func (te *TokenEntry) SentinelGet(key string) (interface{}, error) {
|
||||
|
||||
@@ -22,6 +22,7 @@ var cacheExceptionsPaths = []string{
|
||||
"index/pages/",
|
||||
"index-dr/pages/",
|
||||
"sys/expire/",
|
||||
"core/poison-pill",
|
||||
}
|
||||
|
||||
// Cache is used to wrap an underlying physical backend
|
||||
|
||||
@@ -73,6 +73,7 @@ var _ physical.Backend = (*ConsulBackend)(nil)
|
||||
var _ physical.HABackend = (*ConsulBackend)(nil)
|
||||
var _ physical.Lock = (*ConsulLock)(nil)
|
||||
var _ physical.Transactional = (*ConsulBackend)(nil)
|
||||
var _ physical.ServiceDiscovery = (*ConsulBackend)(nil)
|
||||
|
||||
var (
|
||||
hostnameRegex = regexp.MustCompile(`^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$`)
|
||||
@@ -97,8 +98,9 @@ type ConsulBackend struct {
|
||||
checkTimeout time.Duration
|
||||
consistencyMode string
|
||||
|
||||
notifyActiveCh chan notifyEvent
|
||||
notifySealedCh chan notifyEvent
|
||||
notifyActiveCh chan notifyEvent
|
||||
notifySealedCh chan notifyEvent
|
||||
notifyPerfStandbyCh chan notifyEvent
|
||||
|
||||
sessionTTL string
|
||||
lockWaitTime time.Duration
|
||||
@@ -292,6 +294,7 @@ func NewConsulBackend(conf map[string]string, logger log.Logger) (physical.Backe
|
||||
consistencyMode: consistencyMode,
|
||||
notifyActiveCh: make(chan notifyEvent),
|
||||
notifySealedCh: make(chan notifyEvent),
|
||||
notifyPerfStandbyCh: make(chan notifyEvent),
|
||||
sessionTTL: sessionTTL,
|
||||
lockWaitTime: lockWaitTime,
|
||||
}
|
||||
@@ -595,6 +598,18 @@ func (c *ConsulBackend) NotifyActiveStateChange() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ConsulBackend) NotifyPerformanceStandbyStateChange() error {
|
||||
select {
|
||||
case c.notifyPerfStandbyCh <- notifyEvent{}:
|
||||
default:
|
||||
// NOTE: If this occurs Vault's active status could be out of
|
||||
// sync with Consul until reconcileTimer expires.
|
||||
c.logger.Warn("concurrent state change notify dropped")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ConsulBackend) NotifySealedStateChange() error {
|
||||
select {
|
||||
case c.notifySealedCh <- notifyEvent{}:
|
||||
@@ -611,7 +626,7 @@ func (c *ConsulBackend) checkDuration() time.Duration {
|
||||
return lib.DurationMinusBuffer(c.checkTimeout, checkMinBuffer, checkJitterFactor)
|
||||
}
|
||||
|
||||
func (c *ConsulBackend) RunServiceDiscovery(waitGroup *sync.WaitGroup, shutdownCh physical.ShutdownChannel, redirectAddr string, activeFunc physical.ActiveFunction, sealedFunc physical.SealedFunction) (err error) {
|
||||
func (c *ConsulBackend) RunServiceDiscovery(waitGroup *sync.WaitGroup, shutdownCh physical.ShutdownChannel, redirectAddr string, activeFunc physical.ActiveFunction, sealedFunc physical.SealedFunction, perfStandbyFunc physical.PerformanceStandbyFunction) (err error) {
|
||||
if err := c.setRedirectAddr(redirectAddr); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -619,12 +634,12 @@ func (c *ConsulBackend) RunServiceDiscovery(waitGroup *sync.WaitGroup, shutdownC
|
||||
// 'server' command will wait for the below goroutine to complete
|
||||
waitGroup.Add(1)
|
||||
|
||||
go c.runEventDemuxer(waitGroup, shutdownCh, redirectAddr, activeFunc, sealedFunc)
|
||||
go c.runEventDemuxer(waitGroup, shutdownCh, redirectAddr, activeFunc, sealedFunc, perfStandbyFunc)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ConsulBackend) runEventDemuxer(waitGroup *sync.WaitGroup, shutdownCh physical.ShutdownChannel, redirectAddr string, activeFunc physical.ActiveFunction, sealedFunc physical.SealedFunction) {
|
||||
func (c *ConsulBackend) runEventDemuxer(waitGroup *sync.WaitGroup, shutdownCh physical.ShutdownChannel, redirectAddr string, activeFunc physical.ActiveFunction, sealedFunc physical.SealedFunction, perfStandbyFunc physical.PerformanceStandbyFunction) {
|
||||
// This defer statement should be executed last. So push it first.
|
||||
defer waitGroup.Done()
|
||||
|
||||
@@ -660,6 +675,9 @@ func (c *ConsulBackend) runEventDemuxer(waitGroup *sync.WaitGroup, shutdownCh ph
|
||||
case <-c.notifySealedCh:
|
||||
// Run check timer immediately upon a seal state change notification
|
||||
checkTimer.Reset(0)
|
||||
case <-c.notifyPerfStandbyCh:
|
||||
// Run check timer immediately upon a seal state change notification
|
||||
checkTimer.Reset(0)
|
||||
case <-reconcileTimer.C:
|
||||
// Unconditionally rearm the reconcileTimer
|
||||
reconcileTimer.Reset(reconcileTimeout - lib.RandomStagger(reconcileTimeout/checkJitterFactor))
|
||||
@@ -671,7 +689,7 @@ func (c *ConsulBackend) runEventDemuxer(waitGroup *sync.WaitGroup, shutdownCh ph
|
||||
go func() {
|
||||
defer atomic.CompareAndSwapInt32(serviceRegLock, 1, 0)
|
||||
for !shutdown {
|
||||
serviceID, err := c.reconcileConsul(registeredServiceID, activeFunc, sealedFunc)
|
||||
serviceID, err := c.reconcileConsul(registeredServiceID, activeFunc, sealedFunc, perfStandbyFunc)
|
||||
if err != nil {
|
||||
if c.logger.IsWarn() {
|
||||
c.logger.Warn("reconcile unable to talk with Consul backend", "error", err)
|
||||
@@ -741,10 +759,11 @@ func (c *ConsulBackend) serviceID() string {
|
||||
// without any locks held and can be run concurrently, therefore no changes
|
||||
// to ConsulBackend can be made in this method (i.e. wtb const receiver for
|
||||
// compiler enforced safety).
|
||||
func (c *ConsulBackend) reconcileConsul(registeredServiceID string, activeFunc physical.ActiveFunction, sealedFunc physical.SealedFunction) (serviceID string, err error) {
|
||||
func (c *ConsulBackend) reconcileConsul(registeredServiceID string, activeFunc physical.ActiveFunction, sealedFunc physical.SealedFunction, perfStandbyFunc physical.PerformanceStandbyFunction) (serviceID string, err error) {
|
||||
// Query vault Core for its current state
|
||||
active := activeFunc()
|
||||
sealed := sealedFunc()
|
||||
perfStandby := perfStandbyFunc()
|
||||
|
||||
agent := c.client.Agent()
|
||||
catalog := c.client.Catalog()
|
||||
@@ -762,7 +781,7 @@ func (c *ConsulBackend) reconcileConsul(registeredServiceID string, activeFunc p
|
||||
}
|
||||
}
|
||||
|
||||
tags := c.fetchServiceTags(active)
|
||||
tags := c.fetchServiceTags(active, perfStandby)
|
||||
|
||||
var reregister bool
|
||||
|
||||
@@ -839,12 +858,19 @@ func (c *ConsulBackend) runCheck(sealed bool) error {
|
||||
}
|
||||
|
||||
// fetchServiceTags returns all of the relevant tags for Consul.
|
||||
func (c *ConsulBackend) fetchServiceTags(active bool) []string {
|
||||
func (c *ConsulBackend) fetchServiceTags(active bool, perfStandby bool) []string {
|
||||
activeTag := "standby"
|
||||
if active {
|
||||
activeTag = "active"
|
||||
}
|
||||
return append(c.serviceTags, activeTag)
|
||||
|
||||
result := append(c.serviceTags, activeTag)
|
||||
|
||||
if perfStandby {
|
||||
result = append(c.serviceTags, "performance-standby")
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (c *ConsulBackend) setRedirectAddr(addr string) (err error) {
|
||||
|
||||
@@ -80,6 +80,17 @@ func testSealedFunc(sealedPct float64) physical.SealedFunction {
|
||||
}
|
||||
}
|
||||
|
||||
func testPerformanceStandbyFunc(perfPct float64) physical.PerformanceStandbyFunction {
|
||||
return func() bool {
|
||||
var ps bool
|
||||
unsealedProb := rand.Float64()
|
||||
if unsealedProb > perfPct {
|
||||
ps = true
|
||||
}
|
||||
return ps
|
||||
}
|
||||
}
|
||||
|
||||
func TestConsul_ServiceTags(t *testing.T) {
|
||||
consulConfig := map[string]string{
|
||||
"path": "seaTech/",
|
||||
@@ -106,15 +117,25 @@ func TestConsul_ServiceTags(t *testing.T) {
|
||||
}
|
||||
|
||||
expected := []string{"deadbeef", "cafeefac", "deadc0de", "feedface"}
|
||||
actual := c.fetchServiceTags(false)
|
||||
actual := c.fetchServiceTags(false, false)
|
||||
if !strutil.EquivalentSlices(actual, append(expected, "standby")) {
|
||||
t.Fatalf("bad: expected:%s actual:%s", append(expected, "standby"), actual)
|
||||
}
|
||||
|
||||
actual = c.fetchServiceTags(true)
|
||||
actual = c.fetchServiceTags(true, false)
|
||||
if !strutil.EquivalentSlices(actual, append(expected, "active")) {
|
||||
t.Fatalf("bad: expected:%s actual:%s", append(expected, "active"), actual)
|
||||
}
|
||||
|
||||
actual = c.fetchServiceTags(false, true)
|
||||
if !strutil.EquivalentSlices(actual, append(expected, "performance-standby")) {
|
||||
t.Fatalf("bad: expected:%s actual:%s", append(expected, "performance-standby"), actual)
|
||||
}
|
||||
|
||||
actual = c.fetchServiceTags(true, true)
|
||||
if !strutil.EquivalentSlices(actual, append(expected, "performance-standby")) {
|
||||
t.Fatalf("bad: expected:%s actual:%s", append(expected, "performance-standby"), actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConsul_ServiceAddress(t *testing.T) {
|
||||
@@ -254,7 +275,7 @@ func TestConsul_newConsulBackend(t *testing.T) {
|
||||
|
||||
var shutdownCh physical.ShutdownChannel
|
||||
waitGroup := &sync.WaitGroup{}
|
||||
if err := c.RunServiceDiscovery(waitGroup, shutdownCh, test.redirectAddr, testActiveFunc(0.5), testSealedFunc(0.5)); err != nil {
|
||||
if err := c.RunServiceDiscovery(waitGroup, shutdownCh, test.redirectAddr, testActiveFunc(0.5), testSealedFunc(0.5), testPerformanceStandbyFunc(0.5)); err != nil {
|
||||
t.Fatalf("bad: %v", err)
|
||||
}
|
||||
|
||||
@@ -283,23 +304,36 @@ func TestConsul_newConsulBackend(t *testing.T) {
|
||||
|
||||
func TestConsul_serviceTags(t *testing.T) {
|
||||
tests := []struct {
|
||||
active bool
|
||||
tags []string
|
||||
active bool
|
||||
perfStandby bool
|
||||
tags []string
|
||||
}{
|
||||
{
|
||||
active: true,
|
||||
tags: []string{"active"},
|
||||
active: true,
|
||||
perfStandby: false,
|
||||
tags: []string{"active"},
|
||||
},
|
||||
{
|
||||
active: false,
|
||||
tags: []string{"standby"},
|
||||
active: false,
|
||||
perfStandby: false,
|
||||
tags: []string{"standby"},
|
||||
},
|
||||
{
|
||||
active: false,
|
||||
perfStandby: true,
|
||||
tags: []string{"performance-standby"},
|
||||
},
|
||||
{
|
||||
active: true,
|
||||
perfStandby: true,
|
||||
tags: []string{"performance-standby"},
|
||||
},
|
||||
}
|
||||
|
||||
c := testConsulBackend(t)
|
||||
|
||||
for _, test := range tests {
|
||||
tags := c.fetchServiceTags(test.active)
|
||||
tags := c.fetchServiceTags(test.active, test.perfStandby)
|
||||
if !reflect.DeepEqual(tags[:], test.tags[:]) {
|
||||
t.Errorf("Bad %v: %v %v", test.active, tags, test.tags)
|
||||
}
|
||||
|
||||
103
physical/error.go
Normal file
103
physical/error.go
Normal file
@@ -0,0 +1,103 @@
|
||||
package physical
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
log "github.com/hashicorp/go-hclog"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultErrorPercent is used to determin how often we error
|
||||
DefaultErrorPercent = 20
|
||||
)
|
||||
|
||||
// ErrorInjector is used to add errors into underlying physical requests
|
||||
type ErrorInjector struct {
|
||||
backend Backend
|
||||
errorPercent int
|
||||
random *rand.Rand
|
||||
}
|
||||
|
||||
// TransactionalErrorInjector is the transactional version of the error
|
||||
// injector
|
||||
type TransactionalErrorInjector struct {
|
||||
*ErrorInjector
|
||||
Transactional
|
||||
}
|
||||
|
||||
// Verify ErrorInjector satisfies the correct interfaces
|
||||
var _ Backend = (*ErrorInjector)(nil)
|
||||
var _ Transactional = (*TransactionalErrorInjector)(nil)
|
||||
|
||||
// NewErrorInjector returns a wrapped physical backend to inject error
|
||||
func NewErrorInjector(b Backend, errorPercent int, logger log.Logger) *ErrorInjector {
|
||||
if errorPercent < 0 || errorPercent > 100 {
|
||||
errorPercent = DefaultJitterPercent
|
||||
}
|
||||
logger.Info("creating error injector")
|
||||
|
||||
return &ErrorInjector{
|
||||
backend: b,
|
||||
errorPercent: errorPercent,
|
||||
random: rand.New(rand.NewSource(int64(time.Now().Nanosecond()))),
|
||||
}
|
||||
}
|
||||
|
||||
// NewTransactionalErrorInjector creates a new transactional ErrorInjector
|
||||
func NewTransactionalErrorInjector(b Backend, errorPercent int, logger log.Logger) *TransactionalErrorInjector {
|
||||
return &TransactionalErrorInjector{
|
||||
ErrorInjector: NewErrorInjector(b, errorPercent, logger),
|
||||
Transactional: b.(Transactional),
|
||||
}
|
||||
}
|
||||
|
||||
func (e *ErrorInjector) SetErrorPercentage(p int) {
|
||||
e.errorPercent = p
|
||||
}
|
||||
|
||||
func (e *ErrorInjector) addError() error {
|
||||
roll := e.random.Intn(100)
|
||||
if roll < e.errorPercent {
|
||||
return errors.New("random error")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *ErrorInjector) Put(ctx context.Context, entry *Entry) error {
|
||||
if err := e.addError(); err != nil {
|
||||
return err
|
||||
}
|
||||
return e.backend.Put(ctx, entry)
|
||||
}
|
||||
|
||||
func (e *ErrorInjector) Get(ctx context.Context, key string) (*Entry, error) {
|
||||
if err := e.addError(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e.backend.Get(ctx, key)
|
||||
}
|
||||
|
||||
func (e *ErrorInjector) Delete(ctx context.Context, key string) error {
|
||||
if err := e.addError(); err != nil {
|
||||
return err
|
||||
}
|
||||
return e.backend.Delete(ctx, key)
|
||||
}
|
||||
|
||||
func (e *ErrorInjector) List(ctx context.Context, prefix string) ([]string, error) {
|
||||
if err := e.addError(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e.backend.List(ctx, prefix)
|
||||
}
|
||||
|
||||
func (e *TransactionalErrorInjector) Transaction(ctx context.Context, txns []*TxnEntry) error {
|
||||
if err := e.addError(); err != nil {
|
||||
return err
|
||||
}
|
||||
return e.Transactional.Transaction(ctx, txns)
|
||||
}
|
||||
@@ -75,6 +75,7 @@ type RedirectDetect interface {
|
||||
// Callback signatures for RunServiceDiscovery
|
||||
type ActiveFunction func() bool
|
||||
type SealedFunction func() bool
|
||||
type PerformanceStandbyFunction func() bool
|
||||
|
||||
// ServiceDiscovery is an optional interface that an HABackend can implement.
|
||||
// If they do, the state of a backend is advertised to the service discovery
|
||||
@@ -90,9 +91,14 @@ type ServiceDiscovery interface {
|
||||
// status to sealed or unsealed.
|
||||
NotifySealedStateChange() error
|
||||
|
||||
// NotifyPerformanceStandbyStateChange is used by Core to notify a backend
|
||||
// capable of ServiceDiscovery that this Vault instance has changed it
|
||||
// status to performance standby or standby.
|
||||
NotifyPerformanceStandbyStateChange() error
|
||||
|
||||
// Run executes any background service discovery tasks until the
|
||||
// shutdown channel is closed.
|
||||
RunServiceDiscovery(waitGroup *sync.WaitGroup, shutdownCh ShutdownChannel, redirectAddr string, activeFunc ActiveFunction, sealedFunc SealedFunction) error
|
||||
RunServiceDiscovery(waitGroup *sync.WaitGroup, shutdownCh ShutdownChannel, redirectAddr string, activeFunc ActiveFunction, sealedFunc SealedFunction, perfStandbyFunc PerformanceStandbyFunction) error
|
||||
}
|
||||
|
||||
type Lock interface {
|
||||
@@ -109,13 +115,6 @@ type Lock interface {
|
||||
Value() (bool, string, error)
|
||||
}
|
||||
|
||||
// Entry is used to represent data stored by the physical backend
|
||||
type Entry struct {
|
||||
Key string
|
||||
Value []byte
|
||||
SealWrap bool `json:"seal_wrap,omitempty"`
|
||||
}
|
||||
|
||||
// Factory is the factory function to create a physical backend.
|
||||
type Factory func(config map[string]string, logger log.Logger) (Backend, error)
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package physical
|
||||
|
||||
import "context"
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// PhysicalAccess is a wrapper around physical.Backend that allows Core to
|
||||
// expose its physical storage operations through PhysicalAccess() while
|
||||
|
||||
10
physical/physical_util.go
Normal file
10
physical/physical_util.go
Normal file
@@ -0,0 +1,10 @@
|
||||
// +build !enterprise
|
||||
|
||||
package physical
|
||||
|
||||
// Entry is used to represent data stored by the physical backend
|
||||
type Entry struct {
|
||||
Key string
|
||||
Value []byte
|
||||
SealWrap bool `json:"seal_wrap,omitempty"`
|
||||
}
|
||||
@@ -21,6 +21,11 @@ type Transactional interface {
|
||||
Transaction(context.Context, []*TxnEntry) error
|
||||
}
|
||||
|
||||
type TransactionalBackend interface {
|
||||
Backend
|
||||
Transactional
|
||||
}
|
||||
|
||||
type PseudoTransactional interface {
|
||||
// An internal function should do no locking or permit pool acquisition.
|
||||
// Depending on the backend and if it natively supports transactions, these
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// +build !enterprise
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: physical/types.proto
|
||||
|
||||
|
||||
144
vault/acl.go
144
vault/acl.go
@@ -6,10 +6,11 @@ import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/armon/go-radix"
|
||||
radix "github.com/armon/go-radix"
|
||||
"github.com/hashicorp/errwrap"
|
||||
multierror "github.com/hashicorp/go-multierror"
|
||||
"github.com/hashicorp/vault/helper/identity"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/helper/strutil"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/mitchellh/copystructure"
|
||||
@@ -26,6 +27,9 @@ type ACL struct {
|
||||
|
||||
// root is enabled if the "root" named policy is present.
|
||||
root bool
|
||||
|
||||
// Stores policies that are actually RGPs for later fetching
|
||||
rgpPolicies []*Policy
|
||||
}
|
||||
|
||||
type PolicyCheckOpts struct {
|
||||
@@ -42,14 +46,16 @@ type AuthResults struct {
|
||||
}
|
||||
|
||||
type ACLResults struct {
|
||||
Allowed bool
|
||||
RootPrivs bool
|
||||
IsRoot bool
|
||||
MFAMethods []string
|
||||
Allowed bool
|
||||
RootPrivs bool
|
||||
IsRoot bool
|
||||
MFAMethods []string
|
||||
ControlGroup *ControlGroup
|
||||
CapabilitiesBitmap uint32
|
||||
}
|
||||
|
||||
// New is used to construct a policy based ACL from a set of policies.
|
||||
func NewACL(policies []*Policy) (*ACL, error) {
|
||||
// NewACL is used to construct a policy based ACL from a set of policies.
|
||||
func NewACL(ctx context.Context, policies []*Policy) (*ACL, error) {
|
||||
// Initialize
|
||||
a := &ACL{
|
||||
exactRules: radix.New(),
|
||||
@@ -57,6 +63,14 @@ func NewACL(policies []*Policy) (*ACL, error) {
|
||||
root: false,
|
||||
}
|
||||
|
||||
ns, err := namespace.FromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ns == nil {
|
||||
return nil, namespace.ErrNoNamespace
|
||||
}
|
||||
|
||||
// Inject each policy
|
||||
for _, policy := range policies {
|
||||
// Ignore a nil policy object
|
||||
@@ -66,12 +80,19 @@ func NewACL(policies []*Policy) (*ACL, error) {
|
||||
|
||||
switch policy.Type {
|
||||
case PolicyTypeACL:
|
||||
case PolicyTypeRGP:
|
||||
a.rgpPolicies = append(a.rgpPolicies, policy)
|
||||
continue
|
||||
default:
|
||||
return nil, fmt.Errorf("unable to parse policy (wrong type)")
|
||||
}
|
||||
|
||||
// Check if this is root
|
||||
if policy.Name == "root" {
|
||||
if ns.ID != namespace.RootNamespaceID {
|
||||
return nil, fmt.Errorf("root policy is only allowed in root namespace")
|
||||
}
|
||||
|
||||
if len(policies) != 1 {
|
||||
return nil, fmt.Errorf("other policies present along with root")
|
||||
}
|
||||
@@ -196,6 +217,30 @@ func NewACL(policies []*Policy) (*ACL, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if len(pc.Permissions.MFAMethods) > 0 {
|
||||
if existingPerms.MFAMethods == nil {
|
||||
existingPerms.MFAMethods = pc.Permissions.MFAMethods
|
||||
} else {
|
||||
for _, method := range pc.Permissions.MFAMethods {
|
||||
existingPerms.MFAMethods = append(existingPerms.MFAMethods, method)
|
||||
}
|
||||
}
|
||||
existingPerms.MFAMethods = strutil.RemoveDuplicates(existingPerms.MFAMethods, false)
|
||||
}
|
||||
|
||||
// No need to dedupe this list since any authorization can satisfy any factor
|
||||
if pc.Permissions.ControlGroup != nil {
|
||||
if len(pc.Permissions.ControlGroup.Factors) > 0 {
|
||||
if existingPerms.ControlGroup == nil {
|
||||
existingPerms.ControlGroup = pc.Permissions.ControlGroup
|
||||
} else {
|
||||
for _, authz := range pc.Permissions.ControlGroup.Factors {
|
||||
existingPerms.ControlGroup.Factors = append(existingPerms.ControlGroup.Factors, authz)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
INSERT:
|
||||
tree.Insert(pc.Prefix, existingPerms)
|
||||
}
|
||||
@@ -203,40 +248,21 @@ func NewACL(policies []*Policy) (*ACL, error) {
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func (a *ACL) Capabilities(path string) (pathCapabilities []string) {
|
||||
// Fast-path root
|
||||
if a.root {
|
||||
func (a *ACL) Capabilities(ctx context.Context, path string) (pathCapabilities []string) {
|
||||
req := &logical.Request{
|
||||
Path: path,
|
||||
// doesn't matter, but use List to trigger fallback behavior so we can
|
||||
// model real behavior
|
||||
Operation: logical.ListOperation,
|
||||
}
|
||||
|
||||
res := a.AllowOperation(ctx, req, true)
|
||||
if res.IsRoot {
|
||||
return []string{RootCapability}
|
||||
}
|
||||
|
||||
// Find an exact matching rule, look for glob if no match
|
||||
var capabilities uint32
|
||||
raw, ok := a.exactRules.Get(path)
|
||||
capabilities := res.CapabilitiesBitmap
|
||||
|
||||
if ok {
|
||||
perm := raw.(*ACLPermissions)
|
||||
capabilities = perm.CapabilitiesBitmap
|
||||
goto CHECK
|
||||
}
|
||||
if strings.HasSuffix(path, "/") {
|
||||
raw, ok = a.exactRules.Get(strings.TrimSuffix(path, "/"))
|
||||
if ok {
|
||||
perm := raw.(*ACLPermissions)
|
||||
capabilities = perm.CapabilitiesBitmap
|
||||
goto CHECK
|
||||
}
|
||||
}
|
||||
|
||||
// Find a glob rule, default deny if no match
|
||||
_, raw, ok = a.globRules.LongestPrefix(path)
|
||||
if !ok {
|
||||
return []string{DenyCapability}
|
||||
} else {
|
||||
perm := raw.(*ACLPermissions)
|
||||
capabilities = perm.CapabilitiesBitmap
|
||||
}
|
||||
|
||||
CHECK:
|
||||
if capabilities&SudoCapabilityInt > 0 {
|
||||
pathCapabilities = append(pathCapabilities, SudoCapability)
|
||||
}
|
||||
@@ -265,7 +291,7 @@ CHECK:
|
||||
}
|
||||
|
||||
// AllowOperation is used to check if the given operation is permitted.
|
||||
func (a *ACL) AllowOperation(req *logical.Request) (ret *ACLResults) {
|
||||
func (a *ACL) AllowOperation(ctx context.Context, req *logical.Request, capCheckOnly bool) (ret *ACLResults) {
|
||||
ret = new(ACLResults)
|
||||
|
||||
// Fast-path root
|
||||
@@ -276,7 +302,6 @@ func (a *ACL) AllowOperation(req *logical.Request) (ret *ACLResults) {
|
||||
return
|
||||
}
|
||||
op := req.Operation
|
||||
path := req.Path
|
||||
|
||||
// Help is always allowed
|
||||
if op == logical.HelpOperation {
|
||||
@@ -286,6 +311,12 @@ func (a *ACL) AllowOperation(req *logical.Request) (ret *ACLResults) {
|
||||
|
||||
var permissions *ACLPermissions
|
||||
|
||||
ns, err := namespace.FromContext(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
path := ns.Path + req.Path
|
||||
|
||||
// Find an exact matching rule, look for glob if no match
|
||||
var capabilities uint32
|
||||
raw, ok := a.exactRules.Get(path)
|
||||
@@ -307,10 +338,9 @@ func (a *ACL) AllowOperation(req *logical.Request) (ret *ACLResults) {
|
||||
_, raw, ok = a.globRules.LongestPrefix(path)
|
||||
if !ok {
|
||||
return
|
||||
} else {
|
||||
permissions = raw.(*ACLPermissions)
|
||||
capabilities = permissions.CapabilitiesBitmap
|
||||
}
|
||||
permissions = raw.(*ACLPermissions)
|
||||
capabilities = permissions.CapabilitiesBitmap
|
||||
|
||||
CHECK:
|
||||
// Check if the minimum permissions are met
|
||||
@@ -318,6 +348,16 @@ CHECK:
|
||||
// only need to check for the existence of other values
|
||||
ret.RootPrivs = capabilities&SudoCapabilityInt > 0
|
||||
|
||||
// This is after the RootPrivs check so we can gate on it being from sudo
|
||||
// rather than policy root
|
||||
if capCheckOnly {
|
||||
ret.CapabilitiesBitmap = capabilities
|
||||
return ret
|
||||
}
|
||||
|
||||
ret.MFAMethods = permissions.MFAMethods
|
||||
ret.ControlGroup = permissions.ControlGroup
|
||||
|
||||
operationAllowed := false
|
||||
switch op {
|
||||
case logical.ReadOperation:
|
||||
@@ -427,31 +467,33 @@ CHECK:
|
||||
ret.Allowed = true
|
||||
return
|
||||
}
|
||||
func (c *Core) performPolicyChecks(ctx context.Context, acl *ACL, te *logical.TokenEntry, req *logical.Request, inEntity *identity.Entity, opts *PolicyCheckOpts) (ret *AuthResults) {
|
||||
ret = new(AuthResults)
|
||||
|
||||
func (c *Core) performPolicyChecks(ctx context.Context, acl *ACL, te *logical.TokenEntry, req *logical.Request, inEntity *identity.Entity, opts *PolicyCheckOpts) *AuthResults {
|
||||
ret := new(AuthResults)
|
||||
|
||||
// First, perform normal ACL checks if requested. The only time no ACL
|
||||
// should be applied is if we are only processing EGPs against a login
|
||||
// path in which case opts.Unauth will be set.
|
||||
if acl != nil && !opts.Unauth {
|
||||
ret.ACLResults = acl.AllowOperation(req)
|
||||
ret.ACLResults = acl.AllowOperation(ctx, req, false)
|
||||
ret.RootPrivs = ret.ACLResults.RootPrivs
|
||||
// Root is always allowed; skip Sentinel/MFA checks
|
||||
if ret.ACLResults.IsRoot {
|
||||
//c.logger.Warn("policy: token is root, skipping checks")
|
||||
//logger.Warn("token is root, skipping checks")
|
||||
ret.Allowed = true
|
||||
return
|
||||
return ret
|
||||
}
|
||||
if !ret.ACLResults.Allowed {
|
||||
return
|
||||
return ret
|
||||
}
|
||||
if !ret.RootPrivs && opts.RootPrivsRequired {
|
||||
return
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
ret.Allowed = true
|
||||
return
|
||||
c.performEntPolicyChecks(ctx, acl, te, req, inEntity, opts, ret)
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func valueInParameterList(v interface{}, list []interface{}) bool {
|
||||
|
||||
@@ -1,62 +1,165 @@
|
||||
package vault
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
)
|
||||
|
||||
func TestACL_Capabilities(t *testing.T) {
|
||||
// Create the root policy ACL
|
||||
func TestACL_NewACL(t *testing.T) {
|
||||
t.Run("root-ns", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
testNewACL(t, namespace.RootNamespace)
|
||||
})
|
||||
}
|
||||
|
||||
func testNewACL(t *testing.T, ns *namespace.Namespace) {
|
||||
ctx := namespace.ContextWithNamespace(context.Background(), ns)
|
||||
policy := []*Policy{&Policy{Name: "root"}}
|
||||
acl, err := NewACL(policy)
|
||||
_, err := NewACL(ctx, policy)
|
||||
switch ns.ID {
|
||||
case namespace.RootNamespaceID:
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
default:
|
||||
if err == nil {
|
||||
t.Fatal("expected an error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestACL_MFAMethods(t *testing.T) {
|
||||
t.Run("root-ns", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
testACLMFAMethods(t, namespace.RootNamespace)
|
||||
})
|
||||
}
|
||||
|
||||
func testACLMFAMethods(t *testing.T, ns *namespace.Namespace) {
|
||||
mfaRules := `
|
||||
path "secret/foo/*" {
|
||||
mfa_methods = ["mfa_method_1", "mfa_method_2", "mfa_method_3"]
|
||||
}
|
||||
path "secret/exact/path" {
|
||||
mfa_methods = ["mfa_method_4", "mfa_method_5"]
|
||||
}
|
||||
path "secret/split/definition" {
|
||||
mfa_methods = ["mfa_method_6", "mfa_method_7"]
|
||||
}
|
||||
path "secret/split/definition" {
|
||||
mfa_methods = ["mfa_method_7", "mfa_method_8", "mfa_method_9"]
|
||||
}
|
||||
`
|
||||
|
||||
policy, err := ParseACLPolicy(ns, mfaRules)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ctx := namespace.ContextWithNamespace(context.Background(), ns)
|
||||
acl, err := NewACL(ctx, []*Policy{policy})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
request := &logical.Request{
|
||||
Operation: logical.UpdateOperation,
|
||||
Path: "secret/foo/testing/glob/pattern",
|
||||
}
|
||||
|
||||
actual := acl.AllowOperation(ctx, request, false).MFAMethods
|
||||
expected := []string{"mfa_method_1", "mfa_method_2", "mfa_method_3"}
|
||||
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Fatalf("bad: MFA methods; expected: %#v\n actual: %#v\n", expected, actual)
|
||||
}
|
||||
|
||||
request.Path = "secret/exact/path"
|
||||
actual = acl.AllowOperation(ctx, request, false).MFAMethods
|
||||
expected = []string{"mfa_method_4", "mfa_method_5"}
|
||||
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Fatalf("bad: MFA methods; expected: %#v\n actual: %#v\n", expected, actual)
|
||||
}
|
||||
|
||||
request.Path = "secret/split/definition"
|
||||
actual = acl.AllowOperation(ctx, request, false).MFAMethods
|
||||
expected = []string{"mfa_method_6", "mfa_method_7", "mfa_method_8", "mfa_method_9"}
|
||||
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Fatalf("bad: MFA methods; expected: %#v\n actual: %#v\n", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestACL_Capabilities(t *testing.T) {
|
||||
t.Run("root-ns", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
policy := []*Policy{&Policy{Name: "root"}}
|
||||
ctx := namespace.RootContext(nil)
|
||||
acl, err := NewACL(ctx, policy)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
actual := acl.Capabilities(ctx, "any/path")
|
||||
expected := []string{"root"}
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("bad: got\n%#v\nexpected\n%#v\n", actual, expected)
|
||||
}
|
||||
testACLCapabilities(t, namespace.RootNamespace)
|
||||
})
|
||||
}
|
||||
|
||||
func testACLCapabilities(t *testing.T, ns *namespace.Namespace) {
|
||||
// Create the root policy ACL
|
||||
ctx := namespace.ContextWithNamespace(context.Background(), ns)
|
||||
policy, err := ParseACLPolicy(ns, aclPolicy)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
actual := acl.Capabilities("any/path")
|
||||
expected := []string{"root"}
|
||||
acl, err := NewACL(ctx, []*Policy{policy})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
actual := acl.Capabilities(ctx, "dev")
|
||||
expected := []string{"deny"}
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("bad: got\n%#v\nexpected\n%#v\n", actual, expected)
|
||||
t.Fatalf("bad: path: %s\ngot\n%#v\nexpected\n%#v\n", "deny", actual, expected)
|
||||
}
|
||||
|
||||
policies, err := ParseACLPolicy(aclPolicy)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
acl, err = NewACL([]*Policy{policies})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
actual = acl.Capabilities("dev")
|
||||
expected = []string{"deny"}
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("bad: path:%s\ngot\n%#v\nexpected\n%#v\n", "deny", actual, expected)
|
||||
}
|
||||
|
||||
actual = acl.Capabilities("dev/")
|
||||
actual = acl.Capabilities(ctx, "dev/")
|
||||
expected = []string{"sudo", "read", "list", "update", "delete", "create"}
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("bad: path:%s\ngot\n%#v\nexpected\n%#v\n", "dev/", actual, expected)
|
||||
t.Fatalf("bad: path: %s\ngot\n%#v\nexpected\n%#v\n", "dev/", actual, expected)
|
||||
}
|
||||
|
||||
actual = acl.Capabilities("stage/aws/test")
|
||||
actual = acl.Capabilities(ctx, "stage/aws/test")
|
||||
expected = []string{"sudo", "read", "list", "update"}
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("bad: path:%s\ngot\n%#v\nexpected\n%#v\n", "stage/aws/test", actual, expected)
|
||||
t.Fatalf("bad: path: %s\ngot\n%#v\nexpected\n%#v\n", "stage/aws/test", actual, expected)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestACL_Root(t *testing.T) {
|
||||
// Create the root policy ACL
|
||||
t.Run("root-ns", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
testACLRoot(t, namespace.RootNamespace)
|
||||
})
|
||||
}
|
||||
|
||||
func testACLRoot(t *testing.T, ns *namespace.Namespace) {
|
||||
// Create the root policy ACL. Always create on root namespace regardless of
|
||||
// which namespace to ACL check on.
|
||||
policy := []*Policy{&Policy{Name: "root"}}
|
||||
acl, err := NewACL(policy)
|
||||
acl, err := NewACL(namespace.TestContext(), policy)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -64,7 +167,9 @@ func TestACL_Root(t *testing.T) {
|
||||
request := new(logical.Request)
|
||||
request.Operation = logical.UpdateOperation
|
||||
request.Path = "sys/mount/foo"
|
||||
authResults := acl.AllowOperation(request)
|
||||
ctx := namespace.ContextWithNamespace(context.Background(), ns)
|
||||
|
||||
authResults := acl.AllowOperation(ctx, request, false)
|
||||
if !authResults.RootPrivs {
|
||||
t.Fatalf("expected root")
|
||||
}
|
||||
@@ -74,22 +179,32 @@ func TestACL_Root(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestACL_Single(t *testing.T) {
|
||||
policy, err := ParseACLPolicy(aclPolicy)
|
||||
t.Run("root-ns", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
testACLSingle(t, namespace.RootNamespace)
|
||||
})
|
||||
}
|
||||
|
||||
func testACLSingle(t *testing.T, ns *namespace.Namespace) {
|
||||
policy, err := ParseACLPolicy(ns, aclPolicy)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
acl, err := NewACL([]*Policy{policy})
|
||||
ctx := namespace.ContextWithNamespace(context.Background(), ns)
|
||||
acl, err := NewACL(ctx, []*Policy{policy})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// Type of operation is not important here as we only care about checking
|
||||
// sudo/root
|
||||
ctx = namespace.ContextWithNamespace(context.Background(), ns)
|
||||
request := new(logical.Request)
|
||||
request.Operation = logical.ReadOperation
|
||||
request.Path = "sys/mount/foo"
|
||||
authResults := acl.AllowOperation(request)
|
||||
|
||||
authResults := acl.AllowOperation(ctx, request, false)
|
||||
if authResults.RootPrivs {
|
||||
t.Fatalf("unexpected root")
|
||||
}
|
||||
@@ -125,10 +240,12 @@ func TestACL_Single(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tc := range tcases {
|
||||
ctx := namespace.ContextWithNamespace(context.Background(), ns)
|
||||
request := new(logical.Request)
|
||||
request.Operation = tc.op
|
||||
request.Path = tc.path
|
||||
authResults := acl.AllowOperation(request)
|
||||
|
||||
authResults := acl.AllowOperation(ctx, request, false)
|
||||
if authResults.Allowed != tc.allowed {
|
||||
t.Fatalf("bad: case %#v: %v, %v", tc, authResults.Allowed, authResults.RootPrivs)
|
||||
}
|
||||
@@ -139,30 +256,34 @@ func TestACL_Single(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestACL_Layered(t *testing.T) {
|
||||
policy1, err := ParseACLPolicy(aclPolicy)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
t.Run("root-ns", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
policy1, err := ParseACLPolicy(namespace.RootNamespace, aclPolicy)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
policy2, err := ParseACLPolicy(aclPolicy2)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
acl, err := NewACL([]*Policy{policy1, policy2})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
testLayeredACL(t, acl)
|
||||
policy2, err := ParseACLPolicy(namespace.RootNamespace, aclPolicy2)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
acl, err := NewACL(namespace.RootContext(nil), []*Policy{policy1, policy2})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
testLayeredACL(t, acl, namespace.RootNamespace)
|
||||
})
|
||||
}
|
||||
|
||||
func testLayeredACL(t *testing.T, acl *ACL) {
|
||||
func testLayeredACL(t *testing.T, acl *ACL, ns *namespace.Namespace) {
|
||||
// Type of operation is not important here as we only care about checking
|
||||
// sudo/root
|
||||
ctx := namespace.ContextWithNamespace(context.Background(), ns)
|
||||
request := new(logical.Request)
|
||||
request.Operation = logical.ReadOperation
|
||||
request.Path = "sys/mount/foo"
|
||||
authResults := acl.AllowOperation(request)
|
||||
|
||||
authResults := acl.AllowOperation(ctx, request, false)
|
||||
if authResults.RootPrivs {
|
||||
t.Fatalf("unexpected root")
|
||||
}
|
||||
@@ -203,10 +324,12 @@ func testLayeredACL(t *testing.T, acl *ACL) {
|
||||
}
|
||||
|
||||
for _, tc := range tcases {
|
||||
ctx := namespace.ContextWithNamespace(context.Background(), ns)
|
||||
request := new(logical.Request)
|
||||
request.Operation = tc.op
|
||||
request.Path = tc.path
|
||||
authResults := acl.AllowOperation(request)
|
||||
|
||||
authResults := acl.AllowOperation(ctx, request, false)
|
||||
if authResults.Allowed != tc.allowed {
|
||||
t.Fatalf("bad: case %#v: %v, %v", tc, authResults.Allowed, authResults.RootPrivs)
|
||||
}
|
||||
@@ -217,11 +340,19 @@ func testLayeredACL(t *testing.T, acl *ACL) {
|
||||
}
|
||||
|
||||
func TestACL_PolicyMerge(t *testing.T) {
|
||||
policy, err := ParseACLPolicy(mergingPolicies)
|
||||
t.Run("root-ns", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
testACLPolicyMerge(t, namespace.RootNamespace)
|
||||
})
|
||||
}
|
||||
|
||||
func testACLPolicyMerge(t *testing.T, ns *namespace.Namespace) {
|
||||
policy, err := ParseACLPolicy(ns, mergingPolicies)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
acl, err := NewACL([]*Policy{policy})
|
||||
ctx := namespace.ContextWithNamespace(context.Background(), ns)
|
||||
acl, err := NewACL(ctx, []*Policy{policy})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -252,9 +383,10 @@ func TestACL_PolicyMerge(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tc := range tcases {
|
||||
raw, ok := acl.exactRules.Get(tc.path)
|
||||
policyPath := ns.Path + tc.path
|
||||
raw, ok := acl.exactRules.Get(policyPath)
|
||||
if !ok {
|
||||
t.Fatalf("Could not find acl entry for path %s", tc.path)
|
||||
t.Fatalf("Could not find acl entry for path %s", policyPath)
|
||||
}
|
||||
|
||||
p := raw.(*ACLPermissions)
|
||||
@@ -277,11 +409,19 @@ func TestACL_PolicyMerge(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestACL_AllowOperation(t *testing.T) {
|
||||
policy, err := ParseACLPolicy(permissionsPolicy)
|
||||
t.Run("root-ns", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
testACLAllowOperation(t, namespace.RootNamespace)
|
||||
})
|
||||
}
|
||||
|
||||
func testACLAllowOperation(t *testing.T, ns *namespace.Namespace) {
|
||||
policy, err := ParseACLPolicy(ns, permissionsPolicy)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
acl, err := NewACL([]*Policy{policy})
|
||||
ctx := namespace.ContextWithNamespace(context.Background(), ns)
|
||||
acl, err := NewACL(ctx, []*Policy{policy})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -328,7 +468,11 @@ func TestACL_AllowOperation(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tc := range tcases {
|
||||
request := logical.Request{Path: tc.path, Data: make(map[string]interface{})}
|
||||
request := &logical.Request{
|
||||
Path: tc.path,
|
||||
Data: make(map[string]interface{}),
|
||||
}
|
||||
|
||||
for _, parameter := range tc.parameters {
|
||||
request.Data[parameter] = ""
|
||||
}
|
||||
@@ -339,7 +483,8 @@ func TestACL_AllowOperation(t *testing.T) {
|
||||
}
|
||||
for _, op := range toperations {
|
||||
request.Operation = op
|
||||
authResults := acl.AllowOperation(&request)
|
||||
ctx := namespace.ContextWithNamespace(context.Background(), ns)
|
||||
authResults := acl.AllowOperation(ctx, request, false)
|
||||
if authResults.Allowed != tc.allowed {
|
||||
t.Fatalf("bad: case %#v: %v", tc, authResults.Allowed)
|
||||
}
|
||||
@@ -348,12 +493,20 @@ func TestACL_AllowOperation(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestACL_ValuePermissions(t *testing.T) {
|
||||
policy, err := ParseACLPolicy(valuePermissionsPolicy)
|
||||
t.Run("root-ns", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
testACLValuePermissions(t, namespace.RootNamespace)
|
||||
})
|
||||
}
|
||||
|
||||
func testACLValuePermissions(t *testing.T, ns *namespace.Namespace) {
|
||||
policy, err := ParseACLPolicy(ns, valuePermissionsPolicy)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
acl, err := NewACL([]*Policy{policy})
|
||||
ctx := namespace.ContextWithNamespace(context.Background(), ns)
|
||||
acl, err := NewACL(ctx, []*Policy{policy})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -408,13 +561,18 @@ func TestACL_ValuePermissions(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tc := range tcases {
|
||||
request := logical.Request{Path: tc.path, Data: make(map[string]interface{})}
|
||||
request := &logical.Request{
|
||||
Path: tc.path,
|
||||
Data: make(map[string]interface{}),
|
||||
}
|
||||
ctx := namespace.ContextWithNamespace(context.Background(), ns)
|
||||
|
||||
for i, parameter := range tc.parameters {
|
||||
request.Data[parameter] = tc.values[i]
|
||||
}
|
||||
for _, op := range toperations {
|
||||
request.Operation = op
|
||||
authResults := acl.AllowOperation(&request)
|
||||
authResults := acl.AllowOperation(ctx, request, false)
|
||||
if authResults.Allowed != tc.allowed {
|
||||
t.Fatalf("bad: case %#v: %v", tc, authResults.Allowed)
|
||||
}
|
||||
@@ -424,7 +582,7 @@ func TestACL_ValuePermissions(t *testing.T) {
|
||||
|
||||
// NOTE: this test doesn't catch any races ATM
|
||||
func TestACL_CreationRace(t *testing.T) {
|
||||
policy, err := ParseACLPolicy(valuePermissionsPolicy)
|
||||
policy, err := ParseACLPolicy(namespace.RootNamespace, valuePermissionsPolicy)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -440,7 +598,7 @@ func TestACL_CreationRace(t *testing.T) {
|
||||
if time.Now().After(stopTime) {
|
||||
return
|
||||
}
|
||||
_, err := NewACL([]*Policy{policy})
|
||||
_, err := NewACL(namespace.TestContext(), []*Policy{policy})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
14
vault/acl_util.go
Normal file
14
vault/acl_util.go
Normal file
@@ -0,0 +1,14 @@
|
||||
// +build !enterprise
|
||||
|
||||
package vault
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/hashicorp/vault/helper/identity"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
)
|
||||
|
||||
func (c *Core) performEntPolicyChecks(ctx context.Context, acl *ACL, te *logical.TokenEntry, req *logical.Request, inEntity *identity.Entity, opts *PolicyCheckOpts, ret *AuthResults) {
|
||||
ret.Allowed = true
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/hashicorp/go-uuid"
|
||||
"github.com/hashicorp/vault/audit"
|
||||
"github.com/hashicorp/vault/helper/jsonutil"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/helper/salt"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
)
|
||||
@@ -39,7 +40,7 @@ var (
|
||||
)
|
||||
|
||||
// enableAudit is used to enable a new audit backend
|
||||
func (c *Core) enableAudit(ctx context.Context, entry *MountEntry) error {
|
||||
func (c *Core) enableAudit(ctx context.Context, entry *MountEntry, updateStorage bool) error {
|
||||
// Ensure we end the path in a slash
|
||||
if !strings.HasSuffix(entry.Path, "/") {
|
||||
entry.Path += "/"
|
||||
@@ -81,14 +82,16 @@ func (c *Core) enableAudit(ctx context.Context, entry *MountEntry) error {
|
||||
}
|
||||
entry.Accessor = accessor
|
||||
}
|
||||
viewPath := auditBarrierPrefix + entry.UUID + "/"
|
||||
viewPath := entry.ViewPath()
|
||||
view := NewBarrierView(c.barrier, viewPath)
|
||||
addAuditPathChecker(c, entry, view, viewPath)
|
||||
origViewReadOnlyErr := view.getReadOnlyErr()
|
||||
|
||||
// Mark the view as read-only until the mounting is complete and
|
||||
// ensure that it is reset after. This ensures that there will be no
|
||||
// writes during the construction of the backend.
|
||||
view.setReadOnlyErr(logical.ErrSetupReadOnly)
|
||||
defer view.setReadOnlyErr(nil)
|
||||
defer view.setReadOnlyErr(origViewReadOnlyErr)
|
||||
|
||||
// Lookup the new backend
|
||||
backend, err := c.newAuditBackend(ctx, entry, view, entry.Options)
|
||||
@@ -101,22 +104,33 @@ func (c *Core) enableAudit(ctx context.Context, entry *MountEntry) error {
|
||||
|
||||
newTable := c.audit.shallowClone()
|
||||
newTable.Entries = append(newTable.Entries, entry)
|
||||
if err := c.persistAudit(ctx, newTable, entry.Local); err != nil {
|
||||
return errors.New("failed to update audit table")
|
||||
|
||||
ns, err := namespace.FromContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
entry.NamespaceID = ns.ID
|
||||
entry.namespace = ns
|
||||
|
||||
if updateStorage {
|
||||
if err := c.persistAudit(ctx, newTable, entry.Local); err != nil {
|
||||
return errors.New("failed to update audit table")
|
||||
}
|
||||
}
|
||||
|
||||
c.audit = newTable
|
||||
|
||||
// Register the backend
|
||||
c.auditBroker.Register(entry.Path, backend, view)
|
||||
c.auditBroker.Register(entry.Path, backend, view, entry.Local)
|
||||
if c.logger.IsInfo() {
|
||||
c.logger.Info("enabled audit backend", "path", entry.Path, "type", entry.Type)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// disableAudit is used to disable an existing audit backend
|
||||
func (c *Core) disableAudit(ctx context.Context, path string) (bool, error) {
|
||||
func (c *Core) disableAudit(ctx context.Context, path string, updateStorage bool) (bool, error) {
|
||||
// Ensure we end the path in a slash
|
||||
if !strings.HasSuffix(path, "/") {
|
||||
path += "/"
|
||||
@@ -127,7 +141,10 @@ func (c *Core) disableAudit(ctx context.Context, path string) (bool, error) {
|
||||
defer c.auditLock.Unlock()
|
||||
|
||||
newTable := c.audit.shallowClone()
|
||||
entry := newTable.remove(path)
|
||||
entry, err := newTable.remove(ctx, path)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Ensure there was a match
|
||||
if entry == nil {
|
||||
@@ -142,9 +159,11 @@ func (c *Core) disableAudit(ctx context.Context, path string) (bool, error) {
|
||||
newTable.Entries = nil
|
||||
}
|
||||
|
||||
// Update the audit table
|
||||
if err := c.persistAudit(ctx, newTable, entry.Local); err != nil {
|
||||
return true, errors.New("failed to update audit table")
|
||||
if updateStorage {
|
||||
// Update the audit table
|
||||
if err := c.persistAudit(ctx, newTable, entry.Local); err != nil {
|
||||
return true, errors.New("failed to update audit table")
|
||||
}
|
||||
}
|
||||
|
||||
c.audit = newTable
|
||||
@@ -155,6 +174,8 @@ func (c *Core) disableAudit(ctx context.Context, path string) (bool, error) {
|
||||
c.logger.Info("disabled audit backend", "path", path)
|
||||
}
|
||||
|
||||
removeAuditPathChecker(c, entry)
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@@ -222,6 +243,20 @@ func (c *Core) loadAudits(ctx context.Context) error {
|
||||
entry.Accessor = accessor
|
||||
needPersist = true
|
||||
}
|
||||
|
||||
if entry.NamespaceID == "" {
|
||||
entry.NamespaceID = namespace.RootNamespaceID
|
||||
needPersist = true
|
||||
}
|
||||
// Get the namespace from the namespace ID and load it in memory
|
||||
ns, err := NamespaceByID(ctx, entry.NamespaceID, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ns == nil {
|
||||
return namespace.ErrNoNamespace
|
||||
}
|
||||
entry.namespace = ns
|
||||
}
|
||||
|
||||
if !needPersist {
|
||||
@@ -319,15 +354,17 @@ func (c *Core) setupAudits(ctx context.Context) error {
|
||||
|
||||
for _, entry := range c.audit.Entries {
|
||||
// Create a barrier view using the UUID
|
||||
viewPath := auditBarrierPrefix + entry.UUID + "/"
|
||||
viewPath := entry.ViewPath()
|
||||
view := NewBarrierView(c.barrier, viewPath)
|
||||
addAuditPathChecker(c, entry, view, viewPath)
|
||||
origViewReadOnlyErr := view.getReadOnlyErr()
|
||||
|
||||
// Mark the view as read-only until the mounting is complete and
|
||||
// ensure that it is reset after. This ensures that there will be no
|
||||
// writes during the construction of the backend.
|
||||
view.setReadOnlyErr(logical.ErrSetupReadOnly)
|
||||
c.postUnsealFuncs = append(c.postUnsealFuncs, func() {
|
||||
view.setReadOnlyErr(nil)
|
||||
view.setReadOnlyErr(origViewReadOnlyErr)
|
||||
})
|
||||
|
||||
// Initialize the backend
|
||||
@@ -342,9 +379,9 @@ func (c *Core) setupAudits(ctx context.Context) error {
|
||||
}
|
||||
|
||||
// Mount the backend
|
||||
broker.Register(entry.Path, backend, view)
|
||||
broker.Register(entry.Path, backend, view, entry.Local)
|
||||
|
||||
successCount += 1
|
||||
successCount++
|
||||
}
|
||||
|
||||
if len(c.audit.Entries) > 0 && successCount == 0 {
|
||||
@@ -364,6 +401,7 @@ func (c *Core) teardownAudits() error {
|
||||
if c.audit != nil {
|
||||
for _, entry := range c.audit.Entries {
|
||||
c.removeAuditReloadFunc(entry)
|
||||
removeAuditPathChecker(c, entry)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
type backendEntry struct {
|
||||
backend audit.Backend
|
||||
view *BarrierView
|
||||
local bool
|
||||
}
|
||||
|
||||
// AuditBroker is used to provide a single ingest interface to auditable
|
||||
@@ -35,12 +36,13 @@ func NewAuditBroker(log log.Logger) *AuditBroker {
|
||||
}
|
||||
|
||||
// Register is used to add new audit backend to the broker
|
||||
func (a *AuditBroker) Register(name string, b audit.Backend, v *BarrierView) {
|
||||
func (a *AuditBroker) Register(name string, b audit.Backend, v *BarrierView, local bool) {
|
||||
a.Lock()
|
||||
defer a.Unlock()
|
||||
a.backends[name] = backendEntry{
|
||||
backend: b,
|
||||
view: v,
|
||||
local: local,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +61,17 @@ func (a *AuditBroker) IsRegistered(name string) bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
// IsLocal is used to check if a given audit backend is registered
|
||||
func (a *AuditBroker) IsLocal(name string) (bool, error) {
|
||||
a.RLock()
|
||||
defer a.RUnlock()
|
||||
be, ok := a.backends[name]
|
||||
if ok {
|
||||
return be.local, nil
|
||||
}
|
||||
return false, fmt.Errorf("unknown audit backend %q", name)
|
||||
}
|
||||
|
||||
// GetHash returns a hash using the salt of the given backend
|
||||
func (a *AuditBroker) GetHash(ctx context.Context, name string, input string) (string, error) {
|
||||
a.RLock()
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/hashicorp/vault/audit"
|
||||
"github.com/hashicorp/vault/helper/jsonutil"
|
||||
"github.com/hashicorp/vault/helper/logging"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/helper/salt"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/mitchellh/copystructure"
|
||||
@@ -122,7 +123,7 @@ func TestAudit_ReadOnlyViewDuringMount(t *testing.T) {
|
||||
Path: "foo",
|
||||
Type: "noop",
|
||||
}
|
||||
err := c.enableAudit(context.Background(), me)
|
||||
err := c.enableAudit(namespace.TestContext(), me, true)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -141,7 +142,7 @@ func TestCore_EnableAudit(t *testing.T) {
|
||||
Path: "foo",
|
||||
Type: "noop",
|
||||
}
|
||||
err := c.enableAudit(context.Background(), me)
|
||||
err := c.enableAudit(namespace.TestContext(), me, true)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -255,18 +256,22 @@ func TestCore_EnableAudit_Local(t *testing.T) {
|
||||
Type: auditTableType,
|
||||
Entries: []*MountEntry{
|
||||
&MountEntry{
|
||||
Table: auditTableType,
|
||||
Path: "noop/",
|
||||
Type: "noop",
|
||||
UUID: "abcd",
|
||||
Accessor: "noop-abcd",
|
||||
Table: auditTableType,
|
||||
Path: "noop/",
|
||||
Type: "noop",
|
||||
UUID: "abcd",
|
||||
Accessor: "noop-abcd",
|
||||
NamespaceID: namespace.RootNamespaceID,
|
||||
namespace: namespace.TestNamespace(),
|
||||
},
|
||||
&MountEntry{
|
||||
Table: auditTableType,
|
||||
Path: "noop2/",
|
||||
Type: "noop",
|
||||
UUID: "bcde",
|
||||
Accessor: "noop-bcde",
|
||||
Table: auditTableType,
|
||||
Path: "noop2/",
|
||||
Type: "noop",
|
||||
UUID: "bcde",
|
||||
Accessor: "noop-bcde",
|
||||
NamespaceID: namespace.RootNamespaceID,
|
||||
namespace: namespace.TestNamespace(),
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -334,7 +339,7 @@ func TestCore_DisableAudit(t *testing.T) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
existed, err := c.disableAudit(context.Background(), "foo")
|
||||
existed, err := c.disableAudit(namespace.TestContext(), "foo", true)
|
||||
if existed && err != nil {
|
||||
t.Fatalf("existed: %v; err: %v", existed, err)
|
||||
}
|
||||
@@ -344,12 +349,12 @@ func TestCore_DisableAudit(t *testing.T) {
|
||||
Path: "foo",
|
||||
Type: "noop",
|
||||
}
|
||||
err = c.enableAudit(context.Background(), me)
|
||||
err = c.enableAudit(namespace.TestContext(), me, true)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
existed, err = c.disableAudit(context.Background(), "foo")
|
||||
existed, err = c.disableAudit(namespace.TestContext(), "foo", true)
|
||||
if !existed || err != nil {
|
||||
t.Fatalf("existed: %v; err: %v", existed, err)
|
||||
}
|
||||
@@ -436,8 +441,8 @@ func TestAuditBroker_LogRequest(t *testing.T) {
|
||||
b := NewAuditBroker(l)
|
||||
a1 := &NoopAudit{}
|
||||
a2 := &NoopAudit{}
|
||||
b.Register("foo", a1, nil)
|
||||
b.Register("bar", a2, nil)
|
||||
b.Register("foo", a1, nil, false)
|
||||
b.Register("bar", a2, nil, false)
|
||||
|
||||
auth := &logical.Auth{
|
||||
ClientToken: "foo",
|
||||
@@ -522,8 +527,8 @@ func TestAuditBroker_LogResponse(t *testing.T) {
|
||||
b := NewAuditBroker(l)
|
||||
a1 := &NoopAudit{}
|
||||
a2 := &NoopAudit{}
|
||||
b.Register("foo", a1, nil)
|
||||
b.Register("bar", a2, nil)
|
||||
b.Register("foo", a1, nil, false)
|
||||
b.Register("bar", a2, nil, false)
|
||||
|
||||
auth := &logical.Auth{
|
||||
NumUses: 10,
|
||||
@@ -628,8 +633,8 @@ func TestAuditBroker_AuditHeaders(t *testing.T) {
|
||||
view := NewBarrierView(barrier, "headers/")
|
||||
a1 := &NoopAudit{}
|
||||
a2 := &NoopAudit{}
|
||||
b.Register("foo", a1, nil)
|
||||
b.Register("bar", a2, nil)
|
||||
b.Register("foo", a1, nil, false)
|
||||
b.Register("bar", a2, nil, false)
|
||||
|
||||
auth := &logical.Auth{
|
||||
ClientToken: "foo",
|
||||
|
||||
271
vault/auth.go
271
vault/auth.go
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/hashicorp/go-uuid"
|
||||
"github.com/hashicorp/vault/helper/consts"
|
||||
"github.com/hashicorp/vault/helper/jsonutil"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/helper/strutil"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
)
|
||||
@@ -46,6 +47,11 @@ var (
|
||||
|
||||
// enableCredential is used to enable a new credential backend
|
||||
func (c *Core) enableCredential(ctx context.Context, entry *MountEntry) error {
|
||||
return c.enableCredentialInternal(ctx, entry, MountTableUpdateStorage)
|
||||
}
|
||||
|
||||
// enableCredential is used to enable a new credential backend
|
||||
func (c *Core) enableCredentialInternal(ctx context.Context, entry *MountEntry, updateStorage bool) error {
|
||||
// Ensure we end the path in a slash
|
||||
if !strings.HasSuffix(entry.Path, "/") {
|
||||
entry.Path += "/"
|
||||
@@ -59,15 +65,27 @@ func (c *Core) enableCredential(ctx context.Context, entry *MountEntry) error {
|
||||
c.authLock.Lock()
|
||||
defer c.authLock.Unlock()
|
||||
|
||||
ns, err := namespace.FromContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
entry.NamespaceID = ns.ID
|
||||
entry.namespace = ns
|
||||
|
||||
// Populate cache
|
||||
NamespaceByID(ctx, ns.ID, c)
|
||||
|
||||
// Look for matching name
|
||||
for _, ent := range c.auth.Entries {
|
||||
switch {
|
||||
// Existing is oauth/github/ new is oauth/ or
|
||||
// existing is oauth/ and new is oauth/github/
|
||||
case strings.HasPrefix(ent.Path, entry.Path):
|
||||
fallthrough
|
||||
case strings.HasPrefix(entry.Path, ent.Path):
|
||||
return logical.CodedError(409, "path is already in use")
|
||||
if ns.ID == ent.NamespaceID {
|
||||
switch {
|
||||
// Existing is oauth/github/ new is oauth/ or
|
||||
// existing is oauth/ and new is oauth/github/
|
||||
case strings.HasPrefix(ent.Path, entry.Path):
|
||||
fallthrough
|
||||
case strings.HasPrefix(entry.Path, ent.Path):
|
||||
return logical.CodedError(409, "path is already in use")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +94,7 @@ func (c *Core) enableCredential(ctx context.Context, entry *MountEntry) error {
|
||||
return fmt.Errorf("token credential backend cannot be instantiated")
|
||||
}
|
||||
|
||||
if conflict := c.router.MountConflict(credentialRoutePrefix + entry.Path); conflict != "" {
|
||||
if conflict := c.router.MountConflict(ctx, credentialRoutePrefix+entry.Path); conflict != "" {
|
||||
return logical.CodedError(409, fmt.Sprintf("existing mount at %s", conflict))
|
||||
}
|
||||
|
||||
@@ -105,18 +123,28 @@ func (c *Core) enableCredential(ctx context.Context, entry *MountEntry) error {
|
||||
// Sync values to the cache
|
||||
entry.SyncCache()
|
||||
|
||||
viewPath := credentialBarrierPrefix + entry.UUID + "/"
|
||||
viewPath := entry.ViewPath()
|
||||
view := NewBarrierView(c.barrier, viewPath)
|
||||
|
||||
nilMount, err := preprocessMount(c, entry, view)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
origViewReadOnlyErr := view.getReadOnlyErr()
|
||||
|
||||
// Mark the view as read-only until the mounting is complete and
|
||||
// ensure that it is reset after. This ensures that there will be no
|
||||
// writes during the construction of the backend.
|
||||
view.setReadOnlyErr(logical.ErrSetupReadOnly)
|
||||
defer view.setReadOnlyErr(nil)
|
||||
defer view.setReadOnlyErr(origViewReadOnlyErr)
|
||||
|
||||
var err error
|
||||
var backend logical.Backend
|
||||
// Create the new backend
|
||||
sysView := c.mountEntrySysView(entry)
|
||||
|
||||
conf := make(map[string]string)
|
||||
if entry.Config.PluginName != "" {
|
||||
conf["plugin_name"] = entry.Config.PluginName
|
||||
}
|
||||
// Create the new backend
|
||||
backend, err = c.newCredentialBackend(ctx, entry, sysView, view)
|
||||
if err != nil {
|
||||
@@ -129,20 +157,34 @@ func (c *Core) enableCredential(ctx context.Context, entry *MountEntry) error {
|
||||
// Check for the correct backend type
|
||||
backendType := backend.Type()
|
||||
if entry.Type == "plugin" && backendType != logical.TypeCredential {
|
||||
return fmt.Errorf("cannot mount %q of type %q as an auth method", entry.Config.PluginName, backendType)
|
||||
return fmt.Errorf("cannot mount %q of type %q as an auth backend", entry.Config.PluginName, backendType)
|
||||
}
|
||||
|
||||
addPathCheckers(c, entry, backend, viewPath)
|
||||
|
||||
// If the mount is filtered or we are on a DR secondary we don't want to
|
||||
// keep the actual backend running, so we clean it up and set it to nil
|
||||
// so the router does not have a pointer to the object.
|
||||
if nilMount {
|
||||
backend.Cleanup(ctx)
|
||||
backend = nil
|
||||
}
|
||||
|
||||
// Update the auth table
|
||||
newTable := c.auth.shallowClone()
|
||||
newTable.Entries = append(newTable.Entries, entry)
|
||||
if err := c.persistAuth(ctx, newTable, &entry.Local); err != nil {
|
||||
return errors.New("failed to update auth table")
|
||||
if updateStorage {
|
||||
if err := c.persistAuth(ctx, newTable, &entry.Local); err != nil {
|
||||
if err == logical.ErrReadOnly && c.perfStandby {
|
||||
return err
|
||||
}
|
||||
return errors.New("failed to update auth table")
|
||||
}
|
||||
}
|
||||
|
||||
c.auth = newTable
|
||||
|
||||
path := credentialRoutePrefix + entry.Path
|
||||
if err := c.router.Mount(backend, path, entry, view); err != nil {
|
||||
if err := c.router.Mount(backend, credentialRoutePrefix+entry.Path, entry, view); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -165,79 +207,121 @@ func (c *Core) disableCredential(ctx context.Context, path string) error {
|
||||
return fmt.Errorf("token credential backend cannot be disabled")
|
||||
}
|
||||
|
||||
return c.disableCredentialInternal(ctx, path, MountTableUpdateStorage)
|
||||
}
|
||||
|
||||
func (c *Core) disableCredentialInternal(ctx context.Context, path string, updateStorage bool) error {
|
||||
path = credentialRoutePrefix + path
|
||||
|
||||
ns, err := namespace.FromContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Verify exact match of the route
|
||||
match := c.router.MatchingMount(ctx, path)
|
||||
if match == "" || ns.Path+path != match {
|
||||
return fmt.Errorf("no matching mount")
|
||||
}
|
||||
|
||||
// Store the view for this backend
|
||||
fullPath := credentialRoutePrefix + path
|
||||
view := c.router.MatchingStorageByAPIPath(fullPath)
|
||||
view := c.router.MatchingStorageByAPIPath(ctx, path)
|
||||
if view == nil {
|
||||
return fmt.Errorf("no matching backend %q", fullPath)
|
||||
return fmt.Errorf("no matching backend %q", path)
|
||||
}
|
||||
|
||||
// Get the backend/mount entry for this path, used to remove ignored
|
||||
// replication prefixes
|
||||
backend := c.router.MatchingBackend(fullPath)
|
||||
entry := c.router.MatchingMountEntry(fullPath)
|
||||
backend := c.router.MatchingBackend(ctx, path)
|
||||
entry := c.router.MatchingMountEntry(ctx, path)
|
||||
|
||||
// Mark the entry as tainted
|
||||
if err := c.taintCredEntry(ctx, path); err != nil {
|
||||
if err := c.taintCredEntry(ctx, path, updateStorage); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Taint the router path to prevent routing
|
||||
if err := c.router.Taint(fullPath); err != nil {
|
||||
if err := c.router.Taint(ctx, path); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if backend != nil {
|
||||
if c.expiration != nil && backend != nil {
|
||||
// Revoke credentials from this path
|
||||
if err := c.expiration.RevokePrefix(c.activeContext, fullPath, true); err != nil {
|
||||
ns, err := namespace.FromContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
revokeCtx := namespace.ContextWithNamespace(c.activeContext, ns)
|
||||
if err := c.expiration.RevokePrefix(revokeCtx, path, true); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if backend != nil {
|
||||
// Call cleanup function if it exists
|
||||
backend.Cleanup(ctx)
|
||||
}
|
||||
|
||||
// Unmount the backend
|
||||
if err := c.router.Unmount(ctx, fullPath); err != nil {
|
||||
if err := c.router.Unmount(ctx, path); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
viewPath := entry.ViewPath()
|
||||
switch {
|
||||
case entry.Local, !c.ReplicationState().HasState(consts.ReplicationPerformanceSecondary):
|
||||
case !updateStorage:
|
||||
case c.IsDRSecondary(), entry.Local, !c.ReplicationState().HasState(consts.ReplicationPerformanceSecondary):
|
||||
// Have writable storage, remove the whole thing
|
||||
if err := logical.ClearView(ctx, view); err != nil {
|
||||
c.logger.Error("failed to clear view for path being unmounted", "error", err, "path", path)
|
||||
return err
|
||||
}
|
||||
|
||||
case !entry.Local && c.ReplicationState().HasState(consts.ReplicationPerformanceSecondary):
|
||||
if err := clearIgnoredPaths(ctx, c, backend, viewPath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the mount table entry
|
||||
if err := c.removeCredEntry(ctx, path); err != nil {
|
||||
if err := c.removeCredEntry(ctx, strings.TrimPrefix(path, credentialRoutePrefix), updateStorage); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
removePathCheckers(c, entry, viewPath)
|
||||
|
||||
if c.logger.IsInfo() {
|
||||
c.logger.Info("disabled credential backend", "path", path)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// removeCredEntry is used to remove an entry in the auth table
|
||||
func (c *Core) removeCredEntry(ctx context.Context, path string) error {
|
||||
func (c *Core) removeCredEntry(ctx context.Context, path string, updateStorage bool) error {
|
||||
c.authLock.Lock()
|
||||
defer c.authLock.Unlock()
|
||||
|
||||
// Taint the entry from the auth table
|
||||
newTable := c.auth.shallowClone()
|
||||
entry := newTable.remove(path)
|
||||
entry, err := newTable.remove(ctx, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if entry == nil {
|
||||
c.logger.Error("nil entry found removing entry in auth table", "path", path)
|
||||
return logical.CodedError(500, "failed to remove entry in auth table")
|
||||
}
|
||||
|
||||
// Update the auth table
|
||||
if err := c.persistAuth(ctx, newTable, &entry.Local); err != nil {
|
||||
return errors.New("failed to update auth table")
|
||||
if updateStorage {
|
||||
// Update the auth table
|
||||
if err := c.persistAuth(ctx, newTable, &entry.Local); err != nil {
|
||||
if err == logical.ErrReadOnly && c.perfStandby {
|
||||
return err
|
||||
}
|
||||
|
||||
return errors.New("failed to update auth table")
|
||||
}
|
||||
}
|
||||
|
||||
c.auth = newTable
|
||||
@@ -250,7 +334,7 @@ func (c *Core) removeCredEntry(ctx context.Context, path string) error {
|
||||
// paths
|
||||
func (c *Core) remountCredEntryForce(ctx context.Context, path string) error {
|
||||
fullPath := credentialRoutePrefix + path
|
||||
me := c.router.MatchingMountEntry(fullPath)
|
||||
me := c.router.MatchingMountEntry(ctx, fullPath)
|
||||
if me == nil {
|
||||
return fmt.Errorf("cannot find mount for path %q", path)
|
||||
}
|
||||
@@ -267,23 +351,31 @@ func (c *Core) remountCredEntryForce(ctx context.Context, path string) error {
|
||||
}
|
||||
|
||||
// taintCredEntry is used to mark an entry in the auth table as tainted
|
||||
func (c *Core) taintCredEntry(ctx context.Context, path string) error {
|
||||
func (c *Core) taintCredEntry(ctx context.Context, path string, updateStorage bool) error {
|
||||
c.authLock.Lock()
|
||||
defer c.authLock.Unlock()
|
||||
|
||||
// Taint the entry from the auth table
|
||||
// We do this on the original since setting the taint operates
|
||||
// on the entries which a shallow clone shares anyways
|
||||
entry := c.auth.setTaint(path, true)
|
||||
entry, err := c.auth.setTaint(ctx, strings.TrimPrefix(path, credentialRoutePrefix), true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ensure there was a match
|
||||
if entry == nil {
|
||||
return fmt.Errorf("no matching backend")
|
||||
}
|
||||
|
||||
// Update the auth table
|
||||
if err := c.persistAuth(ctx, c.auth, &entry.Local); err != nil {
|
||||
return errors.New("failed to update auth table")
|
||||
if updateStorage {
|
||||
// Update the auth table
|
||||
if err := c.persistAuth(ctx, c.auth, &entry.Local); err != nil {
|
||||
if err == logical.ErrReadOnly && c.perfStandby {
|
||||
return err
|
||||
}
|
||||
return errors.New("failed to update auth table")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -291,9 +383,6 @@ func (c *Core) taintCredEntry(ctx context.Context, path string) error {
|
||||
|
||||
// loadCredentials is invoked as part of postUnseal to load the auth table
|
||||
func (c *Core) loadCredentials(ctx context.Context) error {
|
||||
authTable := &MountTable{}
|
||||
localAuthTable := &MountTable{}
|
||||
|
||||
// Load the existing mount table
|
||||
raw, err := c.barrier.Get(ctx, coreAuthConfigPath)
|
||||
if err != nil {
|
||||
@@ -310,9 +399,10 @@ func (c *Core) loadCredentials(ctx context.Context) error {
|
||||
defer c.authLock.Unlock()
|
||||
|
||||
if raw != nil {
|
||||
if err := jsonutil.DecodeJSON(raw.Value, authTable); err != nil {
|
||||
c.logger.Error("failed to decode auth table", "error", err)
|
||||
return errLoadAuthFailed
|
||||
authTable, err := c.decodeMountTable(ctx, raw.Value)
|
||||
if err != nil {
|
||||
c.logger.Error("failed to decompress and/or decode the auth table", "error", err)
|
||||
return err
|
||||
}
|
||||
c.auth = authTable
|
||||
}
|
||||
@@ -324,9 +414,10 @@ func (c *Core) loadCredentials(ctx context.Context) error {
|
||||
}
|
||||
|
||||
if rawLocal != nil {
|
||||
if err := jsonutil.DecodeJSON(rawLocal.Value, localAuthTable); err != nil {
|
||||
c.logger.Error("failed to decode local auth table", "error", err)
|
||||
return errLoadAuthFailed
|
||||
localAuthTable, err := c.decodeMountTable(ctx, rawLocal.Value)
|
||||
if err != nil {
|
||||
c.logger.Error("failed to decompress and/or decode the local mount table", "error", err)
|
||||
return err
|
||||
}
|
||||
if localAuthTable != nil && len(localAuthTable.Entries) > 0 {
|
||||
c.auth.Entries = append(c.auth.Entries, localAuthTable.Entries...)
|
||||
@@ -362,6 +453,19 @@ func (c *Core) loadCredentials(ctx context.Context) error {
|
||||
needPersist = true
|
||||
}
|
||||
|
||||
if entry.NamespaceID == "" {
|
||||
entry.NamespaceID = namespace.RootNamespaceID
|
||||
needPersist = true
|
||||
}
|
||||
ns, err := NamespaceByID(ctx, entry.NamespaceID, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ns == nil {
|
||||
return namespace.ErrNoNamespace
|
||||
}
|
||||
entry.namespace = ns
|
||||
|
||||
// Sync values to the cache
|
||||
entry.SyncCache()
|
||||
}
|
||||
@@ -374,6 +478,7 @@ func (c *Core) loadCredentials(ctx context.Context) error {
|
||||
c.logger.Error("failed to persist auth table", "error", err)
|
||||
return errLoadAuthFailed
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -455,34 +560,50 @@ func (c *Core) persistAuth(ctx context.Context, table *MountTable, local *bool)
|
||||
// setupCredentials is invoked after we've loaded the auth table to
|
||||
// initialize the credential backends and setup the router
|
||||
func (c *Core) setupCredentials(ctx context.Context) error {
|
||||
var err error
|
||||
var persistNeeded bool
|
||||
var backendType logical.BackendType
|
||||
|
||||
c.authLock.Lock()
|
||||
defer c.authLock.Unlock()
|
||||
|
||||
for _, entry := range c.auth.Entries {
|
||||
for _, entry := range c.auth.sortEntriesByPathDepth().Entries {
|
||||
var backend logical.Backend
|
||||
|
||||
// Create a barrier view using the UUID
|
||||
viewPath := credentialBarrierPrefix + entry.UUID + "/"
|
||||
viewPath := entry.ViewPath()
|
||||
|
||||
// Singleton mounts cannot be filtered on a per-secondary basis
|
||||
// from replication
|
||||
if strutil.StrListContains(singletonMounts, entry.Type) {
|
||||
addFilterablePath(c, viewPath)
|
||||
}
|
||||
|
||||
view := NewBarrierView(c.barrier, viewPath)
|
||||
|
||||
// Determining the replicated state of the mount
|
||||
nilMount, err := preprocessMount(c, entry, view)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
origViewReadOnlyErr := view.getReadOnlyErr()
|
||||
|
||||
// Mark the view as read-only until the mounting is complete and
|
||||
// ensure that it is reset after. This ensures that there will be no
|
||||
// writes during the construction of the backend.
|
||||
view.setReadOnlyErr(logical.ErrSetupReadOnly)
|
||||
if strutil.StrListContains(singletonMounts, entry.Type) {
|
||||
defer view.setReadOnlyErr(nil)
|
||||
defer view.setReadOnlyErr(origViewReadOnlyErr)
|
||||
} else {
|
||||
c.postUnsealFuncs = append(c.postUnsealFuncs, func() {
|
||||
view.setReadOnlyErr(nil)
|
||||
view.setReadOnlyErr(origViewReadOnlyErr)
|
||||
})
|
||||
}
|
||||
|
||||
// Initialize the backend
|
||||
sysView := c.mountEntrySysView(entry)
|
||||
conf := make(map[string]string)
|
||||
if entry.Config.PluginName != "" {
|
||||
conf["plugin_name"] = entry.Config.PluginName
|
||||
}
|
||||
|
||||
backend, err = c.newCredentialBackend(ctx, entry, sysView, view)
|
||||
if err != nil {
|
||||
@@ -500,10 +621,22 @@ func (c *Core) setupCredentials(ctx context.Context) error {
|
||||
return fmt.Errorf("nil backend returned from %q factory", entry.Type)
|
||||
}
|
||||
|
||||
// Check for the correct backend type
|
||||
backendType = backend.Type()
|
||||
if entry.Type == "plugin" && backendType != logical.TypeCredential {
|
||||
return fmt.Errorf("cannot mount %q of type %q as an auth backend", entry.Config.PluginName, backendType)
|
||||
{
|
||||
// Check for the correct backend type
|
||||
backendType := backend.Type()
|
||||
if entry.Type == "plugin" && backendType != logical.TypeCredential {
|
||||
return fmt.Errorf("cannot mount %q of type %q as an auth backend", entry.Config.PluginName, backendType)
|
||||
}
|
||||
|
||||
addPathCheckers(c, entry, backend, viewPath)
|
||||
}
|
||||
|
||||
// If the mount is filtered or we are on a DR secondary we don't want to
|
||||
// keep the actual backend running, so we clean it up and set it to nil
|
||||
// so the router does not have a pointer to the object.
|
||||
if nilMount {
|
||||
backend.Cleanup(ctx)
|
||||
backend = nil
|
||||
}
|
||||
|
||||
ROUTER_MOUNT:
|
||||
@@ -515,9 +648,13 @@ func (c *Core) setupCredentials(ctx context.Context) error {
|
||||
return errLoadAuthFailed
|
||||
}
|
||||
|
||||
if c.logger.IsInfo() {
|
||||
c.logger.Info("successfully enabled credential backend", "type", entry.Type, "path", entry.Path)
|
||||
}
|
||||
|
||||
// Ensure the path is tainted if set in the mount table
|
||||
if entry.Tainted {
|
||||
c.router.Taint(path)
|
||||
c.router.Taint(ctx, path)
|
||||
}
|
||||
|
||||
// Check if this is the token store
|
||||
@@ -526,11 +663,17 @@ func (c *Core) setupCredentials(ctx context.Context) error {
|
||||
|
||||
// this is loaded *after* the normal mounts, including cubbyhole
|
||||
c.router.tokenStoreSaltFunc = c.tokenStore.Salt
|
||||
c.tokenStore.cubbyholeBackend = c.router.MatchingBackend("cubbyhole/").(*CubbyholeBackend)
|
||||
if !c.IsDRSecondary() {
|
||||
c.tokenStore.cubbyholeBackend = c.router.MatchingBackend(ctx, cubbyholeMountPath).(*CubbyholeBackend)
|
||||
}
|
||||
}
|
||||
|
||||
// Populate cache
|
||||
NamespaceByID(ctx, entry.NamespaceID, c)
|
||||
}
|
||||
|
||||
if persistNeeded {
|
||||
// persist non-local auth
|
||||
return c.persistAuth(ctx, c.auth, nil)
|
||||
}
|
||||
|
||||
@@ -546,10 +689,13 @@ func (c *Core) teardownCredentials(ctx context.Context) error {
|
||||
if c.auth != nil {
|
||||
authTable := c.auth.shallowClone()
|
||||
for _, e := range authTable.Entries {
|
||||
backend := c.router.MatchingBackend(credentialRoutePrefix + e.Path)
|
||||
backend := c.router.MatchingBackend(namespace.ContextWithNamespace(ctx, e.namespace), credentialRoutePrefix+e.Path)
|
||||
if backend != nil {
|
||||
backend.Cleanup(ctx)
|
||||
}
|
||||
|
||||
viewPath := e.ViewPath()
|
||||
removePathCheckers(c, e, viewPath)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -564,6 +710,7 @@ func (c *Core) newCredentialBackend(ctx context.Context, entry *MountEntry, sysV
|
||||
if alias, ok := credentialAliases[t]; ok {
|
||||
t = alias
|
||||
}
|
||||
|
||||
f, ok := c.credentialBackends[t]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unknown backend type: %q", t)
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/vault/helper/jsonutil"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
)
|
||||
|
||||
@@ -28,7 +29,7 @@ func TestAuth_ReadOnlyViewDuringMount(t *testing.T) {
|
||||
Path: "foo",
|
||||
Type: "noop",
|
||||
}
|
||||
err := c.enableCredential(context.Background(), me)
|
||||
err := c.enableCredential(namespace.TestContext(), me)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -74,14 +75,14 @@ func TestCore_EnableCredential(t *testing.T) {
|
||||
Path: "foo",
|
||||
Type: "noop",
|
||||
}
|
||||
err := c.enableCredential(context.Background(), me)
|
||||
err := c.enableCredential(namespace.TestContext(), me)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
match := c.router.MatchingMount("auth/foo/bar")
|
||||
match := c.router.MatchingMount(namespace.TestContext(), "auth/foo/bar")
|
||||
if match != "auth/foo/" {
|
||||
t.Fatalf("missing mount")
|
||||
t.Fatalf("missing mount, match: %q", match)
|
||||
}
|
||||
|
||||
conf := &CoreConfig{
|
||||
@@ -130,6 +131,8 @@ func TestCore_EnableCredential_Local(t *testing.T) {
|
||||
UUID: "abcd",
|
||||
Accessor: "noop-abcd",
|
||||
BackendAwareUUID: "abcde",
|
||||
NamespaceID: namespace.RootNamespaceID,
|
||||
namespace: namespace.TestNamespace(),
|
||||
},
|
||||
&MountEntry{
|
||||
Table: credentialTableType,
|
||||
@@ -138,6 +141,8 @@ func TestCore_EnableCredential_Local(t *testing.T) {
|
||||
UUID: "bcde",
|
||||
Accessor: "noop-bcde",
|
||||
BackendAwareUUID: "bcdea",
|
||||
NamespaceID: namespace.RootNamespaceID,
|
||||
namespace: namespace.TestNamespace(),
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -208,13 +213,13 @@ func TestCore_EnableCredential_twice_409(t *testing.T) {
|
||||
Path: "foo",
|
||||
Type: "noop",
|
||||
}
|
||||
err := c.enableCredential(context.Background(), me)
|
||||
err := c.enableCredential(namespace.TestContext(), me)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// 2nd should be a 409 error
|
||||
err2 := c.enableCredential(context.Background(), me)
|
||||
err2 := c.enableCredential(namespace.TestContext(), me)
|
||||
switch err2.(type) {
|
||||
case logical.HTTPCodedError:
|
||||
if err2.(logical.HTTPCodedError).Code() != 409 {
|
||||
@@ -232,7 +237,7 @@ func TestCore_EnableCredential_Token(t *testing.T) {
|
||||
Path: "foo",
|
||||
Type: "token",
|
||||
}
|
||||
err := c.enableCredential(context.Background(), me)
|
||||
err := c.enableCredential(namespace.TestContext(), me)
|
||||
if err.Error() != "token credential backend cannot be instantiated" {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -244,9 +249,9 @@ func TestCore_DisableCredential(t *testing.T) {
|
||||
return &NoopBackend{}, nil
|
||||
}
|
||||
|
||||
err := c.disableCredential(context.Background(), "foo")
|
||||
if err != nil && !strings.HasPrefix(err.Error(), "no matching backend") {
|
||||
t.Fatalf("err: %v", err)
|
||||
err := c.disableCredential(namespace.TestContext(), "foo")
|
||||
if err != nil && !strings.HasPrefix(err.Error(), "no matching mount") {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
me := &MountEntry{
|
||||
@@ -254,17 +259,17 @@ func TestCore_DisableCredential(t *testing.T) {
|
||||
Path: "foo",
|
||||
Type: "noop",
|
||||
}
|
||||
err = c.enableCredential(context.Background(), me)
|
||||
err = c.enableCredential(namespace.TestContext(), me)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
err = c.disableCredential(context.Background(), "foo")
|
||||
err = c.disableCredential(namespace.TestContext(), "foo")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
match := c.router.MatchingMount("auth/foo/bar")
|
||||
match := c.router.MatchingMount(namespace.TestContext(), "auth/foo/bar")
|
||||
if match != "" {
|
||||
t.Fatalf("backend present")
|
||||
}
|
||||
@@ -295,7 +300,7 @@ func TestCore_DisableCredential(t *testing.T) {
|
||||
|
||||
func TestCore_DisableCredential_Protected(t *testing.T) {
|
||||
c, _, _ := TestCoreUnsealed(t)
|
||||
err := c.disableCredential(context.Background(), "token")
|
||||
err := c.disableCredential(namespace.TestContext(), "token")
|
||||
if err.Error() != "token credential backend cannot be disabled" {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -315,13 +320,13 @@ func TestCore_DisableCredential_Cleanup(t *testing.T) {
|
||||
Path: "foo",
|
||||
Type: "noop",
|
||||
}
|
||||
err := c.enableCredential(context.Background(), me)
|
||||
err := c.enableCredential(namespace.TestContext(), me)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// Store the view
|
||||
view := c.router.MatchingStorageByAPIPath("auth/foo/")
|
||||
view := c.router.MatchingStorageByAPIPath(namespace.TestContext(), "auth/foo/")
|
||||
|
||||
// Inject data
|
||||
se := &logical.StorageEntry{
|
||||
@@ -342,7 +347,7 @@ func TestCore_DisableCredential_Cleanup(t *testing.T) {
|
||||
Operation: logical.ReadOperation,
|
||||
Path: "auth/foo/login",
|
||||
}
|
||||
resp, err := c.HandleRequest(context.Background(), r)
|
||||
resp, err := c.HandleRequest(namespace.TestContext(), r)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -351,13 +356,13 @@ func TestCore_DisableCredential_Cleanup(t *testing.T) {
|
||||
}
|
||||
|
||||
// Disable should cleanup
|
||||
err = c.disableCredential(context.Background(), "foo")
|
||||
err = c.disableCredential(namespace.TestContext(), "foo")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// Token should be revoked
|
||||
te, err := c.tokenStore.Lookup(context.Background(), resp.Auth.ClientToken)
|
||||
te, err := c.tokenStore.Lookup(namespace.TestContext(), resp.Auth.ClientToken)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ type BarrierView struct {
|
||||
prefix string
|
||||
readOnlyErr error
|
||||
readOnlyErrLock sync.RWMutex
|
||||
iCheck interface{}
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -36,6 +37,10 @@ func NewBarrierView(barrier BarrierStorage, prefix string) *BarrierView {
|
||||
}
|
||||
}
|
||||
|
||||
func (v *BarrierView) setICheck(iCheck interface{}) {
|
||||
v.iCheck = iCheck
|
||||
}
|
||||
|
||||
func (v *BarrierView) setReadOnlyErr(readOnlyErr error) {
|
||||
v.readOnlyErrLock.Lock()
|
||||
defer v.readOnlyErrLock.Unlock()
|
||||
@@ -101,7 +106,9 @@ func (v *BarrierView) Put(ctx context.Context, entry *logical.StorageEntry) erro
|
||||
|
||||
roErr := v.getReadOnlyErr()
|
||||
if roErr != nil {
|
||||
return roErr
|
||||
if runICheck(v, expandedKey, roErr) {
|
||||
return roErr
|
||||
}
|
||||
}
|
||||
|
||||
nested := &Entry{
|
||||
@@ -122,7 +129,9 @@ func (v *BarrierView) Delete(ctx context.Context, key string) error {
|
||||
|
||||
roErr := v.getReadOnlyErr()
|
||||
if roErr != nil {
|
||||
return roErr
|
||||
if runICheck(v, expandedKey, roErr) {
|
||||
return roErr
|
||||
}
|
||||
}
|
||||
|
||||
return v.barrier.Delete(ctx, expandedKey)
|
||||
@@ -131,7 +140,7 @@ func (v *BarrierView) Delete(ctx context.Context, key string) error {
|
||||
// SubView constructs a nested sub-view using the given prefix
|
||||
func (v *BarrierView) SubView(prefix string) *BarrierView {
|
||||
sub := v.expandKey(prefix)
|
||||
return &BarrierView{barrier: v.barrier, prefix: sub, readOnlyErr: v.getReadOnlyErr()}
|
||||
return &BarrierView{barrier: v.barrier, prefix: sub, readOnlyErr: v.getReadOnlyErr(), iCheck: v.iCheck}
|
||||
}
|
||||
|
||||
// expandKey is used to expand to the full key path with the prefix
|
||||
|
||||
@@ -283,6 +283,7 @@ func TestBarrierView_ClearView(t *testing.T) {
|
||||
t.Fatalf("have keys: %#v", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBarrierView_Readonly(t *testing.T) {
|
||||
_, barrier, _ := mockBarrier(t)
|
||||
view := NewBarrierView(barrier, "foo/")
|
||||
|
||||
5
vault/barrier_view_util.go
Normal file
5
vault/barrier_view_util.go
Normal file
@@ -0,0 +1,5 @@
|
||||
// +build !enterprise
|
||||
|
||||
package vault
|
||||
|
||||
func runICheck(v *BarrierView, expandedKey string, roErr error) bool { return true }
|
||||
@@ -4,10 +4,12 @@ import (
|
||||
"context"
|
||||
"sort"
|
||||
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
)
|
||||
|
||||
// Capabilities is used to fetch the capabilities of the given token on the given path
|
||||
// Capabilities is used to fetch the capabilities of the given token on the
|
||||
// given path
|
||||
func (c *Core) Capabilities(ctx context.Context, token, path string) ([]string, error) {
|
||||
if path == "" {
|
||||
return nil, &logical.StatusBadRequest{Err: "missing path"}
|
||||
@@ -25,11 +27,22 @@ func (c *Core) Capabilities(ctx context.Context, token, path string) ([]string,
|
||||
return nil, &logical.StatusBadRequest{Err: "invalid token"}
|
||||
}
|
||||
|
||||
// Start with token entry policies
|
||||
policies := te.Policies
|
||||
tokenNS, err := NamespaceByID(ctx, te.NamespaceID, c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tokenNS == nil {
|
||||
return nil, namespace.ErrNoNamespace
|
||||
}
|
||||
|
||||
// Fetch entity and entity group policies
|
||||
entity, derivedPolicies, err := c.fetchEntityAndDerivedPolicies(te.EntityID)
|
||||
var policyCount int
|
||||
policyNames := make(map[string][]string)
|
||||
policyNames[tokenNS.ID] = te.Policies
|
||||
policyCount += len(te.Policies)
|
||||
|
||||
// Attach token's namespace information to the context
|
||||
ctx = namespace.ContextWithNamespace(ctx, tokenNS)
|
||||
entity, identityPolicies, err := c.fetchEntityAndDerivedPolicies(ctx, tokenNS, te.EntityID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -41,18 +54,22 @@ func (c *Core) Capabilities(ctx context.Context, token, path string) ([]string,
|
||||
c.logger.Warn("permission denied as the entity on the token is invalid")
|
||||
return nil, logical.ErrPermissionDenied
|
||||
}
|
||||
policies = append(policies, derivedPolicies...)
|
||||
|
||||
if len(policies) == 0 {
|
||||
for nsID, nsPolicies := range identityPolicies {
|
||||
policyNames[nsID] = append(policyNames[nsID], nsPolicies...)
|
||||
policyCount += len(nsPolicies)
|
||||
}
|
||||
|
||||
if policyCount == 0 {
|
||||
return []string{DenyCapability}, nil
|
||||
}
|
||||
|
||||
acl, err := c.policyStore.ACL(ctx, entity, policies...)
|
||||
acl, err := c.policyStore.ACL(ctx, entity, policyNames)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
capabilities := acl.Capabilities(path)
|
||||
capabilities := acl.Capabilities(ctx, path)
|
||||
sort.Strings(capabilities)
|
||||
return capabilities, nil
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package vault
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
)
|
||||
|
||||
@@ -15,7 +15,8 @@ func TestCapabilities_DerivedPolicies(t *testing.T) {
|
||||
var resp *logical.Response
|
||||
var err error
|
||||
|
||||
i, _, c := testIdentityStoreWithGithubAuth(t)
|
||||
ctx := namespace.RootContext(nil)
|
||||
i, _, c := testIdentityStoreWithGithubAuth(ctx, t)
|
||||
|
||||
policy1 := `
|
||||
name = "policy1"
|
||||
@@ -37,20 +38,20 @@ path "secret/sample" {
|
||||
}
|
||||
`
|
||||
// Create the above policies
|
||||
policy, _ := ParseACLPolicy(policy1)
|
||||
err = c.policyStore.SetPolicy(context.Background(), policy)
|
||||
policy, _ := ParseACLPolicy(namespace.RootNamespace, policy1)
|
||||
err = c.policyStore.SetPolicy(ctx, policy)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
policy, _ = ParseACLPolicy(policy2)
|
||||
err = c.policyStore.SetPolicy(context.Background(), policy)
|
||||
policy, _ = ParseACLPolicy(namespace.RootNamespace, policy2)
|
||||
err = c.policyStore.SetPolicy(ctx, policy)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
policy, _ = ParseACLPolicy(policy3)
|
||||
err = c.policyStore.SetPolicy(context.Background(), policy)
|
||||
policy, _ = ParseACLPolicy(namespace.RootNamespace, policy3)
|
||||
err = c.policyStore.SetPolicy(ctx, policy)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -63,7 +64,7 @@ path "secret/sample" {
|
||||
"policies": "policy1",
|
||||
},
|
||||
}
|
||||
resp, err = i.HandleRequest(context.Background(), entityReq)
|
||||
resp, err = i.HandleRequest(ctx, entityReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("bad: resp: %#v\nerr: %#v\n", resp, err)
|
||||
}
|
||||
@@ -79,7 +80,7 @@ path "secret/sample" {
|
||||
}
|
||||
testMakeTokenDirectly(t, c.tokenStore, ent)
|
||||
|
||||
actual, err := c.Capabilities(context.Background(), "capabilitiestoken", "secret/sample")
|
||||
actual, err := c.Capabilities(ctx, "capabilitiestoken", "secret/sample")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -99,12 +100,12 @@ path "secret/sample" {
|
||||
"policies": "policy3",
|
||||
},
|
||||
}
|
||||
resp, err = i.HandleRequest(context.Background(), groupReq)
|
||||
resp, err = i.HandleRequest(ctx, groupReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("bad: resp: %#v\nerr: %#v\n", resp, err)
|
||||
}
|
||||
|
||||
actual, err = c.Capabilities(context.Background(), "capabilitiestoken", "secret/sample")
|
||||
actual, err = c.Capabilities(namespace.RootContext(nil), "capabilitiestoken", "secret/sample")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -119,15 +120,13 @@ path "secret/sample" {
|
||||
func TestCapabilities_TemplatedPolicies(t *testing.T) {
|
||||
var resp *logical.Response
|
||||
var err error
|
||||
|
||||
i, _, c := testIdentityStoreWithGithubAuth(t)
|
||||
|
||||
i, _, c := testIdentityStoreWithGithubAuth(namespace.RootContext(nil), t)
|
||||
// Create an entity and assign policy1 to it
|
||||
entityReq := &logical.Request{
|
||||
Path: "entity",
|
||||
Operation: logical.UpdateOperation,
|
||||
}
|
||||
resp, err = i.HandleRequest(context.Background(), entityReq)
|
||||
resp, err = i.HandleRequest(namespace.RootContext(nil), entityReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("bad: resp: %#v\nerr: %#v\n", resp, err)
|
||||
}
|
||||
@@ -168,19 +167,17 @@ func TestCapabilities_TemplatedPolicies(t *testing.T) {
|
||||
[]string{"read"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tCase := range tCases {
|
||||
// Create the above policies
|
||||
policy, err := ParseACLPolicy(tCase.policy)
|
||||
policy, err := ParseACLPolicy(namespace.RootNamespace, tCase.policy)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
err = c.policyStore.SetPolicy(context.Background(), policy)
|
||||
err = c.policyStore.SetPolicy(namespace.RootContext(nil), policy)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
actual, err := c.Capabilities(context.Background(), "capabilitiestoken", tCase.path)
|
||||
actual, err := c.Capabilities(namespace.RootContext(nil), "capabilitiestoken", tCase.path)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -195,7 +192,7 @@ func TestCapabilities_TemplatedPolicies(t *testing.T) {
|
||||
func TestCapabilities(t *testing.T) {
|
||||
c, _, token := TestCoreUnsealed(t)
|
||||
|
||||
actual, err := c.Capabilities(context.Background(), token, "path")
|
||||
actual, err := c.Capabilities(namespace.RootContext(nil), token, "path")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
@@ -205,8 +202,8 @@ func TestCapabilities(t *testing.T) {
|
||||
}
|
||||
|
||||
// Create a policy
|
||||
policy, _ := ParseACLPolicy(aclPolicy)
|
||||
err = c.policyStore.SetPolicy(context.Background(), policy)
|
||||
policy, _ := ParseACLPolicy(namespace.RootNamespace, aclPolicy)
|
||||
err = c.policyStore.SetPolicy(namespace.RootContext(nil), policy)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -220,7 +217,7 @@ func TestCapabilities(t *testing.T) {
|
||||
}
|
||||
testMakeTokenDirectly(t, c.tokenStore, ent)
|
||||
|
||||
actual, err = c.Capabilities(context.Background(), "capabilitiestoken", "foo/bar")
|
||||
actual, err = c.Capabilities(namespace.RootContext(nil), "capabilitiestoken", "foo/bar")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
@@ -37,8 +37,9 @@ var (
|
||||
ErrCannotForward = errors.New("cannot forward request; no connection or address not known")
|
||||
)
|
||||
|
||||
// This is used for enterprise replication information
|
||||
type ReplicatedClusters struct {
|
||||
DR *ReplicatedCluster
|
||||
Performance *ReplicatedCluster
|
||||
}
|
||||
|
||||
// This can be one of a few key types so the different params may or may not be filled
|
||||
@@ -206,7 +207,7 @@ func (c *Core) setupCluster(ctx context.Context) error {
|
||||
if c.ha != nil {
|
||||
// Create a private key
|
||||
if c.localClusterPrivateKey.Load().(*ecdsa.PrivateKey) == nil {
|
||||
c.logger.Trace("generating cluster private key")
|
||||
c.logger.Debug("generating cluster private key")
|
||||
key, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
|
||||
if err != nil {
|
||||
c.logger.Error("failed to generate local cluster key", "error", err)
|
||||
@@ -339,92 +340,15 @@ func (c *Core) stopClusterListener() {
|
||||
|
||||
// ClusterTLSConfig generates a TLS configuration based on the local/replicated
|
||||
// cluster key and cert.
|
||||
func (c *Core) ClusterTLSConfig(ctx context.Context, repClusters *ReplicatedClusters) (*tls.Config, error) {
|
||||
func (c *Core) ClusterTLSConfig(ctx context.Context, repClusters *ReplicatedClusters, perfStandbyCluster *ReplicatedCluster) (*tls.Config, error) {
|
||||
// Using lookup functions allows just-in-time lookup of the current state
|
||||
// of clustering as connections come and go
|
||||
|
||||
serverLookup := func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
switch {
|
||||
default:
|
||||
currCert := c.localClusterCert.Load().([]byte)
|
||||
if len(currCert) == 0 {
|
||||
return nil, fmt.Errorf("got forwarding connection but no local cert")
|
||||
}
|
||||
|
||||
localCert := make([]byte, len(currCert))
|
||||
copy(localCert, currCert)
|
||||
|
||||
return &tls.Certificate{
|
||||
Certificate: [][]byte{localCert},
|
||||
PrivateKey: c.localClusterPrivateKey.Load().(*ecdsa.PrivateKey),
|
||||
Leaf: c.localClusterParsedCert.Load().(*x509.Certificate),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
clientLookup := func(requestInfo *tls.CertificateRequestInfo) (*tls.Certificate, error) {
|
||||
|
||||
if len(requestInfo.AcceptableCAs) != 1 {
|
||||
return nil, fmt.Errorf("expected only a single acceptable CA")
|
||||
}
|
||||
|
||||
currCert := c.localClusterCert.Load().([]byte)
|
||||
if len(currCert) == 0 {
|
||||
return nil, fmt.Errorf("forwarding connection client but no local cert")
|
||||
}
|
||||
|
||||
localCert := make([]byte, len(currCert))
|
||||
copy(localCert, currCert)
|
||||
|
||||
return &tls.Certificate{
|
||||
Certificate: [][]byte{localCert},
|
||||
PrivateKey: c.localClusterPrivateKey.Load().(*ecdsa.PrivateKey),
|
||||
Leaf: c.localClusterParsedCert.Load().(*x509.Certificate),
|
||||
}, nil
|
||||
}
|
||||
|
||||
serverConfigLookup := func(clientHello *tls.ClientHelloInfo) (*tls.Config, error) {
|
||||
|
||||
for _, v := range clientHello.SupportedProtos {
|
||||
switch v {
|
||||
case "h2", requestForwardingALPN:
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown ALPN proto %s", v)
|
||||
}
|
||||
}
|
||||
|
||||
caPool := x509.NewCertPool()
|
||||
|
||||
ret := &tls.Config{
|
||||
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||
GetCertificate: serverLookup,
|
||||
GetClientCertificate: clientLookup,
|
||||
MinVersion: tls.VersionTLS12,
|
||||
RootCAs: caPool,
|
||||
ClientCAs: caPool,
|
||||
NextProtos: clientHello.SupportedProtos,
|
||||
CipherSuites: c.clusterCipherSuites,
|
||||
}
|
||||
|
||||
switch {
|
||||
default:
|
||||
parsedCert := c.localClusterParsedCert.Load().(*x509.Certificate)
|
||||
|
||||
if parsedCert == nil {
|
||||
return nil, fmt.Errorf("forwarding connection client but no local cert")
|
||||
}
|
||||
|
||||
caPool.AddCert(parsedCert)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
tlsConfig := &tls.Config{
|
||||
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||
GetCertificate: serverLookup,
|
||||
GetClientCertificate: clientLookup,
|
||||
GetConfigForClient: serverConfigLookup,
|
||||
GetCertificate: clusterTLSServerLookup(ctx, c, repClusters, perfStandbyCluster),
|
||||
GetClientCertificate: clusterTLSClientLookup(ctx, c, repClusters, perfStandbyCluster),
|
||||
GetConfigForClient: clusterTLSServerConfigLookup(ctx, c, repClusters, perfStandbyCluster),
|
||||
MinVersion: tls.VersionTLS12,
|
||||
CipherSuites: c.clusterCipherSuites,
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ func TestCluster_ListenForRequests(t *testing.T) {
|
||||
// Use this to have a valid config after sealing since ClusterTLSConfig returns nil
|
||||
var lastTLSConfig *tls.Config
|
||||
checkListenersFunc := func(expectFail bool) {
|
||||
tlsConfig, err := cores[0].ClusterTLSConfig(context.Background(), nil)
|
||||
tlsConfig, err := cores[0].ClusterTLSConfig(context.Background(), nil, nil)
|
||||
if err != nil {
|
||||
if err.Error() != consts.ErrSealed.Error() {
|
||||
t.Fatal(err)
|
||||
@@ -346,6 +346,7 @@ func testCluster_ForwardRequests(t *testing.T, c *TestClusterCore, rootToken, re
|
||||
t.Fatal(err)
|
||||
}
|
||||
req.Header.Add("X-Vault-Token", rootToken)
|
||||
req = req.WithContext(context.WithValue(req.Context(), "original_request_path", req.URL.Path))
|
||||
|
||||
statusCode, header, respBytes, err := c.ForwardRequest(req)
|
||||
if err != nil {
|
||||
@@ -391,7 +392,7 @@ func TestCluster_CustomCipherSuites(t *testing.T) {
|
||||
// Wait for core to become active
|
||||
TestWaitActive(t, core.Core)
|
||||
|
||||
tlsConf, err := core.Core.ClusterTLSConfig(context.Background(), nil)
|
||||
tlsConf, err := core.Core.ClusterTLSConfig(context.Background(), nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
85
vault/cluster_tls.go
Normal file
85
vault/cluster_tls.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package vault
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
clusterTLSServerLookup = func(ctx context.Context, c *Core, repClusters *ReplicatedClusters, _ *ReplicatedCluster) func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
return func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
c.logger.Debug("performing server cert lookup")
|
||||
|
||||
switch {
|
||||
default:
|
||||
currCert := c.localClusterCert.Load().([]byte)
|
||||
if len(currCert) == 0 {
|
||||
return nil, fmt.Errorf("got forwarding connection but no local cert")
|
||||
}
|
||||
|
||||
localCert := make([]byte, len(currCert))
|
||||
copy(localCert, currCert)
|
||||
|
||||
return &tls.Certificate{
|
||||
Certificate: [][]byte{localCert},
|
||||
PrivateKey: c.localClusterPrivateKey.Load().(*ecdsa.PrivateKey),
|
||||
Leaf: c.localClusterParsedCert.Load().(*x509.Certificate),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clusterTLSClientLookup = func(ctx context.Context, c *Core, repClusters *ReplicatedClusters, _ *ReplicatedCluster) func(*tls.CertificateRequestInfo) (*tls.Certificate, error) {
|
||||
return func(requestInfo *tls.CertificateRequestInfo) (*tls.Certificate, error) {
|
||||
if len(requestInfo.AcceptableCAs) != 1 {
|
||||
return nil, fmt.Errorf("expected only a single acceptable CA")
|
||||
}
|
||||
|
||||
currCert := c.localClusterCert.Load().([]byte)
|
||||
if len(currCert) == 0 {
|
||||
return nil, fmt.Errorf("forwarding connection client but no local cert")
|
||||
}
|
||||
|
||||
localCert := make([]byte, len(currCert))
|
||||
copy(localCert, currCert)
|
||||
|
||||
return &tls.Certificate{
|
||||
Certificate: [][]byte{localCert},
|
||||
PrivateKey: c.localClusterPrivateKey.Load().(*ecdsa.PrivateKey),
|
||||
Leaf: c.localClusterParsedCert.Load().(*x509.Certificate),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
clusterTLSServerConfigLookup = func(ctx context.Context, c *Core, repClusters *ReplicatedClusters, repCluster *ReplicatedCluster) func(clientHello *tls.ClientHelloInfo) (*tls.Config, error) {
|
||||
return func(clientHello *tls.ClientHelloInfo) (*tls.Config, error) {
|
||||
//c.logger.Trace("performing server config lookup")
|
||||
|
||||
caPool := x509.NewCertPool()
|
||||
|
||||
ret := &tls.Config{
|
||||
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||
GetCertificate: clusterTLSServerLookup(ctx, c, repClusters, repCluster),
|
||||
GetClientCertificate: clusterTLSClientLookup(ctx, c, repClusters, repCluster),
|
||||
MinVersion: tls.VersionTLS12,
|
||||
RootCAs: caPool,
|
||||
ClientCAs: caPool,
|
||||
NextProtos: clientHello.SupportedProtos,
|
||||
CipherSuites: c.clusterCipherSuites,
|
||||
}
|
||||
|
||||
parsedCert := c.localClusterParsedCert.Load().(*x509.Certificate)
|
||||
|
||||
if parsedCert == nil {
|
||||
return nil, fmt.Errorf("forwarding connection client but no local cert")
|
||||
}
|
||||
|
||||
caPool.AddCert(parsedCert)
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
}
|
||||
)
|
||||
254
vault/core.go
254
vault/core.go
@@ -17,6 +17,7 @@ import (
|
||||
|
||||
"github.com/armon/go-metrics"
|
||||
log "github.com/hashicorp/go-hclog"
|
||||
cache "github.com/patrickmn/go-cache"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
|
||||
@@ -27,12 +28,12 @@ import (
|
||||
"github.com/hashicorp/vault/helper/consts"
|
||||
"github.com/hashicorp/vault/helper/logging"
|
||||
"github.com/hashicorp/vault/helper/mlock"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/helper/reload"
|
||||
"github.com/hashicorp/vault/helper/tlsutil"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/physical"
|
||||
"github.com/hashicorp/vault/shamir"
|
||||
cache "github.com/patrickmn/go-cache"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -86,6 +87,7 @@ var (
|
||||
startReplication = startReplicationImpl
|
||||
stopReplication = stopReplicationImpl
|
||||
LastRemoteWAL = lastRemoteWALImpl
|
||||
WaitUntilWALShipped = waitUntilWALShippedImpl
|
||||
)
|
||||
|
||||
// NonFatalError is an error that can be returned during NewCore that should be
|
||||
@@ -113,6 +115,8 @@ func (e *ErrInvalidKey) Error() string {
|
||||
return fmt.Sprintf("invalid key: %v", e.Reason)
|
||||
}
|
||||
|
||||
type RegisterAuthFunc func(context.Context, time.Duration, string, *logical.Auth) error
|
||||
|
||||
type activeAdvertisement struct {
|
||||
RedirectAddr string `json:"redirect_addr"`
|
||||
ClusterAddr string `json:"cluster_addr,omitempty"`
|
||||
@@ -129,6 +133,8 @@ type unlockInformation struct {
|
||||
// interface for API handlers and is responsible for managing the logical and physical
|
||||
// backends, router, security barrier, and audit trails.
|
||||
type Core struct {
|
||||
entCore
|
||||
|
||||
// N.B.: This is used to populate a dev token down replication, as
|
||||
// otherwise, after replication is started, a dev would have to go through
|
||||
// the generate-root process simply to talk to the new follower cluster.
|
||||
@@ -227,6 +233,9 @@ type Core struct {
|
||||
// systemBackend is the backend which is used to manage internal operations
|
||||
systemBackend *SystemBackend
|
||||
|
||||
// cubbyholeBackend is the backend which manages the per-token storage
|
||||
cubbyholeBackend *CubbyholeBackend
|
||||
|
||||
// systemBarrierView is the barrier view for the system backend
|
||||
systemBarrierView *BarrierView
|
||||
|
||||
@@ -338,6 +347,7 @@ type Core struct {
|
||||
atomicPrimaryClusterAddrs *atomic.Value
|
||||
|
||||
atomicPrimaryFailoverAddrs *atomic.Value
|
||||
|
||||
// replicationState keeps the current replication state cached for quick
|
||||
// lookup; activeNodeReplicationState stores the active value on standbys
|
||||
replicationState *uint32
|
||||
@@ -368,6 +378,16 @@ type Core struct {
|
||||
// Stores any funcs that should be run on successful postUnseal
|
||||
postUnsealFuncs []func()
|
||||
|
||||
// replicationFailure is used to mark when replication has entered an
|
||||
// unrecoverable failure.
|
||||
replicationFailure *uint32
|
||||
|
||||
// disablePerfStanby is used to tell a standby not to attempt to become a
|
||||
// perf standby
|
||||
disablePerfStandby bool
|
||||
|
||||
licensingStopCh chan struct{}
|
||||
|
||||
// Stores loggers so we can reset the level
|
||||
allLoggers []log.Logger
|
||||
allLoggersLock sync.RWMutex
|
||||
@@ -422,9 +442,18 @@ type CoreConfig struct {
|
||||
|
||||
PluginDirectory string `json:"plugin_directory" structs:"plugin_directory" mapstructure:"plugin_directory"`
|
||||
|
||||
DisableSealWrap bool `json:"disable_sealwrap" structs:"disable_sealwrap" mapstructure:"disable_sealwrap"`
|
||||
|
||||
ReloadFuncs *map[string][]reload.ReloadFunc
|
||||
ReloadFuncsLock *sync.RWMutex
|
||||
|
||||
// Licensing
|
||||
LicensingConfig *LicensingConfig
|
||||
// Don't set this unless in dev mode, ideally only when using inmem
|
||||
DevLicenseDuration time.Duration
|
||||
|
||||
DisablePerformanceStandby bool
|
||||
|
||||
AllLoggers []log.Logger
|
||||
}
|
||||
|
||||
@@ -465,6 +494,7 @@ func NewCore(conf *CoreConfig) (*Core, error) {
|
||||
|
||||
// Setup the core
|
||||
c := &Core{
|
||||
entCore: entCore{},
|
||||
devToken: conf.DevToken,
|
||||
physical: conf.Physical,
|
||||
redirectAddr: conf.RedirectAddr,
|
||||
@@ -493,6 +523,8 @@ func NewCore(conf *CoreConfig) (*Core, error) {
|
||||
localClusterParsedCert: new(atomic.Value),
|
||||
activeNodeReplicationState: new(uint32),
|
||||
keepHALockOnStepDown: new(uint32),
|
||||
replicationFailure: new(uint32),
|
||||
disablePerfStandby: true,
|
||||
activeContextCancelFunc: new(atomic.Value),
|
||||
allLoggers: conf.AllLoggers,
|
||||
}
|
||||
@@ -521,28 +553,14 @@ func NewCore(conf *CoreConfig) (*Core, error) {
|
||||
Enabled: new(uint32),
|
||||
}
|
||||
|
||||
phys := conf.Physical
|
||||
_, txnOK := conf.Physical.(physical.Transactional)
|
||||
if c.seal == nil {
|
||||
c.seal = NewDefaultSeal()
|
||||
}
|
||||
c.seal.SetCore(c)
|
||||
|
||||
unwrapperLogger := c.baseLogger.Named("storage.sealunwrapper")
|
||||
c.allLoggers = append(c.allLoggers, unwrapperLogger)
|
||||
c.sealUnwrapper = NewSealUnwrapper(phys, unwrapperLogger)
|
||||
|
||||
var ok bool
|
||||
|
||||
// Wrap the physical backend in a cache layer if enabled
|
||||
cacheLogger := c.baseLogger.Named("storage.cache")
|
||||
c.allLoggers = append(c.allLoggers, cacheLogger)
|
||||
if txnOK {
|
||||
c.physical = physical.NewTransactionalCache(c.sealUnwrapper, conf.CacheSize, cacheLogger)
|
||||
} else {
|
||||
c.physical = physical.NewCache(c.sealUnwrapper, conf.CacheSize, cacheLogger)
|
||||
if err := coreInit(c, conf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.physicalCache = c.physical.(physical.ToggleablePurgemonster)
|
||||
|
||||
if !conf.DisableMlock {
|
||||
// Ensure our memory usage is locked into physical RAM
|
||||
@@ -561,6 +579,8 @@ func NewCore(conf *CoreConfig) (*Core, error) {
|
||||
}
|
||||
|
||||
var err error
|
||||
var ok bool
|
||||
|
||||
if conf.PluginDirectory != "" {
|
||||
c.pluginDirectory, err = filepath.Abs(conf.PluginDirectory)
|
||||
if err != nil {
|
||||
@@ -574,6 +594,8 @@ func NewCore(conf *CoreConfig) (*Core, error) {
|
||||
return nil, errwrap.Wrapf("barrier setup failed: {{err}}", err)
|
||||
}
|
||||
|
||||
createSecondaries(c, conf)
|
||||
|
||||
if conf.HAPhysical != nil && conf.HAPhysical.HAEnabled() {
|
||||
c.ha = conf.HAPhysical
|
||||
}
|
||||
@@ -596,7 +618,7 @@ func NewCore(conf *CoreConfig) (*Core, error) {
|
||||
logicalBackends["kv"] = PassthroughBackendFactory
|
||||
}
|
||||
logicalBackends["cubbyhole"] = CubbyholeBackendFactory
|
||||
logicalBackends["system"] = func(ctx context.Context, config *logical.BackendConfig) (logical.Backend, error) {
|
||||
logicalBackends[systemMountType] = func(ctx context.Context, config *logical.BackendConfig) (logical.Backend, error) {
|
||||
sysBackendLogger := conf.Logger.Named("system")
|
||||
c.AddLogger(sysBackendLogger)
|
||||
b := NewSystemBackend(c, sysBackendLogger)
|
||||
@@ -605,13 +627,12 @@ func NewCore(conf *CoreConfig) (*Core, error) {
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
logicalBackends["identity"] = func(ctx context.Context, config *logical.BackendConfig) (logical.Backend, error) {
|
||||
identityLogger := conf.Logger.Named("identity")
|
||||
c.AddLogger(identityLogger)
|
||||
return NewIdentityStore(ctx, c, config, identityLogger)
|
||||
}
|
||||
|
||||
addExtraLogicalBackends(c, logicalBackends)
|
||||
c.logicalBackends = logicalBackends
|
||||
|
||||
credentialBackends := make(map[string]logical.Factory)
|
||||
@@ -623,6 +644,7 @@ func NewCore(conf *CoreConfig) (*Core, error) {
|
||||
c.AddLogger(tsLogger)
|
||||
return NewTokenStore(ctx, tsLogger, c, config)
|
||||
}
|
||||
addExtraCredentialBackends(c, credentialBackends)
|
||||
c.credentialBackends = credentialBackends
|
||||
|
||||
auditBackends := make(map[string]audit.Factory)
|
||||
@@ -655,7 +677,7 @@ func (c *Core) GetContext() (context.Context, context.CancelFunc) {
|
||||
c.stateLock.RLock()
|
||||
defer c.stateLock.RUnlock()
|
||||
|
||||
return context.WithCancel(c.activeContext)
|
||||
return context.WithCancel(namespace.RootContext(c.activeContext))
|
||||
}
|
||||
|
||||
// Sealed checks if the Vault is current sealed
|
||||
@@ -882,6 +904,10 @@ func (c *Core) unsealInternal(ctx context.Context, masterKey []byte) (bool, erro
|
||||
c.logger.Info("vault is unsealed")
|
||||
}
|
||||
|
||||
if err := preUnsealInternal(ctx, c); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Do post-unseal setup if HA is not enabled
|
||||
if c.ha == nil {
|
||||
// We still need to set up cluster info even if it's not part of a
|
||||
@@ -893,8 +919,8 @@ func (c *Core) unsealInternal(ctx context.Context, masterKey []byte) (bool, erro
|
||||
return false, err
|
||||
}
|
||||
|
||||
ctx, ctxCancel := context.WithCancel(context.Background())
|
||||
if err := c.postUnseal(ctx, ctxCancel); err != nil {
|
||||
ctx, ctxCancel := context.WithCancel(namespace.RootContext(nil))
|
||||
if err := c.postUnseal(ctx, ctxCancel, standardUnsealStrategy{}); err != nil {
|
||||
c.logger.Error("post-unseal setup failed", "error", err)
|
||||
c.barrier.Seal()
|
||||
c.logger.Warn("vault is sealed")
|
||||
@@ -944,7 +970,7 @@ func (c *Core) SealWithRequest(httpCtx context.Context, req *logical.Request) er
|
||||
|
||||
// This will unlock the read lock
|
||||
// We use background context since we may not be active
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(namespace.RootContext(nil))
|
||||
defer cancel()
|
||||
|
||||
go func() {
|
||||
@@ -978,7 +1004,7 @@ func (c *Core) Seal(token string) error {
|
||||
|
||||
// This will unlock the read lock
|
||||
// We use background context since we may not be active
|
||||
return c.sealInitCommon(context.Background(), req)
|
||||
return c.sealInitCommon(namespace.RootContext(nil), req)
|
||||
}
|
||||
|
||||
// sealInitCommon is common logic for Seal and SealWithRequest and is used to
|
||||
@@ -1005,7 +1031,7 @@ func (c *Core) sealInitCommon(ctx context.Context, req *logical.Request) (retErr
|
||||
return retErr
|
||||
}
|
||||
|
||||
acl, te, entity, identityPolicies, err := c.fetchACLTokenEntryAndEntity(req)
|
||||
acl, te, entity, identityPolicies, err := c.fetchACLTokenEntryAndEntity(ctx, req)
|
||||
if err != nil {
|
||||
if errwrap.ContainsType(err, new(TemplateError)) {
|
||||
c.logger.Warn("permission denied due to a templated policy being invalid or containing directives not satisfied by the requestor", "error", err)
|
||||
@@ -1016,15 +1042,18 @@ func (c *Core) sealInitCommon(ctx context.Context, req *logical.Request) (retErr
|
||||
return retErr
|
||||
}
|
||||
|
||||
req.SetTokenEntry(te)
|
||||
|
||||
// Audit-log the request before going any further
|
||||
auth := &logical.Auth{
|
||||
ClientToken: req.ClientToken,
|
||||
Policies: identityPolicies,
|
||||
IdentityPolicies: identityPolicies,
|
||||
ClientToken: req.ClientToken,
|
||||
}
|
||||
if te != nil {
|
||||
auth.IdentityPolicies = identityPolicies[te.NamespaceID]
|
||||
delete(identityPolicies, te.NamespaceID)
|
||||
auth.ExternalNamespacePolicies = identityPolicies
|
||||
auth.TokenPolicies = te.Policies
|
||||
auth.Policies = append(te.Policies, identityPolicies...)
|
||||
auth.Policies = append(te.Policies, identityPolicies[te.NamespaceID]...)
|
||||
auth.Metadata = te.Meta
|
||||
auth.DisplayName = te.DisplayName
|
||||
auth.EntityID = te.EntityID
|
||||
@@ -1222,62 +1251,37 @@ func (c *Core) sealInternalWithOptions(grabStateLock, keepHALock bool) error {
|
||||
}
|
||||
}
|
||||
|
||||
postSealInternal(c)
|
||||
|
||||
c.logger.Info("vault is sealed")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// postUnseal is invoked after the barrier is unsealed, but before
|
||||
// allowing any user operations. This allows us to setup any state that
|
||||
// requires the Vault to be unsealed such as mount tables, logical backends,
|
||||
// credential stores, etc.
|
||||
func (c *Core) postUnseal(ctx context.Context, ctxCancelFunc context.CancelFunc) (retErr error) {
|
||||
defer metrics.MeasureSince([]string{"core", "post_unseal"}, time.Now())
|
||||
type UnsealStrategy interface {
|
||||
unseal(context.Context, log.Logger, *Core) error
|
||||
}
|
||||
|
||||
// Clear any out
|
||||
c.postUnsealFuncs = nil
|
||||
|
||||
// Create a new request context
|
||||
c.activeContext = ctx
|
||||
c.activeContextCancelFunc.Store(ctxCancelFunc)
|
||||
|
||||
defer func() {
|
||||
if retErr != nil {
|
||||
ctxCancelFunc()
|
||||
c.preSeal()
|
||||
}
|
||||
}()
|
||||
c.logger.Info("post-unseal setup starting")
|
||||
type standardUnsealStrategy struct{}
|
||||
|
||||
func (s standardUnsealStrategy) unseal(ctx context.Context, logger log.Logger, c *Core) error {
|
||||
// Clear forwarding clients; we're active
|
||||
c.requestForwardingConnectionLock.Lock()
|
||||
c.clearForwardingClients()
|
||||
c.requestForwardingConnectionLock.Unlock()
|
||||
|
||||
// Enable the cache
|
||||
c.physicalCache.Purge(ctx)
|
||||
if !c.cachingDisabled {
|
||||
c.physicalCache.SetEnabled(true)
|
||||
}
|
||||
|
||||
switch c.sealUnwrapper.(type) {
|
||||
case *sealUnwrapper:
|
||||
c.sealUnwrapper.(*sealUnwrapper).runUnwraps()
|
||||
case *transactionalSealUnwrapper:
|
||||
c.sealUnwrapper.(*transactionalSealUnwrapper).runUnwraps()
|
||||
}
|
||||
|
||||
// Purge these for safety in case of a rekey
|
||||
c.seal.SetBarrierConfig(ctx, nil)
|
||||
if c.seal.RecoveryKeySupported() {
|
||||
c.seal.SetRecoveryConfig(ctx, nil)
|
||||
if err := postUnsealPhysical(c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := enterprisePostUnseal(c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.ensureWrappingKey(ctx); err != nil {
|
||||
return err
|
||||
|
||||
if !c.IsDRSecondary() {
|
||||
if err := c.ensureWrappingKey(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := c.setupPluginCatalog(); err != nil {
|
||||
return err
|
||||
@@ -1300,30 +1304,85 @@ func (c *Core) postUnseal(ctx context.Context, ctxCancelFunc context.CancelFunc)
|
||||
if err := c.setupCredentials(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.startRollback(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.setupExpiration(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.loadAudits(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.setupAudits(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.loadIdentityStoreArtifacts(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.setupAuditedHeadersConfig(ctx); err != nil {
|
||||
return err
|
||||
if !c.IsDRSecondary() {
|
||||
if err := c.startRollback(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.setupExpiration(expireLeaseStrategyRevoke); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.loadAudits(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.setupAudits(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.loadIdentityStoreArtifacts(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := loadMFAConfigs(ctx, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.setupAuditedHeadersConfig(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
c.auditBroker = NewAuditBroker(c.logger)
|
||||
}
|
||||
|
||||
if c.ha != nil {
|
||||
if c.ha != nil || shouldStartClusterListener(c) {
|
||||
if err := c.startClusterListener(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
c.clusterParamsLock.Lock()
|
||||
defer c.clusterParamsLock.Unlock()
|
||||
if err := startReplication(c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// postUnseal is invoked after the barrier is unsealed, but before
|
||||
// allowing any user operations. This allows us to setup any state that
|
||||
// requires the Vault to be unsealed such as mount tables, logical backends,
|
||||
// credential stores, etc.
|
||||
func (c *Core) postUnseal(ctx context.Context, ctxCancelFunc context.CancelFunc, unsealer UnsealStrategy) (retErr error) {
|
||||
defer metrics.MeasureSince([]string{"core", "post_unseal"}, time.Now())
|
||||
|
||||
// Clear any out
|
||||
c.postUnsealFuncs = nil
|
||||
|
||||
// Create a new request context
|
||||
c.activeContext = ctx
|
||||
c.activeContextCancelFunc.Store(ctxCancelFunc)
|
||||
|
||||
defer func() {
|
||||
if retErr != nil {
|
||||
ctxCancelFunc()
|
||||
c.preSeal()
|
||||
}
|
||||
}()
|
||||
c.logger.Info("post-unseal setup starting")
|
||||
|
||||
// Enable the cache
|
||||
c.physicalCache.Purge(ctx)
|
||||
if !c.cachingDisabled {
|
||||
c.physicalCache.SetEnabled(true)
|
||||
}
|
||||
|
||||
// Purge these for safety in case of a rekey
|
||||
c.seal.SetBarrierConfig(ctx, nil)
|
||||
if c.seal.RecoveryKeySupported() {
|
||||
c.seal.SetRecoveryConfig(ctx, nil)
|
||||
}
|
||||
|
||||
if err := unsealer.unseal(ctx, c.logger, c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.metricsCh = make(chan struct{})
|
||||
go c.emitMetrics(c.metricsCh)
|
||||
|
||||
@@ -1357,6 +1416,12 @@ func (c *Core) preSeal() error {
|
||||
}
|
||||
var result error
|
||||
|
||||
c.clusterParamsLock.Lock()
|
||||
if err := stopReplication(c); err != nil {
|
||||
result = multierror.Append(result, errwrap.Wrapf("error stopping replication: {{err}}", err))
|
||||
}
|
||||
c.clusterParamsLock.Unlock()
|
||||
|
||||
c.stopClusterListener()
|
||||
|
||||
if err := c.teardownAudits(); err != nil {
|
||||
@@ -1381,16 +1446,7 @@ func (c *Core) preSeal() error {
|
||||
result = multierror.Append(result, err)
|
||||
}
|
||||
|
||||
switch c.sealUnwrapper.(type) {
|
||||
case *sealUnwrapper:
|
||||
c.sealUnwrapper.(*sealUnwrapper).stopUnwraps()
|
||||
case *transactionalSealUnwrapper:
|
||||
c.sealUnwrapper.(*transactionalSealUnwrapper).stopUnwraps()
|
||||
}
|
||||
|
||||
// Purge the cache
|
||||
c.physicalCache.SetEnabled(false)
|
||||
c.physicalCache.Purge(context.Background())
|
||||
preSealPhysical(c)
|
||||
|
||||
c.logger.Info("pre-seal teardown complete")
|
||||
return result
|
||||
@@ -1454,6 +1510,10 @@ func (c *Core) AuditedHeadersConfig() *AuditedHeadersConfig {
|
||||
return c.auditedHeaders
|
||||
}
|
||||
|
||||
func waitUntilWALShippedImpl(ctx context.Context, c *Core, index uint64) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func lastRemoteWALImpl(c *Core) uint64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/hashicorp/vault/audit"
|
||||
"github.com/hashicorp/vault/helper/consts"
|
||||
"github.com/hashicorp/vault/helper/logging"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/physical"
|
||||
"github.com/hashicorp/vault/physical/inmem"
|
||||
@@ -64,7 +65,7 @@ func TestCore_Unseal_MultiShare(t *testing.T) {
|
||||
SecretShares: 5,
|
||||
SecretThreshold: 3,
|
||||
}
|
||||
res, err := c.Initialize(context.Background(), &InitParams{
|
||||
res, err := c.Initialize(namespace.RootContext(nil), &InitParams{
|
||||
BarrierConfig: sealConf,
|
||||
RecoveryConfig: nil,
|
||||
})
|
||||
@@ -140,7 +141,7 @@ func TestCore_Unseal_Single(t *testing.T) {
|
||||
SecretShares: 1,
|
||||
SecretThreshold: 1,
|
||||
}
|
||||
res, err := c.Initialize(context.Background(), &InitParams{
|
||||
res, err := c.Initialize(namespace.RootContext(nil), &InitParams{
|
||||
BarrierConfig: sealConf,
|
||||
RecoveryConfig: nil,
|
||||
})
|
||||
@@ -180,17 +181,19 @@ func TestCore_Route_Sealed(t *testing.T) {
|
||||
SecretThreshold: 1,
|
||||
}
|
||||
|
||||
ctx := namespace.RootContext(nil)
|
||||
|
||||
// Should not route anything
|
||||
req := &logical.Request{
|
||||
Operation: logical.ReadOperation,
|
||||
Path: "sys/mounts",
|
||||
}
|
||||
_, err := c.HandleRequest(context.Background(), req)
|
||||
_, err := c.HandleRequest(ctx, req)
|
||||
if err != consts.ErrSealed {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
res, err := c.Initialize(context.Background(), &InitParams{
|
||||
res, err := c.Initialize(ctx, &InitParams{
|
||||
BarrierConfig: sealConf,
|
||||
RecoveryConfig: nil,
|
||||
})
|
||||
@@ -208,7 +211,7 @@ func TestCore_Route_Sealed(t *testing.T) {
|
||||
|
||||
// Should not error after unseal
|
||||
req.ClientToken = res.RootToken
|
||||
_, err = c.HandleRequest(context.Background(), req)
|
||||
_, err = c.HandleRequest(ctx, req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -256,10 +259,11 @@ func TestCore_Seal_BadToken(t *testing.T) {
|
||||
// GH-3497
|
||||
func TestCore_Seal_SingleUse(t *testing.T) {
|
||||
c, keys, _ := TestCoreUnsealed(t)
|
||||
c.tokenStore.create(context.Background(), &logical.TokenEntry{
|
||||
ID: "foo",
|
||||
NumUses: 1,
|
||||
Policies: []string{"root"},
|
||||
c.tokenStore.create(namespace.RootContext(nil), &logical.TokenEntry{
|
||||
ID: "foo",
|
||||
NumUses: 1,
|
||||
Policies: []string{"root"},
|
||||
NamespaceID: namespace.RootNamespaceID,
|
||||
})
|
||||
if err := c.Seal("foo"); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
@@ -279,7 +283,7 @@ func TestCore_Seal_SingleUse(t *testing.T) {
|
||||
if err := c.Seal("foo"); err == nil {
|
||||
t.Fatal("expected error from revoked token")
|
||||
}
|
||||
te, err := c.tokenStore.Lookup(context.Background(), "foo")
|
||||
te, err := c.tokenStore.Lookup(namespace.RootContext(nil), "foo")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -301,7 +305,8 @@ func TestCore_HandleRequest_Lease(t *testing.T) {
|
||||
},
|
||||
ClientToken: root,
|
||||
}
|
||||
resp, err := c.HandleRequest(context.Background(), req)
|
||||
ctx := namespace.RootContext(nil)
|
||||
resp, err := c.HandleRequest(ctx, req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -312,7 +317,7 @@ func TestCore_HandleRequest_Lease(t *testing.T) {
|
||||
// Read the key
|
||||
req.Operation = logical.ReadOperation
|
||||
req.Data = nil
|
||||
resp, err = c.HandleRequest(context.Background(), req)
|
||||
resp, err = c.HandleRequest(ctx, req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -342,7 +347,8 @@ func TestCore_HandleRequest_Lease_MaxLength(t *testing.T) {
|
||||
},
|
||||
ClientToken: root,
|
||||
}
|
||||
resp, err := c.HandleRequest(context.Background(), req)
|
||||
ctx := namespace.RootContext(nil)
|
||||
resp, err := c.HandleRequest(ctx, req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -353,7 +359,7 @@ func TestCore_HandleRequest_Lease_MaxLength(t *testing.T) {
|
||||
// Read the key
|
||||
req.Operation = logical.ReadOperation
|
||||
req.Data = nil
|
||||
resp, err = c.HandleRequest(context.Background(), req)
|
||||
resp, err = c.HandleRequest(ctx, req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -383,7 +389,8 @@ func TestCore_HandleRequest_Lease_DefaultLength(t *testing.T) {
|
||||
},
|
||||
ClientToken: root,
|
||||
}
|
||||
resp, err := c.HandleRequest(context.Background(), req)
|
||||
ctx := namespace.RootContext(nil)
|
||||
resp, err := c.HandleRequest(ctx, req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -394,7 +401,7 @@ func TestCore_HandleRequest_Lease_DefaultLength(t *testing.T) {
|
||||
// Read the key
|
||||
req.Operation = logical.ReadOperation
|
||||
req.Data = nil
|
||||
resp, err = c.HandleRequest(context.Background(), req)
|
||||
resp, err = c.HandleRequest(ctx, req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -423,7 +430,7 @@ func TestCore_HandleRequest_MissingToken(t *testing.T) {
|
||||
"lease": "1h",
|
||||
},
|
||||
}
|
||||
resp, err := c.HandleRequest(context.Background(), req)
|
||||
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err == nil || !errwrap.Contains(err, logical.ErrInvalidRequest.Error()) {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -444,7 +451,7 @@ func TestCore_HandleRequest_InvalidToken(t *testing.T) {
|
||||
},
|
||||
ClientToken: "foobarbaz",
|
||||
}
|
||||
resp, err := c.HandleRequest(context.Background(), req)
|
||||
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err == nil || !errwrap.Contains(err, logical.ErrPermissionDenied.Error()) {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -462,7 +469,7 @@ func TestCore_HandleRequest_NoSlash(t *testing.T) {
|
||||
Path: "secret",
|
||||
ClientToken: root,
|
||||
}
|
||||
resp, err := c.HandleRequest(context.Background(), req)
|
||||
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v, resp: %v", err, resp)
|
||||
}
|
||||
@@ -481,7 +488,7 @@ func TestCore_HandleRequest_RootPath(t *testing.T) {
|
||||
Path: "sys/policy", // root protected!
|
||||
ClientToken: "child",
|
||||
}
|
||||
resp, err := c.HandleRequest(context.Background(), req)
|
||||
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err == nil || !errwrap.Contains(err, logical.ErrPermissionDenied.Error()) {
|
||||
t.Fatalf("err: %v, resp: %v", err, resp)
|
||||
}
|
||||
@@ -500,7 +507,7 @@ func TestCore_HandleRequest_RootPath_WithSudo(t *testing.T) {
|
||||
},
|
||||
ClientToken: root,
|
||||
}
|
||||
resp, err := c.HandleRequest(context.Background(), req)
|
||||
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -515,7 +522,7 @@ func TestCore_HandleRequest_RootPath_WithSudo(t *testing.T) {
|
||||
Path: "sys/policy", // root protected!
|
||||
ClientToken: "child",
|
||||
}
|
||||
resp, err = c.HandleRequest(context.Background(), req)
|
||||
resp, err = c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -538,7 +545,7 @@ func TestCore_HandleRequest_PermissionDenied(t *testing.T) {
|
||||
},
|
||||
ClientToken: "child",
|
||||
}
|
||||
resp, err := c.HandleRequest(context.Background(), req)
|
||||
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err == nil || !errwrap.Contains(err, logical.ErrPermissionDenied.Error()) {
|
||||
t.Fatalf("err: %v, resp: %v", err, resp)
|
||||
}
|
||||
@@ -558,7 +565,7 @@ func TestCore_HandleRequest_PermissionAllowed(t *testing.T) {
|
||||
},
|
||||
ClientToken: root,
|
||||
}
|
||||
resp, err := c.HandleRequest(context.Background(), req)
|
||||
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -576,7 +583,7 @@ func TestCore_HandleRequest_PermissionAllowed(t *testing.T) {
|
||||
},
|
||||
ClientToken: "child",
|
||||
}
|
||||
resp, err = c.HandleRequest(context.Background(), req)
|
||||
resp, err = c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -599,7 +606,7 @@ func TestCore_HandleRequest_NoClientToken(t *testing.T) {
|
||||
req.Data["type"] = "noop"
|
||||
req.Data["description"] = "foo"
|
||||
req.ClientToken = root
|
||||
_, err := c.HandleRequest(context.Background(), req)
|
||||
_, err := c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -609,7 +616,7 @@ func TestCore_HandleRequest_NoClientToken(t *testing.T) {
|
||||
Path: "foo/login",
|
||||
}
|
||||
req.ClientToken = root
|
||||
if _, err := c.HandleRequest(context.Background(), req); err != nil {
|
||||
if _, err := c.HandleRequest(namespace.RootContext(nil), req); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
@@ -633,7 +640,7 @@ func TestCore_HandleRequest_ConnOnLogin(t *testing.T) {
|
||||
req := logical.TestRequest(t, logical.UpdateOperation, "sys/auth/foo")
|
||||
req.Data["type"] = "noop"
|
||||
req.ClientToken = root
|
||||
_, err := c.HandleRequest(context.Background(), req)
|
||||
_, err := c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -643,7 +650,7 @@ func TestCore_HandleRequest_ConnOnLogin(t *testing.T) {
|
||||
Path: "auth/foo/login",
|
||||
Connection: &logical.Connection{},
|
||||
}
|
||||
if _, err := c.HandleRequest(context.Background(), req); err != nil {
|
||||
if _, err := c.HandleRequest(namespace.RootContext(nil), req); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if noop.Requests[0].Connection == nil {
|
||||
@@ -674,7 +681,7 @@ func TestCore_HandleLogin_Token(t *testing.T) {
|
||||
req := logical.TestRequest(t, logical.UpdateOperation, "sys/auth/foo")
|
||||
req.Data["type"] = "noop"
|
||||
req.ClientToken = root
|
||||
_, err := c.HandleRequest(context.Background(), req)
|
||||
_, err := c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -683,7 +690,7 @@ func TestCore_HandleLogin_Token(t *testing.T) {
|
||||
lreq := &logical.Request{
|
||||
Path: "auth/foo/login",
|
||||
}
|
||||
lresp, err := c.HandleRequest(context.Background(), lreq)
|
||||
lresp, err := c.HandleRequest(namespace.RootContext(nil), lreq)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -695,7 +702,7 @@ func TestCore_HandleLogin_Token(t *testing.T) {
|
||||
}
|
||||
|
||||
// Check the policy and metadata
|
||||
te, err := c.tokenStore.Lookup(context.Background(), clientToken)
|
||||
te, err := c.tokenStore.Lookup(namespace.RootContext(nil), clientToken)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -711,6 +718,7 @@ func TestCore_HandleLogin_Token(t *testing.T) {
|
||||
DisplayName: "foo-armon",
|
||||
TTL: time.Hour * 24,
|
||||
CreationTime: te.CreationTime,
|
||||
NamespaceID: namespace.RootNamespaceID,
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(te, expect) {
|
||||
@@ -738,7 +746,7 @@ func TestCore_HandleRequest_AuditTrail(t *testing.T) {
|
||||
req := logical.TestRequest(t, logical.UpdateOperation, "sys/audit/noop")
|
||||
req.Data["type"] = "noop"
|
||||
req.ClientToken = root
|
||||
resp, err := c.HandleRequest(context.Background(), req)
|
||||
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -754,7 +762,7 @@ func TestCore_HandleRequest_AuditTrail(t *testing.T) {
|
||||
ClientToken: root,
|
||||
}
|
||||
req.ClientToken = root
|
||||
if _, err := c.HandleRequest(context.Background(), req); err != nil {
|
||||
if _, err := c.HandleRequest(namespace.RootContext(nil), req); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
@@ -802,7 +810,7 @@ func TestCore_HandleRequest_AuditTrail_noHMACKeys(t *testing.T) {
|
||||
req := logical.TestRequest(t, logical.UpdateOperation, "sys/mounts/secret/tune")
|
||||
req.Data["audit_non_hmac_request_keys"] = "foo"
|
||||
req.ClientToken = root
|
||||
resp, err := c.HandleRequest(context.Background(), req)
|
||||
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -810,7 +818,7 @@ func TestCore_HandleRequest_AuditTrail_noHMACKeys(t *testing.T) {
|
||||
req = logical.TestRequest(t, logical.UpdateOperation, "sys/mounts/secret/tune")
|
||||
req.Data["audit_non_hmac_response_keys"] = "baz"
|
||||
req.ClientToken = root
|
||||
resp, err = c.HandleRequest(context.Background(), req)
|
||||
resp, err = c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -819,7 +827,7 @@ func TestCore_HandleRequest_AuditTrail_noHMACKeys(t *testing.T) {
|
||||
req = logical.TestRequest(t, logical.UpdateOperation, "sys/audit/noop")
|
||||
req.Data["type"] = "noop"
|
||||
req.ClientToken = root
|
||||
resp, err = c.HandleRequest(context.Background(), req)
|
||||
resp, err = c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -834,7 +842,7 @@ func TestCore_HandleRequest_AuditTrail_noHMACKeys(t *testing.T) {
|
||||
ClientToken: root,
|
||||
}
|
||||
req.ClientToken = root
|
||||
if _, err := c.HandleRequest(context.Background(), req); err != nil {
|
||||
if _, err := c.HandleRequest(namespace.RootContext(nil), req); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
@@ -876,7 +884,7 @@ func TestCore_HandleRequest_AuditTrail_noHMACKeys(t *testing.T) {
|
||||
ClientToken: root,
|
||||
}
|
||||
req.ClientToken = root
|
||||
if _, err := c.HandleRequest(context.Background(), req); err != nil {
|
||||
if _, err := c.HandleRequest(namespace.RootContext(nil), req); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if len(noop.RespNonHMACKeys) != 1 || noop.RespNonHMACKeys[0] != "baz" {
|
||||
@@ -920,7 +928,7 @@ func TestCore_HandleLogin_AuditTrail(t *testing.T) {
|
||||
req := logical.TestRequest(t, logical.UpdateOperation, "sys/auth/foo")
|
||||
req.Data["type"] = "noop"
|
||||
req.ClientToken = root
|
||||
_, err := c.HandleRequest(context.Background(), req)
|
||||
_, err := c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -929,7 +937,7 @@ func TestCore_HandleLogin_AuditTrail(t *testing.T) {
|
||||
req = logical.TestRequest(t, logical.UpdateOperation, "sys/audit/noop")
|
||||
req.Data["type"] = "noop"
|
||||
req.ClientToken = root
|
||||
_, err = c.HandleRequest(context.Background(), req)
|
||||
_, err = c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -938,7 +946,7 @@ func TestCore_HandleLogin_AuditTrail(t *testing.T) {
|
||||
lreq := &logical.Request{
|
||||
Path: "auth/foo/login",
|
||||
}
|
||||
lresp, err := c.HandleRequest(context.Background(), lreq)
|
||||
lresp, err := c.HandleRequest(namespace.RootContext(nil), lreq)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -983,7 +991,7 @@ func TestCore_HandleRequest_CreateToken_Lease(t *testing.T) {
|
||||
req := logical.TestRequest(t, logical.UpdateOperation, "auth/token/create")
|
||||
req.ClientToken = root
|
||||
req.Data["policies"] = []string{"foo"}
|
||||
resp, err := c.HandleRequest(context.Background(), req)
|
||||
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -998,7 +1006,7 @@ func TestCore_HandleRequest_CreateToken_Lease(t *testing.T) {
|
||||
}
|
||||
|
||||
// Check the policy and metadata
|
||||
te, err := c.tokenStore.Lookup(context.Background(), clientToken)
|
||||
te, err := c.tokenStore.Lookup(namespace.RootContext(nil), clientToken)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1011,6 +1019,7 @@ func TestCore_HandleRequest_CreateToken_Lease(t *testing.T) {
|
||||
DisplayName: "token",
|
||||
CreationTime: te.CreationTime,
|
||||
TTL: time.Hour * 24 * 32,
|
||||
NamespaceID: namespace.RootNamespaceID,
|
||||
}
|
||||
if !reflect.DeepEqual(te, expect) {
|
||||
t.Fatalf("Bad: %#v expect: %#v", te, expect)
|
||||
@@ -1031,7 +1040,7 @@ func TestCore_HandleRequest_CreateToken_NoDefaultPolicy(t *testing.T) {
|
||||
req.ClientToken = root
|
||||
req.Data["policies"] = []string{"foo"}
|
||||
req.Data["no_default_policy"] = true
|
||||
resp, err := c.HandleRequest(context.Background(), req)
|
||||
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1043,7 +1052,7 @@ func TestCore_HandleRequest_CreateToken_NoDefaultPolicy(t *testing.T) {
|
||||
}
|
||||
|
||||
// Check the policy and metadata
|
||||
te, err := c.tokenStore.Lookup(context.Background(), clientToken)
|
||||
te, err := c.tokenStore.Lookup(namespace.RootContext(nil), clientToken)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1056,6 +1065,7 @@ func TestCore_HandleRequest_CreateToken_NoDefaultPolicy(t *testing.T) {
|
||||
DisplayName: "token",
|
||||
CreationTime: te.CreationTime,
|
||||
TTL: time.Hour * 24 * 32,
|
||||
NamespaceID: namespace.RootNamespaceID,
|
||||
}
|
||||
if !reflect.DeepEqual(te, expect) {
|
||||
t.Fatalf("Bad: %#v expect: %#v", te, expect)
|
||||
@@ -1069,7 +1079,7 @@ func TestCore_LimitedUseToken(t *testing.T) {
|
||||
req := logical.TestRequest(t, logical.UpdateOperation, "auth/token/create")
|
||||
req.ClientToken = root
|
||||
req.Data["num_uses"] = "1"
|
||||
resp, err := c.HandleRequest(context.Background(), req)
|
||||
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1083,13 +1093,13 @@ func TestCore_LimitedUseToken(t *testing.T) {
|
||||
},
|
||||
ClientToken: resp.Auth.ClientToken,
|
||||
}
|
||||
_, err = c.HandleRequest(context.Background(), req)
|
||||
_, err = c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// Second operation should fail
|
||||
_, err = c.HandleRequest(context.Background(), req)
|
||||
_, err = c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err == nil || !errwrap.Contains(err, logical.ErrPermissionDenied.Error()) {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1310,7 +1320,7 @@ func TestCore_StepDown(t *testing.T) {
|
||||
}
|
||||
|
||||
// Step down core
|
||||
err = core.StepDown(context.Background(), req)
|
||||
err = core.StepDown(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatal("error stepping down core 1")
|
||||
}
|
||||
@@ -1352,7 +1362,7 @@ func TestCore_StepDown(t *testing.T) {
|
||||
}
|
||||
|
||||
// Step down core2
|
||||
err = core2.StepDown(context.Background(), req)
|
||||
err = core2.StepDown(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatal("error stepping down core 1")
|
||||
}
|
||||
@@ -1446,13 +1456,13 @@ func TestCore_CleanLeaderPrefix(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
core.barrier.Put(context.Background(), &Entry{
|
||||
core.barrier.Put(namespace.RootContext(nil), &Entry{
|
||||
Key: coreLeaderPrefix + keyUUID,
|
||||
Value: []byte(valueUUID),
|
||||
})
|
||||
}
|
||||
|
||||
entries, err := core.barrier.List(context.Background(), coreLeaderPrefix)
|
||||
entries, err := core.barrier.List(namespace.RootContext(nil), coreLeaderPrefix)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1548,7 +1558,7 @@ func TestCore_CleanLeaderPrefix(t *testing.T) {
|
||||
// Give time for the entries to clear out; it is conservative at 1/second
|
||||
time.Sleep(10 * leaderPrefixCleanDelay)
|
||||
|
||||
entries, err = core2.barrier.List(context.Background(), coreLeaderPrefix)
|
||||
entries, err = core2.barrier.List(namespace.RootContext(nil), coreLeaderPrefix)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1619,7 +1629,7 @@ func testCore_Standby_Common(t *testing.T, inm physical.Backend, inmha physical.
|
||||
},
|
||||
ClientToken: root,
|
||||
}
|
||||
_, err = core.HandleRequest(context.Background(), req)
|
||||
_, err = core.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1668,7 +1678,7 @@ func testCore_Standby_Common(t *testing.T, inm physical.Backend, inmha physical.
|
||||
}
|
||||
|
||||
// Request should fail in standby mode
|
||||
_, err = core2.HandleRequest(context.Background(), req)
|
||||
_, err = core2.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != consts.ErrStandby {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1709,7 +1719,7 @@ func testCore_Standby_Common(t *testing.T, inm physical.Backend, inmha physical.
|
||||
Path: "secret/foo",
|
||||
ClientToken: root,
|
||||
}
|
||||
resp, err := core2.HandleRequest(context.Background(), req)
|
||||
resp, err := core2.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1772,7 +1782,7 @@ func TestCore_HandleRequest_Login_InternalData(t *testing.T) {
|
||||
req := logical.TestRequest(t, logical.UpdateOperation, "sys/auth/foo")
|
||||
req.Data["type"] = "noop"
|
||||
req.ClientToken = root
|
||||
_, err := c.HandleRequest(context.Background(), req)
|
||||
_, err := c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1781,7 +1791,7 @@ func TestCore_HandleRequest_Login_InternalData(t *testing.T) {
|
||||
lreq := &logical.Request{
|
||||
Path: "auth/foo/login",
|
||||
}
|
||||
lresp, err := c.HandleRequest(context.Background(), lreq)
|
||||
lresp, err := c.HandleRequest(namespace.RootContext(nil), lreq)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1816,7 +1826,7 @@ func TestCore_HandleRequest_InternalData(t *testing.T) {
|
||||
req := logical.TestRequest(t, logical.UpdateOperation, "sys/mounts/foo")
|
||||
req.Data["type"] = "noop"
|
||||
req.ClientToken = root
|
||||
_, err := c.HandleRequest(context.Background(), req)
|
||||
_, err := c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1827,7 +1837,7 @@ func TestCore_HandleRequest_InternalData(t *testing.T) {
|
||||
Path: "foo/test",
|
||||
ClientToken: root,
|
||||
}
|
||||
lresp, err := c.HandleRequest(context.Background(), lreq)
|
||||
lresp, err := c.HandleRequest(namespace.RootContext(nil), lreq)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1859,7 +1869,7 @@ func TestCore_HandleLogin_ReturnSecret(t *testing.T) {
|
||||
req := logical.TestRequest(t, logical.UpdateOperation, "sys/auth/foo")
|
||||
req.Data["type"] = "noop"
|
||||
req.ClientToken = root
|
||||
_, err := c.HandleRequest(context.Background(), req)
|
||||
_, err := c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1868,7 +1878,7 @@ func TestCore_HandleLogin_ReturnSecret(t *testing.T) {
|
||||
lreq := &logical.Request{
|
||||
Path: "auth/foo/login",
|
||||
}
|
||||
_, err = c.HandleRequest(context.Background(), lreq)
|
||||
_, err = c.HandleRequest(namespace.RootContext(nil), lreq)
|
||||
if err != ErrInternalError {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1888,7 +1898,7 @@ func TestCore_RenewSameLease(t *testing.T) {
|
||||
},
|
||||
ClientToken: root,
|
||||
}
|
||||
resp, err := c.HandleRequest(context.Background(), req)
|
||||
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1899,7 +1909,7 @@ func TestCore_RenewSameLease(t *testing.T) {
|
||||
// Read the key
|
||||
req.Operation = logical.ReadOperation
|
||||
req.Data = nil
|
||||
resp, err = c.HandleRequest(context.Background(), req)
|
||||
resp, err = c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1911,7 +1921,7 @@ func TestCore_RenewSameLease(t *testing.T) {
|
||||
// Renew the lease
|
||||
req = logical.TestRequest(t, logical.UpdateOperation, "sys/renew/"+resp.Secret.LeaseID)
|
||||
req.ClientToken = root
|
||||
resp, err = c.HandleRequest(context.Background(), req)
|
||||
resp, err = c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1924,7 +1934,7 @@ func TestCore_RenewSameLease(t *testing.T) {
|
||||
// Renew the lease (alternate path)
|
||||
req = logical.TestRequest(t, logical.UpdateOperation, "sys/leases/renew/"+resp.Secret.LeaseID)
|
||||
req.ClientToken = root
|
||||
resp, err = c.HandleRequest(context.Background(), req)
|
||||
resp, err = c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1948,7 +1958,7 @@ func TestCore_RenewToken_SingleRegister(t *testing.T) {
|
||||
},
|
||||
ClientToken: root,
|
||||
}
|
||||
resp, err := c.HandleRequest(context.Background(), req)
|
||||
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1960,7 +1970,7 @@ func TestCore_RenewToken_SingleRegister(t *testing.T) {
|
||||
req.Data = map[string]interface{}{
|
||||
"token": newClient,
|
||||
}
|
||||
resp, err = c.HandleRequest(context.Background(), req)
|
||||
resp, err = c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1968,7 +1978,7 @@ func TestCore_RenewToken_SingleRegister(t *testing.T) {
|
||||
// Revoke using the renew prefix
|
||||
req = logical.TestRequest(t, logical.UpdateOperation, "sys/revoke-prefix/auth/token/renew/")
|
||||
req.ClientToken = root
|
||||
resp, err = c.HandleRequest(context.Background(), req)
|
||||
resp, err = c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1979,7 +1989,7 @@ func TestCore_RenewToken_SingleRegister(t *testing.T) {
|
||||
"token": newClient,
|
||||
}
|
||||
req.ClientToken = newClient
|
||||
resp, err = c.HandleRequest(context.Background(), req)
|
||||
resp, err = c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -2014,8 +2024,8 @@ path "secret/*" {
|
||||
`
|
||||
|
||||
ps := c.policyStore
|
||||
policy, _ := ParseACLPolicy(secretWritingPolicy)
|
||||
if err := ps.SetPolicy(context.Background(), policy); err != nil {
|
||||
policy, _ := ParseACLPolicy(namespace.RootNamespace, secretWritingPolicy)
|
||||
if err := ps.SetPolicy(namespace.RootContext(nil), policy); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -2023,7 +2033,7 @@ path "secret/*" {
|
||||
req := logical.TestRequest(t, logical.UpdateOperation, "sys/auth/foo")
|
||||
req.Data["type"] = "noop"
|
||||
req.ClientToken = root
|
||||
_, err := c.HandleRequest(context.Background(), req)
|
||||
_, err := c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -2032,7 +2042,7 @@ path "secret/*" {
|
||||
lreq := &logical.Request{
|
||||
Path: "auth/foo/login",
|
||||
}
|
||||
lresp, err := c.HandleRequest(context.Background(), lreq)
|
||||
lresp, err := c.HandleRequest(namespace.RootContext(nil), lreq)
|
||||
if err == nil || lresp == nil || !lresp.IsError() {
|
||||
t.Fatalf("expected error trying to auth and receive root policy")
|
||||
}
|
||||
@@ -2042,7 +2052,7 @@ path "secret/*" {
|
||||
lreq = &logical.Request{
|
||||
Path: "auth/foo/login",
|
||||
}
|
||||
lresp, err = c.HandleRequest(context.Background(), lreq)
|
||||
lresp, err = c.HandleRequest(namespace.RootContext(nil), lreq)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -2057,7 +2067,7 @@ path "secret/*" {
|
||||
},
|
||||
ClientToken: lresp.Auth.ClientToken,
|
||||
}
|
||||
resp, err := c.HandleRequest(context.Background(), req)
|
||||
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -2068,7 +2078,7 @@ path "secret/*" {
|
||||
// Read the key
|
||||
req.Operation = logical.ReadOperation
|
||||
req.Data = nil
|
||||
resp, err = c.HandleRequest(context.Background(), req)
|
||||
resp, err = c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -2082,7 +2092,7 @@ path "secret/*" {
|
||||
"lease_id": resp.Secret.LeaseID,
|
||||
}
|
||||
req.ClientToken = lresp.Auth.ClientToken
|
||||
_, err = c.HandleRequest(context.Background(), req)
|
||||
_, err = c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -2090,7 +2100,7 @@ path "secret/*" {
|
||||
// Disable the credential backend
|
||||
req = logical.TestRequest(t, logical.DeleteOperation, "sys/auth/foo")
|
||||
req.ClientToken = root
|
||||
resp, err = c.HandleRequest(context.Background(), req)
|
||||
resp, err = c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v %#v", err, resp)
|
||||
}
|
||||
@@ -2110,7 +2120,7 @@ func TestCore_HandleRequest_MountPointType(t *testing.T) {
|
||||
req.Data["type"] = "noop"
|
||||
req.Data["description"] = "foo"
|
||||
req.ClientToken = root
|
||||
_, err := c.HandleRequest(context.Background(), req)
|
||||
_, err := c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -2122,7 +2132,7 @@ func TestCore_HandleRequest_MountPointType(t *testing.T) {
|
||||
Connection: &logical.Connection{},
|
||||
}
|
||||
req.ClientToken = root
|
||||
if _, err := c.HandleRequest(context.Background(), req); err != nil {
|
||||
if _, err := c.HandleRequest(namespace.RootContext(nil), req); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
@@ -2194,7 +2204,7 @@ func TestCore_Standby_Rotate(t *testing.T) {
|
||||
Path: "sys/rotate",
|
||||
ClientToken: root,
|
||||
}
|
||||
_, err = core.HandleRequest(context.Background(), req)
|
||||
_, err = core.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -2214,7 +2224,7 @@ func TestCore_Standby_Rotate(t *testing.T) {
|
||||
Path: "sys/key-status",
|
||||
ClientToken: root,
|
||||
}
|
||||
resp, err := core2.HandleRequest(context.Background(), req)
|
||||
resp, err := core2.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -2242,7 +2252,7 @@ func TestCore_HandleRequest_Headers(t *testing.T) {
|
||||
req := logical.TestRequest(t, logical.UpdateOperation, "sys/mounts/foo")
|
||||
req.Data["type"] = "noop"
|
||||
req.ClientToken = root
|
||||
_, err := c.HandleRequest(context.Background(), req)
|
||||
_, err := c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -2251,7 +2261,7 @@ func TestCore_HandleRequest_Headers(t *testing.T) {
|
||||
req = logical.TestRequest(t, logical.UpdateOperation, "sys/mounts/foo/tune")
|
||||
req.Data["passthrough_request_headers"] = []string{"Should-Passthrough", "should-passthrough-case-insensitive"}
|
||||
req.ClientToken = root
|
||||
_, err = c.HandleRequest(context.Background(), req)
|
||||
_, err = c.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -2267,7 +2277,7 @@ func TestCore_HandleRequest_Headers(t *testing.T) {
|
||||
"Should-Not-Passthrough": []string{"bar"},
|
||||
},
|
||||
}
|
||||
_, err = c.HandleRequest(context.Background(), lreq)
|
||||
_, err = c.HandleRequest(namespace.RootContext(nil), lreq)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
102
vault/core_util.go
Normal file
102
vault/core_util.go
Normal file
@@ -0,0 +1,102 @@
|
||||
// +build !enterprise
|
||||
|
||||
package vault
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/hashicorp/vault/helper/license"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/physical"
|
||||
)
|
||||
|
||||
type entCore struct{}
|
||||
|
||||
type LicensingConfig struct{}
|
||||
|
||||
func coreInit(c *Core, conf *CoreConfig) error {
|
||||
phys := conf.Physical
|
||||
_, txnOK := phys.(physical.Transactional)
|
||||
sealUnwrapperLogger := conf.Logger.Named("storage.sealunwrapper")
|
||||
c.allLoggers = append(c.allLoggers, sealUnwrapperLogger)
|
||||
c.sealUnwrapper = NewSealUnwrapper(phys, sealUnwrapperLogger)
|
||||
// Wrap the physical backend in a cache layer if enabled
|
||||
cacheLogger := c.baseLogger.Named("storage.cache")
|
||||
c.allLoggers = append(c.allLoggers, cacheLogger)
|
||||
if txnOK {
|
||||
c.physical = physical.NewTransactionalCache(c.sealUnwrapper, conf.CacheSize, cacheLogger)
|
||||
} else {
|
||||
c.physical = physical.NewCache(c.sealUnwrapper, conf.CacheSize, cacheLogger)
|
||||
}
|
||||
c.physicalCache = c.physical.(physical.ToggleablePurgemonster)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createSecondaries(*Core, *CoreConfig) {}
|
||||
|
||||
func addExtraLogicalBackends(*Core, map[string]logical.Factory) {}
|
||||
|
||||
func addExtraCredentialBackends(*Core, map[string]logical.Factory) {}
|
||||
|
||||
func preUnsealInternal(context.Context, *Core) error { return nil }
|
||||
|
||||
func postSealInternal(*Core) {}
|
||||
|
||||
func preSealPhysical(c *Core) {
|
||||
switch c.sealUnwrapper.(type) {
|
||||
case *sealUnwrapper:
|
||||
c.sealUnwrapper.(*sealUnwrapper).stopUnwraps()
|
||||
case *transactionalSealUnwrapper:
|
||||
c.sealUnwrapper.(*transactionalSealUnwrapper).stopUnwraps()
|
||||
}
|
||||
|
||||
// Purge the cache
|
||||
c.physicalCache.SetEnabled(false)
|
||||
c.physicalCache.Purge(context.Background())
|
||||
}
|
||||
|
||||
func postUnsealPhysical(c *Core) error {
|
||||
switch c.sealUnwrapper.(type) {
|
||||
case *sealUnwrapper:
|
||||
c.sealUnwrapper.(*sealUnwrapper).runUnwraps()
|
||||
case *transactionalSealUnwrapper:
|
||||
c.sealUnwrapper.(*transactionalSealUnwrapper).runUnwraps()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadMFAConfigs(context.Context, *Core) error { return nil }
|
||||
|
||||
func shouldStartClusterListener(*Core) bool { return true }
|
||||
|
||||
func hasNamespaces(*Core) bool { return false }
|
||||
|
||||
func (c *Core) Features() license.Features {
|
||||
return license.FeatureNone
|
||||
}
|
||||
|
||||
func (c *Core) HasFeature(license.Features) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *Core) namepaceByPath(string) *namespace.Namespace {
|
||||
return namespace.RootNamespace
|
||||
}
|
||||
|
||||
func (c *Core) setupReplicatedClusterPrimary(*ReplicatedCluster) error { return nil }
|
||||
|
||||
func (c *Core) perfStandbyCount() int { return 0 }
|
||||
|
||||
func (c *Core) removePrefixFromFilteredPaths(context.Context, string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Core) checkReplicatedFiltering(context.Context, *MountEntry, string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (c *Core) invalidateSentinelPolicy(PolicyType, string) {}
|
||||
|
||||
func (c *Core) removePerfStandbySecondary(context.Context, string) {}
|
||||
@@ -6,7 +6,10 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
|
||||
"github.com/hashicorp/vault/helper/consts"
|
||||
"github.com/hashicorp/vault/helper/license"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/helper/pluginutil"
|
||||
"github.com/hashicorp/vault/helper/wrapping"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
@@ -42,14 +45,35 @@ func (d dynamicSystemView) SudoPrivilege(ctx context.Context, path string, token
|
||||
return false
|
||||
}
|
||||
|
||||
// Construct the corresponding ACL object
|
||||
entity, entityPolicies, err := d.core.fetchEntityAndDerivedPolicies(te.EntityID)
|
||||
policies := make(map[string][]string)
|
||||
// Add token policies
|
||||
policies[te.NamespaceID] = append(policies[te.NamespaceID], te.Policies...)
|
||||
|
||||
tokenNS, err := NamespaceByID(ctx, te.NamespaceID, d.core)
|
||||
if err != nil {
|
||||
d.core.logger.Error("failed to fetch entity information", "error", err)
|
||||
d.core.logger.Error("failed to lookup token namespace", "error", err)
|
||||
return false
|
||||
}
|
||||
if tokenNS == nil {
|
||||
d.core.logger.Error("failed to lookup token namespace", "error", namespace.ErrNoNamespace)
|
||||
return false
|
||||
}
|
||||
|
||||
acl, err := d.core.policyStore.ACL(ctx, entity, append(entityPolicies, te.Policies...)...)
|
||||
// Add identity policies from all the namespaces
|
||||
entity, identityPolicies, err := d.core.fetchEntityAndDerivedPolicies(ctx, tokenNS, te.EntityID)
|
||||
if err != nil {
|
||||
d.core.logger.Error("failed to fetch identity policies", "error", err)
|
||||
return false
|
||||
}
|
||||
for nsID, nsPolicies := range identityPolicies {
|
||||
policies[nsID] = append(policies[nsID], nsPolicies...)
|
||||
}
|
||||
|
||||
tokenCtx := namespace.ContextWithNamespace(ctx, tokenNS)
|
||||
|
||||
// Construct the corresponding ACL object. Derive and use a new context that
|
||||
// uses the req.ClientToken's namespace
|
||||
acl, err := d.core.policyStore.ACL(tokenCtx, entity, policies)
|
||||
if err != nil {
|
||||
d.core.logger.Error("failed to retrieve ACL for token's policies", "token_policies", te.Policies, "error", err)
|
||||
return false
|
||||
@@ -61,7 +85,7 @@ func (d dynamicSystemView) SudoPrivilege(ctx context.Context, path string, token
|
||||
req := new(logical.Request)
|
||||
req.Operation = logical.ReadOperation
|
||||
req.Path = path
|
||||
authResults := acl.AllowOperation(req)
|
||||
authResults := acl.AllowOperation(ctx, req, true)
|
||||
return authResults.RootPrivs
|
||||
}
|
||||
|
||||
@@ -71,11 +95,13 @@ func (d dynamicSystemView) fetchTTLs() (def, max time.Duration) {
|
||||
def = d.core.defaultLeaseTTL
|
||||
max = d.core.maxLeaseTTL
|
||||
|
||||
if d.mountEntry.Config.DefaultLeaseTTL != 0 {
|
||||
def = d.mountEntry.Config.DefaultLeaseTTL
|
||||
}
|
||||
if d.mountEntry.Config.MaxLeaseTTL != 0 {
|
||||
max = d.mountEntry.Config.MaxLeaseTTL
|
||||
if d.mountEntry != nil {
|
||||
if d.mountEntry.Config.DefaultLeaseTTL != 0 {
|
||||
def = d.mountEntry.Config.DefaultLeaseTTL
|
||||
}
|
||||
if d.mountEntry.Config.MaxLeaseTTL != 0 {
|
||||
max = d.mountEntry.Config.MaxLeaseTTL
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
@@ -98,7 +124,15 @@ func (d dynamicSystemView) LocalMount() bool {
|
||||
// Checks if this is a primary Vault instance. Caller should hold the stateLock
|
||||
// in read mode.
|
||||
func (d dynamicSystemView) ReplicationState() consts.ReplicationState {
|
||||
return d.core.ReplicationState()
|
||||
state := d.core.ReplicationState()
|
||||
if d.core.perfStandby {
|
||||
state |= consts.ReplicationPerformanceStandby
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
func (d dynamicSystemView) HasFeature(feature license.Features) bool {
|
||||
return d.core.HasFeature(feature)
|
||||
}
|
||||
|
||||
// ResponseWrapData wraps the given data in a cubbyhole and returns the
|
||||
|
||||
@@ -13,14 +13,14 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/armon/go-metrics"
|
||||
log "github.com/hashicorp/go-hclog"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
log "github.com/hashicorp/go-hclog"
|
||||
multierror "github.com/hashicorp/go-multierror"
|
||||
"github.com/hashicorp/go-uuid"
|
||||
"github.com/hashicorp/vault/helper/base62"
|
||||
"github.com/hashicorp/vault/helper/consts"
|
||||
"github.com/hashicorp/vault/helper/jsonutil"
|
||||
"github.com/hashicorp/vault/helper/locksutil"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/logical/framework"
|
||||
)
|
||||
@@ -86,11 +86,52 @@ type ExpirationManager struct {
|
||||
leaseCheckCounter *uint32
|
||||
|
||||
logLeaseExpirations bool
|
||||
expireFunc ExpireLeaseStrategy
|
||||
}
|
||||
|
||||
type ExpireLeaseStrategy func(context.Context, *ExpirationManager, *leaseEntry)
|
||||
|
||||
// revokeIDFunc is invoked when a given ID is expired
|
||||
func expireLeaseStrategyRevoke(ctx context.Context, m *ExpirationManager, le *leaseEntry) {
|
||||
for attempt := uint(0); attempt < maxRevokeAttempts; attempt++ {
|
||||
revokeCtx, cancel := context.WithTimeout(ctx, DefaultMaxRequestDuration)
|
||||
revokeCtx = namespace.ContextWithNamespace(revokeCtx, le.namespace)
|
||||
|
||||
go func() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case <-m.quitCh:
|
||||
cancel()
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-m.quitCh:
|
||||
m.logger.Error("shutting down, not attempting further revocation of lease", "lease_id", le.LeaseID)
|
||||
return
|
||||
case <-m.quitContext.Done():
|
||||
m.logger.Error("core context canceled, not attempting further revocation of lease", "lease_id", le.LeaseID)
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
m.coreStateLock.RLock()
|
||||
err := m.Revoke(revokeCtx, le.LeaseID)
|
||||
m.coreStateLock.RUnlock()
|
||||
cancel()
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
m.logger.Error("failed to revoke lease", "lease_id", le.LeaseID, "error", err)
|
||||
time.Sleep((1 << attempt) * revokeRetryBase)
|
||||
}
|
||||
m.logger.Error("maximum revoke attempts reached", "lease_id", le.LeaseID)
|
||||
}
|
||||
|
||||
// NewExpirationManager creates a new ExpirationManager that is backed
|
||||
// using a given view, and uses the provided router for revocation.
|
||||
func NewExpirationManager(c *Core, view *BarrierView, logger log.Logger) *ExpirationManager {
|
||||
func NewExpirationManager(c *Core, view *BarrierView, e ExpireLeaseStrategy, logger log.Logger) *ExpirationManager {
|
||||
exp := &ExpirationManager{
|
||||
core: c,
|
||||
router: c.router,
|
||||
@@ -112,6 +153,7 @@ func NewExpirationManager(c *Core, view *BarrierView, logger log.Logger) *Expira
|
||||
leaseCheckCounter: new(uint32),
|
||||
|
||||
logLeaseExpirations: os.Getenv("VAULT_SKIP_LOGGING_LEASE_EXPIRATIONS") == "",
|
||||
expireFunc: e,
|
||||
}
|
||||
*exp.restoreMode = 1
|
||||
|
||||
@@ -125,7 +167,7 @@ func NewExpirationManager(c *Core, view *BarrierView, logger log.Logger) *Expira
|
||||
|
||||
// setupExpiration is invoked after we've loaded the mount table to
|
||||
// initialize the expiration manager
|
||||
func (c *Core) setupExpiration() error {
|
||||
func (c *Core) setupExpiration(e ExpireLeaseStrategy) error {
|
||||
c.metricsMutex.Lock()
|
||||
defer c.metricsMutex.Unlock()
|
||||
// Create a sub-view
|
||||
@@ -134,7 +176,7 @@ func (c *Core) setupExpiration() error {
|
||||
// Create the manager
|
||||
expLogger := c.baseLogger.Named("expiration")
|
||||
c.AddLogger(expLogger)
|
||||
mgr := NewExpirationManager(c, view, expLogger)
|
||||
mgr := NewExpirationManager(c, view, e, expLogger)
|
||||
c.expiration = mgr
|
||||
|
||||
// Link the token store to this
|
||||
@@ -182,13 +224,28 @@ func (m *ExpirationManager) inRestoreMode() bool {
|
||||
return atomic.LoadInt32(m.restoreMode) == 1
|
||||
}
|
||||
|
||||
func (m *ExpirationManager) invalidate(key string) {
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(key, leaseViewPrefix):
|
||||
// Clear from the pending expiration
|
||||
leaseID := strings.TrimPrefix(key, leaseViewPrefix)
|
||||
m.pendingLock.Lock()
|
||||
if pending, ok := m.pending[leaseID]; ok {
|
||||
pending.timer.Stop()
|
||||
delete(m.pending, leaseID)
|
||||
}
|
||||
m.pendingLock.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// Tidy cleans up the dangling storage entries for leases. It scans the storage
|
||||
// view to find all the available leases, checks if the token embedded in it is
|
||||
// either empty or invalid and in both the cases, it revokes them. It also uses
|
||||
// a token cache to avoid multiple lookups of the same token ID. It is normally
|
||||
// not required to use the API that invokes this. This is only intended to
|
||||
// clean up the corrupt storage due to bugs.
|
||||
func (m *ExpirationManager) Tidy() error {
|
||||
func (m *ExpirationManager) Tidy(ctx context.Context) error {
|
||||
if m.inRestoreMode() {
|
||||
return errors.New("cannot run tidy while restoring leases")
|
||||
}
|
||||
@@ -218,7 +275,7 @@ func (m *ExpirationManager) Tidy() error {
|
||||
logger.Info("tidying leases", "progress", countLease)
|
||||
}
|
||||
|
||||
le, err := m.loadEntry(m.quitContext, leaseID)
|
||||
le, err := m.loadEntry(ctx, leaseID)
|
||||
if err != nil {
|
||||
tidyErrors = multierror.Append(tidyErrors, errwrap.Wrapf(fmt.Sprintf("failed to load the lease ID %q: {{err}}", leaseID), err))
|
||||
return
|
||||
@@ -240,14 +297,9 @@ func (m *ExpirationManager) Tidy() error {
|
||||
|
||||
isValid, ok = tokenCache[le.ClientToken]
|
||||
if !ok {
|
||||
saltedID, err := m.tokenStore.SaltID(m.quitContext, le.ClientToken)
|
||||
if err != nil {
|
||||
tidyErrors = multierror.Append(tidyErrors, errwrap.Wrapf("failed to lookup salt id: {{err}}", err))
|
||||
return
|
||||
}
|
||||
lock := locksutil.LockForKey(m.tokenStore.tokenLocks, le.ClientToken)
|
||||
lock.RLock()
|
||||
te, err := m.tokenStore.lookupSalted(m.quitContext, saltedID, true)
|
||||
te, err := m.tokenStore.lookupInternal(ctx, le.ClientToken, false, true)
|
||||
lock.RUnlock()
|
||||
|
||||
if err != nil {
|
||||
@@ -279,7 +331,7 @@ func (m *ExpirationManager) Tidy() error {
|
||||
if revokeLease {
|
||||
// Force the revocation and skip going through the token store
|
||||
// again
|
||||
err = m.revokeCommon(m.quitContext, leaseID, true, true)
|
||||
err = m.revokeCommon(ctx, leaseID, true, true)
|
||||
if err != nil {
|
||||
tidyErrors = multierror.Append(tidyErrors, errwrap.Wrapf(fmt.Sprintf("failed to revoke an invalid lease with ID %q: {{err}}", leaseID), err))
|
||||
return
|
||||
@@ -288,7 +340,12 @@ func (m *ExpirationManager) Tidy() error {
|
||||
}
|
||||
}
|
||||
|
||||
if err := logical.ScanView(m.quitContext, m.idView, tidyFunc); err != nil {
|
||||
ns, err := namespace.FromContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
leaseView := m.leaseView(ns)
|
||||
if err := logical.ScanView(m.quitContext, leaseView, tidyFunc); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -330,14 +387,18 @@ func (m *ExpirationManager) Restore(errorFunc func()) (retErr error) {
|
||||
|
||||
// Accumulate existing leases
|
||||
m.logger.Debug("collecting leases")
|
||||
existing, err := logical.CollectKeys(m.quitContext, m.idView)
|
||||
existing, leaseCount, err := m.collectLeases()
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("failed to scan for leases: {{err}}", err)
|
||||
return err
|
||||
}
|
||||
m.logger.Debug("leases collected", "num_existing", len(existing))
|
||||
m.logger.Debug("leases collected", "num_existing", leaseCount)
|
||||
|
||||
// Make the channels used for the worker pool
|
||||
broker := make(chan string)
|
||||
type lease struct {
|
||||
namespace *namespace.Namespace
|
||||
id string
|
||||
}
|
||||
broker := make(chan *lease)
|
||||
quit := make(chan bool)
|
||||
// Buffer these channels to prevent deadlocks
|
||||
errs := make(chan error, len(existing))
|
||||
@@ -354,13 +415,14 @@ func (m *ExpirationManager) Restore(errorFunc func()) (retErr error) {
|
||||
|
||||
for {
|
||||
select {
|
||||
case leaseID, ok := <-broker:
|
||||
case lease, ok := <-broker:
|
||||
// broker has been closed, we are done
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
err := m.processRestore(leaseID)
|
||||
ctx := namespace.ContextWithNamespace(m.quitContext, lease.namespace)
|
||||
err := m.processRestore(ctx, lease.id)
|
||||
if err != nil {
|
||||
errs <- err
|
||||
continue
|
||||
@@ -384,20 +446,27 @@ func (m *ExpirationManager) Restore(errorFunc func()) (retErr error) {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for i, leaseID := range existing {
|
||||
if i > 0 && i%500 == 0 {
|
||||
m.logger.Debug("leases loading", "progress", i)
|
||||
}
|
||||
i := 0
|
||||
for ns := range existing {
|
||||
for _, leaseID := range existing[ns] {
|
||||
i++
|
||||
if i%500 == 0 {
|
||||
m.logger.Debug("leases loading", "progress", i)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-quit:
|
||||
return
|
||||
select {
|
||||
case <-quit:
|
||||
return
|
||||
|
||||
case <-m.quitCh:
|
||||
return
|
||||
case <-m.quitCh:
|
||||
return
|
||||
|
||||
default:
|
||||
broker <- leaseID
|
||||
default:
|
||||
broker <- &lease{
|
||||
namespace: ns,
|
||||
id: leaseID,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,7 +475,7 @@ func (m *ExpirationManager) Restore(errorFunc func()) (retErr error) {
|
||||
}()
|
||||
|
||||
// Ensure all keys on the chan are processed
|
||||
for i := 0; i < len(existing); i++ {
|
||||
for i := 0; i < leaseCount; i++ {
|
||||
select {
|
||||
case err := <-errs:
|
||||
// Close all go routines
|
||||
@@ -436,7 +505,7 @@ func (m *ExpirationManager) Restore(errorFunc func()) (retErr error) {
|
||||
|
||||
// processRestore takes a lease and restores it in the expiration manager if it has
|
||||
// not already been seen
|
||||
func (m *ExpirationManager) processRestore(leaseID string) error {
|
||||
func (m *ExpirationManager) processRestore(ctx context.Context, leaseID string) error {
|
||||
m.restoreRequestLock.RLock()
|
||||
defer m.restoreRequestLock.RUnlock()
|
||||
|
||||
@@ -454,7 +523,7 @@ func (m *ExpirationManager) processRestore(leaseID string) error {
|
||||
}
|
||||
|
||||
// Load lease and restore expiration timer
|
||||
_, err := m.loadEntryInternal(m.quitContext, leaseID, true, false)
|
||||
_, err := m.loadEntryInternal(ctx, leaseID, true, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -560,13 +629,13 @@ func (m *ExpirationManager) revokeCommon(ctx context.Context, leaseID string, fo
|
||||
}
|
||||
|
||||
// Delete the entry
|
||||
if err := m.deleteEntry(ctx, leaseID); err != nil {
|
||||
if err := m.deleteEntry(ctx, le); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete the secondary index, but only if it's a leased secret (not auth)
|
||||
if le.Secret != nil {
|
||||
if err := m.removeIndexByToken(ctx, le.ClientToken, le.LeaseID); err != nil {
|
||||
if err := m.removeIndexByToken(ctx, le); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -609,9 +678,17 @@ func (m *ExpirationManager) RevokePrefix(ctx context.Context, prefix string, syn
|
||||
// token store's revokeSalted function.
|
||||
func (m *ExpirationManager) RevokeByToken(ctx context.Context, te *logical.TokenEntry) error {
|
||||
defer metrics.MeasureSince([]string{"expire", "revoke-by-token"}, time.Now())
|
||||
tokenNS, err := NamespaceByID(ctx, te.NamespaceID, m.core)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tokenNS == nil {
|
||||
return namespace.ErrNoNamespace
|
||||
}
|
||||
|
||||
tokenCtx := namespace.ContextWithNamespace(ctx, tokenNS)
|
||||
// Lookup the leases
|
||||
existing, err := m.lookupLeasesByToken(ctx, te.ID)
|
||||
existing, err := m.lookupLeasesByToken(tokenCtx, te)
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("failed to scan for leases: {{err}}", err)
|
||||
}
|
||||
@@ -645,12 +722,17 @@ func (m *ExpirationManager) RevokeByToken(ctx context.Context, te *logical.Token
|
||||
|
||||
// te.Path should never be empty, but we check just in case
|
||||
if te.Path != "" {
|
||||
saltedID, err := m.tokenStore.SaltID(ctx, te.ID)
|
||||
saltCtx := namespace.ContextWithNamespace(ctx, tokenNS)
|
||||
saltedID, err := m.tokenStore.SaltID(saltCtx, te.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tokenLeaseID := path.Join(te.Path, saltedID)
|
||||
|
||||
if tokenNS.ID != namespace.RootNamespaceID {
|
||||
tokenLeaseID = fmt.Sprintf("%s.%s", tokenLeaseID, tokenNS.ID)
|
||||
}
|
||||
|
||||
// We want to skip the revokeEntry call as that will call back into
|
||||
// revocation logic in the token store, which is what is running this
|
||||
// function in the first place -- it'd be a deadlock loop. Since the only
|
||||
@@ -687,7 +769,12 @@ func (m *ExpirationManager) revokePrefixCommon(ctx context.Context, prefix strin
|
||||
}
|
||||
|
||||
// Accumulate existing leases
|
||||
sub := m.idView.SubView(prefix)
|
||||
ns, err := namespace.FromContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
view := m.leaseView(ns)
|
||||
sub := view.SubView(prefix)
|
||||
existing, err := logical.CollectKeys(ctx, sub)
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("failed to scan for leases: {{err}}", err)
|
||||
@@ -734,7 +821,16 @@ func (m *ExpirationManager) Renew(ctx context.Context, leaseID string, increment
|
||||
return logical.ErrorResponse("lease does not correspond to a secret"), nil
|
||||
}
|
||||
|
||||
sysView := m.router.MatchingSystemView(le.Path)
|
||||
reqNS, err := namespace.FromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if reqNS.ID != le.namespace.ID {
|
||||
return nil, errors.New("cannot renew a lease across namespaces")
|
||||
}
|
||||
|
||||
sysViewCtx := namespace.ContextWithNamespace(ctx, le.namespace)
|
||||
sysView := m.router.MatchingSystemView(sysViewCtx, le.Path)
|
||||
if sysView == nil {
|
||||
return nil, fmt.Errorf("unable to retrieve system view from router")
|
||||
}
|
||||
@@ -792,22 +888,46 @@ func (m *ExpirationManager) Renew(ctx context.Context, leaseID string, increment
|
||||
|
||||
// RenewToken is used to renew a token which does not need to
|
||||
// invoke a logical backend.
|
||||
func (m *ExpirationManager) RenewToken(ctx context.Context, req *logical.Request, source string, token string,
|
||||
func (m *ExpirationManager) RenewToken(ctx context.Context, req *logical.Request, te *logical.TokenEntry,
|
||||
increment time.Duration) (*logical.Response, error) {
|
||||
defer metrics.MeasureSince([]string{"expire", "renew-token"}, time.Now())
|
||||
|
||||
// Compute the Lease ID
|
||||
saltedID, err := m.tokenStore.SaltID(ctx, token)
|
||||
tokenNS, err := NamespaceByID(ctx, te.NamespaceID, m.core)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
leaseID := path.Join(source, saltedID)
|
||||
if tokenNS == nil {
|
||||
return nil, namespace.ErrNoNamespace
|
||||
}
|
||||
|
||||
ns, err := namespace.FromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ns.ID != tokenNS.ID {
|
||||
return nil, errors.New("cannot renew a token across namespaces")
|
||||
}
|
||||
|
||||
// Compute the Lease ID
|
||||
saltedID, err := m.tokenStore.SaltID(ctx, te.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
leaseID := path.Join(te.Path, saltedID)
|
||||
|
||||
if ns.ID != namespace.RootNamespaceID {
|
||||
leaseID = fmt.Sprintf("%s.%s", leaseID, ns.ID)
|
||||
}
|
||||
|
||||
// Load the entry
|
||||
le, err := m.loadEntry(ctx, leaseID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if le == nil {
|
||||
return logical.ErrorResponse("invalid lease ID"), logical.ErrInvalidRequest
|
||||
}
|
||||
|
||||
// Check if the lease is renewable. Note that this also checks for a nil
|
||||
// lease and errors in that case as well.
|
||||
@@ -832,7 +952,8 @@ func (m *ExpirationManager) RenewToken(ctx context.Context, req *logical.Request
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
sysView := m.router.MatchingSystemView(le.Path)
|
||||
sysViewCtx := namespace.ContextWithNamespace(ctx, le.namespace)
|
||||
sysView := m.router.MatchingSystemView(sysViewCtx, le.Path)
|
||||
if sysView == nil {
|
||||
return nil, fmt.Errorf("unable to retrieve system view from router")
|
||||
}
|
||||
@@ -848,7 +969,7 @@ func (m *ExpirationManager) RenewToken(ctx context.Context, req *logical.Request
|
||||
resp.Auth.TTL = ttl
|
||||
|
||||
// Attach the ClientToken
|
||||
resp.Auth.ClientToken = token
|
||||
resp.Auth.ClientToken = te.ID
|
||||
|
||||
// Refresh groups
|
||||
if resp.Auth.EntityID != "" &&
|
||||
@@ -903,37 +1024,23 @@ func (m *ExpirationManager) Register(ctx context.Context, req *logical.Request,
|
||||
}
|
||||
|
||||
// Create a lease entry
|
||||
leaseUUID, err := uuid.GenerateUUID()
|
||||
leaseRand, err := base62.Random(TokenLength, true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
leaseID := path.Join(req.Path, leaseUUID)
|
||||
ns, err := namespace.FromContext(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
// If there is an error we want to rollback as much as possible (note
|
||||
// that errors here are ignored to do as much cleanup as we can). We
|
||||
// want to revoke a generated secret (since an error means we may not
|
||||
// be successfully tracking it), remove indexes, and delete the entry.
|
||||
if retErr != nil {
|
||||
revResp, err := m.router.Route(m.quitContext, logical.RevokeRequest(req.Path, resp.Secret, resp.Data))
|
||||
if err != nil {
|
||||
retErr = multierror.Append(retErr, errwrap.Wrapf("an additional internal error was encountered revoking the newly-generated secret: {{err}}", err))
|
||||
} else if revResp != nil && revResp.IsError() {
|
||||
retErr = multierror.Append(retErr, errwrap.Wrapf("an additional error was encountered revoking the newly-generated secret: {{err}}", revResp.Error()))
|
||||
}
|
||||
leaseID := path.Join(req.Path, leaseRand)
|
||||
|
||||
if err := m.deleteEntry(ctx, leaseID); err != nil {
|
||||
retErr = multierror.Append(retErr, errwrap.Wrapf("an additional error was encountered deleting any lease associated with the newly-generated secret: {{err}}", err))
|
||||
}
|
||||
if ns.ID != namespace.RootNamespaceID {
|
||||
leaseID = fmt.Sprintf("%s.%s", leaseID, ns.ID)
|
||||
}
|
||||
|
||||
if err := m.removeIndexByToken(ctx, req.ClientToken, leaseID); err != nil {
|
||||
retErr = multierror.Append(retErr, errwrap.Wrapf("an additional error was encountered removing lease indexes associated with the newly-generated secret: {{err}}", err))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
le := leaseEntry{
|
||||
le := &leaseEntry{
|
||||
LeaseID: leaseID,
|
||||
ClientToken: req.ClientToken,
|
||||
Path: req.Path,
|
||||
@@ -941,20 +1048,45 @@ func (m *ExpirationManager) Register(ctx context.Context, req *logical.Request,
|
||||
Secret: resp.Secret,
|
||||
IssueTime: time.Now(),
|
||||
ExpireTime: resp.Secret.ExpirationTime(),
|
||||
namespace: ns,
|
||||
}
|
||||
|
||||
defer func() {
|
||||
// If there is an error we want to rollback as much as possible (note
|
||||
// that errors here are ignored to do as much cleanup as we can). We
|
||||
// want to revoke a generated secret (since an error means we may not
|
||||
// be successfully tracking it), remove indexes, and delete the entry.
|
||||
if retErr != nil {
|
||||
revokeCtx := namespace.ContextWithNamespace(m.quitContext, ns)
|
||||
revResp, err := m.router.Route(revokeCtx, logical.RevokeRequest(req.Path, resp.Secret, resp.Data))
|
||||
if err != nil {
|
||||
retErr = multierror.Append(retErr, errwrap.Wrapf("an additional internal error was encountered revoking the newly-generated secret: {{err}}", err))
|
||||
} else if revResp != nil && revResp.IsError() {
|
||||
retErr = multierror.Append(retErr, errwrap.Wrapf("an additional error was encountered revoking the newly-generated secret: {{err}}", revResp.Error()))
|
||||
}
|
||||
|
||||
if err := m.deleteEntry(ctx, le); err != nil {
|
||||
retErr = multierror.Append(retErr, errwrap.Wrapf("an additional error was encountered deleting any lease associated with the newly-generated secret: {{err}}", err))
|
||||
}
|
||||
|
||||
if err := m.removeIndexByToken(ctx, le); err != nil {
|
||||
retErr = multierror.Append(retErr, errwrap.Wrapf("an additional error was encountered removing lease indexes associated with the newly-generated secret: {{err}}", err))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Encode the entry
|
||||
if err := m.persistEntry(ctx, &le); err != nil {
|
||||
if err := m.persistEntry(ctx, le); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Maintain secondary index by token
|
||||
if err := m.createIndexByToken(ctx, le.ClientToken, le.LeaseID); err != nil {
|
||||
if err := m.createIndexByToken(ctx, le); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Setup revocation timer if there is a lease
|
||||
m.updatePending(&le, resp.Secret.LeaseTotal())
|
||||
m.updatePending(le, resp.Secret.LeaseTotal())
|
||||
|
||||
// Done
|
||||
return le.LeaseID, nil
|
||||
@@ -963,30 +1095,45 @@ func (m *ExpirationManager) Register(ctx context.Context, req *logical.Request,
|
||||
// RegisterAuth is used to take an Auth response with an associated lease.
|
||||
// The token does not get a LeaseID, but the lease management is handled by
|
||||
// the expiration manager.
|
||||
func (m *ExpirationManager) RegisterAuth(ctx context.Context, source string, auth *logical.Auth) error {
|
||||
func (m *ExpirationManager) RegisterAuth(ctx context.Context, te *logical.TokenEntry, auth *logical.Auth) error {
|
||||
defer metrics.MeasureSince([]string{"expire", "register-auth"}, time.Now())
|
||||
|
||||
if auth.ClientToken == "" {
|
||||
return fmt.Errorf("cannot register an auth lease with an empty token")
|
||||
}
|
||||
|
||||
if strings.Contains(source, "..") {
|
||||
if strings.Contains(te.Path, "..") {
|
||||
return consts.ErrPathContainsParentReferences
|
||||
}
|
||||
|
||||
saltedID, err := m.tokenStore.SaltID(ctx, auth.ClientToken)
|
||||
tokenNS, err := NamespaceByID(ctx, te.NamespaceID, m.core)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tokenNS == nil {
|
||||
return namespace.ErrNoNamespace
|
||||
}
|
||||
|
||||
saltCtx := namespace.ContextWithNamespace(ctx, tokenNS)
|
||||
saltedID, err := m.tokenStore.SaltID(saltCtx, auth.ClientToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
leaseID := path.Join(te.Path, saltedID)
|
||||
if tokenNS.ID != namespace.RootNamespaceID {
|
||||
leaseID = fmt.Sprintf("%s.%s", leaseID, tokenNS.ID)
|
||||
}
|
||||
|
||||
// Create a lease entry
|
||||
le := leaseEntry{
|
||||
LeaseID: path.Join(source, saltedID),
|
||||
LeaseID: leaseID,
|
||||
ClientToken: auth.ClientToken,
|
||||
Auth: auth,
|
||||
Path: source,
|
||||
Path: te.Path,
|
||||
IssueTime: time.Now(),
|
||||
ExpireTime: auth.ExpirationTime(),
|
||||
namespace: tokenNS,
|
||||
}
|
||||
|
||||
// Encode the entry
|
||||
@@ -1002,15 +1149,29 @@ func (m *ExpirationManager) RegisterAuth(ctx context.Context, source string, aut
|
||||
|
||||
// FetchLeaseTimesByToken is a helper function to use token values to compute
|
||||
// the leaseID, rather than pushing that logic back into the token store.
|
||||
func (m *ExpirationManager) FetchLeaseTimesByToken(ctx context.Context, source, token string) (*leaseEntry, error) {
|
||||
func (m *ExpirationManager) FetchLeaseTimesByToken(ctx context.Context, te *logical.TokenEntry) (*leaseEntry, error) {
|
||||
defer metrics.MeasureSince([]string{"expire", "fetch-lease-times-by-token"}, time.Now())
|
||||
|
||||
// Compute the Lease ID
|
||||
saltedID, err := m.tokenStore.SaltID(ctx, token)
|
||||
tokenNS, err := NamespaceByID(ctx, te.NamespaceID, m.core)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
leaseID := path.Join(source, saltedID)
|
||||
if tokenNS == nil {
|
||||
return nil, namespace.ErrNoNamespace
|
||||
}
|
||||
|
||||
saltCtx := namespace.ContextWithNamespace(ctx, tokenNS)
|
||||
saltedID, err := m.tokenStore.SaltID(saltCtx, te.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
leaseID := path.Join(te.Path, saltedID)
|
||||
|
||||
if tokenNS.ID != namespace.RootNamespaceID {
|
||||
leaseID = fmt.Sprintf("%s.%s", leaseID, tokenNS.ID)
|
||||
}
|
||||
|
||||
return m.FetchLeaseTimes(ctx, leaseID)
|
||||
}
|
||||
|
||||
@@ -1029,7 +1190,7 @@ func (m *ExpirationManager) FetchLeaseTimes(ctx context.Context, leaseID string)
|
||||
}
|
||||
|
||||
// Load the entry
|
||||
le, err := m.loadEntry(ctx, leaseID)
|
||||
le, err := m.loadEntryInternal(ctx, leaseID, true, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1091,7 +1252,7 @@ func (m *ExpirationManager) updatePendingInternal(le *leaseEntry, leaseTotal tim
|
||||
pending.timer.Reset(leaseTotal)
|
||||
} else {
|
||||
timer := time.AfterFunc(leaseTotal, func() {
|
||||
m.expireID(le.LeaseID)
|
||||
m.expireFunc(m.quitContext, m, le)
|
||||
})
|
||||
pending = pendingInfo{
|
||||
timer: timer,
|
||||
@@ -1104,62 +1265,23 @@ func (m *ExpirationManager) updatePendingInternal(le *leaseEntry, leaseTotal tim
|
||||
m.pending[le.LeaseID] = pending
|
||||
}
|
||||
|
||||
// expireID is invoked when a given ID is expired
|
||||
func (m *ExpirationManager) expireID(leaseID string) {
|
||||
// Clear from the pending expiration
|
||||
m.pendingLock.Lock()
|
||||
delete(m.pending, leaseID)
|
||||
m.pendingLock.Unlock()
|
||||
|
||||
for attempt := uint(0); attempt < maxRevokeAttempts; attempt++ {
|
||||
ctx, cancel := context.WithTimeout(m.quitContext, DefaultMaxRequestDuration)
|
||||
|
||||
go func() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case <-m.quitCh:
|
||||
cancel()
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-m.quitCh:
|
||||
m.logger.Error("shutting down, not attempting further revocation of lease", "lease_id", leaseID)
|
||||
return
|
||||
case <-m.quitContext.Done():
|
||||
m.logger.Error("core context canceled, not attempting further revocation of lease", "lease_id", leaseID)
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
m.coreStateLock.RLock()
|
||||
err := m.Revoke(ctx, leaseID)
|
||||
m.coreStateLock.RUnlock()
|
||||
cancel()
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
m.logger.Error("failed to revoke lease", "lease_id", leaseID, "error", err)
|
||||
time.Sleep((1 << attempt) * revokeRetryBase)
|
||||
}
|
||||
m.logger.Error("maximum revoke attempts reached", "lease_id", leaseID)
|
||||
}
|
||||
|
||||
// revokeEntry is used to attempt revocation of an internal entry
|
||||
func (m *ExpirationManager) revokeEntry(ctx context.Context, le *leaseEntry) error {
|
||||
// Revocation of login tokens is special since we can by-pass the
|
||||
// backend and directly interact with the token store
|
||||
if le.Auth != nil {
|
||||
if err := m.tokenStore.revokeTree(ctx, le.ClientToken); err != nil {
|
||||
if err := m.tokenStore.revokeTree(ctx, le); err != nil {
|
||||
return errwrap.Wrapf("failed to revoke token: {{err}}", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Make sure we're operating in the right namespace
|
||||
nsCtx := namespace.ContextWithNamespace(ctx, le.namespace)
|
||||
|
||||
// Handle standard revocation via backends
|
||||
resp, err := m.router.Route(m.quitContext, logical.RevokeRequest(le.Path, le.Secret, le.Data))
|
||||
resp, err := m.router.Route(nsCtx, logical.RevokeRequest(le.Path, le.Secret, le.Data))
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
return errwrap.Wrapf(fmt.Sprintf("failed to revoke entry: resp: %#v err: {{err}}", resp), err)
|
||||
}
|
||||
@@ -1172,8 +1294,12 @@ func (m *ExpirationManager) renewEntry(ctx context.Context, le *leaseEntry, incr
|
||||
secret.IssueTime = le.IssueTime
|
||||
secret.Increment = increment
|
||||
secret.LeaseID = ""
|
||||
|
||||
// Make sure we're operating in the right namespace
|
||||
nsCtx := namespace.ContextWithNamespace(ctx, le.namespace)
|
||||
|
||||
req := logical.RenewRequest(le.Path, &secret, le.Data)
|
||||
resp, err := m.router.Route(ctx, req)
|
||||
resp, err := m.router.Route(nsCtx, req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
return nil, errwrap.Wrapf(fmt.Sprintf("failed to renew entry: resp: %#v err: {{err}}", resp), err)
|
||||
}
|
||||
@@ -1192,9 +1318,12 @@ func (m *ExpirationManager) renewAuthEntry(ctx context.Context, req *logical.Req
|
||||
auth.ClientToken = ""
|
||||
}
|
||||
|
||||
// Make sure we're operating in the right namespace
|
||||
nsCtx := namespace.ContextWithNamespace(ctx, le.namespace)
|
||||
|
||||
authReq := logical.RenewAuthRequest(le.Path, &auth, nil)
|
||||
authReq.Connection = req.Connection
|
||||
resp, err := m.router.Route(ctx, authReq)
|
||||
resp, err := m.router.Route(nsCtx, authReq)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("failed to renew entry: {{err}}", err)
|
||||
}
|
||||
@@ -1215,13 +1344,32 @@ func (m *ExpirationManager) loadEntry(ctx context.Context, leaseID string) (*lea
|
||||
defer m.unlockLease(leaseID)
|
||||
}
|
||||
}
|
||||
|
||||
_, nsID := namespace.SplitIDFromString(leaseID)
|
||||
if nsID != "" {
|
||||
leaseNS, err := NamespaceByID(ctx, nsID, m.core)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if leaseNS != nil {
|
||||
ctx = namespace.ContextWithNamespace(ctx, leaseNS)
|
||||
}
|
||||
} else {
|
||||
ctx = namespace.ContextWithNamespace(ctx, namespace.RootNamespace)
|
||||
}
|
||||
return m.loadEntryInternal(ctx, leaseID, restoreMode, true)
|
||||
}
|
||||
|
||||
// loadEntryInternal is used when you need to load an entry but also need to
|
||||
// control the lifecycle of the restoreLock
|
||||
func (m *ExpirationManager) loadEntryInternal(ctx context.Context, leaseID string, restoreMode bool, checkRestored bool) (*leaseEntry, error) {
|
||||
out, err := m.idView.Get(ctx, leaseID)
|
||||
ns, err := namespace.FromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
view := m.leaseView(ns)
|
||||
out, err := view.Get(ctx, leaseID)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("failed to read lease entry: {{err}}", err)
|
||||
}
|
||||
@@ -1232,6 +1380,7 @@ func (m *ExpirationManager) loadEntryInternal(ctx context.Context, leaseID strin
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("failed to decode lease entry: {{err}}", err)
|
||||
}
|
||||
le.namespace = ns
|
||||
|
||||
if restoreMode {
|
||||
if checkRestored {
|
||||
@@ -1269,56 +1418,87 @@ func (m *ExpirationManager) persistEntry(ctx context.Context, le *leaseEntry) er
|
||||
if le.Auth != nil && len(le.Auth.Policies) == 1 && le.Auth.Policies[0] == "root" {
|
||||
ent.SealWrap = true
|
||||
}
|
||||
if err := m.idView.Put(ctx, &ent); err != nil {
|
||||
|
||||
view := m.leaseView(le.namespace)
|
||||
if err := view.Put(ctx, &ent); err != nil {
|
||||
return errwrap.Wrapf("failed to persist lease entry: {{err}}", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// deleteEntry is used to delete a lease entry
|
||||
func (m *ExpirationManager) deleteEntry(ctx context.Context, leaseID string) error {
|
||||
if err := m.idView.Delete(ctx, leaseID); err != nil {
|
||||
func (m *ExpirationManager) deleteEntry(ctx context.Context, le *leaseEntry) error {
|
||||
view := m.leaseView(le.namespace)
|
||||
if err := view.Delete(ctx, le.LeaseID); err != nil {
|
||||
return errwrap.Wrapf("failed to delete lease entry: {{err}}", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// createIndexByToken creates a secondary index from the token to a lease entry
|
||||
func (m *ExpirationManager) createIndexByToken(ctx context.Context, token, leaseID string) error {
|
||||
saltedID, err := m.tokenStore.SaltID(ctx, token)
|
||||
func (m *ExpirationManager) createIndexByToken(ctx context.Context, le *leaseEntry) error {
|
||||
tokenNS := namespace.RootNamespace
|
||||
saltCtx := namespace.ContextWithNamespace(ctx, namespace.RootNamespace)
|
||||
_, nsID := namespace.SplitIDFromString(le.ClientToken)
|
||||
if nsID != "" {
|
||||
tokenNS, err := NamespaceByID(ctx, nsID, m.core)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tokenNS != nil {
|
||||
saltCtx = namespace.ContextWithNamespace(ctx, tokenNS)
|
||||
}
|
||||
}
|
||||
|
||||
saltedID, err := m.tokenStore.SaltID(saltCtx, le.ClientToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
leaseSaltedID, err := m.tokenStore.SaltID(ctx, leaseID)
|
||||
leaseSaltedID, err := m.tokenStore.SaltID(saltCtx, le.LeaseID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ent := logical.StorageEntry{
|
||||
Key: saltedID + "/" + leaseSaltedID,
|
||||
Value: []byte(leaseID),
|
||||
Value: []byte(le.LeaseID),
|
||||
}
|
||||
if err := m.tokenView.Put(ctx, &ent); err != nil {
|
||||
tokenView := m.tokenIndexView(tokenNS)
|
||||
if err := tokenView.Put(ctx, &ent); err != nil {
|
||||
return errwrap.Wrapf("failed to persist lease index entry: {{err}}", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// indexByToken looks up the secondary index from the token to a lease entry
|
||||
func (m *ExpirationManager) indexByToken(ctx context.Context, token, leaseID string) (*logical.StorageEntry, error) {
|
||||
saltedID, err := m.tokenStore.SaltID(ctx, token)
|
||||
func (m *ExpirationManager) indexByToken(ctx context.Context, le *leaseEntry) (*logical.StorageEntry, error) {
|
||||
tokenNS := namespace.RootNamespace
|
||||
saltCtx := namespace.ContextWithNamespace(ctx, tokenNS)
|
||||
_, nsID := namespace.SplitIDFromString(le.ClientToken)
|
||||
if nsID != "" {
|
||||
tokenNS, err := NamespaceByID(ctx, nsID, m.core)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tokenNS != nil {
|
||||
saltCtx = namespace.ContextWithNamespace(ctx, tokenNS)
|
||||
}
|
||||
}
|
||||
|
||||
saltedID, err := m.tokenStore.SaltID(saltCtx, le.ClientToken)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
leaseSaltedID, err := m.tokenStore.SaltID(ctx, leaseID)
|
||||
leaseSaltedID, err := m.tokenStore.SaltID(saltCtx, le.LeaseID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key := saltedID + "/" + leaseSaltedID
|
||||
entry, err := m.tokenView.Get(ctx, key)
|
||||
tokenView := m.tokenIndexView(tokenNS)
|
||||
entry, err := tokenView.Get(ctx, key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to look up secondary index entry")
|
||||
}
|
||||
@@ -1326,19 +1506,33 @@ func (m *ExpirationManager) indexByToken(ctx context.Context, token, leaseID str
|
||||
}
|
||||
|
||||
// removeIndexByToken removes the secondary index from the token to a lease entry
|
||||
func (m *ExpirationManager) removeIndexByToken(ctx context.Context, token, leaseID string) error {
|
||||
saltedID, err := m.tokenStore.SaltID(ctx, token)
|
||||
func (m *ExpirationManager) removeIndexByToken(ctx context.Context, le *leaseEntry) error {
|
||||
tokenNS := namespace.RootNamespace
|
||||
saltCtx := namespace.ContextWithNamespace(ctx, namespace.RootNamespace)
|
||||
_, nsID := namespace.SplitIDFromString(le.ClientToken)
|
||||
if nsID != "" {
|
||||
tokenNS, err := NamespaceByID(ctx, nsID, m.core)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tokenNS != nil {
|
||||
saltCtx = namespace.ContextWithNamespace(ctx, tokenNS)
|
||||
}
|
||||
}
|
||||
|
||||
saltedID, err := m.tokenStore.SaltID(saltCtx, le.ClientToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
leaseSaltedID, err := m.tokenStore.SaltID(ctx, leaseID)
|
||||
leaseSaltedID, err := m.tokenStore.SaltID(saltCtx, le.LeaseID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
key := saltedID + "/" + leaseSaltedID
|
||||
if err := m.tokenView.Delete(ctx, key); err != nil {
|
||||
tokenView := m.tokenIndexView(tokenNS)
|
||||
if err := tokenView.Delete(ctx, key); err != nil {
|
||||
return errwrap.Wrapf("failed to delete lease index entry: {{err}}", err)
|
||||
}
|
||||
return nil
|
||||
@@ -1349,12 +1543,25 @@ func (m *ExpirationManager) removeIndexByToken(ctx context.Context, token, lease
|
||||
// it's created.
|
||||
func (m *ExpirationManager) CreateOrFetchRevocationLeaseByToken(ctx context.Context, te *logical.TokenEntry) (string, error) {
|
||||
// Fetch the saltedID of the token and construct the leaseID
|
||||
saltedID, err := m.tokenStore.SaltID(ctx, te.ID)
|
||||
tokenNS, err := NamespaceByID(ctx, te.NamespaceID, m.core)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if tokenNS == nil {
|
||||
return "", namespace.ErrNoNamespace
|
||||
}
|
||||
|
||||
saltCtx := namespace.ContextWithNamespace(ctx, tokenNS)
|
||||
saltedID, err := m.tokenStore.SaltID(saltCtx, te.ID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
leaseID := path.Join(te.Path, saltedID)
|
||||
|
||||
if tokenNS.ID != namespace.RootNamespaceID {
|
||||
leaseID = fmt.Sprintf("%s.%s", leaseID, tokenNS.ID)
|
||||
}
|
||||
|
||||
// Load the entry
|
||||
le, err := m.loadEntry(ctx, leaseID)
|
||||
if err != nil {
|
||||
@@ -1383,6 +1590,7 @@ func (m *ExpirationManager) CreateOrFetchRevocationLeaseByToken(ctx context.Cont
|
||||
Path: te.Path,
|
||||
IssueTime: now,
|
||||
ExpireTime: now.Add(time.Nanosecond),
|
||||
namespace: tokenNS,
|
||||
}
|
||||
|
||||
// Encode the entry
|
||||
@@ -1395,15 +1603,26 @@ func (m *ExpirationManager) CreateOrFetchRevocationLeaseByToken(ctx context.Cont
|
||||
}
|
||||
|
||||
// lookupLeasesByToken is used to lookup all the leaseID's via the tokenID
|
||||
func (m *ExpirationManager) lookupLeasesByToken(ctx context.Context, token string) ([]string, error) {
|
||||
saltedID, err := m.tokenStore.SaltID(ctx, token)
|
||||
func (m *ExpirationManager) lookupLeasesByToken(ctx context.Context, te *logical.TokenEntry) ([]string, error) {
|
||||
tokenNS, err := NamespaceByID(ctx, te.NamespaceID, m.core)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tokenNS == nil {
|
||||
return nil, namespace.ErrNoNamespace
|
||||
}
|
||||
|
||||
saltCtx := namespace.ContextWithNamespace(ctx, tokenNS)
|
||||
saltedID, err := m.tokenStore.SaltID(saltCtx, te.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tokenView := m.tokenIndexView(tokenNS)
|
||||
|
||||
// Scan via the index for sub-leases
|
||||
prefix := saltedID + "/"
|
||||
subKeys, err := m.tokenView.List(ctx, prefix)
|
||||
subKeys, err := tokenView.List(ctx, prefix)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("failed to list leases: {{err}}", err)
|
||||
}
|
||||
@@ -1411,7 +1630,7 @@ func (m *ExpirationManager) lookupLeasesByToken(ctx context.Context, token strin
|
||||
// Read each index entry
|
||||
leaseIDs := make([]string, 0, len(subKeys))
|
||||
for _, sub := range subKeys {
|
||||
out, err := m.tokenView.Get(ctx, prefix+sub)
|
||||
out, err := tokenView.Get(ctx, prefix+sub)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("failed to read lease index: {{err}}", err)
|
||||
}
|
||||
@@ -1452,6 +1671,8 @@ type leaseEntry struct {
|
||||
IssueTime time.Time `json:"issue_time"`
|
||||
ExpireTime time.Time `json:"expire_time"`
|
||||
LastRenewalTime time.Time `json:"last_renewal_time"`
|
||||
|
||||
namespace *namespace.Namespace
|
||||
}
|
||||
|
||||
// encode is used to JSON encode the lease entry
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
log "github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/go-uuid"
|
||||
"github.com/hashicorp/vault/helper/logging"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/logical/framework"
|
||||
"github.com/hashicorp/vault/physical"
|
||||
@@ -64,7 +65,7 @@ func TestExpiration_Tidy(t *testing.T) {
|
||||
}
|
||||
|
||||
// Scan the storage with the count func set
|
||||
if err = logical.ScanView(context.Background(), exp.idView, countFunc); err != nil {
|
||||
if err = logical.ScanView(namespace.TestContext(), exp.idView, countFunc); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -75,12 +76,13 @@ func TestExpiration_Tidy(t *testing.T) {
|
||||
|
||||
// Create a lease entry without a client token in it
|
||||
le := &leaseEntry{
|
||||
LeaseID: "lease/with/no/client/token",
|
||||
Path: "foo/bar",
|
||||
LeaseID: "lease/with/no/client/token",
|
||||
Path: "foo/bar",
|
||||
namespace: namespace.TestNamespace(),
|
||||
}
|
||||
|
||||
// Persist the invalid lease entry
|
||||
if err = exp.persistEntry(context.Background(), le); err != nil {
|
||||
if err = exp.persistEntry(namespace.TestContext(), le); err != nil {
|
||||
t.Fatalf("error persisting entry: %v", err)
|
||||
}
|
||||
|
||||
@@ -96,7 +98,7 @@ func TestExpiration_Tidy(t *testing.T) {
|
||||
}
|
||||
|
||||
// Run the tidy operation
|
||||
err = exp.Tidy()
|
||||
err = exp.Tidy(namespace.TestContext())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -115,7 +117,7 @@ func TestExpiration_Tidy(t *testing.T) {
|
||||
le.ClientToken = "invalidtoken"
|
||||
|
||||
// Persist the invalid lease entry
|
||||
if err = exp.persistEntry(context.Background(), le); err != nil {
|
||||
if err = exp.persistEntry(namespace.TestContext(), le); err != nil {
|
||||
t.Fatalf("error persisting entry: %v", err)
|
||||
}
|
||||
|
||||
@@ -131,7 +133,7 @@ func TestExpiration_Tidy(t *testing.T) {
|
||||
}
|
||||
|
||||
// Run the tidy operation
|
||||
err = exp.Tidy()
|
||||
err = exp.Tidy(namespace.TestContext())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -147,7 +149,7 @@ func TestExpiration_Tidy(t *testing.T) {
|
||||
}
|
||||
|
||||
// Attach an invalid token with 2 leases
|
||||
if err = exp.persistEntry(context.Background(), le); err != nil {
|
||||
if err = exp.persistEntry(namespace.TestContext(), le); err != nil {
|
||||
t.Fatalf("error persisting entry: %v", err)
|
||||
}
|
||||
|
||||
@@ -157,7 +159,7 @@ func TestExpiration_Tidy(t *testing.T) {
|
||||
}
|
||||
|
||||
// Run the tidy operation
|
||||
err = exp.Tidy()
|
||||
err = exp.Tidy(namespace.TestContext())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -188,7 +190,7 @@ func TestExpiration_Tidy(t *testing.T) {
|
||||
"test_key": "test_value",
|
||||
},
|
||||
}
|
||||
_, err := exp.Register(context.Background(), req, resp)
|
||||
_, err := exp.Register(namespace.TestContext(), req, resp)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -211,11 +213,11 @@ func TestExpiration_Tidy(t *testing.T) {
|
||||
// one tidy operation can be in flight at any time. One of these requests
|
||||
// should error out.
|
||||
go func() {
|
||||
errCh1 <- exp.Tidy()
|
||||
errCh1 <- exp.Tidy(namespace.TestContext())
|
||||
}()
|
||||
|
||||
go func() {
|
||||
errCh2 <- exp.Tidy()
|
||||
errCh2 <- exp.Tidy(namespace.TestContext())
|
||||
}()
|
||||
|
||||
var err1, err2 error
|
||||
@@ -241,12 +243,12 @@ func TestExpiration_Tidy(t *testing.T) {
|
||||
le.ClientToken = root.ID
|
||||
|
||||
// Attach a valid token with the leases
|
||||
if err = exp.persistEntry(context.Background(), le); err != nil {
|
||||
if err = exp.persistEntry(namespace.TestContext(), le); err != nil {
|
||||
t.Fatalf("error persisting entry: %v", err)
|
||||
}
|
||||
|
||||
// Run the tidy operation
|
||||
err = exp.Tidy()
|
||||
err = exp.Tidy(namespace.TestContext())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -318,7 +320,7 @@ func benchmarkExpirationBackend(b *testing.B, physicalBackend physical.Backend,
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
err = exp.router.Mount(noop, "prod/aws/", &MountEntry{Path: "prod/aws/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor"}, view)
|
||||
err = exp.router.Mount(noop, "prod/aws/", &MountEntry{Path: "prod/aws/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor", namespace: namespace.TestNamespace()}, view)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -378,7 +380,7 @@ func TestExpiration_Restore(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = exp.router.Mount(noop, "prod/aws/", &MountEntry{Path: "prod/aws/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor"}, view)
|
||||
err = exp.router.Mount(noop, "prod/aws/", &MountEntry{Path: "prod/aws/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor", namespace: namespace.TestNamespace()}, view)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -405,7 +407,7 @@ func TestExpiration_Restore(t *testing.T) {
|
||||
"secret_key": "abcd",
|
||||
},
|
||||
}
|
||||
_, err := exp.Register(context.Background(), req, resp)
|
||||
_, err := exp.Register(namespace.TestContext(), req, resp)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -462,7 +464,7 @@ func TestExpiration_Register(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
id, err := exp.Register(context.Background(), req, resp)
|
||||
id, err := exp.Register(namespace.TestContext(), req, resp)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -490,12 +492,20 @@ func TestExpiration_RegisterAuth(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
err = exp.RegisterAuth(context.Background(), "auth/github/login", auth)
|
||||
te := &logical.TokenEntry{
|
||||
Path: "auth/github/login",
|
||||
NamespaceID: namespace.RootNamespaceID,
|
||||
}
|
||||
err = exp.RegisterAuth(namespace.TestContext(), te, auth)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
err = exp.RegisterAuth(context.Background(), "auth/github/../login", auth)
|
||||
te = &logical.TokenEntry{
|
||||
Path: "auth/github/../login",
|
||||
NamespaceID: namespace.RootNamespaceID,
|
||||
}
|
||||
err = exp.RegisterAuth(namespace.TestContext(), te, auth)
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
@@ -512,13 +522,23 @@ func TestExpiration_RegisterAuth_NoLease(t *testing.T) {
|
||||
ClientToken: root.ID,
|
||||
}
|
||||
|
||||
err = exp.RegisterAuth(context.Background(), "auth/github/login", auth)
|
||||
te := &logical.TokenEntry{
|
||||
ID: root.ID,
|
||||
Path: "auth/github/login",
|
||||
NamespaceID: namespace.RootNamespaceID,
|
||||
}
|
||||
err = exp.RegisterAuth(namespace.TestContext(), te, auth)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// Should not be able to renew, no expiration
|
||||
resp, err := exp.RenewToken(context.Background(), &logical.Request{}, "auth/github/login", root.ID, 0)
|
||||
te = &logical.TokenEntry{
|
||||
ID: root.ID,
|
||||
Path: "auth/github/login",
|
||||
NamespaceID: namespace.RootNamespaceID,
|
||||
}
|
||||
resp, err := exp.RenewToken(namespace.TestContext(), &logical.Request{}, te, 0)
|
||||
if err != nil && (err != logical.ErrInvalidRequest || (resp != nil && resp.IsError() && resp.Error().Error() != "lease not found or lease is not renewable")) {
|
||||
t.Fatalf("bad: err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -530,7 +550,7 @@ func TestExpiration_RegisterAuth_NoLease(t *testing.T) {
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
|
||||
// Verify token does not get revoked
|
||||
out, err := exp.tokenStore.Lookup(context.Background(), root.ID)
|
||||
out, err := exp.tokenStore.Lookup(namespace.TestContext(), root.ID)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -548,7 +568,7 @@ func TestExpiration_Revoke(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = exp.router.Mount(noop, "prod/aws/", &MountEntry{Path: "prod/aws/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor"}, view)
|
||||
err = exp.router.Mount(noop, "prod/aws/", &MountEntry{Path: "prod/aws/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor", namespace: namespace.TestNamespace()}, view)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -570,12 +590,12 @@ func TestExpiration_Revoke(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
id, err := exp.Register(context.Background(), req, resp)
|
||||
id, err := exp.Register(namespace.TestContext(), req, resp)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
if err := exp.Revoke(context.Background(), id); err != nil {
|
||||
if err := exp.Revoke(namespace.TestContext(), id); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
@@ -594,7 +614,7 @@ func TestExpiration_RevokeOnExpire(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = exp.router.Mount(noop, "prod/aws/", &MountEntry{Path: "prod/aws/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor"}, view)
|
||||
err = exp.router.Mount(noop, "prod/aws/", &MountEntry{Path: "prod/aws/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor", namespace: namespace.TestNamespace()}, view)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -616,7 +636,7 @@ func TestExpiration_RevokeOnExpire(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
_, err = exp.Register(context.Background(), req, resp)
|
||||
_, err = exp.Register(namespace.TestContext(), req, resp)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -651,7 +671,7 @@ func TestExpiration_RevokePrefix(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = exp.router.Mount(noop, "prod/aws/", &MountEntry{Path: "prod/aws/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor"}, view)
|
||||
err = exp.router.Mount(noop, "prod/aws/", &MountEntry{Path: "prod/aws/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor", namespace: namespace.TestNamespace()}, view)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -678,14 +698,14 @@ func TestExpiration_RevokePrefix(t *testing.T) {
|
||||
"secret_key": "abcd",
|
||||
},
|
||||
}
|
||||
_, err := exp.Register(context.Background(), req, resp)
|
||||
_, err := exp.Register(namespace.TestContext(), req, resp)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Should nuke all the keys
|
||||
if err := exp.RevokePrefix(context.Background(), "prod/aws/", true); err != nil {
|
||||
if err := exp.RevokePrefix(namespace.TestContext(), "prod/aws/", true); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
@@ -719,7 +739,7 @@ func TestExpiration_RevokeByToken(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = exp.router.Mount(noop, "prod/aws/", &MountEntry{Path: "prod/aws/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor"}, view)
|
||||
err = exp.router.Mount(noop, "prod/aws/", &MountEntry{Path: "prod/aws/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor", namespace: namespace.TestNamespace()}, view)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -746,7 +766,7 @@ func TestExpiration_RevokeByToken(t *testing.T) {
|
||||
"secret_key": "abcd",
|
||||
},
|
||||
}
|
||||
_, err := exp.Register(context.Background(), req, resp)
|
||||
_, err := exp.Register(namespace.TestContext(), req, resp)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -754,9 +774,10 @@ func TestExpiration_RevokeByToken(t *testing.T) {
|
||||
|
||||
// Should nuke all the keys
|
||||
te := &logical.TokenEntry{
|
||||
ID: "foobarbaz",
|
||||
ID: "foobarbaz",
|
||||
NamespaceID: namespace.RootNamespaceID,
|
||||
}
|
||||
if err := exp.RevokeByToken(context.Background(), te); err != nil {
|
||||
if err := exp.RevokeByToken(namespace.TestContext(), te); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
@@ -806,7 +827,7 @@ func TestExpiration_RevokeByToken_Blocking(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = exp.router.Mount(noop, "prod/aws/", &MountEntry{Path: "prod/aws/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor"}, view)
|
||||
err = exp.router.Mount(noop, "prod/aws/", &MountEntry{Path: "prod/aws/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor", namespace: namespace.TestNamespace()}, view)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -833,7 +854,7 @@ func TestExpiration_RevokeByToken_Blocking(t *testing.T) {
|
||||
"secret_key": "abcd",
|
||||
},
|
||||
}
|
||||
_, err := exp.Register(context.Background(), req, resp)
|
||||
_, err := exp.Register(namespace.TestContext(), req, resp)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -841,9 +862,10 @@ func TestExpiration_RevokeByToken_Blocking(t *testing.T) {
|
||||
|
||||
// Should nuke all the keys
|
||||
te := &logical.TokenEntry{
|
||||
ID: "foobarbaz",
|
||||
ID: "foobarbaz",
|
||||
NamespaceID: namespace.RootNamespaceID,
|
||||
}
|
||||
if err := exp.RevokeByToken(context.Background(), te); err != nil {
|
||||
if err := exp.RevokeByToken(namespace.TestContext(), te); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
@@ -898,13 +920,24 @@ func TestExpiration_RenewToken(t *testing.T) {
|
||||
Renewable: true,
|
||||
},
|
||||
}
|
||||
err = exp.RegisterAuth(context.Background(), "auth/token/login", auth)
|
||||
|
||||
te := &logical.TokenEntry{
|
||||
ID: root.ID,
|
||||
Path: "auth/token/login",
|
||||
NamespaceID: namespace.RootNamespaceID,
|
||||
}
|
||||
err = exp.RegisterAuth(namespace.TestContext(), te, auth)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// Renew the token
|
||||
out, err := exp.RenewToken(context.Background(), &logical.Request{}, "auth/token/login", root.ID, 0)
|
||||
te = &logical.TokenEntry{
|
||||
ID: root.ID,
|
||||
Path: "auth/token/login",
|
||||
NamespaceID: namespace.RootNamespaceID,
|
||||
}
|
||||
out, err := exp.RenewToken(namespace.TestContext(), &logical.Request{}, te, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -922,8 +955,9 @@ func TestExpiration_RenewToken_period(t *testing.T) {
|
||||
DisplayName: "root",
|
||||
CreationTime: time.Now().Unix(),
|
||||
Period: time.Minute,
|
||||
NamespaceID: namespace.RootNamespaceID,
|
||||
}
|
||||
if err := exp.tokenStore.create(context.Background(), root); err != nil {
|
||||
if err := exp.tokenStore.create(namespace.TestContext(), root); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
@@ -936,13 +970,23 @@ func TestExpiration_RenewToken_period(t *testing.T) {
|
||||
},
|
||||
Period: time.Minute,
|
||||
}
|
||||
err := exp.RegisterAuth(context.Background(), "auth/token/login", auth)
|
||||
te := &logical.TokenEntry{
|
||||
ID: root.ID,
|
||||
Path: "auth/token/login",
|
||||
NamespaceID: namespace.RootNamespaceID,
|
||||
}
|
||||
err := exp.RegisterAuth(namespace.TestContext(), te, auth)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// Renew the token
|
||||
out, err := exp.RenewToken(context.Background(), &logical.Request{}, "auth/token/login", root.ID, 0)
|
||||
te = &logical.TokenEntry{
|
||||
ID: root.ID,
|
||||
Path: "auth/token/login",
|
||||
NamespaceID: namespace.RootNamespaceID,
|
||||
}
|
||||
out, err := exp.RenewToken(namespace.TestContext(), &logical.Request{}, te, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -984,7 +1028,7 @@ func TestExpiration_RenewToken_period_backend(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = exp.router.Mount(noop, "auth/foo/", &MountEntry{Path: "auth/foo/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor"}, view)
|
||||
err = exp.router.Mount(noop, "auth/foo/", &MountEntry{Path: "auth/foo/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor", namespace: namespace.TestNamespace()}, view)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -998,15 +1042,25 @@ func TestExpiration_RenewToken_period_backend(t *testing.T) {
|
||||
},
|
||||
Period: 5 * time.Second,
|
||||
}
|
||||
te := &logical.TokenEntry{
|
||||
ID: root.ID,
|
||||
Path: "auth/foo/login",
|
||||
NamespaceID: namespace.RootNamespaceID,
|
||||
}
|
||||
|
||||
err = exp.RegisterAuth(context.Background(), "auth/foo/login", auth)
|
||||
err = exp.RegisterAuth(namespace.TestContext(), te, auth)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// Wait 3 seconds
|
||||
time.Sleep(3 * time.Second)
|
||||
resp, err := exp.RenewToken(context.Background(), &logical.Request{}, "auth/foo/login", root.ID, 0)
|
||||
te = &logical.TokenEntry{
|
||||
ID: root.ID,
|
||||
Path: "auth/foo/login",
|
||||
NamespaceID: namespace.RootNamespaceID,
|
||||
}
|
||||
resp, err := exp.RenewToken(namespace.TestContext(), &logical.Request{}, te, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1019,7 +1073,7 @@ func TestExpiration_RenewToken_period_backend(t *testing.T) {
|
||||
|
||||
// Wait another 3 seconds. If period works correctly, this should not fail
|
||||
time.Sleep(3 * time.Second)
|
||||
resp, err = exp.RenewToken(context.Background(), &logical.Request{}, "auth/foo/login", root.ID, 0)
|
||||
resp, err = exp.RenewToken(namespace.TestContext(), &logical.Request{}, te, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1046,14 +1100,24 @@ func TestExpiration_RenewToken_NotRenewable(t *testing.T) {
|
||||
Renewable: false,
|
||||
},
|
||||
}
|
||||
err = exp.RegisterAuth(context.Background(), "auth/github/login", auth)
|
||||
te := &logical.TokenEntry{
|
||||
ID: root.ID,
|
||||
Path: "auth/foo/login",
|
||||
NamespaceID: namespace.RootNamespaceID,
|
||||
}
|
||||
err = exp.RegisterAuth(namespace.TestContext(), te, auth)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// Attempt to renew the token
|
||||
resp, err := exp.RenewToken(context.Background(), &logical.Request{}, "auth/github/login", root.ID, 0)
|
||||
if err != nil && (err != logical.ErrInvalidRequest || (resp != nil && resp.IsError() && resp.Error().Error() != "lease is not renewable")) {
|
||||
te = &logical.TokenEntry{
|
||||
ID: root.ID,
|
||||
Path: "auth/github/login",
|
||||
NamespaceID: namespace.RootNamespaceID,
|
||||
}
|
||||
resp, err := exp.RenewToken(namespace.TestContext(), &logical.Request{}, te, 0)
|
||||
if err != nil && (err != logical.ErrInvalidRequest || (resp != nil && resp.IsError() && resp.Error().Error() != "invalid lease ID")) {
|
||||
t.Fatalf("bad: err:%v resp:%#v", err, resp)
|
||||
}
|
||||
if resp == nil {
|
||||
@@ -1071,7 +1135,7 @@ func TestExpiration_Renew(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = exp.router.Mount(noop, "prod/aws/", &MountEntry{Path: "prod/aws/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor"}, view)
|
||||
err = exp.router.Mount(noop, "prod/aws/", &MountEntry{Path: "prod/aws/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor", namespace: namespace.TestNamespace()}, view)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1094,7 +1158,7 @@ func TestExpiration_Renew(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
id, err := exp.Register(context.Background(), req, resp)
|
||||
id, err := exp.Register(namespace.TestContext(), req, resp)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1111,7 +1175,7 @@ func TestExpiration_Renew(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
out, err := exp.Renew(context.Background(), id, 0)
|
||||
out, err := exp.Renew(namespace.TestContext(), id, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1141,7 +1205,7 @@ func TestExpiration_Renew_NotRenewable(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = exp.router.Mount(noop, "prod/aws/", &MountEntry{Path: "prod/aws/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor"}, view)
|
||||
err = exp.router.Mount(noop, "prod/aws/", &MountEntry{Path: "prod/aws/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor", namespace: namespace.TestNamespace()}, view)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1164,12 +1228,12 @@ func TestExpiration_Renew_NotRenewable(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
id, err := exp.Register(context.Background(), req, resp)
|
||||
id, err := exp.Register(namespace.TestContext(), req, resp)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
_, err = exp.Renew(context.Background(), id, 0)
|
||||
_, err = exp.Renew(namespace.TestContext(), id, 0)
|
||||
if err.Error() != "lease is not renewable" {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1191,7 +1255,7 @@ func TestExpiration_Renew_RevokeOnExpire(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = exp.router.Mount(noop, "prod/aws/", &MountEntry{Path: "prod/aws/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor"}, view)
|
||||
err = exp.router.Mount(noop, "prod/aws/", &MountEntry{Path: "prod/aws/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor", namespace: namespace.TestNamespace()}, view)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1214,7 +1278,7 @@ func TestExpiration_Renew_RevokeOnExpire(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
id, err := exp.Register(context.Background(), req, resp)
|
||||
id, err := exp.Register(namespace.TestContext(), req, resp)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1231,7 +1295,7 @@ func TestExpiration_Renew_RevokeOnExpire(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
_, err = exp.Renew(context.Background(), id, 0)
|
||||
_, err = exp.Renew(namespace.TestContext(), id, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1267,7 +1331,7 @@ func TestExpiration_revokeEntry(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = exp.router.Mount(noop, "foo/bar/", &MountEntry{Path: "foo/bar/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor"}, view)
|
||||
err = exp.router.Mount(noop, "foo/bar/", &MountEntry{Path: "foo/bar/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor", namespace: namespace.TestNamespace()}, view)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1285,9 +1349,10 @@ func TestExpiration_revokeEntry(t *testing.T) {
|
||||
},
|
||||
IssueTime: time.Now(),
|
||||
ExpireTime: time.Now(),
|
||||
namespace: namespace.TestNamespace(),
|
||||
}
|
||||
|
||||
err = exp.revokeEntry(context.Background(), le)
|
||||
err = exp.revokeEntry(namespace.TestContext(), le)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1336,17 +1401,18 @@ func TestExpiration_revokeEntry_token(t *testing.T) {
|
||||
Path: "foo/bar",
|
||||
IssueTime: time.Now(),
|
||||
ExpireTime: time.Now(),
|
||||
namespace: namespace.TestNamespace(),
|
||||
}
|
||||
|
||||
if err := exp.persistEntry(context.Background(), le); err != nil {
|
||||
if err := exp.persistEntry(namespace.TestContext(), le); err != nil {
|
||||
t.Fatalf("error persisting entry: %v", err)
|
||||
}
|
||||
if err := exp.createIndexByToken(context.Background(), le.ClientToken, le.LeaseID); err != nil {
|
||||
if err := exp.createIndexByToken(namespace.TestContext(), le); err != nil {
|
||||
t.Fatalf("error creating secondary index: %v", err)
|
||||
}
|
||||
exp.updatePending(le, le.Secret.LeaseTotal())
|
||||
|
||||
indexEntry, err := exp.indexByToken(context.Background(), le.ClientToken, le.LeaseID)
|
||||
indexEntry, err := exp.indexByToken(namespace.TestContext(), le)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1354,14 +1420,14 @@ func TestExpiration_revokeEntry_token(t *testing.T) {
|
||||
t.Fatalf("err: should have found a secondary index entry")
|
||||
}
|
||||
|
||||
err = exp.revokeEntry(context.Background(), le)
|
||||
err = exp.revokeEntry(namespace.TestContext(), le)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
|
||||
out, err := exp.tokenStore.Lookup(context.Background(), le.ClientToken)
|
||||
out, err := exp.tokenStore.Lookup(namespace.TestContext(), le.ClientToken)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1369,7 +1435,7 @@ func TestExpiration_revokeEntry_token(t *testing.T) {
|
||||
t.Fatalf("bad: %v", out)
|
||||
}
|
||||
|
||||
indexEntry, err = exp.indexByToken(context.Background(), le.ClientToken, le.LeaseID)
|
||||
indexEntry, err = exp.indexByToken(namespace.TestContext(), le)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1400,7 +1466,7 @@ func TestExpiration_renewEntry(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = exp.router.Mount(noop, "foo/bar/", &MountEntry{Path: "foo/bar/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor"}, view)
|
||||
err = exp.router.Mount(noop, "foo/bar/", &MountEntry{Path: "foo/bar/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor", namespace: namespace.TestNamespace()}, view)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1418,9 +1484,10 @@ func TestExpiration_renewEntry(t *testing.T) {
|
||||
},
|
||||
IssueTime: time.Now(),
|
||||
ExpireTime: time.Now(),
|
||||
namespace: namespace.TestNamespace(),
|
||||
}
|
||||
|
||||
resp, err := exp.renewEntry(context.Background(), le, 0)
|
||||
resp, err := exp.renewEntry(namespace.TestContext(), le, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1465,7 +1532,7 @@ func TestExpiration_revokeEntry_rejected(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = exp.router.Mount(noop, "foo/bar/", &MountEntry{Path: "foo/bar/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor"}, view)
|
||||
err = exp.router.Mount(noop, "foo/bar/", &MountEntry{Path: "foo/bar/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor", namespace: namespace.TestNamespace()}, view)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1483,14 +1550,15 @@ func TestExpiration_revokeEntry_rejected(t *testing.T) {
|
||||
},
|
||||
IssueTime: time.Now(),
|
||||
ExpireTime: time.Now().Add(time.Minute),
|
||||
namespace: namespace.TestNamespace(),
|
||||
}
|
||||
|
||||
err = exp.persistEntry(context.Background(), le)
|
||||
err = exp.persistEntry(namespace.TestContext(), le)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = exp.LazyRevoke(context.Background(), le.LeaseID)
|
||||
err = exp.LazyRevoke(namespace.TestContext(), le.LeaseID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1507,7 +1575,7 @@ func TestExpiration_revokeEntry_rejected(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = core.setupExpiration()
|
||||
err = core.setupExpiration(expireLeaseStrategyRevoke)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1523,7 +1591,7 @@ func TestExpiration_revokeEntry_rejected(t *testing.T) {
|
||||
// Now let the revocation actually process
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
le, err = exp.FetchLeaseTimes(context.Background(), le.LeaseID)
|
||||
le, err = exp.FetchLeaseTimes(namespace.TestContext(), le.LeaseID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1551,7 +1619,7 @@ func TestExpiration_renewAuthEntry(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = exp.router.Mount(noop, "auth/foo/", &MountEntry{Path: "auth/foo/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor"}, view)
|
||||
err = exp.router.Mount(noop, "auth/foo/", &MountEntry{Path: "auth/foo/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor", namespace: namespace.TestNamespace()}, view)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1570,9 +1638,10 @@ func TestExpiration_renewAuthEntry(t *testing.T) {
|
||||
},
|
||||
IssueTime: time.Now(),
|
||||
ExpireTime: time.Now().Add(time.Minute),
|
||||
namespace: namespace.TestNamespace(),
|
||||
}
|
||||
|
||||
resp, err := exp.renewAuthEntry(context.Background(), &logical.Request{}, le, 0)
|
||||
resp, err := exp.renewAuthEntry(namespace.TestContext(), &logical.Request{}, le, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1613,12 +1682,13 @@ func TestExpiration_PersistLoadDelete(t *testing.T) {
|
||||
IssueTime: lastTime,
|
||||
ExpireTime: lastTime,
|
||||
LastRenewalTime: lastTime,
|
||||
namespace: namespace.TestNamespace(),
|
||||
}
|
||||
if err := exp.persistEntry(context.Background(), le); err != nil {
|
||||
if err := exp.persistEntry(namespace.TestContext(), le); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
out, err := exp.loadEntry(context.Background(), "foo/bar/1234")
|
||||
out, err := exp.loadEntry(namespace.TestContext(), "foo/bar/1234")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1634,12 +1704,12 @@ func TestExpiration_PersistLoadDelete(t *testing.T) {
|
||||
t.Fatalf("bad: expected:\n%#v\nactual:\n%#v", le, out)
|
||||
}
|
||||
|
||||
err = exp.deleteEntry(context.Background(), "foo/bar/1234")
|
||||
err = exp.deleteEntry(namespace.TestContext(), le)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
out, err = exp.loadEntry(context.Background(), "foo/bar/1234")
|
||||
out, err = exp.loadEntry(namespace.TestContext(), "foo/bar/1234")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -1722,7 +1792,7 @@ func TestExpiration_RevokeForce(t *testing.T) {
|
||||
Accessor: "badrenewaccessor",
|
||||
}
|
||||
|
||||
err := core.mount(context.Background(), me)
|
||||
err := core.mount(namespace.TestContext(), me)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1733,7 +1803,7 @@ func TestExpiration_RevokeForce(t *testing.T) {
|
||||
ClientToken: root,
|
||||
}
|
||||
|
||||
resp, err := core.HandleRequest(context.Background(), req)
|
||||
resp, err := core.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1747,13 +1817,13 @@ func TestExpiration_RevokeForce(t *testing.T) {
|
||||
req.Operation = logical.UpdateOperation
|
||||
req.Path = "sys/revoke-prefix/badrenew/creds"
|
||||
|
||||
resp, err = core.HandleRequest(context.Background(), req)
|
||||
resp, err = core.HandleRequest(namespace.TestContext(), req)
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
|
||||
req.Path = "sys/revoke-force/badrenew/creds"
|
||||
resp, err = core.HandleRequest(context.Background(), req)
|
||||
resp, err = core.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil {
|
||||
t.Fatalf("got error: %s", err)
|
||||
}
|
||||
@@ -1770,7 +1840,7 @@ func TestExpiration_RevokeForceSingle(t *testing.T) {
|
||||
Accessor: "badrenewaccessor",
|
||||
}
|
||||
|
||||
err := core.mount(context.Background(), me)
|
||||
err := core.mount(namespace.TestContext(), me)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1781,7 +1851,7 @@ func TestExpiration_RevokeForceSingle(t *testing.T) {
|
||||
ClientToken: root,
|
||||
}
|
||||
|
||||
resp, err := core.HandleRequest(context.Background(), req)
|
||||
resp, err := core.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1796,7 +1866,7 @@ func TestExpiration_RevokeForceSingle(t *testing.T) {
|
||||
req.Operation = logical.UpdateOperation
|
||||
req.Path = "sys/leases/lookup"
|
||||
req.Data = map[string]interface{}{"lease_id": leaseID}
|
||||
resp, err = core.HandleRequest(context.Background(), req)
|
||||
resp, err = core.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1809,20 +1879,20 @@ func TestExpiration_RevokeForceSingle(t *testing.T) {
|
||||
|
||||
req.Path = "sys/revoke-prefix/" + leaseID
|
||||
|
||||
resp, err = core.HandleRequest(context.Background(), req)
|
||||
resp, err = core.HandleRequest(namespace.TestContext(), req)
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
|
||||
req.Path = "sys/revoke-force/" + leaseID
|
||||
resp, err = core.HandleRequest(context.Background(), req)
|
||||
resp, err = core.HandleRequest(namespace.TestContext(), req)
|
||||
if err != nil {
|
||||
t.Fatalf("got error: %s", err)
|
||||
}
|
||||
|
||||
req.Path = "sys/leases/lookup"
|
||||
req.Data = map[string]interface{}{"lease_id": leaseID}
|
||||
resp, err = core.HandleRequest(context.Background(), req)
|
||||
resp, err = core.HandleRequest(namespace.TestContext(), req)
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
@@ -1834,7 +1904,7 @@ func TestExpiration_RevokeForceSingle(t *testing.T) {
|
||||
func badRenewFactory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) {
|
||||
be := &framework.Backend{
|
||||
Paths: []*framework.Path{
|
||||
&framework.Path{
|
||||
{
|
||||
Pattern: "creds",
|
||||
Callbacks: map[logical.Operation]framework.OperationFunc{
|
||||
logical.ReadOperation: func(context.Context, *logical.Request, *framework.FieldData) (*logical.Response, error) {
|
||||
@@ -1862,7 +1932,7 @@ func badRenewFactory(ctx context.Context, conf *logical.BackendConfig) (logical.
|
||||
},
|
||||
}
|
||||
|
||||
err := be.Setup(context.Background(), conf)
|
||||
err := be.Setup(namespace.TestContext(), conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
29
vault/expiration_util.go
Normal file
29
vault/expiration_util.go
Normal file
@@ -0,0 +1,29 @@
|
||||
// +build !enterprise
|
||||
|
||||
package vault
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/errwrap"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
)
|
||||
|
||||
func (m *ExpirationManager) leaseView(*namespace.Namespace) *BarrierView {
|
||||
return m.idView
|
||||
}
|
||||
|
||||
func (m *ExpirationManager) tokenIndexView(*namespace.Namespace) *BarrierView {
|
||||
return m.tokenView
|
||||
}
|
||||
|
||||
func (m *ExpirationManager) collectLeases() (map[*namespace.Namespace][]string, int, error) {
|
||||
leaseCount := 0
|
||||
existing := make(map[*namespace.Namespace][]string)
|
||||
keys, err := logical.CollectKeys(m.quitContext, m.leaseView(namespace.RootNamespace))
|
||||
if err != nil {
|
||||
return nil, 0, errwrap.Wrapf("failed to scan for leases: {{err}}", err)
|
||||
}
|
||||
existing[namespace.RootNamespace] = keys
|
||||
leaseCount += len(keys)
|
||||
return existing, leaseCount, nil
|
||||
}
|
||||
@@ -20,6 +20,10 @@ var (
|
||||
// GenerateStandardRootTokenStrategy is the strategy used to generate a
|
||||
// typical root token
|
||||
GenerateStandardRootTokenStrategy GenerateRootStrategy = generateStandardRootToken{}
|
||||
|
||||
// GenerateDROperationTokenStrategy is the strategy used to generate a
|
||||
// DR operational token
|
||||
GenerateDROperationTokenStrategy GenerateRootStrategy = generateStandardRootToken{}
|
||||
)
|
||||
|
||||
// GenerateRootStrategy allows us to swap out the strategy we want to use to
|
||||
@@ -117,12 +121,8 @@ func (c *Core) GenerateRootInit(otp, pgpKey string, strategy GenerateRootStrateg
|
||||
var fingerprint string
|
||||
switch {
|
||||
case len(otp) > 0:
|
||||
otpBytes, err := base64.StdEncoding.DecodeString(otp)
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("error decoding base64 OTP value: {{err}}", err)
|
||||
}
|
||||
if otpBytes == nil || len(otpBytes) != 16 {
|
||||
return fmt.Errorf("decoded OTP value is invalid or wrong length")
|
||||
if len(otp) != TokenLength {
|
||||
return fmt.Errorf("OTP string is wrong length")
|
||||
}
|
||||
|
||||
case len(pgpKey) > 0:
|
||||
@@ -136,7 +136,7 @@ func (c *Core) GenerateRootInit(otp, pgpKey string, strategy GenerateRootStrateg
|
||||
fingerprint = fingerprints[0]
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unreachable condition")
|
||||
return fmt.Errorf("otp or pgp_key parameter must be provided")
|
||||
}
|
||||
|
||||
c.stateLock.RLock()
|
||||
@@ -171,8 +171,14 @@ func (c *Core) GenerateRootInit(otp, pgpKey string, strategy GenerateRootStrateg
|
||||
}
|
||||
|
||||
if c.logger.IsInfo() {
|
||||
c.logger.Info("root generation initialized", "nonce", c.generateRootConfig.Nonce)
|
||||
switch strategy.(type) {
|
||||
case generateStandardRootToken:
|
||||
c.logger.Info("root generation initialized", "nonce", c.generateRootConfig.Nonce)
|
||||
default:
|
||||
c.logger.Info("dr operation token generation initialized", "nonce", c.generateRootConfig.Nonce)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -284,45 +290,35 @@ func (c *Core) GenerateRootUpdate(ctx context.Context, key []byte, nonce string,
|
||||
}
|
||||
|
||||
// Run the generate strategy
|
||||
tokenUUID, cleanupFunc, err := strategy.generate(ctx, c)
|
||||
token, cleanupFunc, err := strategy.generate(ctx, c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
uuidBytes, err := uuid.ParseUUID(tokenUUID)
|
||||
if err != nil {
|
||||
cleanupFunc()
|
||||
c.logger.Error("error getting generated token bytes", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
if uuidBytes == nil {
|
||||
cleanupFunc()
|
||||
c.logger.Error("got nil parsed UUID bytes")
|
||||
return nil, fmt.Errorf("got nil parsed UUID bytes")
|
||||
}
|
||||
|
||||
var tokenBytes []byte
|
||||
|
||||
// Get the encoded value first so that if there is an error we don't create
|
||||
// the root token.
|
||||
switch {
|
||||
case len(c.generateRootConfig.OTP) > 0:
|
||||
// This function performs decoding checks so rather than decode the OTP,
|
||||
// just encode the value we're passing in.
|
||||
tokenBytes, err = xor.XORBase64(c.generateRootConfig.OTP, base64.StdEncoding.EncodeToString(uuidBytes))
|
||||
tokenBytes, err = xor.XORBytes([]byte(c.generateRootConfig.OTP), []byte(token))
|
||||
if err != nil {
|
||||
cleanupFunc()
|
||||
c.logger.Error("xor of root token failed", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
token = base64.RawStdEncoding.EncodeToString(tokenBytes)
|
||||
|
||||
case len(c.generateRootConfig.PGPKey) > 0:
|
||||
_, tokenBytesArr, err := pgpkeys.EncryptShares([][]byte{[]byte(tokenUUID)}, []string{c.generateRootConfig.PGPKey})
|
||||
_, tokenBytesArr, err := pgpkeys.EncryptShares([][]byte{[]byte(token)}, []string{c.generateRootConfig.PGPKey})
|
||||
if err != nil {
|
||||
cleanupFunc()
|
||||
c.logger.Error("error encrypting new root token", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
tokenBytes = tokenBytesArr[0]
|
||||
token = base64.StdEncoding.EncodeToString(tokenBytesArr[0])
|
||||
|
||||
default:
|
||||
cleanupFunc()
|
||||
@@ -332,12 +328,19 @@ func (c *Core) GenerateRootUpdate(ctx context.Context, key []byte, nonce string,
|
||||
results := &GenerateRootResult{
|
||||
Progress: progress,
|
||||
Required: config.SecretThreshold,
|
||||
EncodedToken: base64.StdEncoding.EncodeToString(tokenBytes),
|
||||
EncodedToken: token,
|
||||
PGPFingerprint: c.generateRootConfig.PGPFingerprint,
|
||||
}
|
||||
|
||||
if c.logger.IsInfo() {
|
||||
c.logger.Info("root generation finished", "nonce", c.generateRootConfig.Nonce)
|
||||
switch strategy.(type) {
|
||||
case generateStandardRootToken:
|
||||
if c.logger.IsInfo() {
|
||||
c.logger.Info("root generation finished", "nonce", c.generateRootConfig.Nonce)
|
||||
}
|
||||
default:
|
||||
if c.logger.IsInfo() {
|
||||
c.logger.Info("dr operation token generation finished", "nonce", c.generateRootConfig.Nonce)
|
||||
}
|
||||
}
|
||||
|
||||
c.generateRootProgress = nil
|
||||
|
||||
@@ -1,24 +1,22 @@
|
||||
package vault
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/go-uuid"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/helper/pgpkeys"
|
||||
"github.com/hashicorp/vault/helper/xor"
|
||||
)
|
||||
|
||||
func TestCore_GenerateRoot_Lifecycle(t *testing.T) {
|
||||
bc, rc := TestSealDefConfigs()
|
||||
c, masterKeys, _, _ := TestCoreUnsealedWithConfigs(t, bc, rc)
|
||||
c, masterKeys, _ := TestCoreUnsealed(t)
|
||||
testCore_GenerateRoot_Lifecycle_Common(t, c, masterKeys)
|
||||
}
|
||||
|
||||
func testCore_GenerateRoot_Lifecycle_Common(t *testing.T, c *Core, keys [][]byte) {
|
||||
// Verify update not allowed
|
||||
if _, err := c.GenerateRootUpdate(context.Background(), keys[0], "", GenerateStandardRootTokenStrategy); err == nil {
|
||||
if _, err := c.GenerateRootUpdate(namespace.RootContext(nil), keys[0], "", GenerateStandardRootTokenStrategy); err == nil {
|
||||
t.Fatalf("no root generation in progress")
|
||||
}
|
||||
|
||||
@@ -107,10 +105,7 @@ func testCore_GenerateRoot_Init_Common(t *testing.T, c *Core) {
|
||||
}
|
||||
|
||||
func TestCore_GenerateRoot_InvalidMasterNonce(t *testing.T) {
|
||||
bc, _ := TestSealDefConfigs()
|
||||
bc.SecretShares = 3
|
||||
bc.SecretThreshold = 3
|
||||
c, masterKeys, _, _ := TestCoreUnsealedWithConfigs(t, bc, nil)
|
||||
c, masterKeys, _ := TestCoreUnsealed(t)
|
||||
// Pass in master keys as they'll be invalid
|
||||
masterKeys[0][0]++
|
||||
testCore_GenerateRoot_InvalidMasterNonce_Common(t, c, masterKeys)
|
||||
@@ -137,14 +132,14 @@ func testCore_GenerateRoot_InvalidMasterNonce_Common(t *testing.T, c *Core, keys
|
||||
}
|
||||
|
||||
// Provide the nonce (invalid)
|
||||
_, err = c.GenerateRootUpdate(context.Background(), keys[0], "abcd", GenerateStandardRootTokenStrategy)
|
||||
_, err = c.GenerateRootUpdate(namespace.RootContext(nil), keys[0], "abcd", GenerateStandardRootTokenStrategy)
|
||||
if err == nil {
|
||||
t.Fatalf("expected error")
|
||||
}
|
||||
|
||||
// Provide the master (invalid)
|
||||
for _, key := range keys {
|
||||
_, err = c.GenerateRootUpdate(context.Background(), key, rgconf.Nonce, GenerateStandardRootTokenStrategy)
|
||||
_, err = c.GenerateRootUpdate(namespace.RootContext(nil), key, rgconf.Nonce, GenerateStandardRootTokenStrategy)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatalf("expected error")
|
||||
@@ -152,9 +147,8 @@ func testCore_GenerateRoot_InvalidMasterNonce_Common(t *testing.T, c *Core, keys
|
||||
}
|
||||
|
||||
func TestCore_GenerateRoot_Update_OTP(t *testing.T) {
|
||||
bc, rc := TestSealDefConfigs()
|
||||
c, masterKeys, _, _ := TestCoreUnsealedWithConfigs(t, bc, rc)
|
||||
testCore_GenerateRoot_Update_OTP_Common(t, c, masterKeys[0:bc.SecretThreshold])
|
||||
c, masterKeys, _ := TestCoreUnsealed(t)
|
||||
testCore_GenerateRoot_Update_OTP_Common(t, c, masterKeys)
|
||||
}
|
||||
|
||||
func testCore_GenerateRoot_Update_OTP_Common(t *testing.T, c *Core, keys [][]byte) {
|
||||
@@ -182,10 +176,13 @@ func testCore_GenerateRoot_Update_OTP_Common(t *testing.T, c *Core, keys [][]byt
|
||||
// Provide the keys
|
||||
var result *GenerateRootResult
|
||||
for _, key := range keys {
|
||||
result, err = c.GenerateRootUpdate(context.Background(), key, rkconf.Nonce, GenerateStandardRootTokenStrategy)
|
||||
result, err = c.GenerateRootUpdate(namespace.RootContext(nil), key, rkconf.Nonce, GenerateStandardRootTokenStrategy)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if result.EncodedToken != "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
if result == nil {
|
||||
t.Fatalf("Bad, result is nil")
|
||||
@@ -211,17 +208,20 @@ func testCore_GenerateRoot_Update_OTP_Common(t *testing.T, c *Core, keys [][]byt
|
||||
t.Fatalf("bad: %v", conf)
|
||||
}
|
||||
|
||||
tokenBytes, err := xor.XORBase64(encodedToken, otp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
token, err := uuid.FormatUUID(tokenBytes)
|
||||
tokenBytes, err := base64.StdEncoding.DecodeString(encodedToken)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tokenBytes, err = xor.XORBytes(tokenBytes, []byte(otp))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
token := string(tokenBytes)
|
||||
|
||||
// Ensure that the token is a root token
|
||||
te, err := c.tokenStore.Lookup(context.Background(), token)
|
||||
te, err := c.tokenStore.Lookup(namespace.RootContext(nil), token)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -235,9 +235,8 @@ func testCore_GenerateRoot_Update_OTP_Common(t *testing.T, c *Core, keys [][]byt
|
||||
}
|
||||
|
||||
func TestCore_GenerateRoot_Update_PGP(t *testing.T) {
|
||||
bc, rc := TestSealDefConfigs()
|
||||
c, masterKeys, _, _ := TestCoreUnsealedWithConfigs(t, bc, rc)
|
||||
testCore_GenerateRoot_Update_PGP_Common(t, c, masterKeys[0:bc.SecretThreshold])
|
||||
c, masterKeys, _ := TestCoreUnsealed(t)
|
||||
testCore_GenerateRoot_Update_PGP_Common(t, c, masterKeys)
|
||||
}
|
||||
|
||||
func testCore_GenerateRoot_Update_PGP_Common(t *testing.T, c *Core, keys [][]byte) {
|
||||
@@ -259,10 +258,13 @@ func testCore_GenerateRoot_Update_PGP_Common(t *testing.T, c *Core, keys [][]byt
|
||||
// Provide the keys
|
||||
var result *GenerateRootResult
|
||||
for _, key := range keys {
|
||||
result, err = c.GenerateRootUpdate(context.Background(), key, rkconf.Nonce, GenerateStandardRootTokenStrategy)
|
||||
result, err = c.GenerateRootUpdate(namespace.RootContext(nil), key, rkconf.Nonce, GenerateStandardRootTokenStrategy)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if result.EncodedToken != "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
if result == nil {
|
||||
t.Fatalf("Bad, result is nil")
|
||||
@@ -299,7 +301,7 @@ func testCore_GenerateRoot_Update_PGP_Common(t *testing.T, c *Core, keys [][]byt
|
||||
token := ptBuf.String()
|
||||
|
||||
// Ensure that the token is a root token
|
||||
te, err := c.tokenStore.Lookup(context.Background(), token)
|
||||
te, err := c.tokenStore.Lookup(namespace.RootContext(nil), token)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
14
vault/ha.go
14
vault/ha.go
@@ -210,7 +210,7 @@ func (c *Core) StepDown(httpCtx context.Context, req *logical.Request) (retErr e
|
||||
}
|
||||
}()
|
||||
|
||||
acl, te, entity, identityPolicies, err := c.fetchACLTokenEntryAndEntity(req)
|
||||
acl, te, entity, identityPolicies, err := c.fetchACLTokenEntryAndEntity(ctx, req)
|
||||
if err != nil {
|
||||
if errwrap.ContainsType(err, new(TemplateError)) {
|
||||
c.logger.Warn("permission denied due to a templated policy being invalid or containing directives not satisfied by the requestor", "error", err)
|
||||
@@ -222,13 +222,14 @@ func (c *Core) StepDown(httpCtx context.Context, req *logical.Request) (retErr e
|
||||
|
||||
// Audit-log the request before going any further
|
||||
auth := &logical.Auth{
|
||||
ClientToken: req.ClientToken,
|
||||
Policies: identityPolicies,
|
||||
IdentityPolicies: identityPolicies,
|
||||
ClientToken: req.ClientToken,
|
||||
}
|
||||
if te != nil {
|
||||
auth.IdentityPolicies = identityPolicies[te.NamespaceID]
|
||||
delete(identityPolicies, te.NamespaceID)
|
||||
auth.ExternalNamespacePolicies = identityPolicies
|
||||
auth.TokenPolicies = te.Policies
|
||||
auth.Policies = append(te.Policies, identityPolicies...)
|
||||
auth.Policies = append(te.Policies, identityPolicies[te.NamespaceID]...)
|
||||
auth.Metadata = te.Meta
|
||||
auth.DisplayName = te.DisplayName
|
||||
auth.EntityID = te.EntityID
|
||||
@@ -477,6 +478,7 @@ func (c *Core) waitForLeadership(newLeaderCh chan func(), manualStepDownCh, stop
|
||||
metrics.MeasureSince([]string{"core", "leadership_setup_failed"}, activeTime)
|
||||
continue
|
||||
}
|
||||
|
||||
}
|
||||
// Advertise as leader
|
||||
if err := c.advertiseLeader(activeCtx, uuid, leaderLostCh); err != nil {
|
||||
@@ -490,7 +492,7 @@ func (c *Core) waitForLeadership(newLeaderCh chan func(), manualStepDownCh, stop
|
||||
}
|
||||
|
||||
// Attempt the post-unseal process
|
||||
err = c.postUnseal(activeCtx, activeCtxCancel)
|
||||
err = c.postUnseal(activeCtx, activeCtxCancel, standardUnsealStrategy{})
|
||||
if err == nil {
|
||||
c.standby = false
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ func (i *IdentityStore) pathLookupEntityUpdate() framework.OperationFunc {
|
||||
}
|
||||
|
||||
case name != "":
|
||||
entity, err = i.MemDBEntityByName(name, false)
|
||||
entity, err = i.MemDBEntityByName(ctx, name, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -185,7 +185,7 @@ func (i *IdentityStore) pathLookupEntityUpdate() framework.OperationFunc {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return i.handleEntityReadCommon(entity)
|
||||
return i.handleEntityReadCommon(ctx, entity)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,7 +256,7 @@ func (i *IdentityStore) pathLookupGroupUpdate() framework.OperationFunc {
|
||||
return nil, err
|
||||
}
|
||||
case name != "":
|
||||
group, err = i.MemDBGroupByName(name, false)
|
||||
group, err = i.MemDBGroupByName(ctx, name, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -295,7 +295,7 @@ func (i *IdentityStore) pathLookupGroupUpdate() framework.OperationFunc {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return i.handleGroupReadCommon(group)
|
||||
return i.handleGroupReadCommon(ctx, group)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package vault
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
)
|
||||
|
||||
@@ -11,13 +11,14 @@ func TestIdentityStore_Lookup_Entity(t *testing.T) {
|
||||
var err error
|
||||
var resp *logical.Response
|
||||
|
||||
i, accessor, _ := testIdentityStoreWithGithubAuth(t)
|
||||
ctx := namespace.RootContext(nil)
|
||||
i, accessor, _ := testIdentityStoreWithGithubAuth(ctx, t)
|
||||
|
||||
entityReq := &logical.Request{
|
||||
Path: "entity",
|
||||
Operation: logical.UpdateOperation,
|
||||
}
|
||||
resp, err = i.HandleRequest(context.Background(), entityReq)
|
||||
resp, err = i.HandleRequest(ctx, entityReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("bad: err: %#v\nresp: %v", err, resp)
|
||||
}
|
||||
@@ -33,7 +34,7 @@ func TestIdentityStore_Lookup_Entity(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err = i.HandleRequest(context.Background(), aliasReq)
|
||||
resp, err = i.HandleRequest(ctx, aliasReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("bad: err: %#v\nresp: %v", err, resp)
|
||||
}
|
||||
@@ -51,7 +52,7 @@ func TestIdentityStore_Lookup_Entity(t *testing.T) {
|
||||
"id": entityID,
|
||||
},
|
||||
}
|
||||
resp, err = i.HandleRequest(context.Background(), lookupReq)
|
||||
resp, err = i.HandleRequest(ctx, lookupReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("bad: err: %#v\nresp: %v", err, resp)
|
||||
}
|
||||
@@ -64,7 +65,7 @@ func TestIdentityStore_Lookup_Entity(t *testing.T) {
|
||||
"name": entity.Name,
|
||||
}
|
||||
|
||||
resp, err = i.HandleRequest(context.Background(), lookupReq)
|
||||
resp, err = i.HandleRequest(ctx, lookupReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("bad: err: %#v\nresp: %v", err, resp)
|
||||
}
|
||||
@@ -77,7 +78,7 @@ func TestIdentityStore_Lookup_Entity(t *testing.T) {
|
||||
"alias_id": aliasID,
|
||||
}
|
||||
|
||||
resp, err = i.HandleRequest(context.Background(), lookupReq)
|
||||
resp, err = i.HandleRequest(ctx, lookupReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("bad: err: %#v\nresp: %v", err, resp)
|
||||
}
|
||||
@@ -91,7 +92,7 @@ func TestIdentityStore_Lookup_Entity(t *testing.T) {
|
||||
"alias_mount_accessor": accessor,
|
||||
}
|
||||
|
||||
resp, err = i.HandleRequest(context.Background(), lookupReq)
|
||||
resp, err = i.HandleRequest(ctx, lookupReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("bad: err: %#v\nresp: %v", err, resp)
|
||||
}
|
||||
@@ -106,7 +107,7 @@ func TestIdentityStore_Lookup_Entity(t *testing.T) {
|
||||
"name": entity.Name,
|
||||
}
|
||||
|
||||
resp, err = i.HandleRequest(context.Background(), lookupReq)
|
||||
resp, err = i.HandleRequest(ctx, lookupReq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -119,7 +120,7 @@ func TestIdentityStore_Lookup_Entity(t *testing.T) {
|
||||
"alias_name": "testaliasname",
|
||||
}
|
||||
|
||||
resp, err = i.HandleRequest(context.Background(), lookupReq)
|
||||
resp, err = i.HandleRequest(ctx, lookupReq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -132,7 +133,7 @@ func TestIdentityStore_Lookup_Entity(t *testing.T) {
|
||||
"alias_mount_accessor": accessor,
|
||||
}
|
||||
|
||||
resp, err = i.HandleRequest(context.Background(), lookupReq)
|
||||
resp, err = i.HandleRequest(ctx, lookupReq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -143,7 +144,7 @@ func TestIdentityStore_Lookup_Entity(t *testing.T) {
|
||||
// Don't supply any criteria
|
||||
lookupReq.Data = nil
|
||||
|
||||
resp, err = i.HandleRequest(context.Background(), lookupReq)
|
||||
resp, err = i.HandleRequest(ctx, lookupReq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -154,7 +155,7 @@ func TestIdentityStore_Lookup_Entity(t *testing.T) {
|
||||
// Delete the alias in the entity
|
||||
aliasReq.Path = "entity-alias/id/" + aliasID
|
||||
aliasReq.Operation = logical.DeleteOperation
|
||||
resp, err = i.HandleRequest(context.Background(), aliasReq)
|
||||
resp, err = i.HandleRequest(ctx, aliasReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("bad: err: %#v\nresp: %v", err, resp)
|
||||
}
|
||||
@@ -163,7 +164,7 @@ func TestIdentityStore_Lookup_Entity(t *testing.T) {
|
||||
"alias_id": aliasID,
|
||||
}
|
||||
|
||||
resp, err = i.HandleRequest(context.Background(), lookupReq)
|
||||
resp, err = i.HandleRequest(ctx, lookupReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("bad: err: %#v\nresp: %v", err, resp)
|
||||
}
|
||||
@@ -176,13 +177,14 @@ func TestIdentityStore_Lookup_Group(t *testing.T) {
|
||||
var err error
|
||||
var resp *logical.Response
|
||||
|
||||
i, accessor, _ := testIdentityStoreWithGithubAuth(t)
|
||||
ctx := namespace.RootContext(nil)
|
||||
i, accessor, _ := testIdentityStoreWithGithubAuth(ctx, t)
|
||||
|
||||
groupReq := &logical.Request{
|
||||
Path: "group",
|
||||
Operation: logical.UpdateOperation,
|
||||
}
|
||||
resp, err = i.HandleRequest(context.Background(), groupReq)
|
||||
resp, err = i.HandleRequest(ctx, groupReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("bad: resp: %#v\n err: %#v\n", resp, err)
|
||||
}
|
||||
@@ -197,7 +199,7 @@ func TestIdentityStore_Lookup_Group(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err = i.HandleRequest(context.Background(), lookupReq)
|
||||
resp, err = i.HandleRequest(ctx, lookupReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("bad: resp: %#v\n err: %#v\n", resp, err)
|
||||
}
|
||||
@@ -209,7 +211,7 @@ func TestIdentityStore_Lookup_Group(t *testing.T) {
|
||||
"name": groupName,
|
||||
}
|
||||
|
||||
resp, err = i.HandleRequest(context.Background(), lookupReq)
|
||||
resp, err = i.HandleRequest(ctx, lookupReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("bad: resp: %#v\n err: %#v\n", resp, err)
|
||||
}
|
||||
@@ -221,7 +223,7 @@ func TestIdentityStore_Lookup_Group(t *testing.T) {
|
||||
lookupReq.Data = map[string]interface{}{
|
||||
"alias_id": "invalidaliasid",
|
||||
}
|
||||
resp, err = i.HandleRequest(context.Background(), lookupReq)
|
||||
resp, err = i.HandleRequest(ctx, lookupReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("bad: resp: %#v\n err: %#v\n", resp, err)
|
||||
}
|
||||
@@ -232,7 +234,7 @@ func TestIdentityStore_Lookup_Group(t *testing.T) {
|
||||
groupReq.Data = map[string]interface{}{
|
||||
"type": "external",
|
||||
}
|
||||
resp, err = i.HandleRequest(context.Background(), groupReq)
|
||||
resp, err = i.HandleRequest(ctx, groupReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("bad: resp: %#v\n err: %#v\n", resp, err)
|
||||
}
|
||||
@@ -247,7 +249,7 @@ func TestIdentityStore_Lookup_Group(t *testing.T) {
|
||||
"mount_accessor": accessor,
|
||||
},
|
||||
}
|
||||
resp, err = i.HandleRequest(context.Background(), aliasReq)
|
||||
resp, err = i.HandleRequest(ctx, aliasReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("bad: resp: %#v\n err: %#v\n", resp, err)
|
||||
}
|
||||
@@ -257,7 +259,7 @@ func TestIdentityStore_Lookup_Group(t *testing.T) {
|
||||
"alias_id": aliasID,
|
||||
}
|
||||
|
||||
resp, err = i.HandleRequest(context.Background(), lookupReq)
|
||||
resp, err = i.HandleRequest(ctx, lookupReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("bad: resp: %#v\n err: %#v\n", resp, err)
|
||||
}
|
||||
@@ -270,7 +272,7 @@ func TestIdentityStore_Lookup_Group(t *testing.T) {
|
||||
"alias_mount_accessor": accessor,
|
||||
}
|
||||
|
||||
resp, err = i.HandleRequest(context.Background(), lookupReq)
|
||||
resp, err = i.HandleRequest(ctx, lookupReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("bad: resp: %#v\n err: %#v\n", resp, err)
|
||||
}
|
||||
@@ -284,7 +286,7 @@ func TestIdentityStore_Lookup_Group(t *testing.T) {
|
||||
"name": groupName,
|
||||
}
|
||||
|
||||
resp, err = i.HandleRequest(context.Background(), lookupReq)
|
||||
resp, err = i.HandleRequest(ctx, lookupReq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -297,7 +299,7 @@ func TestIdentityStore_Lookup_Group(t *testing.T) {
|
||||
"alias_name": "testgroupalias",
|
||||
}
|
||||
|
||||
resp, err = i.HandleRequest(context.Background(), lookupReq)
|
||||
resp, err = i.HandleRequest(ctx, lookupReq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -310,7 +312,7 @@ func TestIdentityStore_Lookup_Group(t *testing.T) {
|
||||
"alias_mount_accessor": accessor,
|
||||
}
|
||||
|
||||
resp, err = i.HandleRequest(context.Background(), lookupReq)
|
||||
resp, err = i.HandleRequest(ctx, lookupReq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -321,7 +323,7 @@ func TestIdentityStore_Lookup_Group(t *testing.T) {
|
||||
// Don't supply any criteria
|
||||
lookupReq.Data = nil
|
||||
|
||||
resp, err = i.HandleRequest(context.Background(), lookupReq)
|
||||
resp, err = i.HandleRequest(ctx, lookupReq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,9 @@ import (
|
||||
"github.com/hashicorp/errwrap"
|
||||
log "github.com/hashicorp/go-hclog"
|
||||
memdb "github.com/hashicorp/go-memdb"
|
||||
"github.com/hashicorp/vault/helper/consts"
|
||||
"github.com/hashicorp/vault/helper/identity"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/helper/storagepacker"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/logical/framework"
|
||||
@@ -19,6 +21,12 @@ const (
|
||||
groupBucketsPrefix = "packer/group/buckets/"
|
||||
)
|
||||
|
||||
var (
|
||||
sendGroupUpgrade = func(*IdentityStore, *identity.Group) (bool, error) { return false, nil }
|
||||
parseExtraEntityFromBucket = func(context.Context, *IdentityStore, *identity.Entity) (bool, error) { return false, nil }
|
||||
addExtraEntityDataToResponse = func(*identity.Entity, map[string]interface{}) {}
|
||||
)
|
||||
|
||||
func (c *Core) IdentityStore() *IdentityStore {
|
||||
return c.identityStore
|
||||
}
|
||||
@@ -56,15 +64,8 @@ func NewIdentityStore(ctx context.Context, core *Core, config *logical.BackendCo
|
||||
|
||||
iStore.Backend = &framework.Backend{
|
||||
BackendType: logical.TypeLogical,
|
||||
Paths: framework.PathAppend(
|
||||
entityPaths(iStore),
|
||||
aliasPaths(iStore),
|
||||
groupAliasPaths(iStore),
|
||||
groupPaths(iStore),
|
||||
lookupPaths(iStore),
|
||||
upgradePaths(iStore),
|
||||
),
|
||||
Invalidate: iStore.Invalidate,
|
||||
Paths: iStore.paths(),
|
||||
Invalidate: iStore.Invalidate,
|
||||
}
|
||||
|
||||
err = iStore.Setup(ctx, config)
|
||||
@@ -75,6 +76,17 @@ func NewIdentityStore(ctx context.Context, core *Core, config *logical.BackendCo
|
||||
return iStore, nil
|
||||
}
|
||||
|
||||
func (i *IdentityStore) paths() []*framework.Path {
|
||||
return framework.PathAppend(
|
||||
entityPaths(i),
|
||||
aliasPaths(i),
|
||||
groupAliasPaths(i),
|
||||
groupPaths(i),
|
||||
lookupPaths(i),
|
||||
upgradePaths(i),
|
||||
)
|
||||
}
|
||||
|
||||
// Invalidate is a callback wherein the backend is informed that the value at
|
||||
// the given key is updated. In identity store's case, it would be the entity
|
||||
// storage entries that get updated. The value needs to be read and MemDB needs
|
||||
@@ -82,6 +94,9 @@ func NewIdentityStore(ctx context.Context, core *Core, config *logical.BackendCo
|
||||
func (i *IdentityStore) Invalidate(ctx context.Context, key string) {
|
||||
i.logger.Debug("invalidate notification received", "key", key)
|
||||
|
||||
i.lock.Lock()
|
||||
defer i.lock.Unlock()
|
||||
|
||||
switch {
|
||||
// Check if the key is a storage entry key for an entity bucket
|
||||
case strings.HasPrefix(key, storagepacker.StoragePackerBucketsPrefix):
|
||||
@@ -146,7 +161,7 @@ func (i *IdentityStore) Invalidate(ctx context.Context, key string) {
|
||||
}
|
||||
|
||||
// Only update MemDB and don't touch the storage
|
||||
err = i.upsertEntityInTxn(txn, entity, nil, false)
|
||||
err = i.upsertEntityInTxn(ctx, txn, entity, nil, false)
|
||||
if err != nil {
|
||||
i.logger.Error("failed to update entity in MemDB", "error", err)
|
||||
return
|
||||
@@ -237,10 +252,81 @@ func (i *IdentityStore) parseEntityFromBucketItem(ctx context.Context, item *sto
|
||||
return nil, fmt.Errorf("nil item")
|
||||
}
|
||||
|
||||
persistNeeded := false
|
||||
|
||||
var entity identity.Entity
|
||||
err := ptypes.UnmarshalAny(item.Message, &entity)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("failed to decode entity from storage bucket item: {{err}}", err)
|
||||
// If we encounter an error, it would mean that the format of the
|
||||
// entity is an older one. Try decoding using the older format and if
|
||||
// successful, upgrage the storage with the newer format.
|
||||
var oldEntity identity.EntityStorageEntry
|
||||
oldEntityErr := ptypes.UnmarshalAny(item.Message, &oldEntity)
|
||||
if oldEntityErr != nil {
|
||||
return nil, errwrap.Wrapf("failed to decode entity from storage bucket item: {{err}}", err)
|
||||
}
|
||||
|
||||
i.logger.Debug("upgrading the entity using patch introduced with vault 0.8.2.1", "entity_id", oldEntity.ID)
|
||||
|
||||
// Successfully decoded entity using older format. Entity is stored
|
||||
// with older format. Upgrade it.
|
||||
entity.ID = oldEntity.ID
|
||||
entity.Name = oldEntity.Name
|
||||
entity.Metadata = oldEntity.Metadata
|
||||
entity.CreationTime = oldEntity.CreationTime
|
||||
entity.LastUpdateTime = oldEntity.LastUpdateTime
|
||||
entity.MergedEntityIDs = oldEntity.MergedEntityIDs
|
||||
entity.Policies = oldEntity.Policies
|
||||
entity.BucketKeyHash = oldEntity.BucketKeyHash
|
||||
entity.MFASecrets = oldEntity.MFASecrets
|
||||
// Copy each alias individually since the format of aliases were
|
||||
// also different
|
||||
for _, oldAlias := range oldEntity.Personas {
|
||||
var newAlias identity.Alias
|
||||
newAlias.ID = oldAlias.ID
|
||||
newAlias.Name = oldAlias.Name
|
||||
newAlias.CanonicalID = oldAlias.EntityID
|
||||
newAlias.MountType = oldAlias.MountType
|
||||
newAlias.MountAccessor = oldAlias.MountAccessor
|
||||
newAlias.MountPath = oldAlias.MountPath
|
||||
newAlias.Metadata = oldAlias.Metadata
|
||||
newAlias.CreationTime = oldAlias.CreationTime
|
||||
newAlias.LastUpdateTime = oldAlias.LastUpdateTime
|
||||
newAlias.MergedFromCanonicalIDs = oldAlias.MergedFromEntityIDs
|
||||
entity.Aliases = append(entity.Aliases, &newAlias)
|
||||
}
|
||||
|
||||
persistNeeded = true
|
||||
}
|
||||
|
||||
pN, err := parseExtraEntityFromBucket(ctx, i, &entity)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if pN {
|
||||
persistNeeded = true
|
||||
}
|
||||
|
||||
if persistNeeded && !i.core.ReplicationState().HasState(consts.ReplicationPerformanceSecondary) {
|
||||
entityAsAny, err := ptypes.MarshalAny(&entity)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
item := &storagepacker.Item{
|
||||
ID: entity.ID,
|
||||
Message: entityAsAny,
|
||||
}
|
||||
|
||||
// Store the entity with new format
|
||||
err = i.entityPacker.PutItem(item)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if entity.NamespaceID == "" {
|
||||
entity.NamespaceID = namespace.RootNamespaceID
|
||||
}
|
||||
|
||||
return &entity, nil
|
||||
@@ -257,6 +343,10 @@ func (i *IdentityStore) parseGroupFromBucketItem(item *storagepacker.Item) (*ide
|
||||
return nil, errwrap.Wrapf("failed to decode group from storage bucket item: {{err}}", err)
|
||||
}
|
||||
|
||||
if group.NamespaceID == "" {
|
||||
group.NamespaceID = namespace.RootNamespaceID
|
||||
}
|
||||
|
||||
return &group, nil
|
||||
}
|
||||
|
||||
@@ -305,7 +395,7 @@ func (i *IdentityStore) entityByAliasFactorsInTxn(txn *memdb.Txn, mountAccessor,
|
||||
|
||||
// CreateOrFetchEntity creates a new entity. This is used by core to
|
||||
// associate each login attempt by an alias to a unified entity in Vault.
|
||||
func (i *IdentityStore) CreateOrFetchEntity(alias *logical.Alias) (*identity.Entity, error) {
|
||||
func (i *IdentityStore) CreateOrFetchEntity(ctx context.Context, alias *logical.Alias) (*identity.Entity, error) {
|
||||
var entity *identity.Entity
|
||||
var err error
|
||||
|
||||
@@ -355,9 +445,8 @@ func (i *IdentityStore) CreateOrFetchEntity(alias *logical.Alias) (*identity.Ent
|
||||
return entity, nil
|
||||
}
|
||||
|
||||
entity = &identity.Entity{}
|
||||
|
||||
err = i.sanitizeEntity(entity)
|
||||
entity = new(identity.Entity)
|
||||
err = i.sanitizeEntity(ctx, entity)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -372,7 +461,7 @@ func (i *IdentityStore) CreateOrFetchEntity(alias *logical.Alias) (*identity.Ent
|
||||
MountType: mountValidationResp.MountType,
|
||||
}
|
||||
|
||||
err = i.sanitizeAlias(newAlias)
|
||||
err = i.sanitizeAlias(ctx, newAlias)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -385,7 +474,7 @@ func (i *IdentityStore) CreateOrFetchEntity(alias *logical.Alias) (*identity.Ent
|
||||
}
|
||||
|
||||
// Update MemDB and persist entity object
|
||||
err = i.upsertEntityInTxn(txn, entity, nil, true)
|
||||
err = i.upsertEntityInTxn(ctx, txn, entity, nil, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -6,9 +6,8 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/golang/protobuf/ptypes"
|
||||
"github.com/hashicorp/errwrap"
|
||||
memdb "github.com/hashicorp/go-memdb"
|
||||
"github.com/hashicorp/vault/helper/identity"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/helper/storagepacker"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/logical/framework"
|
||||
@@ -237,7 +236,7 @@ func (i *IdentityStore) handleAliasUpdateCommon() framework.OperationFunc {
|
||||
// ID creation and other validations; This is more useful for new entities
|
||||
// and may not perform anything for the existing entities. Placing the
|
||||
// check here to make the flow common for both new and existing entities.
|
||||
err = i.sanitizeEntity(entity)
|
||||
err = i.sanitizeEntity(ctx, entity)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -251,7 +250,7 @@ func (i *IdentityStore) handleAliasUpdateCommon() framework.OperationFunc {
|
||||
alias.CanonicalID = entity.ID
|
||||
|
||||
// ID creation and other validations
|
||||
err = i.sanitizeAlias(alias)
|
||||
err = i.sanitizeAlias(ctx, alias)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -260,7 +259,7 @@ func (i *IdentityStore) handleAliasUpdateCommon() framework.OperationFunc {
|
||||
// aliases in storage. If the alias is being transferred over from
|
||||
// one entity to another, previous entity needs to get refreshed in MemDB
|
||||
// and persisted in storage as well.
|
||||
if err := i.upsertEntity(entity, previousEntity, true); err != nil {
|
||||
if err := i.upsertEntity(ctx, entity, previousEntity, true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -288,15 +287,23 @@ func (i *IdentityStore) pathAliasIDRead() framework.OperationFunc {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return i.handleAliasReadCommon(alias)
|
||||
return i.handleAliasReadCommon(ctx, alias)
|
||||
}
|
||||
}
|
||||
|
||||
func (i *IdentityStore) handleAliasReadCommon(alias *identity.Alias) (*logical.Response, error) {
|
||||
func (i *IdentityStore) handleAliasReadCommon(ctx context.Context, alias *identity.Alias) (*logical.Response, error) {
|
||||
if alias == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
ns, err := namespace.FromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ns.ID != alias.NamespaceID {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
respData := map[string]interface{}{}
|
||||
respData["id"] = alias.ID
|
||||
respData["canonical_id"] = alias.CanonicalID
|
||||
@@ -345,6 +352,14 @@ func (i *IdentityStore) pathAliasIDDelete() framework.OperationFunc {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
ns, err := namespace.FromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ns.ID != alias.NamespaceID {
|
||||
return nil, logical.ErrUnsupportedPath
|
||||
}
|
||||
|
||||
// Fetch the associated entity
|
||||
entity, err := i.MemDBEntityByAliasIDInTxn(txn, alias.ID, true)
|
||||
if err != nil {
|
||||
@@ -399,53 +414,7 @@ func (i *IdentityStore) pathAliasIDDelete() framework.OperationFunc {
|
||||
// store
|
||||
func (i *IdentityStore) pathAliasIDList() framework.OperationFunc {
|
||||
return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||
ws := memdb.NewWatchSet()
|
||||
iter, err := i.MemDBAliases(ws, false)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("failed to fetch iterator for aliases in memdb: {{err}}", err)
|
||||
}
|
||||
|
||||
var aliasIDs []string
|
||||
aliasInfo := map[string]interface{}{}
|
||||
|
||||
type mountInfo struct {
|
||||
MountType string
|
||||
MountPath string
|
||||
}
|
||||
mountAccessorMap := map[string]mountInfo{}
|
||||
|
||||
for {
|
||||
raw := iter.Next()
|
||||
if raw == nil {
|
||||
break
|
||||
}
|
||||
alias := raw.(*identity.Alias)
|
||||
aliasIDs = append(aliasIDs, alias.ID)
|
||||
aliasInfoEntry := map[string]interface{}{
|
||||
"name": alias.Name,
|
||||
"canonical_id": alias.CanonicalID,
|
||||
"mount_accessor": alias.MountAccessor,
|
||||
}
|
||||
|
||||
mi, ok := mountAccessorMap[alias.MountAccessor]
|
||||
if ok {
|
||||
aliasInfoEntry["mount_type"] = mi.MountType
|
||||
aliasInfoEntry["mount_path"] = mi.MountPath
|
||||
} else {
|
||||
mi = mountInfo{}
|
||||
if mountValidationResp := i.core.router.validateMountByAccessor(alias.MountAccessor); mountValidationResp != nil {
|
||||
mi.MountType = mountValidationResp.MountType
|
||||
mi.MountPath = mountValidationResp.MountPath
|
||||
aliasInfoEntry["mount_type"] = mi.MountType
|
||||
aliasInfoEntry["mount_path"] = mi.MountPath
|
||||
}
|
||||
mountAccessorMap[alias.MountAccessor] = mi
|
||||
}
|
||||
|
||||
aliasInfo[alias.ID] = aliasInfoEntry
|
||||
}
|
||||
|
||||
return logical.ListResponseWithInfo(aliasIDs, aliasInfo), nil
|
||||
return i.handleAliasListCommon(ctx, false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package vault
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/vault/helper/identity"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
)
|
||||
|
||||
@@ -14,7 +14,9 @@ import (
|
||||
func TestIdentityStore_AliasSameAliasNames(t *testing.T) {
|
||||
var err error
|
||||
var resp *logical.Response
|
||||
is, githubAccessor, _ := testIdentityStoreWithGithubAuth(t)
|
||||
|
||||
ctx := namespace.RootContext(nil)
|
||||
is, githubAccessor, _ := testIdentityStoreWithGithubAuth(ctx, t)
|
||||
|
||||
aliasData := map[string]interface{}{
|
||||
"name": "testaliasname",
|
||||
@@ -28,13 +30,13 @@ func TestIdentityStore_AliasSameAliasNames(t *testing.T) {
|
||||
}
|
||||
|
||||
// Register an alias
|
||||
resp, err = is.HandleRequest(context.Background(), aliasReq)
|
||||
resp, err = is.HandleRequest(ctx, aliasReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
|
||||
// Register another alias with same name
|
||||
resp, err = is.HandleRequest(context.Background(), aliasReq)
|
||||
resp, err = is.HandleRequest(ctx, aliasReq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -46,7 +48,8 @@ func TestIdentityStore_AliasSameAliasNames(t *testing.T) {
|
||||
func TestIdentityStore_MemDBAliasIndexes(t *testing.T) {
|
||||
var err error
|
||||
|
||||
is, githubAccessor, _ := testIdentityStoreWithGithubAuth(t)
|
||||
ctx := namespace.RootContext(nil)
|
||||
is, githubAccessor, _ := testIdentityStoreWithGithubAuth(ctx, t)
|
||||
if is == nil {
|
||||
t.Fatal("failed to create test identity store")
|
||||
}
|
||||
@@ -147,7 +150,8 @@ func TestIdentityStore_AliasRegister(t *testing.T) {
|
||||
var err error
|
||||
var resp *logical.Response
|
||||
|
||||
is, githubAccessor, _ := testIdentityStoreWithGithubAuth(t)
|
||||
ctx := namespace.RootContext(nil)
|
||||
is, githubAccessor, _ := testIdentityStoreWithGithubAuth(ctx, t)
|
||||
|
||||
if is == nil {
|
||||
t.Fatal("failed to create test alias store")
|
||||
@@ -166,7 +170,7 @@ func TestIdentityStore_AliasRegister(t *testing.T) {
|
||||
}
|
||||
|
||||
// Register the alias
|
||||
resp, err = is.HandleRequest(context.Background(), aliasReq)
|
||||
resp, err = is.HandleRequest(ctx, aliasReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -195,7 +199,8 @@ func TestIdentityStore_AliasRegister(t *testing.T) {
|
||||
func TestIdentityStore_AliasUpdate(t *testing.T) {
|
||||
var err error
|
||||
var resp *logical.Response
|
||||
is, githubAccessor, _ := testIdentityStoreWithGithubAuth(t)
|
||||
ctx := namespace.RootContext(nil)
|
||||
is, githubAccessor, _ := testIdentityStoreWithGithubAuth(ctx, t)
|
||||
|
||||
aliasData := map[string]interface{}{
|
||||
"name": "testaliasname",
|
||||
@@ -209,7 +214,7 @@ func TestIdentityStore_AliasUpdate(t *testing.T) {
|
||||
}
|
||||
|
||||
// This will create an alias and a corresponding entity
|
||||
resp, err = is.HandleRequest(context.Background(), aliasReq)
|
||||
resp, err = is.HandleRequest(ctx, aliasReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -222,13 +227,13 @@ func TestIdentityStore_AliasUpdate(t *testing.T) {
|
||||
|
||||
aliasReq.Data = updateData
|
||||
aliasReq.Path = "entity-alias/id/" + aliasID
|
||||
resp, err = is.HandleRequest(context.Background(), aliasReq)
|
||||
resp, err = is.HandleRequest(ctx, aliasReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
|
||||
aliasReq.Operation = logical.ReadOperation
|
||||
resp, err = is.HandleRequest(context.Background(), aliasReq)
|
||||
resp, err = is.HandleRequest(ctx, aliasReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -241,7 +246,8 @@ func TestIdentityStore_AliasUpdate(t *testing.T) {
|
||||
func TestIdentityStore_AliasUpdate_ByID(t *testing.T) {
|
||||
var err error
|
||||
var resp *logical.Response
|
||||
is, githubAccessor, _ := testIdentityStoreWithGithubAuth(t)
|
||||
ctx := namespace.RootContext(nil)
|
||||
is, githubAccessor, _ := testIdentityStoreWithGithubAuth(ctx, t)
|
||||
|
||||
updateData := map[string]interface{}{
|
||||
"name": "updatedaliasname",
|
||||
@@ -255,7 +261,7 @@ func TestIdentityStore_AliasUpdate_ByID(t *testing.T) {
|
||||
}
|
||||
|
||||
// Try to update an non-existent alias
|
||||
resp, err = is.HandleRequest(context.Background(), updateReq)
|
||||
resp, err = is.HandleRequest(ctx, updateReq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -274,7 +280,7 @@ func TestIdentityStore_AliasUpdate_ByID(t *testing.T) {
|
||||
Data: registerData,
|
||||
}
|
||||
|
||||
resp, err = is.HandleRequest(context.Background(), registerReq)
|
||||
resp, err = is.HandleRequest(ctx, registerReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -289,7 +295,7 @@ func TestIdentityStore_AliasUpdate_ByID(t *testing.T) {
|
||||
}
|
||||
|
||||
updateReq.Path = "entity-alias/id/" + id
|
||||
resp, err = is.HandleRequest(context.Background(), updateReq)
|
||||
resp, err = is.HandleRequest(ctx, updateReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -298,7 +304,7 @@ func TestIdentityStore_AliasUpdate_ByID(t *testing.T) {
|
||||
Operation: logical.ReadOperation,
|
||||
Path: updateReq.Path,
|
||||
}
|
||||
resp, err = is.HandleRequest(context.Background(), readReq)
|
||||
resp, err = is.HandleRequest(ctx, readReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -309,7 +315,7 @@ func TestIdentityStore_AliasUpdate_ByID(t *testing.T) {
|
||||
|
||||
delete(registerReq.Data, "name")
|
||||
|
||||
resp, err = is.HandleRequest(context.Background(), registerReq)
|
||||
resp, err = is.HandleRequest(ctx, registerReq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -320,7 +326,7 @@ func TestIdentityStore_AliasUpdate_ByID(t *testing.T) {
|
||||
registerReq.Data["name"] = "testaliasname"
|
||||
delete(registerReq.Data, "mount_accessor")
|
||||
|
||||
resp, err = is.HandleRequest(context.Background(), registerReq)
|
||||
resp, err = is.HandleRequest(ctx, registerReq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -333,7 +339,8 @@ func TestIdentityStore_AliasReadDelete(t *testing.T) {
|
||||
var err error
|
||||
var resp *logical.Response
|
||||
|
||||
is, githubAccessor, _ := testIdentityStoreWithGithubAuth(t)
|
||||
ctx := namespace.RootContext(nil)
|
||||
is, githubAccessor, _ := testIdentityStoreWithGithubAuth(ctx, t)
|
||||
|
||||
registerData := map[string]interface{}{
|
||||
"name": "testaliasname",
|
||||
@@ -347,7 +354,7 @@ func TestIdentityStore_AliasReadDelete(t *testing.T) {
|
||||
Data: registerData,
|
||||
}
|
||||
|
||||
resp, err = is.HandleRequest(context.Background(), registerReq)
|
||||
resp, err = is.HandleRequest(ctx, registerReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -366,7 +373,7 @@ func TestIdentityStore_AliasReadDelete(t *testing.T) {
|
||||
Operation: logical.ReadOperation,
|
||||
Path: "entity-alias/id/" + id,
|
||||
}
|
||||
resp, err = is.HandleRequest(context.Background(), aliasReq)
|
||||
resp, err = is.HandleRequest(ctx, aliasReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -379,13 +386,13 @@ func TestIdentityStore_AliasReadDelete(t *testing.T) {
|
||||
}
|
||||
|
||||
aliasReq.Operation = logical.DeleteOperation
|
||||
resp, err = is.HandleRequest(context.Background(), aliasReq)
|
||||
resp, err = is.HandleRequest(ctx, aliasReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
|
||||
aliasReq.Operation = logical.ReadOperation
|
||||
resp, err = is.HandleRequest(context.Background(), aliasReq)
|
||||
resp, err = is.HandleRequest(ctx, aliasReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/hashicorp/errwrap"
|
||||
memdb "github.com/hashicorp/go-memdb"
|
||||
"github.com/hashicorp/vault/helper/identity"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/helper/storagepacker"
|
||||
"github.com/hashicorp/vault/helper/strutil"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
@@ -154,7 +155,7 @@ func (i *IdentityStore) pathEntityMergeID() framework.OperationFunc {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userErr, intErr := i.mergeEntity(txn, toEntity, fromEntityIDs, force, true, false)
|
||||
userErr, intErr := i.mergeEntity(ctx, txn, toEntity, fromEntityIDs, force, true, false)
|
||||
if userErr != nil {
|
||||
return logical.ErrorResponse(userErr.Error()), nil
|
||||
}
|
||||
@@ -176,7 +177,7 @@ func (i *IdentityStore) handleEntityUpdateCommon() framework.OperationFunc {
|
||||
i.lock.Lock()
|
||||
defer i.lock.Unlock()
|
||||
|
||||
var entity *identity.Entity
|
||||
entity := new(identity.Entity)
|
||||
var err error
|
||||
|
||||
entityID := d.Get("id").(string)
|
||||
@@ -193,17 +194,17 @@ func (i *IdentityStore) handleEntityUpdateCommon() framework.OperationFunc {
|
||||
// Get the name
|
||||
entityName := d.Get("name").(string)
|
||||
if entityName != "" {
|
||||
entityByName, err := i.MemDBEntityByName(entityName, false)
|
||||
entityByName, err := i.MemDBEntityByName(ctx, entityName, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch {
|
||||
case entityByName == nil:
|
||||
// Not found, safe to use this name with an existing or new entity
|
||||
case entity == nil:
|
||||
case entity.ID == "":
|
||||
// We found an entity by name, but we don't currently allow
|
||||
// updating based on name, only ID, so return an error
|
||||
return logical.ErrorResponse("entity name is already in use"), nil
|
||||
return logical.ErrorResponse("updating entity by name is not currently supported"), nil
|
||||
case entity.ID == entityByName.ID:
|
||||
// Same exact entity, carry on (this is basically a noop then)
|
||||
default:
|
||||
@@ -211,11 +212,6 @@ func (i *IdentityStore) handleEntityUpdateCommon() framework.OperationFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// Entity will be nil when a new entity is being registered; create a new
|
||||
// struct in that case.
|
||||
if entity == nil {
|
||||
entity = &identity.Entity{}
|
||||
}
|
||||
if entityName != "" {
|
||||
entity.Name = entityName
|
||||
}
|
||||
@@ -244,7 +240,7 @@ func (i *IdentityStore) handleEntityUpdateCommon() framework.OperationFunc {
|
||||
entity.Metadata = metadata.(map[string]string)
|
||||
}
|
||||
// ID creation and some validations
|
||||
err = i.sanitizeEntity(entity)
|
||||
err = i.sanitizeEntity(ctx, entity)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -263,7 +259,7 @@ func (i *IdentityStore) handleEntityUpdateCommon() framework.OperationFunc {
|
||||
|
||||
// Update MemDB and persist entity object. New entities have not been
|
||||
// looked up yet so we need to take the lock on the entity on upsert
|
||||
if err := i.upsertEntity(entity, nil, true); err != nil {
|
||||
if err := i.upsertEntity(ctx, entity, nil, true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -291,11 +287,19 @@ func (i *IdentityStore) pathEntityIDRead() framework.OperationFunc {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return i.handleEntityReadCommon(entity)
|
||||
return i.handleEntityReadCommon(ctx, entity)
|
||||
}
|
||||
}
|
||||
|
||||
func (i *IdentityStore) handleEntityReadCommon(entity *identity.Entity) (*logical.Response, error) {
|
||||
func (i *IdentityStore) handleEntityReadCommon(ctx context.Context, entity *identity.Entity) (*logical.Response, error) {
|
||||
ns, err := namespace.FromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ns.ID != entity.NamespaceID {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
respData := map[string]interface{}{}
|
||||
respData["id"] = entity.ID
|
||||
respData["name"] = entity.Name
|
||||
@@ -333,6 +337,8 @@ func (i *IdentityStore) handleEntityReadCommon(entity *identity.Entity) (*logica
|
||||
// formats
|
||||
respData["aliases"] = aliasesToReturn
|
||||
|
||||
addExtraEntityDataToResponse(entity, respData)
|
||||
|
||||
// Fetch the groups this entity belongs to and return their identifiers
|
||||
groups, inheritedGroups, err := i.groupsByEntityID(entity.ID)
|
||||
if err != nil {
|
||||
@@ -378,12 +384,19 @@ func (i *IdentityStore) pathEntityIDDelete() framework.OperationFunc {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If there is no entity for the ID, do nothing
|
||||
if entity == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
ns, err := namespace.FromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if entity.NamespaceID != ns.ID {
|
||||
return nil, logical.ErrUnsupportedPath
|
||||
}
|
||||
|
||||
// Delete all the aliases in the entity. This function will also remove
|
||||
// the corresponding alias indexes too.
|
||||
err = i.deleteAliasesInEntityInTxn(txn, entity, entity.Aliases)
|
||||
@@ -414,11 +427,16 @@ func (i *IdentityStore) pathEntityIDDelete() framework.OperationFunc {
|
||||
// store
|
||||
func (i *IdentityStore) pathEntityIDList() framework.OperationFunc {
|
||||
return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||
ns, err := namespace.FromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ws := memdb.NewWatchSet()
|
||||
|
||||
txn := i.db.Txn(false)
|
||||
|
||||
iter, err := txn.Get(entitiesTable, "id")
|
||||
iter, err := txn.Get(entitiesTable, "namespace_id", ns.ID)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("failed to fetch iterator for entities in memdb: {{err}}", err)
|
||||
}
|
||||
@@ -479,7 +497,7 @@ func (i *IdentityStore) pathEntityIDList() framework.OperationFunc {
|
||||
}
|
||||
}
|
||||
|
||||
func (i *IdentityStore) mergeEntity(txn *memdb.Txn, toEntity *identity.Entity, fromEntityIDs []string, force, grabLock, mergePolicies bool) (error, error) {
|
||||
func (i *IdentityStore) mergeEntity(ctx context.Context, txn *memdb.Txn, toEntity *identity.Entity, fromEntityIDs []string, force, grabLock, mergePolicies bool) (error, error) {
|
||||
if grabLock {
|
||||
i.lock.Lock()
|
||||
defer i.lock.Unlock()
|
||||
@@ -489,6 +507,43 @@ func (i *IdentityStore) mergeEntity(txn *memdb.Txn, toEntity *identity.Entity, f
|
||||
return errors.New("entity id to merge to is invalid"), nil
|
||||
}
|
||||
|
||||
ns, err := namespace.FromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if toEntity.NamespaceID != ns.ID {
|
||||
return errors.New("entity id to merge into does not belong to the request's namespace"), nil
|
||||
}
|
||||
|
||||
// Merge the MFA secrets
|
||||
for _, fromEntityID := range fromEntityIDs {
|
||||
if fromEntityID == toEntity.ID {
|
||||
return errors.New("to_entity_id should not be present in from_entity_ids"), nil
|
||||
}
|
||||
|
||||
fromEntity, err := i.MemDBEntityByID(fromEntityID, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if fromEntity == nil {
|
||||
return errors.New("entity id to merge from is invalid"), nil
|
||||
}
|
||||
|
||||
if fromEntity.NamespaceID != toEntity.NamespaceID {
|
||||
return errors.New("entity id to merge from does not belong to this namespace"), nil
|
||||
}
|
||||
|
||||
for configID, configSecret := range fromEntity.MFASecrets {
|
||||
_, ok := toEntity.MFASecrets[configID]
|
||||
if ok && !force {
|
||||
return nil, fmt.Errorf("conflicting MFA config ID %q in entity ID %q", configID, fromEntity.ID)
|
||||
} else {
|
||||
toEntity.MFASecrets[configID] = configSecret
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, fromEntityID := range fromEntityIDs {
|
||||
if fromEntityID == toEntity.ID {
|
||||
return errors.New("to_entity_id should not be present in from_entity_ids"), nil
|
||||
@@ -503,6 +558,10 @@ func (i *IdentityStore) mergeEntity(txn *memdb.Txn, toEntity *identity.Entity, f
|
||||
return errors.New("entity id to merge from is invalid"), nil
|
||||
}
|
||||
|
||||
if fromEntity.NamespaceID != toEntity.NamespaceID {
|
||||
return errors.New("entity id to merge from does not belong to this namespace"), nil
|
||||
}
|
||||
|
||||
for _, alias := range fromEntity.Aliases {
|
||||
// Set the desired canonical ID
|
||||
alias.CanonicalID = toEntity.ID
|
||||
@@ -546,7 +605,7 @@ func (i *IdentityStore) mergeEntity(txn *memdb.Txn, toEntity *identity.Entity, f
|
||||
}
|
||||
|
||||
// Update MemDB with changes to the entity we are merging to
|
||||
err := i.MemDBUpsertEntityInTxn(txn, toEntity)
|
||||
err = i.MemDBUpsertEntityInTxn(txn, toEntity)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
uuid "github.com/hashicorp/go-uuid"
|
||||
credGithub "github.com/hashicorp/vault/builtin/credential/github"
|
||||
"github.com/hashicorp/vault/helper/identity"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
)
|
||||
|
||||
@@ -17,14 +18,15 @@ func TestIdentityStore_EntityReadGroupIDs(t *testing.T) {
|
||||
var err error
|
||||
var resp *logical.Response
|
||||
|
||||
i, _, _ := testIdentityStoreWithGithubAuth(t)
|
||||
ctx := namespace.RootContext(nil)
|
||||
i, _, _ := testIdentityStoreWithGithubAuth(ctx, t)
|
||||
|
||||
entityReq := &logical.Request{
|
||||
Path: "entity",
|
||||
Operation: logical.UpdateOperation,
|
||||
}
|
||||
|
||||
resp, err = i.HandleRequest(context.Background(), entityReq)
|
||||
resp, err = i.HandleRequest(ctx, entityReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
||||
}
|
||||
@@ -41,7 +43,7 @@ func TestIdentityStore_EntityReadGroupIDs(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err = i.HandleRequest(context.Background(), groupReq)
|
||||
resp, err = i.HandleRequest(ctx, groupReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
||||
}
|
||||
@@ -53,7 +55,7 @@ func TestIdentityStore_EntityReadGroupIDs(t *testing.T) {
|
||||
groupReq.Data = map[string]interface{}{
|
||||
"member_group_ids": []string{groupID},
|
||||
}
|
||||
resp, err = i.HandleRequest(context.Background(), groupReq)
|
||||
resp, err = i.HandleRequest(ctx, groupReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
||||
}
|
||||
@@ -69,7 +71,7 @@ func TestIdentityStore_EntityReadGroupIDs(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err = i.HandleRequest(context.Background(), lookupReq)
|
||||
resp, err = i.HandleRequest(ctx, lookupReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
||||
}
|
||||
@@ -97,7 +99,8 @@ func TestIdentityStore_EntityCreateUpdate(t *testing.T) {
|
||||
var err error
|
||||
var resp *logical.Response
|
||||
|
||||
is, _, _ := testIdentityStoreWithGithubAuth(t)
|
||||
ctx := namespace.RootContext(nil)
|
||||
is, _, _ := testIdentityStoreWithGithubAuth(ctx, t)
|
||||
|
||||
entityData := map[string]interface{}{
|
||||
"name": "testentityname",
|
||||
@@ -112,7 +115,7 @@ func TestIdentityStore_EntityCreateUpdate(t *testing.T) {
|
||||
}
|
||||
|
||||
// Create the entity
|
||||
resp, err = is.HandleRequest(context.Background(), entityReq)
|
||||
resp, err = is.HandleRequest(ctx, entityReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -128,7 +131,7 @@ func TestIdentityStore_EntityCreateUpdate(t *testing.T) {
|
||||
entityReq.Data = updateData
|
||||
|
||||
// Update the entity
|
||||
resp, err = is.HandleRequest(context.Background(), entityReq)
|
||||
resp, err = is.HandleRequest(ctx, entityReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -137,7 +140,7 @@ func TestIdentityStore_EntityCreateUpdate(t *testing.T) {
|
||||
entityReq.Operation = logical.ReadOperation
|
||||
|
||||
// Read the entity
|
||||
resp, err = is.HandleRequest(context.Background(), entityReq)
|
||||
resp, err = is.HandleRequest(ctx, entityReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -190,7 +193,8 @@ func TestIdentityStore_CloneImmutability(t *testing.T) {
|
||||
|
||||
func TestIdentityStore_MemDBImmutability(t *testing.T) {
|
||||
var err error
|
||||
is, githubAccessor, _ := testIdentityStoreWithGithubAuth(t)
|
||||
ctx := namespace.RootContext(nil)
|
||||
is, githubAccessor, _ := testIdentityStoreWithGithubAuth(ctx, t)
|
||||
|
||||
validateMountResp := is.core.router.validateMountByAccessor(githubAccessor)
|
||||
if validateMountResp == nil {
|
||||
@@ -254,7 +258,8 @@ func TestIdentityStore_ListEntities(t *testing.T) {
|
||||
var err error
|
||||
var resp *logical.Response
|
||||
|
||||
is, _, _ := testIdentityStoreWithGithubAuth(t)
|
||||
ctx := namespace.RootContext(nil)
|
||||
is, _, _ := testIdentityStoreWithGithubAuth(ctx, t)
|
||||
|
||||
entityReq := &logical.Request{
|
||||
Operation: logical.UpdateOperation,
|
||||
@@ -263,7 +268,7 @@ func TestIdentityStore_ListEntities(t *testing.T) {
|
||||
|
||||
expected := []string{}
|
||||
for i := 0; i < 10; i++ {
|
||||
resp, err = is.HandleRequest(context.Background(), entityReq)
|
||||
resp, err = is.HandleRequest(ctx, entityReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -275,7 +280,7 @@ func TestIdentityStore_ListEntities(t *testing.T) {
|
||||
Path: "entity/id",
|
||||
}
|
||||
|
||||
resp, err = is.HandleRequest(context.Background(), listReq)
|
||||
resp, err = is.HandleRequest(ctx, listReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -315,6 +320,7 @@ func TestIdentityStore_LoadingEntities(t *testing.T) {
|
||||
Path: "github/",
|
||||
Type: "github",
|
||||
Description: "github auth",
|
||||
namespace: namespace.RootNamespace,
|
||||
}
|
||||
|
||||
// Mount UUID for github auth
|
||||
@@ -350,7 +356,7 @@ func TestIdentityStore_LoadingEntities(t *testing.T) {
|
||||
}
|
||||
|
||||
// Identity store will be mounted by now, just fetch it from router
|
||||
identitystore := c.router.MatchingBackend("identity/")
|
||||
identitystore := c.router.MatchingBackend(namespace.TestContext(), "identity/")
|
||||
if identitystore == nil {
|
||||
t.Fatalf("failed to fetch identity store from router")
|
||||
}
|
||||
@@ -369,8 +375,10 @@ func TestIdentityStore_LoadingEntities(t *testing.T) {
|
||||
Data: registerData,
|
||||
}
|
||||
|
||||
ctx := namespace.RootContext(nil)
|
||||
|
||||
// Register the entity
|
||||
resp, err = is.HandleRequest(context.Background(), registerReq)
|
||||
resp, err = is.HandleRequest(ctx, registerReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -383,7 +391,7 @@ func TestIdentityStore_LoadingEntities(t *testing.T) {
|
||||
}
|
||||
|
||||
// Ensure that entity is created
|
||||
resp, err = is.HandleRequest(context.Background(), readReq)
|
||||
resp, err = is.HandleRequest(ctx, readReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -413,7 +421,7 @@ func TestIdentityStore_LoadingEntities(t *testing.T) {
|
||||
}
|
||||
|
||||
// Check if the entity is restored
|
||||
resp, err = is.HandleRequest(context.Background(), readReq)
|
||||
resp, err = is.HandleRequest(ctx, readReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -426,7 +434,8 @@ func TestIdentityStore_LoadingEntities(t *testing.T) {
|
||||
func TestIdentityStore_MemDBEntityIndexes(t *testing.T) {
|
||||
var err error
|
||||
|
||||
is, githubAccessor, _ := testIdentityStoreWithGithubAuth(t)
|
||||
ctx := namespace.RootContext(nil)
|
||||
is, githubAccessor, _ := testIdentityStoreWithGithubAuth(ctx, t)
|
||||
|
||||
validateMountResp := is.core.router.validateMountByAccessor(githubAccessor)
|
||||
if validateMountResp == nil {
|
||||
@@ -490,7 +499,7 @@ func TestIdentityStore_MemDBEntityIndexes(t *testing.T) {
|
||||
}
|
||||
|
||||
// Fetch the entity using its name
|
||||
entityFetched, err = is.MemDBEntityByName(entity.Name, false)
|
||||
entityFetched, err = is.MemDBEntityByName(namespace.RootContext(nil), entity.Name, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -523,7 +532,7 @@ func TestIdentityStore_MemDBEntityIndexes(t *testing.T) {
|
||||
t.Fatalf("bad: entity; expected: nil, actual: %#v\n", entityFetched)
|
||||
}
|
||||
|
||||
entityFetched, err = is.MemDBEntityByName(entity.Name, false)
|
||||
entityFetched, err = is.MemDBEntityByName(namespace.RootContext(nil), entity.Name, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -531,6 +540,7 @@ func TestIdentityStore_MemDBEntityIndexes(t *testing.T) {
|
||||
if entityFetched != nil {
|
||||
t.Fatalf("bad: entity; expected: nil, actual: %#v\n", entityFetched)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// This test is required because MemDB does not take care of ensuring
|
||||
@@ -539,7 +549,8 @@ func TestIdentityStore_MemDBEntityIndexes(t *testing.T) {
|
||||
func TestIdentityStore_EntitySameEntityNames(t *testing.T) {
|
||||
var err error
|
||||
var resp *logical.Response
|
||||
is, _, _ := testIdentityStoreWithGithubAuth(t)
|
||||
ctx := namespace.RootContext(nil)
|
||||
is, _, _ := testIdentityStoreWithGithubAuth(ctx, t)
|
||||
|
||||
registerData := map[string]interface{}{
|
||||
"name": "testentityname",
|
||||
@@ -552,13 +563,13 @@ func TestIdentityStore_EntitySameEntityNames(t *testing.T) {
|
||||
}
|
||||
|
||||
// Register an entity
|
||||
resp, err = is.HandleRequest(context.Background(), registerReq)
|
||||
resp, err = is.HandleRequest(ctx, registerReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
|
||||
// Register another entity with same name
|
||||
resp, err = is.HandleRequest(context.Background(), registerReq)
|
||||
resp, err = is.HandleRequest(ctx, registerReq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -571,7 +582,8 @@ func TestIdentityStore_EntityCRUD(t *testing.T) {
|
||||
var err error
|
||||
var resp *logical.Response
|
||||
|
||||
is, _, _ := testIdentityStoreWithGithubAuth(t)
|
||||
ctx := namespace.RootContext(nil)
|
||||
is, _, _ := testIdentityStoreWithGithubAuth(ctx, t)
|
||||
|
||||
registerData := map[string]interface{}{
|
||||
"name": "testentityname",
|
||||
@@ -586,7 +598,7 @@ func TestIdentityStore_EntityCRUD(t *testing.T) {
|
||||
}
|
||||
|
||||
// Register the entity
|
||||
resp, err = is.HandleRequest(context.Background(), registerReq)
|
||||
resp, err = is.HandleRequest(ctx, registerReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -605,7 +617,7 @@ func TestIdentityStore_EntityCRUD(t *testing.T) {
|
||||
Operation: logical.ReadOperation,
|
||||
}
|
||||
|
||||
resp, err = is.HandleRequest(context.Background(), readReq)
|
||||
resp, err = is.HandleRequest(ctx, readReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -628,12 +640,12 @@ func TestIdentityStore_EntityCRUD(t *testing.T) {
|
||||
Data: updateData,
|
||||
}
|
||||
|
||||
resp, err = is.HandleRequest(context.Background(), updateReq)
|
||||
resp, err = is.HandleRequest(ctx, updateReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
|
||||
resp, err = is.HandleRequest(context.Background(), readReq)
|
||||
resp, err = is.HandleRequest(ctx, readReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -649,12 +661,12 @@ func TestIdentityStore_EntityCRUD(t *testing.T) {
|
||||
Operation: logical.DeleteOperation,
|
||||
}
|
||||
|
||||
resp, err = is.HandleRequest(context.Background(), deleteReq)
|
||||
resp, err = is.HandleRequest(ctx, deleteReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
|
||||
resp, err = is.HandleRequest(context.Background(), readReq)
|
||||
resp, err = is.HandleRequest(ctx, readReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -667,7 +679,8 @@ func TestIdentityStore_MergeEntitiesByID(t *testing.T) {
|
||||
var err error
|
||||
var resp *logical.Response
|
||||
|
||||
is, githubAccessor, _ := testIdentityStoreWithGithubAuth(t)
|
||||
ctx := namespace.RootContext(nil)
|
||||
is, githubAccessor, _ := testIdentityStoreWithGithubAuth(ctx, t)
|
||||
|
||||
registerData := map[string]interface{}{
|
||||
"name": "testentityname2",
|
||||
@@ -710,7 +723,7 @@ func TestIdentityStore_MergeEntitiesByID(t *testing.T) {
|
||||
}
|
||||
|
||||
// Register the entity
|
||||
resp, err = is.HandleRequest(context.Background(), registerReq)
|
||||
resp, err = is.HandleRequest(ctx, registerReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -728,14 +741,14 @@ func TestIdentityStore_MergeEntitiesByID(t *testing.T) {
|
||||
}
|
||||
|
||||
// Register the alias
|
||||
resp, err = is.HandleRequest(context.Background(), aliasReq)
|
||||
resp, err = is.HandleRequest(ctx, aliasReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
|
||||
// Register the alias
|
||||
aliasReq.Data = aliasRegisterData2
|
||||
resp, err = is.HandleRequest(context.Background(), aliasReq)
|
||||
resp, err = is.HandleRequest(ctx, aliasReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -753,7 +766,7 @@ func TestIdentityStore_MergeEntitiesByID(t *testing.T) {
|
||||
|
||||
registerReq.Data = registerData2
|
||||
// Register another entity
|
||||
resp, err = is.HandleRequest(context.Background(), registerReq)
|
||||
resp, err = is.HandleRequest(ctx, registerReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -770,14 +783,14 @@ func TestIdentityStore_MergeEntitiesByID(t *testing.T) {
|
||||
}
|
||||
|
||||
// Register the alias
|
||||
resp, err = is.HandleRequest(context.Background(), aliasReq)
|
||||
resp, err = is.HandleRequest(ctx, aliasReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
|
||||
// Register the alias
|
||||
aliasReq.Data = aliasRegisterData4
|
||||
resp, err = is.HandleRequest(context.Background(), aliasReq)
|
||||
resp, err = is.HandleRequest(ctx, aliasReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -804,7 +817,7 @@ func TestIdentityStore_MergeEntitiesByID(t *testing.T) {
|
||||
Data: mergeData,
|
||||
}
|
||||
|
||||
resp, err = is.HandleRequest(context.Background(), mergeReq)
|
||||
resp, err = is.HandleRequest(ctx, mergeReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -813,7 +826,7 @@ func TestIdentityStore_MergeEntitiesByID(t *testing.T) {
|
||||
Operation: logical.ReadOperation,
|
||||
Path: "entity/id/" + entityID2,
|
||||
}
|
||||
resp, err = is.HandleRequest(context.Background(), entityReq)
|
||||
resp, err = is.HandleRequest(ctx, entityReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
@@ -822,7 +835,7 @@ func TestIdentityStore_MergeEntitiesByID(t *testing.T) {
|
||||
}
|
||||
|
||||
entityReq.Path = "entity/id/" + entityID1
|
||||
resp, err = is.HandleRequest(context.Background(), entityReq)
|
||||
resp, err = is.HandleRequest(ctx, entityReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
|
||||
@@ -5,9 +5,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
memdb "github.com/hashicorp/go-memdb"
|
||||
"github.com/hashicorp/vault/helper/identity"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/logical/framework"
|
||||
)
|
||||
@@ -92,7 +91,7 @@ func (i *IdentityStore) pathGroupAliasRegister() framework.OperationFunc {
|
||||
i.groupLock.Lock()
|
||||
defer i.groupLock.Unlock()
|
||||
|
||||
return i.handleGroupAliasUpdateCommon(req, d, nil)
|
||||
return i.handleGroupAliasUpdateCommon(ctx, req, d, nil)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,14 +113,14 @@ func (i *IdentityStore) pathGroupAliasIDUpdate() framework.OperationFunc {
|
||||
return logical.ErrorResponse("invalid group alias ID"), nil
|
||||
}
|
||||
|
||||
return i.handleGroupAliasUpdateCommon(req, d, groupAlias)
|
||||
return i.handleGroupAliasUpdateCommon(ctx, req, d, groupAlias)
|
||||
}
|
||||
}
|
||||
|
||||
func (i *IdentityStore) handleGroupAliasUpdateCommon(req *logical.Request, d *framework.FieldData, groupAlias *identity.Alias) (*logical.Response, error) {
|
||||
var err error
|
||||
func (i *IdentityStore) handleGroupAliasUpdateCommon(ctx context.Context, req *logical.Request, d *framework.FieldData, groupAlias *identity.Alias) (*logical.Response, error) {
|
||||
var newGroupAlias bool
|
||||
var group *identity.Group
|
||||
var err error
|
||||
|
||||
if groupAlias == nil {
|
||||
groupAlias = &identity.Alias{}
|
||||
@@ -214,7 +213,7 @@ func (i *IdentityStore) handleGroupAliasUpdateCommon(req *logical.Request, d *fr
|
||||
// Explicitly correct for previous versions that persisted this
|
||||
group.Alias.MountType = ""
|
||||
|
||||
err = i.sanitizeAndUpsertGroup(group, nil)
|
||||
err = i.sanitizeAndUpsertGroup(ctx, group, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -241,7 +240,7 @@ func (i *IdentityStore) pathGroupAliasIDRead() framework.OperationFunc {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return i.handleAliasReadCommon(groupAlias)
|
||||
return i.handleAliasReadCommon(ctx, groupAlias)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,6 +267,14 @@ func (i *IdentityStore) pathGroupAliasIDDelete() framework.OperationFunc {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
ns, err := namespace.FromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ns.ID != alias.NamespaceID {
|
||||
return nil, logical.ErrUnsupportedOperation
|
||||
}
|
||||
|
||||
group, err := i.MemDBGroupByAliasIDInTxn(txn, alias.ID, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -302,53 +309,7 @@ func (i *IdentityStore) pathGroupAliasIDDelete() framework.OperationFunc {
|
||||
// identity store
|
||||
func (i *IdentityStore) pathGroupAliasIDList() framework.OperationFunc {
|
||||
return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||
ws := memdb.NewWatchSet()
|
||||
iter, err := i.MemDBAliases(ws, true)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("failed to fetch iterator for group aliases in memdb: {{err}}", err)
|
||||
}
|
||||
|
||||
var groupAliasIDs []string
|
||||
aliasInfo := map[string]interface{}{}
|
||||
|
||||
type mountInfo struct {
|
||||
MountType string
|
||||
MountPath string
|
||||
}
|
||||
mountAccessorMap := map[string]mountInfo{}
|
||||
|
||||
for {
|
||||
raw := iter.Next()
|
||||
if raw == nil {
|
||||
break
|
||||
}
|
||||
alias := raw.(*identity.Alias)
|
||||
groupAliasIDs = append(groupAliasIDs, alias.ID)
|
||||
entry := map[string]interface{}{
|
||||
"name": alias.Name,
|
||||
"canonical_id": alias.CanonicalID,
|
||||
"mount_accessor": alias.MountAccessor,
|
||||
}
|
||||
|
||||
mi, ok := mountAccessorMap[alias.MountAccessor]
|
||||
if ok {
|
||||
entry["mount_type"] = mi.MountType
|
||||
entry["mount_path"] = mi.MountPath
|
||||
} else {
|
||||
mi = mountInfo{}
|
||||
if mountValidationResp := i.core.router.validateMountByAccessor(alias.MountAccessor); mountValidationResp != nil {
|
||||
mi.MountType = mountValidationResp.MountType
|
||||
mi.MountPath = mountValidationResp.MountPath
|
||||
entry["mount_type"] = mi.MountType
|
||||
entry["mount_path"] = mi.MountPath
|
||||
}
|
||||
mountAccessorMap[alias.MountAccessor] = mi
|
||||
}
|
||||
|
||||
aliasInfo[alias.ID] = entry
|
||||
}
|
||||
|
||||
return logical.ListResponseWithInfo(groupAliasIDs, aliasInfo), nil
|
||||
return i.handleAliasListCommon(ctx, true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user