diff --git a/vault/token_store.go b/vault/token_store.go index af4c984ae767..b400c551afd4 100644 --- a/vault/token_store.go +++ b/vault/token_store.go @@ -2236,14 +2236,27 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque continue } - // Remove asterisk - allowedAlias = strings.ReplaceAll(allowedAlias, "*", "") + // Split by asterisk to get prefix and suffix + split := strings.Split(allowedAlias, "*") - // Check if it matches - if strings.HasPrefix(strings.ToLower(data.EntityAlias), strings.ToLower(allowedAlias)) { - match = true - break + // Multiple asterisks are not allowed. Skip this invalid glob pattern. + if len(split) != 2 { + continue + } + + // Check if prefix matches + if !strings.HasPrefix(data.EntityAlias, split[0]) { + continue } + + // Check if suffix matches + if !strings.HasSuffix(data.EntityAlias, split[1]) { + continue + } + + // Found a match + match = true + break } // Throw an error if it does not match diff --git a/vault/token_store_test.go b/vault/token_store_test.go index 156526129752..46e2fac3b720 100644 --- a/vault/token_store_test.go +++ b/vault/token_store_test.go @@ -15,9 +15,9 @@ import ( "github.com/go-test/deep" "github.com/hashicorp/errwrap" - hclog "github.com/hashicorp/go-hclog" - sockaddr "github.com/hashicorp/go-sockaddr" - uuid "github.com/hashicorp/go-uuid" + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/go-sockaddr" + "github.com/hashicorp/go-uuid" "github.com/hashicorp/vault/helper/identity" "github.com/hashicorp/vault/helper/namespace" "github.com/hashicorp/vault/sdk/helper/locksutil" @@ -2766,11 +2766,10 @@ func TestTokenStore_HandleRequest_CreateToken_NonExistingEntityAlias(t *testing. } } -func TestTokenStore_HandleRequest_CreateToken_GlobPatternEntityAlias(t *testing.T) { +func TestTokenStore_HandleRequest_CreateToken_GlobPattern_MultipleAsterisk_EntityAlias(t *testing.T) { core, _, root := TestCoreUnsealed(t) - i := core.identityStore ctx := namespace.RootContext(nil) - entityAliasGlobPattern := "testentity*" + entityAliasGlobPattern := "*testentity*" entityAliasName := "testentity12345" testRoleName := "test" @@ -2799,35 +2798,11 @@ func TestTokenStore_HandleRequest_CreateToken_GlobPatternEntityAlias(t *testing. "entity_alias": entityAliasName, }, }) - if err != nil || (resp != nil && resp.IsError()) { - t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) - } - if resp == nil { - t.Fatal("expected a response") - } - - // Read the new entity - resp, err = i.HandleRequest(ctx, &logical.Request{ - Path: "entity/id/" + resp.Auth.EntityID, - Operation: logical.ReadOperation, - }) - if err != nil || (resp != nil && resp.IsError()) { - t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) - } - - // Get the attached alias information - aliases := resp.Data["aliases"].([]interface{}) - if len(aliases) != 1 { - t.Fatalf("expected only one alias but got %d; Aliases: %#v", len(aliases), aliases) - } - alias := &identity.Alias{} - if err := mapstructure.Decode(aliases[0], alias); err != nil { - t.Fatal(err) + if err == nil { + t.Fatal("err is nil but should be 'invalid request'") } - - // Validate - if alias.Name != entityAliasName { - t.Fatalf("alias name should be '%s' but is '%s'", entityAliasName, alias.Name) + if !strings.Contains(err.Error(), "invalid request") { + t.Fatalf("err should contain 'invalid request' but is '%s'", err.Error()) } } @@ -2835,64 +2810,88 @@ func TestTokenStore_HandleRequest_CreateToken_GlobPatternWildcardEntityAlias(t * core, _, root := TestCoreUnsealed(t) i := core.identityStore ctx := namespace.RootContext(nil) - entityAliasGlobPattern := "*" - entityAliasName := "testentity12345" testRoleName := "test" - // Create token role - resp, err := core.HandleRequest(ctx, &logical.Request{ - Path: "auth/token/roles/" + testRoleName, - ClientToken: root, - Operation: logical.CreateOperation, - Data: map[string]interface{}{ - "period": "72h", - "path_suffix": "happening", - "bound_cidrs": []string{"0.0.0.0/0"}, - "allowed_entity_aliases": []string{"test1", "test2", entityAliasGlobPattern}, + tests := []struct { + name string + globPattern string + aliasName string + }{ + { + name: "prefix-asterisk", + globPattern: "*-web", + aliasName: "department-web", }, - }) - if err != nil || (resp != nil && resp.IsError()) { - t.Fatalf("err: %v\nresp: %#v", err, resp) - } - - // Create token with non existing entity alias - resp, err = core.HandleRequest(ctx, &logical.Request{ - Path: "auth/token/create/" + testRoleName, - Operation: logical.UpdateOperation, - ClientToken: root, - Data: map[string]interface{}{ - "entity_alias": entityAliasName, + { + name: "suffix-asterisk", + globPattern: "web-*", + aliasName: "web-department", + }, + { + name: "middle-asterisk", + globPattern: "web-*-web", + aliasName: "web-department-web", }, - }) - if err != nil || (resp != nil && resp.IsError()) { - t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) - } - if resp == nil { - t.Fatal("expected a response") } - // Read the new entity - resp, err = i.HandleRequest(ctx, &logical.Request{ - Path: "entity/id/" + resp.Auth.EntityID, - Operation: logical.ReadOperation, - }) - if err != nil || (resp != nil && resp.IsError()) { - t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) - } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + // Create token role + resp, err := core.HandleRequest(ctx, &logical.Request{ + Path: "auth/token/roles/" + testRoleName, + ClientToken: root, + Operation: logical.CreateOperation, + Data: map[string]interface{}{ + "period": "72h", + "path_suffix": "happening", + "bound_cidrs": []string{"0.0.0.0/0"}, + "allowed_entity_aliases": []string{"test1", "test2", test.globPattern}, + }, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("err: %v\nresp: %#v", err, resp) + } - // Get the attached alias information - aliases := resp.Data["aliases"].([]interface{}) - if len(aliases) != 1 { - t.Fatalf("expected only one alias but got %d; Aliases: %#v", len(aliases), aliases) - } - alias := &identity.Alias{} - if err := mapstructure.Decode(aliases[0], alias); err != nil { - t.Fatal(err) - } + // Create token with non existing entity alias + resp, err = core.HandleRequest(ctx, &logical.Request{ + Path: "auth/token/create/" + testRoleName, + Operation: logical.UpdateOperation, + ClientToken: root, + Data: map[string]interface{}{ + "entity_alias": test.aliasName, + }, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) + } + if resp == nil { + t.Fatal("expected a response") + } - // Validate - if alias.Name != entityAliasName { - t.Fatalf("alias name should be '%s' but is '%s'", entityAliasName, alias.Name) + // Read the new entity + resp, err = i.HandleRequest(ctx, &logical.Request{ + Path: "entity/id/" + resp.Auth.EntityID, + Operation: logical.ReadOperation, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) + } + + // Get the attached alias information + aliases := resp.Data["aliases"].([]interface{}) + if len(aliases) != 1 { + t.Fatalf("expected only one alias but got %d; Aliases: %#v", len(aliases), aliases) + } + alias := &identity.Alias{} + if err := mapstructure.Decode(aliases[0], alias); err != nil { + t.Fatal(err) + } + + // Validate + if alias.Name != test.aliasName { + t.Fatalf("alias name should be '%s' but is '%s'", test.aliasName, alias.Name) + } + }) } }