diff --git a/changelog/10743.txt b/changelog/10743.txt new file mode 100644 index 000000000..b0a86e0ba --- /dev/null +++ b/changelog/10743.txt @@ -0,0 +1,3 @@ +```release-note:bug +core: Turn off case sensitivity for allowed entity alias check during token create operation. +``` diff --git a/vault/token_store.go b/vault/token_store.go index 6a65862ca..3d177e83f 100644 --- a/vault/token_store.go +++ b/vault/token_store.go @@ -2334,9 +2334,14 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque return logical.ErrorResponse("'entity_alias' is only allowed in combination with token role"), logical.ErrInvalidRequest } + // Convert entity alias to lowercase to match the fact that role.AllowedEntityAliases + // has also been lowercased. An entity alias will keep its case formatting, but be + // treated as lowercase during any value cheek anywhere. + entityAlias := strings.ToLower(data.EntityAlias) + // Check if there is a concrete match - if !strutil.StrListContains(role.AllowedEntityAliases, data.EntityAlias) && - !strutil.StrListContainsGlob(role.AllowedEntityAliases, data.EntityAlias) { + if !strutil.StrListContains(role.AllowedEntityAliases, entityAlias) && + !strutil.StrListContainsGlob(role.AllowedEntityAliases, entityAlias) { return logical.ErrorResponse("invalid 'entity_alias' value"), logical.ErrInvalidRequest } diff --git a/vault/token_store_test.go b/vault/token_store_test.go index 306975435..7643927c0 100644 --- a/vault/token_store_test.go +++ b/vault/token_store_test.go @@ -2704,6 +2704,99 @@ func TestTokenStore_HandleRequest_CreateToken_ExistingEntityAlias(t *testing.T) } } +func TestTokenStore_HandleRequest_CreateToken_ExistingEntityAliasMixedCase(t *testing.T) { + core, _, root := TestCoreUnsealed(t) + i := core.identityStore + ctx := namespace.RootContext(nil) + testPolicyName := "testpolicy" + entityAliasName := "tEStEntityAliaS" + entityAliasNameLower := "testentityalias" + testRoleName := "test" + + // Create manually an entity + resp, err := i.HandleRequest(ctx, &logical.Request{ + Path: "entity", + Operation: logical.UpdateOperation, + Data: map[string]interface{}{ + "name": "testentity", + "policies": []string{testPolicyName}, + }, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("err: %v\nresp: %#v", err, resp) + } + entityID := resp.Data["id"].(string) + + // Find mount accessor + resp, err = core.systemBackend.HandleRequest(namespace.RootContext(nil), &logical.Request{ + Path: "auth", + Operation: logical.ReadOperation, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) + } + tokenMountAccessor := resp.Data["token/"].(map[string]interface{})["accessor"].(string) + + // Create manually an entity alias + resp, err = i.HandleRequest(ctx, &logical.Request{ + Path: "entity-alias", + Operation: logical.UpdateOperation, + Data: map[string]interface{}{ + "name": entityAliasName, + "canonical_id": entityID, + "mount_accessor": tokenMountAccessor, + }, + }) + if err != nil { + t.Fatalf("error handling request: %v", err) + } + + // Create token role + resp, err = core.HandleRequest(ctx, &logical.Request{ + Path: "auth/token/roles/" + testRoleName, + ClientToken: root, + Operation: logical.CreateOperation, + Data: map[string]interface{}{ + "orphan": true, + "period": "72h", + "path_suffix": "happenin", + "bound_cidrs": []string{"0.0.0.0/0"}, + "allowed_entity_aliases": []string{"test1", "test2", entityAliasName}, + }, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("err: %v\nresp: %#v", err, resp) + } + + respMixedCase, err := core.HandleRequest(ctx, &logical.Request{ + Path: "auth/token/create/" + testRoleName, + Operation: logical.UpdateOperation, + ClientToken: root, + Data: map[string]interface{}{ + "entity_alias": entityAliasName, + }, + }) + if respMixedCase.Auth.EntityID != entityID { + t.Fatalf("expected '%s' got '%s'", entityID, respMixedCase.Auth.EntityID) + } + + // lowercase entity alias should match a mixed case alias + respLowerCase, err := core.HandleRequest(ctx, &logical.Request{ + Path: "auth/token/create/" + testRoleName, + Operation: logical.UpdateOperation, + ClientToken: root, + Data: map[string]interface{}{ + "entity_alias": entityAliasNameLower, + }, + }) + + // A token created with the mixed case alias should return the same entity + // id as the normal case response. + if respLowerCase.Auth.EntityID != entityID { + t.Fatalf("expected '%s' got '%s'", entityID, respLowerCase.Auth.EntityID) + } +} + func TestTokenStore_HandleRequest_CreateToken_NonExistingEntityAlias(t *testing.T) { core, _, root := TestCoreUnsealed(t) i := core.identityStore diff --git a/website/content/api-docs/auth/token.mdx b/website/content/api-docs/auth/token.mdx index 7777e8016..d7f504453 100644 --- a/website/content/api-docs/auth/token.mdx +++ b/website/content/api-docs/auth/token.mdx @@ -709,6 +709,7 @@ tokens created against a role to be revoked using the - `allowed_entity_aliases` `(string: "", or list: [])` - String or JSON list of allowed entity aliases. If set, specifies the entity aliases which are allowed to be used during token generation. This field supports globbing. + Note that `allowed_entity_aliases` is not case sensitive. @include 'tokenstorefields.mdx'