The big one (#5346)

This commit is contained in:
Jeff Mitchell
2018-09-17 23:03:00 -04:00
committed by GitHub
parent 07f5a27d85
commit b7d6d55ac1
156 changed files with 11177 additions and 5181 deletions

View File

@@ -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

View File

@@ -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..."

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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,
},
})

View File

@@ -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)
}

View File

@@ -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)
}
})

View File

@@ -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)
}
})

View File

@@ -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
}

View File

@@ -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
}

View 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
}

View 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
}

View File

@@ -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,
}

View File

@@ -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;
}

View 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,
}

View File

@@ -0,0 +1,7 @@
syntax = "proto3";
option go_package = "github.com/hashicorp/vault/helper/identity/mfa";
package mfa;
message Secret {}

View File

@@ -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] {

View File

@@ -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 {

View File

@@ -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,
}

View File

@@ -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
View 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
}

View File

@@ -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:]
}

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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() {

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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,
},

View File

@@ -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 {

View File

@@ -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)
}

View File

@@ -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) {

View File

@@ -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 {

View File

@@ -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
View 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) {}
)

View File

@@ -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.

View File

@@ -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()
}

View File

@@ -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))

View File

@@ -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

View File

@@ -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:"-"`

View File

@@ -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 {

View File

@@ -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,
}

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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)

View File

@@ -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
View 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) {
}

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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) {

View File

@@ -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

View File

@@ -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) {

View File

@@ -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
View 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)
}

View File

@@ -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)

View File

@@ -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
View 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"`
}

View File

@@ -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

View File

@@ -1,3 +1,4 @@
// +build !enterprise
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: physical/types.proto

View File

@@ -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 {

View File

@@ -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
View 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
}

View File

@@ -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)
}
}

View File

@@ -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()

View File

@@ -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",

View File

@@ -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)

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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/")

View File

@@ -0,0 +1,5 @@
// +build !enterprise
package vault
func runICheck(v *BarrierView, expandedKey string, roErr error) bool { return true }

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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,
}

View File

@@ -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
View 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
}
}
)

View File

@@ -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
}

View File

@@ -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
View 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) {}

View File

@@ -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

View File

@@ -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

View File

@@ -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
View 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
}

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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)
}
}

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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)
}
}

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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