Add creation time to returned wrapped token info

This makes it easier to understand the expected lifetime without a
lookup call that uses the single use left on the token.

This also adds a couple of safety checks and for JSON uses int, rather
than int64, for the TTL for the wrapped token.
This commit is contained in:
Jeff Mitchell
2016-06-07 15:00:35 -04:00
parent 83771f1e72
commit 91053b7471
11 changed files with 51 additions and 27 deletions

View File

@@ -32,8 +32,9 @@ type Secret struct {
// SecretWrapInfo contains wrapping information if we have it.
type SecretWrapInfo struct {
Token string `json:"token"`
TTL int `json:"ttl"`
Token string `json:"token"`
TTL int `json:"ttl"`
CreationTime int64 `json:"creation_time"`
}
// SecretAuth is the structure containing auth information if we have it.

View File

@@ -20,7 +20,8 @@ func TestParseSecret(t *testing.T) {
],
"wrap_info": {
"token": "token",
"ttl": 60
"ttl": 60,
"creation_time": 100000
}
}`)
@@ -40,8 +41,9 @@ func TestParseSecret(t *testing.T) {
"a warning!",
},
WrapInfo: &SecretWrapInfo{
Token: "token",
TTL: 60,
Token: "token",
TTL: 60,
CreationTime: int64(100000),
},
}
if !reflect.DeepEqual(secret, expected) {

View File

@@ -46,7 +46,7 @@ func (f *FormatJSON) FormatRequest(
Path: req.Path,
Data: req.Data,
RemoteAddr: getRemoteAddr(req),
WrapTTL: int64(req.WrapTTL / time.Second),
WrapTTL: int(req.WrapTTL / time.Second),
},
})
}
@@ -90,8 +90,9 @@ func (f *FormatJSON) FormatResponse(
var respWrapInfo *JSONWrapInfo
if resp.WrapInfo != nil {
respWrapInfo = &JSONWrapInfo{
TTL: int64(resp.WrapInfo.TTL / time.Second),
Token: resp.WrapInfo.Token,
TTL: int(resp.WrapInfo.TTL / time.Second),
Token: resp.WrapInfo.Token,
CreationTime: resp.WrapInfo.CreationTime,
}
}
@@ -113,7 +114,7 @@ func (f *FormatJSON) FormatResponse(
Path: req.Path,
Data: req.Data,
RemoteAddr: getRemoteAddr(req),
WrapTTL: int64(req.WrapTTL / time.Second),
WrapTTL: int(req.WrapTTL / time.Second),
},
Response: JSONResponse{
@@ -151,7 +152,7 @@ type JSONRequest struct {
Path string `json:"path"`
Data map[string]interface{} `json:"data"`
RemoteAddr string `json:"remote_address"`
WrapTTL int64 `json:"wrap_ttl"`
WrapTTL int `json:"wrap_ttl"`
}
type JSONResponse struct {
@@ -175,8 +176,9 @@ type JSONSecret struct {
}
type JSONWrapInfo struct {
TTL int64 `json:"ttl"`
Token string `json:"token"`
TTL int `json:"ttl"`
Token string `json:"token"`
CreationTime int64 `json:"creation_time"`
}
// getRemoteAddr safely gets the remote address avoiding a nil pointer

View File

@@ -68,8 +68,9 @@ func TestCopy_response(t *testing.T) {
"foo": "bar",
},
WrapInfo: &logical.WrapInfo{
TTL: 60,
Token: "foo",
TTL: 60,
Token: "foo",
CreationTime: 100000,
},
}
arg := expected
@@ -137,8 +138,9 @@ func TestHash(t *testing.T) {
"foo": "bar",
},
WrapInfo: &logical.WrapInfo{
TTL: 60,
Token: "bar",
TTL: 60,
Token: "bar",
CreationTime: 100000,
},
},
&logical.Response{
@@ -146,8 +148,9 @@ func TestHash(t *testing.T) {
"foo": "hmac-sha256:f9320baf0249169e73850cd6156ded0106e2bb6ad8cab01b7bbbebe6d1065317",
},
WrapInfo: &logical.WrapInfo{
TTL: 60,
Token: "hmac-sha256:f9320baf0249169e73850cd6156ded0106e2bb6ad8cab01b7bbbebe6d1065317",
TTL: 60,
Token: "hmac-sha256:f9320baf0249169e73850cd6156ded0106e2bb6ad8cab01b7bbbebe6d1065317",
CreationTime: 100000,
},
},
},

View File

@@ -160,6 +160,7 @@ func (t TableFormatter) OutputSecret(ui cli.Ui, secret, s *api.Secret) error {
if s.WrapInfo != nil {
input = append(input, fmt.Sprintf("wrapping_token: %s %s", config.Delim, s.WrapInfo.Token))
input = append(input, fmt.Sprintf("wrapping_token_ttl: %s %d", config.Delim, s.WrapInfo.TTL))
input = append(input, fmt.Sprintf("wrapping_token_creation_time: %s %d", config.Delim, s.WrapInfo.CreationTime))
}
keys := make([]string, 0, len(s.Data))

View File

@@ -40,6 +40,10 @@ func PrintRawField(ui cli.Ui, secret *api.Secret, field string) int {
if secret.WrapInfo != nil {
val = secret.WrapInfo.TTL
}
case "wrapping_token_creation_time":
if secret.WrapInfo != nil {
val = secret.WrapInfo.CreationTime
}
case "refresh_interval":
val = secret.LeaseDuration
default:

View File

@@ -185,6 +185,9 @@ func requestWrapTTL(r *http.Request, req *logical.Request) (*logical.Request, er
}
req.WrapTTL = time.Duration(seconds) * time.Second
}
if int64(req.WrapTTL) < 0 {
return req, fmt.Errorf("requested wrap ttl cannot be negative")
}
return req, nil
}

View File

@@ -163,8 +163,9 @@ func respondLogical(w http.ResponseWriter, r *http.Request, path string, dataOnl
if resp.WrapInfo != nil && resp.WrapInfo.Token != "" {
httpResp = logical.HTTPResponse{
WrapInfo: &logical.HTTPWrapInfo{
Token: resp.WrapInfo.Token,
TTL: int(resp.WrapInfo.TTL.Seconds()),
Token: resp.WrapInfo.Token,
TTL: int(resp.WrapInfo.TTL.Seconds()),
CreationTime: resp.WrapInfo.CreationTime,
},
}
} else {

View File

@@ -34,6 +34,10 @@ type WrapInfo struct {
// The token containing the wrapped response
Token string
// The creation time in seconds since Unix epoch. This can be used with the
// TTL to figure out an expected expiration.
CreationTime int64
}
// Response is a struct that stores the response of a request.

View File

@@ -52,6 +52,7 @@ type HTTPAuth struct {
}
type HTTPWrapInfo struct {
Token string `json:"token"`
TTL int `json:"ttl"`
Token string `json:"token"`
TTL int `json:"ttl"`
CreationTime int64 `json:"creation_time"`
}

View File

@@ -376,11 +376,12 @@ func (c *Core) wrapInCubbyhole(req *logical.Request, resp *logical.Response) (*l
// wrapping token ID in the audit logs, so that it can be determined from
// the audit logs whether the token was ever actually used.
te := TokenEntry{
Path: req.Path,
Policies: []string{"cubbyhole-response-wrapping"},
CreationTime: time.Now().Unix(),
TTL: resp.WrapInfo.TTL,
NumUses: 1,
Path: req.Path,
Policies: []string{"cubbyhole-response-wrapping"},
CreationTime: time.Now().Unix(),
TTL: resp.WrapInfo.TTL,
NumUses: 1,
ExplicitMaxTTL: resp.WrapInfo.TTL,
}
if err := c.tokenStore.create(&te); err != nil {
@@ -389,6 +390,7 @@ func (c *Core) wrapInCubbyhole(req *logical.Request, resp *logical.Response) (*l
}
resp.WrapInfo.Token = te.ID
resp.WrapInfo.CreationTime = te.CreationTime
httpResponse := logical.SanitizeResponse(resp)