diff --git a/api/secret.go b/api/secret.go index 7478a0c544..b111501490 100644 --- a/api/secret.go +++ b/api/secret.go @@ -40,6 +40,7 @@ type Secret struct { // available in WrappedAccessor. type SecretWrapInfo struct { Token string `json:"token"` + Accessor string `json:"accessor"` TTL int `json:"ttl"` CreationTime time.Time `json:"creation_time"` CreationPath string `json:"creation_path"` diff --git a/api/secret_test.go b/api/secret_test.go index 3b6496677a..327de46c11 100644 --- a/api/secret_test.go +++ b/api/secret_test.go @@ -21,6 +21,7 @@ func TestParseSecret(t *testing.T) { ], "wrap_info": { "token": "token", + "accessor": "accessor", "ttl": 60, "creation_time": "2016-06-07T15:52:10-04:00", "wrapped_accessor": "abcd1234" @@ -46,6 +47,7 @@ func TestParseSecret(t *testing.T) { }, WrapInfo: &SecretWrapInfo{ Token: "token", + Accessor: "accessor", TTL: 60, CreationTime: rawTime, WrappedAccessor: "abcd1234", diff --git a/audit/format.go b/audit/format.go index bd74ca4b1b..eaf29f0ede 100644 --- a/audit/format.go +++ b/audit/format.go @@ -242,12 +242,13 @@ func (f *AuditFormatter) FormatResponse( // Cache and restore accessor in the response if resp != nil { - var accessor, wrappedAccessor string + var accessor, wrappedAccessor, wrappingAccessor string if !config.HMACAccessor && resp != nil && resp.Auth != nil && resp.Auth.Accessor != "" { accessor = resp.Auth.Accessor } if !config.HMACAccessor && resp != nil && resp.WrapInfo != nil && resp.WrapInfo.WrappedAccessor != "" { wrappedAccessor = resp.WrapInfo.WrappedAccessor + wrappingAccessor = resp.WrapInfo.Accessor } if err := Hash(salt, resp); err != nil { return err @@ -258,6 +259,9 @@ func (f *AuditFormatter) FormatResponse( if wrappedAccessor != "" { resp.WrapInfo.WrappedAccessor = wrappedAccessor } + if wrappingAccessor != "" { + resp.WrapInfo.Accessor = wrappingAccessor + } } } @@ -301,6 +305,7 @@ func (f *AuditFormatter) FormatResponse( respWrapInfo = &AuditResponseWrapInfo{ TTL: int(resp.WrapInfo.TTL / time.Second), Token: token, + Accessor: resp.WrapInfo.Accessor, CreationTime: resp.WrapInfo.CreationTime.Format(time.RFC3339Nano), CreationPath: resp.WrapInfo.CreationPath, WrappedAccessor: resp.WrapInfo.WrappedAccessor, @@ -412,6 +417,7 @@ type AuditSecret struct { type AuditResponseWrapInfo struct { TTL int `json:"ttl"` Token string `json:"token"` + Accessor string `json:"accessor"` CreationTime string `json:"creation_time"` CreationPath string `json:"creation_path"` WrappedAccessor string `json:"wrapped_accessor,omitempty"` diff --git a/audit/hashstructure.go b/audit/hashstructure.go index 8caf3eb793..d3925721be 100644 --- a/audit/hashstructure.go +++ b/audit/hashstructure.go @@ -93,6 +93,7 @@ func Hash(salter *salt.Salt, raw interface{}) error { } s.Token = fn(s.Token) + s.Accessor = fn(s.Accessor) if s.WrappedAccessor != "" { s.WrappedAccessor = fn(s.WrappedAccessor) diff --git a/audit/hashstructure_test.go b/audit/hashstructure_test.go index 49afa6eacf..898e78630b 100644 --- a/audit/hashstructure_test.go +++ b/audit/hashstructure_test.go @@ -148,6 +148,7 @@ func TestHash(t *testing.T) { WrapInfo: &wrapping.ResponseWrapInfo{ TTL: 60, Token: "bar", + Accessor: "flimflam", CreationTime: now, WrappedAccessor: "bar", }, @@ -160,6 +161,7 @@ func TestHash(t *testing.T) { WrapInfo: &wrapping.ResponseWrapInfo{ TTL: 60, Token: "hmac-sha256:f9320baf0249169e73850cd6156ded0106e2bb6ad8cab01b7bbbebe6d1065317", + Accessor: "hmac-sha256:7c9c6fe666d0af73b3ebcfbfabe6885015558213208e6635ba104047b22f6390", CreationTime: now, WrappedAccessor: "hmac-sha256:f9320baf0249169e73850cd6156ded0106e2bb6ad8cab01b7bbbebe6d1065317", }, @@ -206,6 +208,11 @@ func TestHash(t *testing.T) { if err := Hash(localSalt, tc.Input); err != nil { t.Fatalf("err: %s\n\n%s", err, input) } + if _, ok := tc.Input.(*logical.Response); ok { + if !reflect.DeepEqual(tc.Input.(*logical.Response).WrapInfo, tc.Output.(*logical.Response).WrapInfo) { + t.Fatalf("bad:\nInput:\n%s\nTest case input:\n%#v\nTest case output\n%#v", input, tc.Input.(*logical.Response).WrapInfo, tc.Output.(*logical.Response).WrapInfo) + } + } if !reflect.DeepEqual(tc.Input, tc.Output) { t.Fatalf("bad:\nInput:\n%s\nTest case input:\n%#v\nTest case output\n%#v", input, tc.Input, tc.Output) } diff --git a/command/format.go b/command/format.go index 38f24d49e7..aab5a856f2 100644 --- a/command/format.go +++ b/command/format.go @@ -182,6 +182,7 @@ func (t TableFormatter) OutputSecret(ui cli.Ui, secret, s *api.Secret) error { if s.WrapInfo != nil { onceHeader.Do(headerFunc) input = append(input, fmt.Sprintf("wrapping_token: %s %s", config.Delim, s.WrapInfo.Token)) + input = append(input, fmt.Sprintf("wrapping_accessor: %s %s", config.Delim, s.WrapInfo.Accessor)) input = append(input, fmt.Sprintf("wrapping_token_ttl: %s %s", config.Delim, (time.Second*time.Duration(s.WrapInfo.TTL)).String())) input = append(input, fmt.Sprintf("wrapping_token_creation_time: %s %s", config.Delim, s.WrapInfo.CreationTime.String())) input = append(input, fmt.Sprintf("wrapping_token_creation_path: %s %s", config.Delim, s.WrapInfo.CreationPath)) diff --git a/command/util.go b/command/util.go index 1eefc92c0f..e8d46152c9 100644 --- a/command/util.go +++ b/command/util.go @@ -53,6 +53,8 @@ func PrintRawField(ui cli.Ui, secret *api.Secret, field string) int { switch field { case "wrapping_token": val = secret.WrapInfo.Token + case "wrapping_accessor": + val = secret.WrapInfo.Accessor case "wrapping_token_ttl": val = secret.WrapInfo.TTL case "wrapping_token_creation_time": diff --git a/helper/identity/sentinel.go b/helper/identity/sentinel.go index 45f4b807f4..bf3cfff552 100644 --- a/helper/identity/sentinel.go +++ b/helper/identity/sentinel.go @@ -28,6 +28,20 @@ func (e *Entity) SentinelGet(key string) (interface{}, error) { return nil, nil } +func (e *Entity) SentinelKeys() []string { + return []string{ + "id", + "aliases", + "metadata", + "meta", + "name", + "creation_time", + "last_update_time", + "merged_entity_ids", + "policies", + } +} + func (p *Alias) SentinelGet(key string) (interface{}, error) { if p == nil { return nil, nil @@ -56,6 +70,20 @@ func (p *Alias) SentinelGet(key string) (interface{}, error) { return nil, nil } +func (a *Alias) SentinelKeys() []string { + return []string{ + "id", + "mount_type", + "mount_path", + "meta", + "metadata", + "name", + "creation_time", + "last_update_time", + "merged_from_entity_ids", + } +} + func (g *Group) SentinelGet(key string) (interface{}, error) { if g == nil { return nil, nil @@ -81,3 +109,17 @@ func (g *Group) SentinelGet(key string) (interface{}, error) { return nil, nil } + +func (g *Group) SentinelKeys() []string { + return []string{ + "id", + "name", + "policies", + "parent_group_ids", + "member_entity_ids", + "metadata", + "meta", + "creation_time", + "last_update_time", + } +} diff --git a/helper/wrapping/wrapinfo.go b/helper/wrapping/wrapinfo.go index e2c7c5170e..07e37c27d3 100644 --- a/helper/wrapping/wrapinfo.go +++ b/helper/wrapping/wrapinfo.go @@ -10,6 +10,9 @@ type ResponseWrapInfo struct { // The token containing the wrapped response Token string `json:"token" structs:"token" mapstructure:"token" sentinel:""` + // The token accessor for the wrapped response token + Accessor string `json:"accessor" structs:"accessor" mapstructure:"accessor"` + // The creation time. This can be used with the TTL to figure out an // expected expiration. CreationTime time.Time `json:"creation_time" structs:"creation_time" mapstructure:"creation_time" sentinel:""` diff --git a/http/handler_test.go b/http/handler_test.go index d16581b8e0..f6e015c985 100644 --- a/http/handler_test.go +++ b/http/handler_test.go @@ -325,6 +325,12 @@ func TestSysMounts_headerAuth_Wrapped(t *testing.T) { } expected["wrap_info"].(map[string]interface{})["creation_path"] = actualCreationPath + actualAccessor, ok := actual["wrap_info"].(map[string]interface{})["accessor"] + if !ok || actualAccessor == "" { + t.Fatal("accessor missing in wrap info") + } + expected["wrap_info"].(map[string]interface{})["accessor"] = actualAccessor + if !reflect.DeepEqual(actual, expected) { t.Fatalf("bad:\nExpected: %#v\nActual: %#v\n%T %T", expected, actual, actual["warnings"], actual["data"]) } diff --git a/http/logical.go b/http/logical.go index 5aa7d077d8..bcc5ba902b 100644 --- a/http/logical.go +++ b/http/logical.go @@ -151,6 +151,7 @@ func respondLogical(w http.ResponseWriter, r *http.Request, req *logical.Request httpResp = &logical.HTTPResponse{ WrapInfo: &logical.HTTPWrapInfo{ Token: resp.WrapInfo.Token, + Accessor: resp.WrapInfo.Accessor, TTL: int(resp.WrapInfo.TTL.Seconds()), CreationTime: resp.WrapInfo.CreationTime.Format(time.RFC3339Nano), CreationPath: resp.WrapInfo.CreationPath, diff --git a/logical/request.go b/logical/request.go index bac6c0bfca..edde0417fd 100644 --- a/logical/request.go +++ b/logical/request.go @@ -37,6 +37,13 @@ func (r *RequestWrapInfo) SentinelGet(key string) (interface{}, error) { return nil, nil } +func (r *RequestWrapInfo) SentinelKeys() []string { + return []string{ + "ttl", + "ttl_seconds", + } +} + // Request is a struct that stores the parameters and context of a request // being made to Vault. It is used to abstract the details of the higher level // request protocol from the handlers. @@ -176,6 +183,14 @@ func (r *Request) SentinelGet(key string) (interface{}, error) { return nil, nil } +func (r *Request) SentinelKeys() []string { + return []string{ + "path", + "wrapping", + "wrap_info", + } +} + func (r *Request) LastRemoteWAL() uint64 { return r.lastRemoteWAL } @@ -260,4 +275,8 @@ var ( // ErrPermissionDenied is returned if the client is not authorized ErrPermissionDenied = errors.New("permission denied") + + // ErrMultiAuthzPending is returned if the the request needs more + // authorizations + ErrMultiAuthzPending = errors.New("request needs further approval") ) diff --git a/logical/translate_response.go b/logical/translate_response.go index 8d2b386236..433530194b 100644 --- a/logical/translate_response.go +++ b/logical/translate_response.go @@ -92,6 +92,7 @@ type HTTPAuth struct { type HTTPWrapInfo struct { Token string `json:"token"` + Accessor string `json:"accessor"` TTL int `json:"ttl"` CreationTime string `json:"creation_time"` CreationPath string `json:"creation_path"` diff --git a/vault/identity_store_test.go b/vault/identity_store_test.go index 239a7b4c1c..a3b42bf706 100644 --- a/vault/identity_store_test.go +++ b/vault/identity_store_test.go @@ -221,18 +221,29 @@ func testCoreWithIdentityTokenGithub(t *testing.T) (*Core, *IdentityStore, *Toke return core, is, ts, ghAccessor } +func testCoreWithIdentityTokenGithubRoot(t *testing.T) (*Core, *IdentityStore, *TokenStore, string, string) { + is, ghAccessor, core, root := testIdentityStoreWithGithubAuthRoot(t) + ts := testTokenStore(t, core) + return core, is, ts, ghAccessor, root +} + +func testIdentityStoreWithGithubAuth(t *testing.T) (*IdentityStore, string, *Core) { + is, ghA, c, _ := testIdentityStoreWithGithubAuthRoot(t) + return is, ghA, c +} + // testIdentityStoreWithGithubAuth returns an instance of identity store which // is mounted by default. This function also enables the github auth backend to // assist with testing aliases and entities that require an valid mount // accessor of an auth backend. -func testIdentityStoreWithGithubAuth(t *testing.T) (*IdentityStore, string, *Core) { +func testIdentityStoreWithGithubAuthRoot(t *testing.T) (*IdentityStore, string, *Core, string) { // Add github credential factory to core config err := AddTestCredentialBackend("github", credGithub.Factory) if err != nil { t.Fatalf("err: %s", err) } - c, _, _ := TestCoreUnsealed(t) + c, _, root := TestCoreUnsealed(t) meGH := &MountEntry{ Table: credentialTableType, @@ -252,7 +263,7 @@ func testIdentityStoreWithGithubAuth(t *testing.T) (*IdentityStore, string, *Cor t.Fatalf("failed to fetch identity store from router") } - return identitystore.(*IdentityStore), meGH.Accessor, c + return identitystore.(*IdentityStore), meGH.Accessor, c, root } func TestIdentityStore_MetadataKeyRegex(t *testing.T) { diff --git a/vault/logical_system.go b/vault/logical_system.go index 96884bfe6d..3b174baadd 100644 --- a/vault/logical_system.go +++ b/vault/logical_system.go @@ -6,6 +6,7 @@ import ( "encoding/base64" "encoding/hex" "encoding/json" + "errors" "fmt" "hash" "strconv" @@ -2507,42 +2508,36 @@ func (b *SystemBackend) handleWrappingUnwrap( token = req.ClientToken } - if thirdParty { - // Use the token to decrement the use count to avoid a second operation on the token. - _, err := b.Core.tokenStore.UseTokenByID(token) - if err != nil { - return nil, fmt.Errorf("error decrementing wrapping token's use-count: %v", err) + // Get the policies so we can determine if this is a normal response + // wrapping request or a control group token. + // + // We use lookupTainted here because the token might have already been used + // by handleRequest(), this happens when it's a normal response wrapping + // request and the token was provided "first party". We want to inspect the + // token policies but will not use this token entry for anything else. + te, err := b.Core.tokenStore.lookupTainted(token) + if err != nil { + return nil, err + } + if te == nil { + return nil, errors.New("could not find token") + } + if len(te.Policies) != 1 { + return nil, errors.New("token is not a valid unwrap token") + } + + var response string + switch te.Policies[0] { + case responseWrappingPolicyName: + response, err = b.responseWrappingUnwrap(token, thirdParty) + } + if err != nil { + var respErr *logical.Response + if len(response) > 0 { + respErr = logical.ErrorResponse(response) } - defer b.Core.tokenStore.Revoke(token) - } - - cubbyReq := &logical.Request{ - Operation: logical.ReadOperation, - Path: "cubbyhole/response", - ClientToken: token, - } - cubbyResp, err := b.Core.router.Route(cubbyReq) - if err != nil { - return nil, fmt.Errorf("error looking up wrapping information: %v", err) - } - if cubbyResp == nil { - return logical.ErrorResponse("no information found; wrapping token may be from a previous Vault version"), nil - } - if cubbyResp != nil && cubbyResp.IsError() { - return cubbyResp, nil - } - if cubbyResp.Data == nil { - return logical.ErrorResponse("wrapping information was nil; wrapping token may be from a previous Vault version"), nil - } - - responseRaw := cubbyResp.Data["response"] - if responseRaw == nil { - return nil, fmt.Errorf("no response found inside the cubbyhole") - } - response, ok := responseRaw.(string) - if !ok { - return nil, fmt.Errorf("could not decode response inside the cubbyhole") + return respErr, err } resp := &logical.Response{ @@ -2559,6 +2554,50 @@ func (b *SystemBackend) handleWrappingUnwrap( return resp, nil } +// responseWrappingUnwrap will read the stored response in the cubbyhole and +// return the raw HTTP response. +func (b *SystemBackend) responseWrappingUnwrap(token string, thirdParty bool) (string, error) { + if thirdParty { + // Use the token to decrement the use count to avoid a second operation on the token. + _, err := b.Core.tokenStore.UseTokenByID(token) + if err != nil { + return "", fmt.Errorf("error decrementing wrapping token's use-count: %v", err) + } + + defer b.Core.tokenStore.Revoke(token) + } + + cubbyReq := &logical.Request{ + Operation: logical.ReadOperation, + Path: "cubbyhole/response", + ClientToken: token, + } + cubbyResp, err := b.Core.router.Route(cubbyReq) + if err != nil { + return "", fmt.Errorf("error looking up wrapping information: %v", err) + } + if cubbyResp == nil { + return "no information found; wrapping token may be from a previous Vault version", ErrInternalError + } + if cubbyResp != nil && cubbyResp.IsError() { + return cubbyResp.Error().Error(), nil + } + if cubbyResp.Data == nil { + return "wrapping information was nil; wrapping token may be from a previous Vault version", ErrInternalError + } + + responseRaw := cubbyResp.Data["response"] + if responseRaw == nil { + return "", fmt.Errorf("no response found inside the cubbyhole") + } + response, ok := responseRaw.(string) + if !ok { + return "", fmt.Errorf("could not decode response inside the cubbyhole") + } + + return response, nil +} + func (b *SystemBackend) handleWrappingLookup( req *logical.Request, data *framework.FieldData) (*logical.Response, error) { // This ordering of lookups has been validated already in the wrapping diff --git a/vault/policy_store.go b/vault/policy_store.go index 6ac74c98bd..e0e86c4719 100644 --- a/vault/policy_store.go +++ b/vault/policy_store.go @@ -22,9 +22,16 @@ const ( // policyCacheSize is the number of policies that are kept cached policyCacheSize = 1024 + // defaultPolicyName is the name of the default policy + defaultPolicyName = "default" + // responseWrappingPolicyName is the name of the fixed policy responseWrappingPolicyName = "response-wrapping" + // controlGroupPolicyName is the name of the fixed policy for control group + // tokens + controlGroupPolicyName = "control-group" + // responseWrappingPolicy is the policy that ensures cubbyhole response // wrapping can always succeed. responseWrappingPolicy = ` @@ -117,9 +124,11 @@ var ( immutablePolicies = []string{ "root", responseWrappingPolicyName, + controlGroupPolicyName, } nonAssignablePolicies = []string{ responseWrappingPolicyName, + controlGroupPolicyName, } ) @@ -181,27 +190,12 @@ func (c *Core) setupPolicyStore() error { } // Ensure that the default policy exists, and if not, create it - policy, err := c.policyStore.GetPolicy("default", PolicyTypeACL) - if err != nil { - return errwrap.Wrapf("error fetching default policy from store: {{err}}", err) + if err := c.policyStore.loadACLPolicy(defaultPolicyName, defaultPolicy); err != nil { + return err } - if policy == nil { - err := c.policyStore.createDefaultPolicy() - if err != nil { - return err - } - } - - // Ensure that the cubbyhole response wrapping policy exists - policy, err = c.policyStore.GetPolicy(responseWrappingPolicyName, PolicyTypeACL) - if err != nil { - return errwrap.Wrapf("error fetching response-wrapping policy from store: {{err}}", err) - } - if policy == nil || policy.Raw != responseWrappingPolicy { - err := c.policyStore.createResponseWrappingPolicy() - if err != nil { - return err - } + // Ensure that the response wrapping policy exists + if err := c.policyStore.loadACLPolicy(responseWrappingPolicyName, responseWrappingPolicy); err != nil { + return err } return nil @@ -478,32 +472,30 @@ func (ps *PolicyStore) ACL(names ...string) (*ACL, error) { return acl, nil } -func (ps *PolicyStore) createDefaultPolicy() error { - policy, err := ParseACLPolicy(defaultPolicy) +func (ps *PolicyStore) loadACLPolicy(policyName, policyText string) error { + // Check if the policy already exists + policy, err := ps.GetPolicy(policyName, PolicyTypeACL) + if err != nil { - return errwrap.Wrapf("error parsing default policy: {{err}}", err) + return errwrap.Wrapf(fmt.Sprintf("error fetching %s policy from store: {{err}}", policyName), err) + } + + if policy != nil { + if !strutil.StrListContains(immutablePolicies, policyName) || policyText == policy.Raw { + return nil + } + } + + policy, err = ParseACLPolicy(policyText) + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("error parsing %s policy: {{err}}", policyName), err) } if policy == nil { - return fmt.Errorf("parsing default policy resulted in nil policy") + return fmt.Errorf("parsing %s policy resulted in nil policy", policyName) } - policy.Name = "default" - policy.Type = PolicyTypeACL - return ps.setPolicyInternal(policy) -} - -func (ps *PolicyStore) createResponseWrappingPolicy() error { - policy, err := ParseACLPolicy(responseWrappingPolicy) - if err != nil { - return errwrap.Wrapf(fmt.Sprintf("error parsing %s policy: {{err}}", responseWrappingPolicyName), err) - } - - if policy == nil { - return fmt.Errorf("parsing %s policy resulted in nil policy", responseWrappingPolicyName) - } - - policy.Name = responseWrappingPolicyName + policy.Name = policyName policy.Type = PolicyTypeACL return ps.setPolicyInternal(policy) } diff --git a/vault/request_handling.go b/vault/request_handling.go index 2d16be4e45..7fb7ea1d32 100644 --- a/vault/request_handling.go +++ b/vault/request_handling.go @@ -68,7 +68,8 @@ func (c *Core) HandleRequest(req *logical.Request) (resp *logical.Response, err err == nil && !resp.IsError() && resp.WrapInfo != nil && - resp.WrapInfo.TTL != 0 + resp.WrapInfo.TTL != 0 && + resp.WrapInfo.Token == "" if wrapping { cubbyResp, cubbyErr := c.wrapInCubbyhole(req, resp, auth) @@ -161,12 +162,10 @@ func (c *Core) handleRequest(req *logical.Request) (retResp *logical.Response, r if ctErr != nil { // If it is an internal error we return that, otherwise we // return invalid request so that the status codes can be correct - var errType error + errType := logical.ErrInvalidRequest switch ctErr { case ErrInternalError, logical.ErrPermissionDenied: errType = ctErr - default: - errType = logical.ErrInvalidRequest } if err := c.auditBroker.LogRequest(auth, req, c.auditedHeaders, ctErr); err != nil { diff --git a/vault/token_store.go b/vault/token_store.go index fd52a71e25..b72fba6fad 100644 --- a/vault/token_store.go +++ b/vault/token_store.go @@ -623,6 +623,21 @@ func (te *TokenEntry) SentinelGet(key string) (interface{}, error) { return nil, nil } +func (te *TokenEntry) SentinelKeys() []string { + return []string{ + "period", + "period_seconds", + "explicit_max_ttl", + "explicit_max_ttl_seconds", + "creation_ttl", + "creation_ttl_seconds", + "creation_time", + "creation_time_unix", + "meta", + "metadata", + } +} + // tsRoleEntry contains token store role information type tsRoleEntry struct { // The name of the role. Embedded so it can be used for pathing @@ -865,6 +880,12 @@ func (ts *TokenStore) UseToken(te *TokenEntry) (*TokenEntry, error) { return te, nil } + // If we are attempting to unwrap a control group request, don't use the token. + // It will be manually revoked by the handler. + if len(te.Policies) == 1 && te.Policies[0] == controlGroupPolicyName { + return te, nil + } + lock := locksutil.LockForKey(ts.tokenLocks, te.ID) lock.Lock() defer lock.Unlock() @@ -934,6 +955,25 @@ func (ts *TokenStore) Lookup(id string) (*TokenEntry, error) { return ts.lookupSalted(saltedID, false) } +// lookupTainted is used to find a token that may or maynot be tainted given its +// ID. It acquires a read lock, then calls lookupSalted. +func (ts *TokenStore) lookupTainted(id string) (*TokenEntry, error) { + defer metrics.MeasureSince([]string{"token", "lookup"}, time.Now()) + if id == "" { + return nil, fmt.Errorf("cannot lookup blank token") + } + + lock := locksutil.LockForKey(ts.tokenLocks, id) + lock.RLock() + defer lock.RUnlock() + + saltedID, err := ts.SaltID(id) + if err != nil { + return nil, err + } + return ts.lookupSalted(saltedID, true) +} + // lookupSalted is used to find a token given its salted ID. If tainted is // true, entries that are in some revocation state (currently, indicated by num // uses < 0), the entry will be returned anyways diff --git a/vault/wrapping.go b/vault/wrapping.go index 6c3bf1df5f..b23c7f0342 100644 --- a/vault/wrapping.go +++ b/vault/wrapping.go @@ -115,6 +115,7 @@ func (c *Core) wrapInCubbyhole(req *logical.Request, resp *logical.Response, aut } resp.WrapInfo.Token = te.ID + resp.WrapInfo.Accessor = te.Accessor resp.WrapInfo.CreationTime = creationTime // If this is not a rewrap, store the request path as creation_path if req.Path != "sys/wrapping/rewrap" { @@ -328,7 +329,7 @@ func (c *Core) ValidateWrappingToken(req *logical.Request) (bool, error) { return false, nil } - if te.Policies[0] != responseWrappingPolicyName { + if te.Policies[0] != responseWrappingPolicyName && te.Policies[0] != controlGroupPolicyName { return false, nil }