diff --git a/vault/identity_store.go b/vault/identity_store.go index c0c435614bd9..c2976ce675c8 100644 --- a/vault/identity_store.go +++ b/vault/identity_store.go @@ -31,23 +31,31 @@ func (c *Core) IdentityStore() *IdentityStore { return c.identityStore } -// NewIdentityStore creates a new identity store -func NewIdentityStore(ctx context.Context, core *Core, config *logical.BackendConfig, logger log.Logger) (*IdentityStore, error) { +func (i *IdentityStore) resetDB(ctx context.Context) error { var err error - // Create a new in-memory database for the identity store - db, err := memdb.NewMemDB(identityStoreSchema()) + i.db, err = memdb.NewMemDB(identityStoreSchema(!i.disableLowerCasedNames)) if err != nil { - return nil, errwrap.Wrapf("failed to create memdb for identity store: {{err}}", err) + return err } + return nil +} + +func NewIdentityStore(ctx context.Context, core *Core, config *logical.BackendConfig, logger log.Logger) (*IdentityStore, error) { iStore := &IdentityStore{ view: config.StorageView, - db: db, logger: logger, core: core, } + // Create a memdb instance, which by default, operates on lower cased + // identity names + err := iStore.resetDB(ctx) + if err != nil { + return nil, err + } + entitiesPackerLogger := iStore.logger.Named("storagepacker").Named("entities") core.AddLogger(entitiesPackerLogger) groupsPackerLogger := iStore.logger.Named("storagepacker").Named("groups") diff --git a/vault/identity_store_aliases.go b/vault/identity_store_aliases.go index 43b1ddbb06a6..e81851283a6f 100644 --- a/vault/identity_store_aliases.go +++ b/vault/identity_store_aliases.go @@ -181,10 +181,6 @@ func (i *IdentityStore) handleAliasUpdateCommon() framework.OperationFunc { if entity == nil { return nil, fmt.Errorf("existing alias is not associated with an entity") } - if canonicalID == "" || entity.ID == canonicalID { - // Nothing to do - return nil, nil - } } resp := &logical.Response{} @@ -255,6 +251,12 @@ func (i *IdentityStore) handleAliasUpdateCommon() framework.OperationFunc { return nil, err } + for index, item := range entity.Aliases { + if item.ID == alias.ID { + entity.Aliases[index] = alias + } + } + // Index entity and its aliases in MemDB and persist entity along with // aliases in storage. If the alias is being transferred over from // one entity to another, previous entity needs to get refreshed in MemDB diff --git a/vault/identity_store_aliases_test.go b/vault/identity_store_aliases_test.go index 1e1494eda010..a09b8a6e9661 100644 --- a/vault/identity_store_aliases_test.go +++ b/vault/identity_store_aliases_test.go @@ -2,6 +2,7 @@ package vault import ( "reflect" + "strings" "testing" "github.com/hashicorp/vault/helper/identity" @@ -9,6 +10,89 @@ import ( "github.com/hashicorp/vault/logical" ) +func TestIdentityStore_CaseInsensitiveEntityAliasName(t *testing.T) { + ctx := namespace.RootContext(nil) + i, accessor, _ := testIdentityStoreWithGithubAuth(ctx, t) + + // Create an entity + resp, err := i.HandleRequest(ctx, &logical.Request{ + Path: "entity", + Operation: logical.UpdateOperation, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: err:%v\nresp: %#v", err, resp) + } + entityID := resp.Data["id"].(string) + + testAliasName := "testAliasName" + // Create a case sensitive alias name + resp, err = i.HandleRequest(ctx, &logical.Request{ + Path: "entity-alias", + Operation: logical.UpdateOperation, + Data: map[string]interface{}{ + "mount_accessor": accessor, + "canonical_id": entityID, + "name": testAliasName, + }, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: err:%v\nresp: %#v", err, resp) + } + aliasID := resp.Data["id"].(string) + + // Ensure that reading the alias returns case sensitive alias name + resp, err = i.HandleRequest(ctx, &logical.Request{ + Path: "entity-alias/id/" + aliasID, + Operation: logical.ReadOperation, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: err:%v\nresp: %#v", err, resp) + } + aliasName := resp.Data["name"].(string) + if aliasName != testAliasName { + t.Fatalf("bad alias name; expected: %q, actual: %q", testAliasName, aliasName) + } + + // Overwrite the alias using lower cased alias name. This shouldn't error. + resp, err = i.HandleRequest(ctx, &logical.Request{ + Path: "entity-alias/id/" + aliasID, + Operation: logical.UpdateOperation, + Data: map[string]interface{}{ + "mount_accessor": accessor, + "canonical_id": entityID, + "name": strings.ToLower(testAliasName), + }, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: err:%v\nresp: %#v", err, resp) + } + + // Ensure that reading the alias returns lower cased alias name + resp, err = i.HandleRequest(ctx, &logical.Request{ + Path: "entity-alias/id/" + aliasID, + Operation: logical.ReadOperation, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: err:%v\nresp: %#v", err, resp) + } + aliasName = resp.Data["name"].(string) + if aliasName != strings.ToLower(testAliasName) { + t.Fatalf("bad alias name; expected: %q, actual: %q", testAliasName, aliasName) + } + + // Ensure that there is one entity alias + resp, err = i.HandleRequest(ctx, &logical.Request{ + Path: "entity-alias/id", + Operation: logical.ListOperation, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: err:%v\nresp: %#v", err, resp) + } + if len(resp.Data["keys"].([]string)) != 1 { + t.Fatalf("bad length of entity aliases; expected: 1, actual: %d", len(resp.Data["keys"].([]string))) + } +} + // This test is required because MemDB does not take care of ensuring // uniqueness of indexes that are marked unique. func TestIdentityStore_AliasSameAliasNames(t *testing.T) { diff --git a/vault/identity_store_entities.go b/vault/identity_store_entities.go index c1f06fa8107f..3097b1b57376 100644 --- a/vault/identity_store_entities.go +++ b/vault/identity_store_entities.go @@ -467,7 +467,7 @@ func (i *IdentityStore) pathEntityNameDelete() framework.OperationFunc { defer txn.Abort() // Fetch the entity using its name - entity, err := i.MemDBEntityByNameInTxn(txn, ctx, entityName, true) + entity, err := i.MemDBEntityByNameInTxn(ctx, txn, entityName, true) if err != nil { return nil, err } diff --git a/vault/identity_store_entities_test.go b/vault/identity_store_entities_test.go index b1e03bca7a7f..e6a379fe30e1 100644 --- a/vault/identity_store_entities_test.go +++ b/vault/identity_store_entities_test.go @@ -5,6 +5,7 @@ import ( "fmt" "reflect" "sort" + "strings" "testing" uuid "github.com/hashicorp/go-uuid" @@ -14,6 +15,77 @@ import ( "github.com/hashicorp/vault/logical" ) +func TestIdentityStore_CaseInsensitiveEntityName(t *testing.T) { + ctx := namespace.RootContext(nil) + i, _, _ := testIdentityStoreWithGithubAuth(ctx, t) + + testEntityName := "testEntityName" + + // Create an entity with case sensitive name + resp, err := i.HandleRequest(ctx, &logical.Request{ + Path: "entity", + Operation: logical.UpdateOperation, + Data: map[string]interface{}{ + "name": testEntityName, + }, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: err:%v\nresp: %#v", err, resp) + } + entityID := resp.Data["id"].(string) + + // Lookup the entity by ID and check that name returned is case sensitive + resp, err = i.HandleRequest(ctx, &logical.Request{ + Path: "entity/id/" + entityID, + Operation: logical.ReadOperation, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: err:%v\nresp: %#v", err, resp) + } + entityName := resp.Data["name"].(string) + if entityName != testEntityName { + t.Fatalf("bad entity name; expected: %q, actual: %q", testEntityName, entityName) + } + + // Lookup the entity by case sensitive name + resp, err = i.HandleRequest(ctx, &logical.Request{ + Path: "entity/name/" + testEntityName, + Operation: logical.ReadOperation, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: err: %v\nresp: %#v", err, resp) + } + entityName = resp.Data["name"].(string) + if entityName != testEntityName { + t.Fatalf("bad entity name; expected: %q, actual: %q", testEntityName, entityName) + } + + // Lookup the entity by case insensitive name + resp, err = i.HandleRequest(ctx, &logical.Request{ + Path: "entity/name/" + strings.ToLower(testEntityName), + Operation: logical.ReadOperation, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: err: %v\nresp: %#v", err, resp) + } + entityName = resp.Data["name"].(string) + if entityName != testEntityName { + t.Fatalf("bad entity name; expected: %q, actual: %q", testEntityName, entityName) + } + + // Ensure that there is only one entity + resp, err = i.HandleRequest(ctx, &logical.Request{ + Path: "entity/name", + Operation: logical.ListOperation, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: err: %v\nresp: %#v", err, resp) + } + if len(resp.Data["keys"].([]string)) != 1 { + t.Fatalf("bad length of entities; expected: 1, actual: %d", len(resp.Data["keys"].([]string))) + } +} + func TestIdentityStore_EntityByName(t *testing.T) { ctx := namespace.RootContext(nil) i, _, _ := testIdentityStoreWithGithubAuth(ctx, t) @@ -270,8 +342,8 @@ func TestIdentityStore_EntityCreateUpdate(t *testing.T) { func TestIdentityStore_CloneImmutability(t *testing.T) { alias := &identity.Alias{ - ID: "testaliasid", - Name: "testaliasname", + ID: "testaliasid", + Name: "testaliasname", MergedFromCanonicalIDs: []string{"entityid1"}, } diff --git a/vault/identity_store_group_aliases_test.go b/vault/identity_store_group_aliases_test.go index 9b3788c09b15..ca1ca3c46532 100644 --- a/vault/identity_store_group_aliases_test.go +++ b/vault/identity_store_group_aliases_test.go @@ -1,6 +1,7 @@ package vault import ( + "strings" "testing" credLdap "github.com/hashicorp/vault/builtin/credential/ldap" @@ -10,6 +11,81 @@ import ( "github.com/hashicorp/vault/logical" ) +func TestIdentityStore_CaseInsensitiveGroupAliasName(t *testing.T) { + ctx := namespace.RootContext(nil) + i, accessor, _ := testIdentityStoreWithGithubAuth(ctx, t) + + // Create a group + resp, err := i.HandleRequest(ctx, &logical.Request{ + Path: "group", + Operation: logical.UpdateOperation, + Data: map[string]interface{}{ + "type": "external", + }, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: err: %v\nresp: %#v", err, resp) + } + groupID := resp.Data["id"].(string) + + testAliasName := "testAliasName" + + // Create a case sensitive alias name + resp, err = i.HandleRequest(ctx, &logical.Request{ + Path: "group-alias", + Operation: logical.UpdateOperation, + Data: map[string]interface{}{ + "mount_accessor": accessor, + "canonical_id": groupID, + "name": testAliasName, + }, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: err:%v\nresp: %#v", err, resp) + } + aliasID := resp.Data["id"].(string) + + // Ensure that reading the alias returns case sensitive alias name + resp, err = i.HandleRequest(ctx, &logical.Request{ + Path: "group-alias/id/" + aliasID, + Operation: logical.ReadOperation, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: err:%v\nresp: %#v", err, resp) + } + aliasName := resp.Data["name"].(string) + if aliasName != testAliasName { + t.Fatalf("bad alias name; expected: %q, actual: %q", testAliasName, aliasName) + } + + // Overwrite the alias using lower cased alias name. This shouldn't error. + resp, err = i.HandleRequest(ctx, &logical.Request{ + Path: "group-alias/id/" + aliasID, + Operation: logical.UpdateOperation, + Data: map[string]interface{}{ + "mount_accessor": accessor, + "canonical_id": groupID, + "name": strings.ToLower(testAliasName), + }, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: err:%v\nresp: %#v", err, resp) + } + + // Ensure that reading the alias returns lower cased alias name + resp, err = i.HandleRequest(ctx, &logical.Request{ + Path: "group-alias/id/" + aliasID, + Operation: logical.ReadOperation, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: err:%v\nresp: %#v", err, resp) + } + aliasName = resp.Data["name"].(string) + if aliasName != strings.ToLower(testAliasName) { + t.Fatalf("bad alias name; expected: %q, actual: %q", testAliasName, aliasName) + } +} + func TestIdentityStore_EnsureNoDanglingGroupAlias(t *testing.T) { err := AddTestCredentialBackend("userpass", credUserpass.Factory) if err != nil { diff --git a/vault/identity_store_groups_test.go b/vault/identity_store_groups_test.go index 20efae7f164a..2f326630b1b1 100644 --- a/vault/identity_store_groups_test.go +++ b/vault/identity_store_groups_test.go @@ -3,6 +3,7 @@ package vault import ( "reflect" "sort" + "strings" "testing" "github.com/go-test/deep" @@ -80,6 +81,77 @@ func TestIdentityStore_MemberGroupIDDelete(t *testing.T) { } } +func TestIdentityStore_CaseInsensitiveGroupName(t *testing.T) { + ctx := namespace.RootContext(nil) + i, _, _ := testIdentityStoreWithGithubAuth(ctx, t) + + testGroupName := "testGroupName" + + // Create an group with case sensitive name + resp, err := i.HandleRequest(ctx, &logical.Request{ + Path: "group", + Operation: logical.UpdateOperation, + Data: map[string]interface{}{ + "name": testGroupName, + }, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: err:%v\nresp: %#v", err, resp) + } + groupID := resp.Data["id"].(string) + + // Lookup the group by ID and check that name returned is case sensitive + resp, err = i.HandleRequest(ctx, &logical.Request{ + Path: "group/id/" + groupID, + Operation: logical.ReadOperation, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: err:%v\nresp: %#v", err, resp) + } + groupName := resp.Data["name"].(string) + if groupName != testGroupName { + t.Fatalf("bad group name; expected: %q, actual: %q", testGroupName, groupName) + } + + // Lookup the group by case sensitive name + resp, err = i.HandleRequest(ctx, &logical.Request{ + Path: "group/name/" + testGroupName, + Operation: logical.ReadOperation, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: err: %v\nresp: %#v", err, resp) + } + groupName = resp.Data["name"].(string) + if groupName != testGroupName { + t.Fatalf("bad group name; expected: %q, actual: %q", testGroupName, groupName) + } + + // Lookup the group by case insensitive name + resp, err = i.HandleRequest(ctx, &logical.Request{ + Path: "group/name/" + strings.ToLower(testGroupName), + Operation: logical.ReadOperation, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: err: %v\nresp: %#v", err, resp) + } + groupName = resp.Data["name"].(string) + if groupName != testGroupName { + t.Fatalf("bad group name; expected: %q, actual: %q", testGroupName, groupName) + } + + // Ensure that there is only one group + resp, err = i.HandleRequest(ctx, &logical.Request{ + Path: "group/name", + Operation: logical.ListOperation, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: err: %v\nresp: %#v", err, resp) + } + if len(resp.Data["keys"].([]string)) != 1 { + t.Fatalf("bad length of groups; expected: 1, actual: %d", len(resp.Data["keys"].([]string))) + } +} + func TestIdentityStore_GroupByName(t *testing.T) { ctx := namespace.RootContext(nil) i, _, _ := testIdentityStoreWithGithubAuth(ctx, t) diff --git a/vault/identity_store_schema.go b/vault/identity_store_schema.go index 34915f45342f..5989c4f162e1 100644 --- a/vault/identity_store_schema.go +++ b/vault/identity_store_schema.go @@ -13,12 +13,12 @@ const ( groupAliasesTable = "group_aliases" ) -func identityStoreSchema() *memdb.DBSchema { +func identityStoreSchema(lowerCaseName bool) *memdb.DBSchema { iStoreSchema := &memdb.DBSchema{ Tables: make(map[string]*memdb.TableSchema), } - schemas := []func() *memdb.TableSchema{ + schemas := []func(bool) *memdb.TableSchema{ entitiesTableSchema, aliasesTableSchema, groupsTableSchema, @@ -26,7 +26,7 @@ func identityStoreSchema() *memdb.DBSchema { } for _, schemaFunc := range schemas { - schema := schemaFunc() + schema := schemaFunc(lowerCaseName) if _, ok := iStoreSchema.Tables[schema.Name]; ok { panic(fmt.Sprintf("duplicate table name: %s", schema.Name)) } @@ -36,7 +36,7 @@ func identityStoreSchema() *memdb.DBSchema { return iStoreSchema } -func aliasesTableSchema() *memdb.TableSchema { +func aliasesTableSchema(lowerCaseName bool) *memdb.TableSchema { return &memdb.TableSchema{ Name: entityAliasesTable, Indexes: map[string]*memdb.IndexSchema{ @@ -56,7 +56,8 @@ func aliasesTableSchema() *memdb.TableSchema { Field: "MountAccessor", }, &memdb.StringFieldIndex{ - Field: "Name", + Field: "Name", + Lowercase: lowerCaseName, }, }, }, @@ -71,7 +72,7 @@ func aliasesTableSchema() *memdb.TableSchema { } } -func entitiesTableSchema() *memdb.TableSchema { +func entitiesTableSchema(lowerCaseName bool) *memdb.TableSchema { return &memdb.TableSchema{ Name: entitiesTable, Indexes: map[string]*memdb.IndexSchema{ @@ -91,7 +92,8 @@ func entitiesTableSchema() *memdb.TableSchema { Field: "NamespaceID", }, &memdb.StringFieldIndex{ - Field: "Name", + Field: "Name", + Lowercase: lowerCaseName, }, }, }, @@ -120,7 +122,7 @@ func entitiesTableSchema() *memdb.TableSchema { } } -func groupsTableSchema() *memdb.TableSchema { +func groupsTableSchema(lowerCaseName bool) *memdb.TableSchema { return &memdb.TableSchema{ Name: groupsTable, Indexes: map[string]*memdb.IndexSchema{ @@ -140,7 +142,8 @@ func groupsTableSchema() *memdb.TableSchema { Field: "NamespaceID", }, &memdb.StringFieldIndex{ - Field: "Name", + Field: "Name", + Lowercase: lowerCaseName, }, }, }, @@ -175,7 +178,7 @@ func groupsTableSchema() *memdb.TableSchema { } } -func groupAliasesTableSchema() *memdb.TableSchema { +func groupAliasesTableSchema(lowerCaseName bool) *memdb.TableSchema { return &memdb.TableSchema{ Name: groupAliasesTable, Indexes: map[string]*memdb.IndexSchema{ @@ -195,7 +198,8 @@ func groupAliasesTableSchema() *memdb.TableSchema { Field: "MountAccessor", }, &memdb.StringFieldIndex{ - Field: "Name", + Field: "Name", + Lowercase: lowerCaseName, }, }, }, diff --git a/vault/identity_store_structs.go b/vault/identity_store_structs.go index c9ddb245bd11..c8e8026c59eb 100644 --- a/vault/identity_store_structs.go +++ b/vault/identity_store_structs.go @@ -70,6 +70,10 @@ type IdentityStore struct { // core is the pointer to Vault's core core *Core + + // disableLowerCaseNames indicates whether or not identity artifacts are + // operated case insensitively + disableLowerCasedNames bool } type groupDiff struct { diff --git a/vault/identity_store_util.go b/vault/identity_store_util.go index 2df22e9ea51a..50a9ad68a2c4 100644 --- a/vault/identity_store_util.go +++ b/vault/identity_store_util.go @@ -2,6 +2,7 @@ package vault import ( "context" + "errors" "fmt" "strings" "sync" @@ -19,24 +20,57 @@ import ( "github.com/hashicorp/vault/logical" ) +var ( + errDuplicateIdentityName = errors.New("duplicate identity name") +) + func (c *Core) loadIdentityStoreArtifacts(ctx context.Context) error { - var err error if c.identityStore == nil { c.logger.Warn("identity store is not setup, skipping loading") return nil } - err = c.identityStore.loadEntities(ctx) - if err != nil { + loadFunc := func(context.Context) error { + err := c.identityStore.loadEntities(ctx) + if err != nil { + return err + } + return c.identityStore.loadGroups(ctx) + } + + // Load everything when memdb is set to operate on lower cased names + err := loadFunc(ctx) + switch { + case err == nil: + // If it succeeds, all is well + return nil + case err != nil && !errwrap.Contains(err, errDuplicateIdentityName.Error()): return err } - err = c.identityStore.loadGroups(ctx) + c.identityStore.logger.Warn("enabling case sensitive identity names") + + // Set identity store to operate on case sensitive identity names + c.identityStore.disableLowerCasedNames = true + + // Swap the memdb instance by the one which operates on case sensitive + // names, hence obviating the need to unload anything that's already + // loaded. + err = c.identityStore.resetDB(ctx) if err != nil { return err } - return nil + // Attempt to load identity artifacts once more after memdb is reset to + // accept case sensitive names + return loadFunc(ctx) +} + +func (i *IdentityStore) sanitizeName(name string) string { + if i.disableLowerCasedNames { + return name + } + return strings.ToLower(name) } func (i *IdentityStore) loadGroups(ctx context.Context) error { @@ -66,6 +100,18 @@ func (i *IdentityStore) loadGroups(ctx context.Context) error { continue } + // Ensure that there are no groups with duplicate names + groupByName, err := i.MemDBGroupByName(ctx, group.Name, false) + if err != nil { + return err + } + if groupByName != nil { + i.logger.Warn(errDuplicateIdentityName.Error(), "group_name", group.Name, "conflicting_group_name", groupByName.Name, "action", "merge the contents of duplicated groups into one and delete the other") + if !i.disableLowerCasedNames { + return errDuplicateIdentityName + } + } + if i.logger.IsDebug() { i.logger.Debug("loading group", "name", group.Name, "id", group.ID) } @@ -187,6 +233,18 @@ func (i *IdentityStore) loadEntities(ctx context.Context) error { continue } + // Ensure that there are no entities with duplicate names + entityByName, err := i.MemDBEntityByName(ctx, entity.Name, false) + if err != nil { + return nil + } + if entityByName != nil { + i.logger.Warn(errDuplicateIdentityName.Error(), "entity_name", entity.Name, "conflicting_entity_name", entityByName.Name, "action", "merge the duplicate entities into one") + if !i.disableLowerCasedNames { + return errDuplicateIdentityName + } + } + // Only update MemDB and don't hit the storage again err = i.upsertEntity(ctx, entity, nil, false) if err != nil { @@ -223,7 +281,9 @@ func (i *IdentityStore) upsertEntityInTxn(ctx context.Context, txn *memdb.Txn, e return fmt.Errorf("entity is nil") } - for _, alias := range entity.Aliases { + aliasFactors := make([]string, len(entity.Aliases)) + + for index, alias := range entity.Aliases { // Verify that alias is not associated to a different one already aliasByFactors, err := i.MemDBAliasByFactors(alias.MountAccessor, alias.Name, false, false) if err != nil { @@ -244,11 +304,20 @@ func (i *IdentityStore) upsertEntityInTxn(ctx context.Context, txn *memdb.Txn, e return nil } + if strutil.StrListContains(aliasFactors, i.sanitizeName(alias.Name)+alias.MountAccessor) { + i.logger.Warn(errDuplicateIdentityName.Error(), "alias_name", alias.Name, "mount_accessor", alias.MountAccessor, "entity_name", entity.Name, "action", "delete one of the duplicate aliases") + if !i.disableLowerCasedNames { + return errDuplicateIdentityName + } + } + // Insert or update alias in MemDB using the transaction created above err = i.MemDBUpsertAliasInTxn(txn, alias, false) if err != nil { return err } + + aliasFactors[index] = i.sanitizeName(alias.Name) + alias.MountAccessor } // If previous entity is set, update it in MemDB and persist it @@ -583,10 +652,10 @@ func (i *IdentityStore) MemDBEntityByName(ctx context.Context, entityName string txn := i.db.Txn(false) - return i.MemDBEntityByNameInTxn(txn, ctx, entityName, clone) + return i.MemDBEntityByNameInTxn(ctx, txn, entityName, clone) } -func (i *IdentityStore) MemDBEntityByNameInTxn(txn *memdb.Txn, ctx context.Context, entityName string, clone bool) (*identity.Entity, error) { +func (i *IdentityStore) MemDBEntityByNameInTxn(ctx context.Context, txn *memdb.Txn, entityName string, clone bool) (*identity.Entity, error) { if entityName == "" { return nil, fmt.Errorf("missing entity name") }