From db9d9e6415685214e48c4837edcbbf1dce1441c2 Mon Sep 17 00:00:00 2001 From: Calvin Leung Huang Date: Wed, 2 Aug 2017 18:28:58 -0400 Subject: [PATCH] Store original request path in WrapInfo (#3100) * Store original request path in WrapInfo as CreationPath * Add wrapping_token_creation_path to CLI output * Add CreationPath to AuditResponseWrapInfo * Fix tests * Add and fix tests, update API docs with new sample responses --- api/secret.go | 1 + audit/format.go | 2 ++ command/format.go | 1 + command/util.go | 2 ++ helper/wrapping/wrapinfo.go | 6 +++++- http/handler_test.go | 6 ++++++ http/logical.go | 1 + http/sys_wrapping_test.go | 11 +++++++++++ logical/translate_response.go | 1 + vault/logical_system.go | 14 +++++++++++++- vault/request_handling.go | 16 ++++++++++------ vault/wrapping.go | 11 +++++++++++ .../source/api/system/wrapping-lookup.html.md | 5 ++++- .../source/api/system/wrapping-rewrap.html.md | 2 +- website/source/api/system/wrapping-wrap.html.md | 2 +- 15 files changed, 70 insertions(+), 11 deletions(-) diff --git a/api/secret.go b/api/secret.go index 14924f9d0..7478a0c54 100644 --- a/api/secret.go +++ b/api/secret.go @@ -42,6 +42,7 @@ type SecretWrapInfo struct { Token string `json:"token"` TTL int `json:"ttl"` CreationTime time.Time `json:"creation_time"` + CreationPath string `json:"creation_path"` WrappedAccessor string `json:"wrapped_accessor"` } diff --git a/audit/format.go b/audit/format.go index 0f42f9ec9..18eb254eb 100644 --- a/audit/format.go +++ b/audit/format.go @@ -300,6 +300,7 @@ func (f *AuditFormatter) FormatResponse( TTL: int(resp.WrapInfo.TTL / time.Second), Token: token, CreationTime: resp.WrapInfo.CreationTime.Format(time.RFC3339Nano), + CreationPath: resp.WrapInfo.CreationPath, WrappedAccessor: resp.WrapInfo.WrappedAccessor, } } @@ -406,6 +407,7 @@ type AuditResponseWrapInfo struct { TTL int `json:"ttl"` Token string `json:"token"` CreationTime string `json:"creation_time"` + CreationPath string `json:"creation_path"` WrappedAccessor string `json:"wrapped_accessor,omitempty"` } diff --git a/command/format.go b/command/format.go index 4520b203f..286b9670e 100644 --- a/command/format.go +++ b/command/format.go @@ -181,6 +181,7 @@ func (t TableFormatter) OutputSecret(ui cli.Ui, secret, s *api.Secret) error { input = append(input, fmt.Sprintf("wrapping_token: %s %s", config.Delim, s.WrapInfo.Token)) 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)) if s.WrapInfo.WrappedAccessor != "" { input = append(input, fmt.Sprintf("wrapped_accessor: %s %s", config.Delim, s.WrapInfo.WrappedAccessor)) } diff --git a/command/util.go b/command/util.go index 0ec3916a7..1eefc92c0 100644 --- a/command/util.go +++ b/command/util.go @@ -57,6 +57,8 @@ func PrintRawField(ui cli.Ui, secret *api.Secret, field string) int { val = secret.WrapInfo.TTL case "wrapping_token_creation_time": val = secret.WrapInfo.CreationTime.Format(time.RFC3339Nano) + case "wrapping_token_creation_path": + val = secret.WrapInfo.CreationPath case "wrapped_accessor": val = secret.WrapInfo.WrappedAccessor default: diff --git a/helper/wrapping/wrapinfo.go b/helper/wrapping/wrapinfo.go index a27219b8a..2242c7b30 100644 --- a/helper/wrapping/wrapinfo.go +++ b/helper/wrapping/wrapinfo.go @@ -12,7 +12,7 @@ type ResponseWrapInfo struct { // 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:"cration_time"` + CreationTime time.Time `json:"creation_time" structs:"creation_time" mapstructure:"creation_time"` // If the contained response is the output of a token creation call, the // created token's accessor will be accessible here @@ -20,4 +20,8 @@ type ResponseWrapInfo struct { // The format to use. This doesn't get returned, it's only internal. Format string `json:"format" structs:"format" mapstructure:"format"` + + // CreationPath is the original request path that was used to create + // the wrapped response. + CreationPath string `json:"creation_path" structs:"creation_path" mapstructure:"creation_path"` } diff --git a/http/handler_test.go b/http/handler_test.go index 41a7a69c7..40885fbd8 100644 --- a/http/handler_test.go +++ b/http/handler_test.go @@ -282,6 +282,12 @@ func TestSysMounts_headerAuth_Wrapped(t *testing.T) { } expected["wrap_info"].(map[string]interface{})["creation_time"] = actualCreationTime + actualCreationPath, ok := actual["wrap_info"].(map[string]interface{})["creation_path"] + if !ok || actualCreationPath == "" { + t.Fatal("creation_path missing in wrap info") + } + expected["wrap_info"].(map[string]interface{})["creation_path"] = actualCreationPath + 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 1de2ef245..642314e59 100644 --- a/http/logical.go +++ b/http/logical.go @@ -153,6 +153,7 @@ func respondLogical(w http.ResponseWriter, r *http.Request, req *logical.Request Token: resp.WrapInfo.Token, TTL: int(resp.WrapInfo.TTL.Seconds()), CreationTime: resp.WrapInfo.CreationTime.Format(time.RFC3339Nano), + CreationPath: resp.WrapInfo.CreationPath, WrappedAccessor: resp.WrapInfo.WrappedAccessor, }, } diff --git a/http/sys_wrapping_test.go b/http/sys_wrapping_test.go index e75cf3177..7ab2143b1 100644 --- a/http/sys_wrapping_test.go +++ b/http/sys_wrapping_test.go @@ -308,6 +308,11 @@ func TestHTTP_Wrapping(t *testing.T) { } wrapInfo = secret.WrapInfo + // Check for correct CreationPath before rewrap + if wrapInfo.CreationPath != "secret/foo" { + t.Fatal("error on wrapInfo.CreationPath: expected: secret/foo, got: %s", wrapInfo.CreationPath) + } + // Test rewrapping secret, err = client.Logical().Write("sys/wrapping/rewrap", map[string]interface{}{ "token": wrapInfo.Token, @@ -315,6 +320,12 @@ func TestHTTP_Wrapping(t *testing.T) { if err != nil { t.Fatal(err) } + + // Check for correct Creation path after rewrap + if wrapInfo.CreationPath != "secret/foo" { + t.Fatal("error on wrapInfo.CreationPath: expected: secret/foo, got: %s", wrapInfo.CreationPath) + } + // Should be expired and fail _, err = client.Logical().Write("sys/wrapping/unwrap", map[string]interface{}{ "token": wrapInfo.Token, diff --git a/logical/translate_response.go b/logical/translate_response.go index 3632237ea..d3d727163 100644 --- a/logical/translate_response.go +++ b/logical/translate_response.go @@ -91,6 +91,7 @@ type HTTPWrapInfo struct { Token string `json:"token"` TTL int `json:"ttl"` CreationTime string `json:"creation_time"` + CreationPath string `json:"creation_path"` WrappedAccessor string `json:"wrapped_accessor,omitempty"` } diff --git a/vault/logical_system.go b/vault/logical_system.go index 61b37e328..848eea530 100644 --- a/vault/logical_system.go +++ b/vault/logical_system.go @@ -2204,6 +2204,7 @@ func (b *SystemBackend) handleWrappingLookup( creationTTLRaw := cubbyResp.Data["creation_ttl"] creationTime := cubbyResp.Data["creation_time"] + creationPath := cubbyResp.Data["creation_path"] resp := &logical.Response{ Data: map[string]interface{}{}, @@ -2219,6 +2220,9 @@ func (b *SystemBackend) handleWrappingLookup( // This was JSON marshaled so it's already a string in RFC3339 format resp.Data["creation_time"] = cubbyResp.Data["creation_time"] } + if creationPath != nil { + resp.Data["creation_path"] = cubbyResp.Data["creation_path"] + } return resp, nil } @@ -2278,6 +2282,13 @@ func (b *SystemBackend) handleWrappingRewrap( return nil, fmt.Errorf("error reading creation_ttl value from wrapping information: %v", err) } + // Get creation_path to return as the response later + creationPathRaw := cubbyResp.Data["creation_path"] + if creationPathRaw == nil { + return nil, fmt.Errorf("creation_path value in wrapping information was nil") + } + creationPath := creationPathRaw.(string) + // Fetch the original response and return it as the data for the new response cubbyReq = &logical.Request{ Operation: logical.ReadOperation, @@ -2310,7 +2321,8 @@ func (b *SystemBackend) handleWrappingRewrap( "response": response, }, WrapInfo: &wrapping.ResponseWrapInfo{ - TTL: time.Duration(creationTTL), + TTL: time.Duration(creationTTL), + CreationPath: creationPath, }, }, nil } diff --git a/vault/request_handling.go b/vault/request_handling.go index a55cf4fc3..26fcf01a4 100644 --- a/vault/request_handling.go +++ b/vault/request_handling.go @@ -189,7 +189,7 @@ func (c *Core) handleRequest(req *logical.Request) (retResp *logical.Response, r if resp != nil { // If wrapping is used, use the shortest between the request and response var wrapTTL time.Duration - var wrapFormat string + var wrapFormat, creationPath string // Ensure no wrap info information is set other than, possibly, the TTL if resp.WrapInfo != nil { @@ -197,6 +197,7 @@ func (c *Core) handleRequest(req *logical.Request) (retResp *logical.Response, r wrapTTL = resp.WrapInfo.TTL } wrapFormat = resp.WrapInfo.Format + creationPath = resp.WrapInfo.CreationPath resp.WrapInfo = nil } @@ -218,8 +219,9 @@ func (c *Core) handleRequest(req *logical.Request) (retResp *logical.Response, r if wrapTTL > 0 { resp.WrapInfo = &wrapping.ResponseWrapInfo{ - TTL: wrapTTL, - Format: wrapFormat, + TTL: wrapTTL, + Format: wrapFormat, + CreationPath: creationPath, } } } @@ -338,7 +340,7 @@ func (c *Core) handleLoginRequest(req *logical.Request) (*logical.Response, *log if resp != nil { // If wrapping is used, use the shortest between the request and response var wrapTTL time.Duration - var wrapFormat string + var wrapFormat, creationPath string // Ensure no wrap info information is set other than, possibly, the TTL if resp.WrapInfo != nil { @@ -346,6 +348,7 @@ func (c *Core) handleLoginRequest(req *logical.Request) (*logical.Response, *log wrapTTL = resp.WrapInfo.TTL } wrapFormat = resp.WrapInfo.Format + creationPath = resp.WrapInfo.CreationPath resp.WrapInfo = nil } @@ -365,8 +368,9 @@ func (c *Core) handleLoginRequest(req *logical.Request) (*logical.Response, *log if wrapTTL > 0 { resp.WrapInfo = &wrapping.ResponseWrapInfo{ - TTL: wrapTTL, - Format: wrapFormat, + TTL: wrapTTL, + Format: wrapFormat, + CreationPath: creationPath, } } } diff --git a/vault/wrapping.go b/vault/wrapping.go index 46409c39b..51715938d 100644 --- a/vault/wrapping.go +++ b/vault/wrapping.go @@ -115,6 +115,10 @@ func (c *Core) wrapInCubbyhole(req *logical.Request, resp *logical.Response) (*l resp.WrapInfo.Token = te.ID resp.WrapInfo.CreationTime = creationTime + // If this is not a rewrap, store the request path as creation_path + if req.Path != "sys/wrapping/rewrap" { + resp.WrapInfo.CreationPath = req.Path + } // This will only be non-nil if this response contains a token, so in that // case put the accessor in the wrap info. @@ -200,6 +204,12 @@ func (c *Core) wrapInCubbyhole(req *logical.Request, resp *logical.Response) (*l "creation_ttl": resp.WrapInfo.TTL, "creation_time": creationTime, } + // Store creation_path if not a rewrap + if req.Path != "sys/wrapping/rewrap" { + cubbyReq.Data["creation_path"] = req.Path + } else { + cubbyReq.Data["creation_path"] = resp.WrapInfo.CreationPath + } cubbyResp, err = c.router.Route(cubbyReq) if err != nil { // Revoke since it's not yet being tracked for expiration @@ -233,6 +243,7 @@ func (c *Core) wrapInCubbyhole(req *logical.Request, resp *logical.Response) (*l return nil, nil } +// ValidateWrappingToken checks whether a token is a wrapping token. func (c *Core) ValidateWrappingToken(req *logical.Request) (bool, error) { if req == nil { return false, fmt.Errorf("invalid request") diff --git a/website/source/api/system/wrapping-lookup.html.md b/website/source/api/system/wrapping-lookup.html.md index b54dbd2ce..b2b50e267 100644 --- a/website/source/api/system/wrapping-lookup.html.md +++ b/website/source/api/system/wrapping-lookup.html.md @@ -49,9 +49,12 @@ $ curl \ "lease_duration": 0, "renewable": false, "data": { + "creation_path": "sys/wrapping/wrap", "creation_time": "2016-09-28T14:16:13.07103516-04:00", "creation_ttl": 300 }, - "warnings": null + "wrap_info": null, + "warnings": null, + "auth": null } ``` diff --git a/website/source/api/system/wrapping-rewrap.html.md b/website/source/api/system/wrapping-rewrap.html.md index 2f8665803..ebe6a1051 100644 --- a/website/source/api/system/wrapping-rewrap.html.md +++ b/website/source/api/system/wrapping-rewrap.html.md @@ -58,7 +58,7 @@ $ curl \ "token": "3b6f1193-0707-ac17-284d-e41032e74d1f", "ttl": 300, "creation_time": "2016-09-28T14:22:26.486186607-04:00", - "wrapped_accessor": "" + "creation_path": "sys/wrapping/wrap" } } ``` diff --git a/website/source/api/system/wrapping-wrap.html.md b/website/source/api/system/wrapping-wrap.html.md index c3c4065d5..18b704f5b 100644 --- a/website/source/api/system/wrapping-wrap.html.md +++ b/website/source/api/system/wrapping-wrap.html.md @@ -61,7 +61,7 @@ $ curl \ "token": "fb79b9d3-d94e-9eb6-4919-c559311133d6", "ttl": 300, "creation_time": "2016-09-28T14:41:00.56961496-04:00", - "wrapped_accessor": "" + "creation_path": "sys/wrapping/wrap", } } ```