token: disallow periods on custom token IDs (#8646)

* token: disallow periods on custom token IDs

* docs: update token API docs
This commit is contained in:
Calvin Leung Huang 2020-04-27 09:39:33 -07:00 committed by GitHub
parent 1dbc6d3dd0
commit ec8448ab56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 93 additions and 54 deletions

View File

@ -817,8 +817,13 @@ func (ts *TokenStore) create(ctx context.Context, entry *logical.TokenEntry) err
} }
} }
if userSelectedID && strings.HasPrefix(entry.ID, "s.") { if userSelectedID {
switch {
case strings.HasPrefix(entry.ID, "s."):
return fmt.Errorf("custom token ID cannot have the 's.' prefix") return fmt.Errorf("custom token ID cannot have the 's.' prefix")
case strings.Contains(entry.ID, "."):
return fmt.Errorf("custom token ID cannot have a '.' in the value")
}
} }
if !userSelectedID { if !userSelectedID {

View File

@ -231,57 +231,6 @@ func TestTokenStore_Salting(t *testing.T) {
} }
} }
func TestTokenStore_ServiceTokenPrefix(t *testing.T) {
c, _, initToken := TestCoreUnsealed(t)
ts := c.tokenStore
// Ensure that a regular service token has a "s." prefix
resp, err := ts.HandleRequest(namespace.RootContext(nil), &logical.Request{
ClientToken: initToken,
Path: "create",
Operation: logical.UpdateOperation,
})
if err != nil || (resp != nil && resp.IsError()) {
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
}
if !strings.HasPrefix(resp.Auth.ClientToken, "s.") {
t.Fatalf("token %q does not have a 's.' prefix", resp.Auth.ClientToken)
}
// Ensure that using a custon token ID results in a warning
resp, err = ts.HandleRequest(namespace.RootContext(nil), &logical.Request{
ClientToken: initToken,
Path: "create",
Operation: logical.UpdateOperation,
Data: map[string]interface{}{
"id": "foobar",
},
})
if err != nil || (resp != nil && resp.IsError()) {
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
}
expectedWarning := "Supplying a custom ID for the token uses the weaker SHA1 hashing instead of the more secure SHA2-256 HMAC for token obfuscation. SHA1 hashed tokens on the wire leads to less secure lookups."
if resp.Warnings[0] != expectedWarning {
t.Fatalf("expected warning not present")
}
// Ensure that custom token ID having a "s." prefix fails
resp, err = ts.HandleRequest(namespace.RootContext(nil), &logical.Request{
ClientToken: initToken,
Path: "create",
Operation: logical.UpdateOperation,
Data: map[string]interface{}{
"id": "s.foobar",
},
})
if err == nil {
t.Fatalf("expected an error")
}
if resp.Error().Error() != "custom token ID cannot have the 's.' prefix" {
t.Fatalf("expected input error not present in error response")
}
}
type TokenEntryOld struct { type TokenEntryOld struct {
ID string ID string
Accessor string Accessor string
@ -5633,3 +5582,87 @@ func TestTokenStore_Batch_NoCubbyhole(t *testing.T) {
t.Fatalf("bad: expected error, got %#v", *resp) t.Fatalf("bad: expected error, got %#v", *resp)
} }
} }
func TestTokenStore_TokenID(t *testing.T) {
t.Run("no custom ID provided", func(t *testing.T) {
c, _, initToken := TestCoreUnsealed(t)
ts := c.tokenStore
// Ensure that a regular service token has a "s." prefix
resp, err := ts.HandleRequest(namespace.RootContext(nil), &logical.Request{
ClientToken: initToken,
Path: "create",
Operation: logical.UpdateOperation,
})
if err != nil || (resp != nil && resp.IsError()) {
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
}
if !strings.HasPrefix(resp.Auth.ClientToken, "s.") {
t.Fatalf("token %q does not have a 's.' prefix", resp.Auth.ClientToken)
}
})
t.Run("plain custom ID", func(t *testing.T) {
core, _, root := TestCoreUnsealed(t)
ts := core.tokenStore
resp, err := ts.HandleRequest(namespace.RootContext(nil), &logical.Request{
ClientToken: root,
Path: "create",
Operation: logical.UpdateOperation,
Data: map[string]interface{}{
"id": "foobar",
},
})
if err != nil || (resp != nil && resp.IsError()) {
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
}
// Ensure that using a custom token ID results in a warning
expectedWarning := "Supplying a custom ID for the token uses the weaker SHA1 hashing instead of the more secure SHA2-256 HMAC for token obfuscation. SHA1 hashed tokens on the wire leads to less secure lookups."
if resp.Warnings[0] != expectedWarning {
t.Fatalf("expected warning not present")
}
})
t.Run("service token prefix in custom ID", func(t *testing.T) {
c, _, initToken := TestCoreUnsealed(t)
ts := c.tokenStore
// Ensure that custom token ID having a "s." prefix fails
resp, err := ts.HandleRequest(namespace.RootContext(nil), &logical.Request{
ClientToken: initToken,
Path: "create",
Operation: logical.UpdateOperation,
Data: map[string]interface{}{
"id": "s.foobar",
},
})
if err == nil {
t.Fatalf("expected an error")
}
if resp.Error().Error() != "custom token ID cannot have the 's.' prefix" {
t.Fatalf("expected input error not present in error response")
}
})
t.Run("period in custom ID", func(t *testing.T) {
core, _, root := TestCoreUnsealed(t)
ts := core.tokenStore
resp, err := ts.HandleRequest(namespace.RootContext(nil), &logical.Request{
ClientToken: root,
Path: "create",
Operation: logical.UpdateOperation,
Data: map[string]interface{}{
"id": "foobar.baz",
},
})
if err == nil {
t.Fatalf("expected an error")
}
if resp.Error().Error() != "custom token ID cannot have a '.' in the value" {
t.Fatalf("expected input error not present in error response")
}
})
}

View File

@ -67,7 +67,8 @@ during this call.
### Parameters ### Parameters
- `id` `(string: "")` The ID of the client token. Can only be specified by a - `id` `(string: "")` The ID of the client token. Can only be specified by a
root token. Otherwise, the token ID is a randomly generated value. root token. The ID provided may not contain a `.` character. Otherwise, the
token ID is a randomly generated value.
- `role_name` `(string: "")` The name of the token role. - `role_name` `(string: "")` The name of the token role.
- `policies` `(array: "")` A list of policies for the token. This must be a - `policies` `(array: "")` A list of policies for the token. This must be a
subset of the policies belonging to the token making the request, unless root. subset of the policies belonging to the token making the request, unless root.