mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-01 19:17:58 +00:00
Port over bits (#3575)
This commit is contained in:
@@ -40,6 +40,7 @@ type Secret struct {
|
|||||||
// available in WrappedAccessor.
|
// available in WrappedAccessor.
|
||||||
type SecretWrapInfo struct {
|
type SecretWrapInfo struct {
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
|
Accessor string `json:"accessor"`
|
||||||
TTL int `json:"ttl"`
|
TTL int `json:"ttl"`
|
||||||
CreationTime time.Time `json:"creation_time"`
|
CreationTime time.Time `json:"creation_time"`
|
||||||
CreationPath string `json:"creation_path"`
|
CreationPath string `json:"creation_path"`
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ func TestParseSecret(t *testing.T) {
|
|||||||
],
|
],
|
||||||
"wrap_info": {
|
"wrap_info": {
|
||||||
"token": "token",
|
"token": "token",
|
||||||
|
"accessor": "accessor",
|
||||||
"ttl": 60,
|
"ttl": 60,
|
||||||
"creation_time": "2016-06-07T15:52:10-04:00",
|
"creation_time": "2016-06-07T15:52:10-04:00",
|
||||||
"wrapped_accessor": "abcd1234"
|
"wrapped_accessor": "abcd1234"
|
||||||
@@ -46,6 +47,7 @@ func TestParseSecret(t *testing.T) {
|
|||||||
},
|
},
|
||||||
WrapInfo: &SecretWrapInfo{
|
WrapInfo: &SecretWrapInfo{
|
||||||
Token: "token",
|
Token: "token",
|
||||||
|
Accessor: "accessor",
|
||||||
TTL: 60,
|
TTL: 60,
|
||||||
CreationTime: rawTime,
|
CreationTime: rawTime,
|
||||||
WrappedAccessor: "abcd1234",
|
WrappedAccessor: "abcd1234",
|
||||||
|
|||||||
@@ -242,12 +242,13 @@ func (f *AuditFormatter) FormatResponse(
|
|||||||
|
|
||||||
// Cache and restore accessor in the response
|
// Cache and restore accessor in the response
|
||||||
if resp != nil {
|
if resp != nil {
|
||||||
var accessor, wrappedAccessor string
|
var accessor, wrappedAccessor, wrappingAccessor string
|
||||||
if !config.HMACAccessor && resp != nil && resp.Auth != nil && resp.Auth.Accessor != "" {
|
if !config.HMACAccessor && resp != nil && resp.Auth != nil && resp.Auth.Accessor != "" {
|
||||||
accessor = resp.Auth.Accessor
|
accessor = resp.Auth.Accessor
|
||||||
}
|
}
|
||||||
if !config.HMACAccessor && resp != nil && resp.WrapInfo != nil && resp.WrapInfo.WrappedAccessor != "" {
|
if !config.HMACAccessor && resp != nil && resp.WrapInfo != nil && resp.WrapInfo.WrappedAccessor != "" {
|
||||||
wrappedAccessor = resp.WrapInfo.WrappedAccessor
|
wrappedAccessor = resp.WrapInfo.WrappedAccessor
|
||||||
|
wrappingAccessor = resp.WrapInfo.Accessor
|
||||||
}
|
}
|
||||||
if err := Hash(salt, resp); err != nil {
|
if err := Hash(salt, resp); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -258,6 +259,9 @@ func (f *AuditFormatter) FormatResponse(
|
|||||||
if wrappedAccessor != "" {
|
if wrappedAccessor != "" {
|
||||||
resp.WrapInfo.WrappedAccessor = wrappedAccessor
|
resp.WrapInfo.WrappedAccessor = wrappedAccessor
|
||||||
}
|
}
|
||||||
|
if wrappingAccessor != "" {
|
||||||
|
resp.WrapInfo.Accessor = wrappingAccessor
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,6 +305,7 @@ func (f *AuditFormatter) FormatResponse(
|
|||||||
respWrapInfo = &AuditResponseWrapInfo{
|
respWrapInfo = &AuditResponseWrapInfo{
|
||||||
TTL: int(resp.WrapInfo.TTL / time.Second),
|
TTL: int(resp.WrapInfo.TTL / time.Second),
|
||||||
Token: token,
|
Token: token,
|
||||||
|
Accessor: resp.WrapInfo.Accessor,
|
||||||
CreationTime: resp.WrapInfo.CreationTime.Format(time.RFC3339Nano),
|
CreationTime: resp.WrapInfo.CreationTime.Format(time.RFC3339Nano),
|
||||||
CreationPath: resp.WrapInfo.CreationPath,
|
CreationPath: resp.WrapInfo.CreationPath,
|
||||||
WrappedAccessor: resp.WrapInfo.WrappedAccessor,
|
WrappedAccessor: resp.WrapInfo.WrappedAccessor,
|
||||||
@@ -412,6 +417,7 @@ type AuditSecret struct {
|
|||||||
type AuditResponseWrapInfo struct {
|
type AuditResponseWrapInfo struct {
|
||||||
TTL int `json:"ttl"`
|
TTL int `json:"ttl"`
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
|
Accessor string `json:"accessor"`
|
||||||
CreationTime string `json:"creation_time"`
|
CreationTime string `json:"creation_time"`
|
||||||
CreationPath string `json:"creation_path"`
|
CreationPath string `json:"creation_path"`
|
||||||
WrappedAccessor string `json:"wrapped_accessor,omitempty"`
|
WrappedAccessor string `json:"wrapped_accessor,omitempty"`
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ func Hash(salter *salt.Salt, raw interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.Token = fn(s.Token)
|
s.Token = fn(s.Token)
|
||||||
|
s.Accessor = fn(s.Accessor)
|
||||||
|
|
||||||
if s.WrappedAccessor != "" {
|
if s.WrappedAccessor != "" {
|
||||||
s.WrappedAccessor = fn(s.WrappedAccessor)
|
s.WrappedAccessor = fn(s.WrappedAccessor)
|
||||||
|
|||||||
@@ -148,6 +148,7 @@ func TestHash(t *testing.T) {
|
|||||||
WrapInfo: &wrapping.ResponseWrapInfo{
|
WrapInfo: &wrapping.ResponseWrapInfo{
|
||||||
TTL: 60,
|
TTL: 60,
|
||||||
Token: "bar",
|
Token: "bar",
|
||||||
|
Accessor: "flimflam",
|
||||||
CreationTime: now,
|
CreationTime: now,
|
||||||
WrappedAccessor: "bar",
|
WrappedAccessor: "bar",
|
||||||
},
|
},
|
||||||
@@ -160,6 +161,7 @@ func TestHash(t *testing.T) {
|
|||||||
WrapInfo: &wrapping.ResponseWrapInfo{
|
WrapInfo: &wrapping.ResponseWrapInfo{
|
||||||
TTL: 60,
|
TTL: 60,
|
||||||
Token: "hmac-sha256:f9320baf0249169e73850cd6156ded0106e2bb6ad8cab01b7bbbebe6d1065317",
|
Token: "hmac-sha256:f9320baf0249169e73850cd6156ded0106e2bb6ad8cab01b7bbbebe6d1065317",
|
||||||
|
Accessor: "hmac-sha256:7c9c6fe666d0af73b3ebcfbfabe6885015558213208e6635ba104047b22f6390",
|
||||||
CreationTime: now,
|
CreationTime: now,
|
||||||
WrappedAccessor: "hmac-sha256:f9320baf0249169e73850cd6156ded0106e2bb6ad8cab01b7bbbebe6d1065317",
|
WrappedAccessor: "hmac-sha256:f9320baf0249169e73850cd6156ded0106e2bb6ad8cab01b7bbbebe6d1065317",
|
||||||
},
|
},
|
||||||
@@ -206,6 +208,11 @@ func TestHash(t *testing.T) {
|
|||||||
if err := Hash(localSalt, tc.Input); err != nil {
|
if err := Hash(localSalt, tc.Input); err != nil {
|
||||||
t.Fatalf("err: %s\n\n%s", err, input)
|
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) {
|
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)
|
t.Fatalf("bad:\nInput:\n%s\nTest case input:\n%#v\nTest case output\n%#v", input, tc.Input, tc.Output)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -182,6 +182,7 @@ func (t TableFormatter) OutputSecret(ui cli.Ui, secret, s *api.Secret) error {
|
|||||||
if s.WrapInfo != nil {
|
if s.WrapInfo != nil {
|
||||||
onceHeader.Do(headerFunc)
|
onceHeader.Do(headerFunc)
|
||||||
input = append(input, fmt.Sprintf("wrapping_token: %s %s", config.Delim, s.WrapInfo.Token))
|
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_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_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))
|
input = append(input, fmt.Sprintf("wrapping_token_creation_path: %s %s", config.Delim, s.WrapInfo.CreationPath))
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ func PrintRawField(ui cli.Ui, secret *api.Secret, field string) int {
|
|||||||
switch field {
|
switch field {
|
||||||
case "wrapping_token":
|
case "wrapping_token":
|
||||||
val = secret.WrapInfo.Token
|
val = secret.WrapInfo.Token
|
||||||
|
case "wrapping_accessor":
|
||||||
|
val = secret.WrapInfo.Accessor
|
||||||
case "wrapping_token_ttl":
|
case "wrapping_token_ttl":
|
||||||
val = secret.WrapInfo.TTL
|
val = secret.WrapInfo.TTL
|
||||||
case "wrapping_token_creation_time":
|
case "wrapping_token_creation_time":
|
||||||
|
|||||||
@@ -28,6 +28,20 @@ func (e *Entity) SentinelGet(key string) (interface{}, error) {
|
|||||||
return nil, nil
|
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) {
|
func (p *Alias) SentinelGet(key string) (interface{}, error) {
|
||||||
if p == nil {
|
if p == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -56,6 +70,20 @@ func (p *Alias) SentinelGet(key string) (interface{}, error) {
|
|||||||
return nil, nil
|
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) {
|
func (g *Group) SentinelGet(key string) (interface{}, error) {
|
||||||
if g == nil {
|
if g == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -81,3 +109,17 @@ func (g *Group) SentinelGet(key string) (interface{}, error) {
|
|||||||
|
|
||||||
return nil, nil
|
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",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ type ResponseWrapInfo struct {
|
|||||||
// The token containing the wrapped response
|
// The token containing the wrapped response
|
||||||
Token string `json:"token" structs:"token" mapstructure:"token" sentinel:""`
|
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
|
// The creation time. This can be used with the TTL to figure out an
|
||||||
// expected expiration.
|
// expected expiration.
|
||||||
CreationTime time.Time `json:"creation_time" structs:"creation_time" mapstructure:"creation_time" sentinel:""`
|
CreationTime time.Time `json:"creation_time" structs:"creation_time" mapstructure:"creation_time" sentinel:""`
|
||||||
|
|||||||
@@ -325,6 +325,12 @@ func TestSysMounts_headerAuth_Wrapped(t *testing.T) {
|
|||||||
}
|
}
|
||||||
expected["wrap_info"].(map[string]interface{})["creation_path"] = actualCreationPath
|
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) {
|
if !reflect.DeepEqual(actual, expected) {
|
||||||
t.Fatalf("bad:\nExpected: %#v\nActual: %#v\n%T %T", expected, actual, actual["warnings"], actual["data"])
|
t.Fatalf("bad:\nExpected: %#v\nActual: %#v\n%T %T", expected, actual, actual["warnings"], actual["data"])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -151,6 +151,7 @@ func respondLogical(w http.ResponseWriter, r *http.Request, req *logical.Request
|
|||||||
httpResp = &logical.HTTPResponse{
|
httpResp = &logical.HTTPResponse{
|
||||||
WrapInfo: &logical.HTTPWrapInfo{
|
WrapInfo: &logical.HTTPWrapInfo{
|
||||||
Token: resp.WrapInfo.Token,
|
Token: resp.WrapInfo.Token,
|
||||||
|
Accessor: resp.WrapInfo.Accessor,
|
||||||
TTL: int(resp.WrapInfo.TTL.Seconds()),
|
TTL: int(resp.WrapInfo.TTL.Seconds()),
|
||||||
CreationTime: resp.WrapInfo.CreationTime.Format(time.RFC3339Nano),
|
CreationTime: resp.WrapInfo.CreationTime.Format(time.RFC3339Nano),
|
||||||
CreationPath: resp.WrapInfo.CreationPath,
|
CreationPath: resp.WrapInfo.CreationPath,
|
||||||
|
|||||||
@@ -37,6 +37,13 @@ func (r *RequestWrapInfo) SentinelGet(key string) (interface{}, error) {
|
|||||||
return nil, nil
|
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
|
// 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
|
// being made to Vault. It is used to abstract the details of the higher level
|
||||||
// request protocol from the handlers.
|
// request protocol from the handlers.
|
||||||
@@ -176,6 +183,14 @@ func (r *Request) SentinelGet(key string) (interface{}, error) {
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Request) SentinelKeys() []string {
|
||||||
|
return []string{
|
||||||
|
"path",
|
||||||
|
"wrapping",
|
||||||
|
"wrap_info",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Request) LastRemoteWAL() uint64 {
|
func (r *Request) LastRemoteWAL() uint64 {
|
||||||
return r.lastRemoteWAL
|
return r.lastRemoteWAL
|
||||||
}
|
}
|
||||||
@@ -260,4 +275,8 @@ var (
|
|||||||
|
|
||||||
// ErrPermissionDenied is returned if the client is not authorized
|
// ErrPermissionDenied is returned if the client is not authorized
|
||||||
ErrPermissionDenied = errors.New("permission denied")
|
ErrPermissionDenied = errors.New("permission denied")
|
||||||
|
|
||||||
|
// ErrMultiAuthzPending is returned if the the request needs more
|
||||||
|
// authorizations
|
||||||
|
ErrMultiAuthzPending = errors.New("request needs further approval")
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ type HTTPAuth struct {
|
|||||||
|
|
||||||
type HTTPWrapInfo struct {
|
type HTTPWrapInfo struct {
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
|
Accessor string `json:"accessor"`
|
||||||
TTL int `json:"ttl"`
|
TTL int `json:"ttl"`
|
||||||
CreationTime string `json:"creation_time"`
|
CreationTime string `json:"creation_time"`
|
||||||
CreationPath string `json:"creation_path"`
|
CreationPath string `json:"creation_path"`
|
||||||
|
|||||||
@@ -221,18 +221,29 @@ func testCoreWithIdentityTokenGithub(t *testing.T) (*Core, *IdentityStore, *Toke
|
|||||||
return core, is, ts, ghAccessor
|
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
|
// testIdentityStoreWithGithubAuth returns an instance of identity store which
|
||||||
// is mounted by default. This function also enables the github auth backend to
|
// is mounted by default. This function also enables the github auth backend to
|
||||||
// assist with testing aliases and entities that require an valid mount
|
// assist with testing aliases and entities that require an valid mount
|
||||||
// accessor of an auth backend.
|
// 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
|
// Add github credential factory to core config
|
||||||
err := AddTestCredentialBackend("github", credGithub.Factory)
|
err := AddTestCredentialBackend("github", credGithub.Factory)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
c, _, _ := TestCoreUnsealed(t)
|
c, _, root := TestCoreUnsealed(t)
|
||||||
|
|
||||||
meGH := &MountEntry{
|
meGH := &MountEntry{
|
||||||
Table: credentialTableType,
|
Table: credentialTableType,
|
||||||
@@ -252,7 +263,7 @@ func testIdentityStoreWithGithubAuth(t *testing.T) (*IdentityStore, string, *Cor
|
|||||||
t.Fatalf("failed to fetch identity store from router")
|
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) {
|
func TestIdentityStore_MetadataKeyRegex(t *testing.T) {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"hash"
|
"hash"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -2507,42 +2508,36 @@ func (b *SystemBackend) handleWrappingUnwrap(
|
|||||||
token = req.ClientToken
|
token = req.ClientToken
|
||||||
}
|
}
|
||||||
|
|
||||||
if thirdParty {
|
// Get the policies so we can determine if this is a normal response
|
||||||
// Use the token to decrement the use count to avoid a second operation on the token.
|
// wrapping request or a control group token.
|
||||||
_, err := b.Core.tokenStore.UseTokenByID(token)
|
//
|
||||||
if err != nil {
|
// We use lookupTainted here because the token might have already been used
|
||||||
return nil, fmt.Errorf("error decrementing wrapping token's use-count: %v", err)
|
// 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)
|
return respErr, err
|
||||||
}
|
|
||||||
|
|
||||||
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")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resp := &logical.Response{
|
resp := &logical.Response{
|
||||||
@@ -2559,6 +2554,50 @@ func (b *SystemBackend) handleWrappingUnwrap(
|
|||||||
return resp, nil
|
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(
|
func (b *SystemBackend) handleWrappingLookup(
|
||||||
req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||||
// This ordering of lookups has been validated already in the wrapping
|
// This ordering of lookups has been validated already in the wrapping
|
||||||
|
|||||||
@@ -22,9 +22,16 @@ const (
|
|||||||
// policyCacheSize is the number of policies that are kept cached
|
// policyCacheSize is the number of policies that are kept cached
|
||||||
policyCacheSize = 1024
|
policyCacheSize = 1024
|
||||||
|
|
||||||
|
// defaultPolicyName is the name of the default policy
|
||||||
|
defaultPolicyName = "default"
|
||||||
|
|
||||||
// responseWrappingPolicyName is the name of the fixed policy
|
// responseWrappingPolicyName is the name of the fixed policy
|
||||||
responseWrappingPolicyName = "response-wrapping"
|
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
|
// responseWrappingPolicy is the policy that ensures cubbyhole response
|
||||||
// wrapping can always succeed.
|
// wrapping can always succeed.
|
||||||
responseWrappingPolicy = `
|
responseWrappingPolicy = `
|
||||||
@@ -117,9 +124,11 @@ var (
|
|||||||
immutablePolicies = []string{
|
immutablePolicies = []string{
|
||||||
"root",
|
"root",
|
||||||
responseWrappingPolicyName,
|
responseWrappingPolicyName,
|
||||||
|
controlGroupPolicyName,
|
||||||
}
|
}
|
||||||
nonAssignablePolicies = []string{
|
nonAssignablePolicies = []string{
|
||||||
responseWrappingPolicyName,
|
responseWrappingPolicyName,
|
||||||
|
controlGroupPolicyName,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -181,27 +190,12 @@ func (c *Core) setupPolicyStore() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that the default policy exists, and if not, create it
|
// Ensure that the default policy exists, and if not, create it
|
||||||
policy, err := c.policyStore.GetPolicy("default", PolicyTypeACL)
|
if err := c.policyStore.loadACLPolicy(defaultPolicyName, defaultPolicy); err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return errwrap.Wrapf("error fetching default policy from store: {{err}}", err)
|
|
||||||
}
|
}
|
||||||
if policy == nil {
|
// Ensure that the response wrapping policy exists
|
||||||
err := c.policyStore.createDefaultPolicy()
|
if err := c.policyStore.loadACLPolicy(responseWrappingPolicyName, responseWrappingPolicy); err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -478,32 +472,30 @@ func (ps *PolicyStore) ACL(names ...string) (*ACL, error) {
|
|||||||
return acl, nil
|
return acl, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *PolicyStore) createDefaultPolicy() error {
|
func (ps *PolicyStore) loadACLPolicy(policyName, policyText string) error {
|
||||||
policy, err := ParseACLPolicy(defaultPolicy)
|
// Check if the policy already exists
|
||||||
|
policy, err := ps.GetPolicy(policyName, PolicyTypeACL)
|
||||||
|
|
||||||
if err != nil {
|
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 {
|
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.Name = policyName
|
||||||
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.Type = PolicyTypeACL
|
policy.Type = PolicyTypeACL
|
||||||
return ps.setPolicyInternal(policy)
|
return ps.setPolicyInternal(policy)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,8 @@ func (c *Core) HandleRequest(req *logical.Request) (resp *logical.Response, err
|
|||||||
err == nil &&
|
err == nil &&
|
||||||
!resp.IsError() &&
|
!resp.IsError() &&
|
||||||
resp.WrapInfo != nil &&
|
resp.WrapInfo != nil &&
|
||||||
resp.WrapInfo.TTL != 0
|
resp.WrapInfo.TTL != 0 &&
|
||||||
|
resp.WrapInfo.Token == ""
|
||||||
|
|
||||||
if wrapping {
|
if wrapping {
|
||||||
cubbyResp, cubbyErr := c.wrapInCubbyhole(req, resp, auth)
|
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 ctErr != nil {
|
||||||
// If it is an internal error we return that, otherwise we
|
// If it is an internal error we return that, otherwise we
|
||||||
// return invalid request so that the status codes can be correct
|
// return invalid request so that the status codes can be correct
|
||||||
var errType error
|
errType := logical.ErrInvalidRequest
|
||||||
switch ctErr {
|
switch ctErr {
|
||||||
case ErrInternalError, logical.ErrPermissionDenied:
|
case ErrInternalError, logical.ErrPermissionDenied:
|
||||||
errType = ctErr
|
errType = ctErr
|
||||||
default:
|
|
||||||
errType = logical.ErrInvalidRequest
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.auditBroker.LogRequest(auth, req, c.auditedHeaders, ctErr); err != nil {
|
if err := c.auditBroker.LogRequest(auth, req, c.auditedHeaders, ctErr); err != nil {
|
||||||
|
|||||||
@@ -623,6 +623,21 @@ func (te *TokenEntry) SentinelGet(key string) (interface{}, error) {
|
|||||||
return nil, nil
|
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
|
// tsRoleEntry contains token store role information
|
||||||
type tsRoleEntry struct {
|
type tsRoleEntry struct {
|
||||||
// The name of the role. Embedded so it can be used for pathing
|
// 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
|
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 := locksutil.LockForKey(ts.tokenLocks, te.ID)
|
||||||
lock.Lock()
|
lock.Lock()
|
||||||
defer lock.Unlock()
|
defer lock.Unlock()
|
||||||
@@ -934,6 +955,25 @@ func (ts *TokenStore) Lookup(id string) (*TokenEntry, error) {
|
|||||||
return ts.lookupSalted(saltedID, false)
|
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
|
// 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
|
// true, entries that are in some revocation state (currently, indicated by num
|
||||||
// uses < 0), the entry will be returned anyways
|
// uses < 0), the entry will be returned anyways
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ func (c *Core) wrapInCubbyhole(req *logical.Request, resp *logical.Response, aut
|
|||||||
}
|
}
|
||||||
|
|
||||||
resp.WrapInfo.Token = te.ID
|
resp.WrapInfo.Token = te.ID
|
||||||
|
resp.WrapInfo.Accessor = te.Accessor
|
||||||
resp.WrapInfo.CreationTime = creationTime
|
resp.WrapInfo.CreationTime = creationTime
|
||||||
// If this is not a rewrap, store the request path as creation_path
|
// If this is not a rewrap, store the request path as creation_path
|
||||||
if req.Path != "sys/wrapping/rewrap" {
|
if req.Path != "sys/wrapping/rewrap" {
|
||||||
@@ -328,7 +329,7 @@ func (c *Core) ValidateWrappingToken(req *logical.Request) (bool, error) {
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if te.Policies[0] != responseWrappingPolicyName {
|
if te.Policies[0] != responseWrappingPolicyName && te.Policies[0] != controlGroupPolicyName {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user