parent
561d8d45f8
commit
62c09bc2be
|
@ -283,6 +283,7 @@ func (f *AuditFormatter) FormatResponse(ctx context.Context, w io.Writer, config
|
||||||
Metadata: auth.Metadata,
|
Metadata: auth.Metadata,
|
||||||
RemainingUses: req.ClientTokenRemainingUses,
|
RemainingUses: req.ClientTokenRemainingUses,
|
||||||
EntityID: auth.EntityID,
|
EntityID: auth.EntityID,
|
||||||
|
EntityCreated: auth.EntityCreated,
|
||||||
TokenType: auth.TokenType.String(),
|
TokenType: auth.TokenType.String(),
|
||||||
TokenTTL: int64(auth.TTL.Seconds()),
|
TokenTTL: int64(auth.TTL.Seconds()),
|
||||||
},
|
},
|
||||||
|
@ -415,6 +416,7 @@ type AuditAuth struct {
|
||||||
NumUses int `json:"num_uses,omitempty"`
|
NumUses int `json:"num_uses,omitempty"`
|
||||||
RemainingUses int `json:"remaining_uses,omitempty"`
|
RemainingUses int `json:"remaining_uses,omitempty"`
|
||||||
EntityID string `json:"entity_id,omitempty"`
|
EntityID string `json:"entity_id,omitempty"`
|
||||||
|
EntityCreated bool `json:"entity_created,omitempty"`
|
||||||
TokenType string `json:"token_type,omitempty"`
|
TokenType string `json:"token_type,omitempty"`
|
||||||
TokenTTL int64 `json:"token_ttl,omitempty"`
|
TokenTTL int64 `json:"token_ttl,omitempty"`
|
||||||
TokenIssueTime string `json:"token_issue_time,omitempty"`
|
TokenIssueTime string `json:"token_issue_time,omitempty"`
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:improvement
|
||||||
|
audit: added entity_created boolean to audit log, set when login operations create an entity
|
||||||
|
```
|
|
@ -108,6 +108,9 @@ type Auth struct {
|
||||||
|
|
||||||
// MFARequirement
|
// MFARequirement
|
||||||
MFARequirement *MFARequirement `json:"mfa_requirement"`
|
MFARequirement *MFARequirement `json:"mfa_requirement"`
|
||||||
|
|
||||||
|
// EntityCreated is set to true if an entity is created as part of a login request
|
||||||
|
EntityCreated bool `json:"entity_created"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Auth) GoString() string {
|
func (a *Auth) GoString() string {
|
||||||
|
|
|
@ -269,7 +269,7 @@ func TestCoreMetrics_EntityGauges(t *testing.T) {
|
||||||
Name: "githubuser",
|
Name: "githubuser",
|
||||||
}
|
}
|
||||||
|
|
||||||
entity, err := is.CreateOrFetchEntity(ctx, alias1)
|
entity, _, err := is.CreateOrFetchEntity(ctx, alias1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1099,37 +1099,38 @@ func (i *IdentityStore) CreateEntity(ctx context.Context) (*identity.Entity, err
|
||||||
|
|
||||||
// CreateOrFetchEntity creates a new entity. This is used by core to
|
// CreateOrFetchEntity creates a new entity. This is used by core to
|
||||||
// associate each login attempt by an alias to a unified entity in Vault.
|
// associate each login attempt by an alias to a unified entity in Vault.
|
||||||
func (i *IdentityStore) CreateOrFetchEntity(ctx context.Context, alias *logical.Alias) (*identity.Entity, error) {
|
func (i *IdentityStore) CreateOrFetchEntity(ctx context.Context, alias *logical.Alias) (*identity.Entity, bool, error) {
|
||||||
defer metrics.MeasureSince([]string{"identity", "create_or_fetch_entity"}, time.Now())
|
defer metrics.MeasureSince([]string{"identity", "create_or_fetch_entity"}, time.Now())
|
||||||
|
|
||||||
var entity *identity.Entity
|
var entity *identity.Entity
|
||||||
var err error
|
var err error
|
||||||
var update bool
|
var update bool
|
||||||
|
var entityCreated bool
|
||||||
|
|
||||||
if alias == nil {
|
if alias == nil {
|
||||||
return nil, fmt.Errorf("alias is nil")
|
return nil, false, fmt.Errorf("alias is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
if alias.Name == "" {
|
if alias.Name == "" {
|
||||||
return nil, fmt.Errorf("empty alias name")
|
return nil, false, fmt.Errorf("empty alias name")
|
||||||
}
|
}
|
||||||
|
|
||||||
mountValidationResp := i.router.ValidateMountByAccessor(alias.MountAccessor)
|
mountValidationResp := i.router.ValidateMountByAccessor(alias.MountAccessor)
|
||||||
if mountValidationResp == nil {
|
if mountValidationResp == nil {
|
||||||
return nil, fmt.Errorf("invalid mount accessor %q", alias.MountAccessor)
|
return nil, false, fmt.Errorf("invalid mount accessor %q", alias.MountAccessor)
|
||||||
}
|
}
|
||||||
|
|
||||||
if mountValidationResp.MountType != alias.MountType {
|
if mountValidationResp.MountType != alias.MountType {
|
||||||
return nil, fmt.Errorf("mount accessor %q is not a mount of type %q", alias.MountAccessor, alias.MountType)
|
return nil, false, fmt.Errorf("mount accessor %q is not a mount of type %q", alias.MountAccessor, alias.MountType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if an entity already exists for the given alias
|
// Check if an entity already exists for the given alias
|
||||||
entity, err = i.entityByAliasFactors(alias.MountAccessor, alias.Name, true)
|
entity, err = i.entityByAliasFactors(alias.MountAccessor, alias.Name, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
if entity != nil && changedAliasIndex(entity, alias) == -1 {
|
if entity != nil && changedAliasIndex(entity, alias) == -1 {
|
||||||
return entity, nil
|
return entity, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
i.lock.Lock()
|
i.lock.Lock()
|
||||||
|
@ -1142,12 +1143,12 @@ func (i *IdentityStore) CreateOrFetchEntity(ctx context.Context, alias *logical.
|
||||||
// Check if an entity was created before acquiring the lock
|
// Check if an entity was created before acquiring the lock
|
||||||
entity, err = i.entityByAliasFactorsInTxn(txn, alias.MountAccessor, alias.Name, true)
|
entity, err = i.entityByAliasFactorsInTxn(txn, alias.MountAccessor, alias.Name, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
if entity != nil {
|
if entity != nil {
|
||||||
idx := changedAliasIndex(entity, alias)
|
idx := changedAliasIndex(entity, alias)
|
||||||
if idx == -1 {
|
if idx == -1 {
|
||||||
return entity, nil
|
return entity, false, nil
|
||||||
}
|
}
|
||||||
a := entity.Aliases[idx]
|
a := entity.Aliases[idx]
|
||||||
a.Metadata = alias.Metadata
|
a.Metadata = alias.Metadata
|
||||||
|
@ -1160,7 +1161,7 @@ func (i *IdentityStore) CreateOrFetchEntity(ctx context.Context, alias *logical.
|
||||||
entity = new(identity.Entity)
|
entity = new(identity.Entity)
|
||||||
err = i.sanitizeEntity(ctx, entity)
|
err = i.sanitizeEntity(ctx, entity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new alias
|
// Create a new alias
|
||||||
|
@ -1176,7 +1177,7 @@ func (i *IdentityStore) CreateOrFetchEntity(ctx context.Context, alias *logical.
|
||||||
|
|
||||||
err = i.sanitizeAlias(ctx, newAlias)
|
err = i.sanitizeAlias(ctx, newAlias)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
i.logger.Debug("creating a new entity", "alias", newAlias)
|
i.logger.Debug("creating a new entity", "alias", newAlias)
|
||||||
|
@ -1202,16 +1203,18 @@ func (i *IdentityStore) CreateOrFetchEntity(ctx context.Context, alias *logical.
|
||||||
{"auth_method", newAlias.MountType},
|
{"auth_method", newAlias.MountType},
|
||||||
{"mount_point", newAlias.MountPath},
|
{"mount_point", newAlias.MountPath},
|
||||||
})
|
})
|
||||||
|
entityCreated = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update MemDB and persist entity object
|
// Update MemDB and persist entity object
|
||||||
err = i.upsertEntityInTxn(ctx, txn, entity, nil, true)
|
err = i.upsertEntityInTxn(ctx, txn, entity, nil, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
txn.Commit()
|
txn.Commit()
|
||||||
return entity.Clone()
|
clonedEntity, err := entity.Clone()
|
||||||
|
return clonedEntity, entityCreated, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// changedAliasIndex searches an entity for changed alias metadata.
|
// changedAliasIndex searches an entity for changed alias metadata.
|
||||||
|
|
|
@ -182,7 +182,7 @@ func TestIdentityStore_EntityIDPassthrough(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an entity with GitHub alias
|
// Create an entity with GitHub alias
|
||||||
entity, err := is.CreateOrFetchEntity(ctx, alias)
|
entity, _, err := is.CreateOrFetchEntity(ctx, alias)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -258,7 +258,7 @@ func TestIdentityStore_CreateOrFetchEntity(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
entity, err := is.CreateOrFetchEntity(ctx, alias)
|
entity, _, err := is.CreateOrFetchEntity(ctx, alias)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -274,7 +274,7 @@ func TestIdentityStore_CreateOrFetchEntity(t *testing.T) {
|
||||||
t.Fatalf("bad: alias name; expected: %q, actual: %q", alias.Name, entity.Aliases[0].Name)
|
t.Fatalf("bad: alias name; expected: %q, actual: %q", alias.Name, entity.Aliases[0].Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
entity, err = is.CreateOrFetchEntity(ctx, alias)
|
entity, _, err = is.CreateOrFetchEntity(ctx, alias)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -309,7 +309,7 @@ func TestIdentityStore_CreateOrFetchEntity(t *testing.T) {
|
||||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
entity, err = is.CreateOrFetchEntity(ctx, alias)
|
entity, _, err = is.CreateOrFetchEntity(ctx, alias)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -335,7 +335,7 @@ func TestIdentityStore_CreateOrFetchEntity(t *testing.T) {
|
||||||
"foo": "zzzz",
|
"foo": "zzzz",
|
||||||
}
|
}
|
||||||
|
|
||||||
entity, err = is.CreateOrFetchEntity(ctx, alias)
|
entity, _, err = is.CreateOrFetchEntity(ctx, alias)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -599,7 +599,7 @@ func TestIdentityStore_MergeConflictingAliases(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
newEntity, err := c.identityStore.CreateOrFetchEntity(namespace.RootContext(nil), &logical.Alias{
|
newEntity, _, err := c.identityStore.CreateOrFetchEntity(namespace.RootContext(nil), &logical.Alias{
|
||||||
MountAccessor: meGH.Accessor,
|
MountAccessor: meGH.Accessor,
|
||||||
MountType: "github",
|
MountType: "github",
|
||||||
Name: "githubuser",
|
Name: "githubuser",
|
||||||
|
@ -792,14 +792,14 @@ func TestIdentityStore_NewEntityCounter(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = is.CreateOrFetchEntity(ctx, alias)
|
_, _, err = is.CreateOrFetchEntity(ctx, alias)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expectSingleCount(t, sink, "identity.entity.creation")
|
expectSingleCount(t, sink, "identity.entity.creation")
|
||||||
|
|
||||||
_, err = is.CreateOrFetchEntity(ctx, alias)
|
_, _, err = is.CreateOrFetchEntity(ctx, alias)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -488,7 +488,6 @@ func (c *Core) handleCancelableRequest(ctx context.Context, req *logical.Request
|
||||||
req.Operation == logical.PatchOperation) {
|
req.Operation == logical.PatchOperation) {
|
||||||
return logical.ErrorResponse("cannot write to a path ending in '/'"), nil
|
return logical.ErrorResponse("cannot write to a path ending in '/'"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
waitGroup, err := waitForReplicationState(ctx, c, req)
|
waitGroup, err := waitForReplicationState(ctx, c, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -1437,7 +1436,7 @@ func (c *Core) handleLoginRequest(ctx context.Context, req *logical.Request) (re
|
||||||
var err error
|
var err error
|
||||||
// Fetch the entity for the alias, or create an entity if one
|
// Fetch the entity for the alias, or create an entity if one
|
||||||
// doesn't exist.
|
// doesn't exist.
|
||||||
entity, err = c.identityStore.CreateOrFetchEntity(ctx, auth.Alias)
|
entity, entityCreated, err := c.identityStore.CreateOrFetchEntity(ctx, auth.Alias)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch auth.Alias.Local {
|
switch auth.Alias.Local {
|
||||||
case true:
|
case true:
|
||||||
|
@ -1446,8 +1445,12 @@ func (c *Core) handleLoginRequest(ctx context.Context, req *logical.Request) (re
|
||||||
resp.AddWarning("primary cluster doesn't yet issue entities for local auth mounts; falling back to not issuing entities for local auth mounts")
|
resp.AddWarning("primary cluster doesn't yet issue entities for local auth mounts; falling back to not issuing entities for local auth mounts")
|
||||||
goto CREATE_TOKEN
|
goto CREATE_TOKEN
|
||||||
}
|
}
|
||||||
|
// If the entity creation via forwarding was successful, update the bool flag
|
||||||
|
if entity != nil && err == nil {
|
||||||
|
entityCreated = true
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
entity, err = possiblyForwardAliasCreation(ctx, c, err, auth, entity)
|
entity, entityCreated, err = possiblyForwardAliasCreation(ctx, c, err, auth, entity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1462,6 +1465,7 @@ func (c *Core) handleLoginRequest(ctx context.Context, req *logical.Request) (re
|
||||||
}
|
}
|
||||||
|
|
||||||
auth.EntityID = entity.ID
|
auth.EntityID = entity.ID
|
||||||
|
auth.EntityCreated = entityCreated
|
||||||
validAliases, err := c.identityStore.refreshExternalGroupMembershipsByEntityID(ctx, auth.EntityID, auth.GroupAliases, req.MountAccessor)
|
validAliases, err := c.identityStore.refreshExternalGroupMembershipsByEntityID(ctx, auth.EntityID, auth.GroupAliases, req.MountAccessor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
|
|
@ -50,8 +50,8 @@ func getAuthRegisterFunc(c *Core) (RegisterAuthFunc, error) {
|
||||||
return c.RegisterAuth, nil
|
return c.RegisterAuth, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func possiblyForwardAliasCreation(ctx context.Context, c *Core, inErr error, auth *logical.Auth, entity *identity.Entity) (*identity.Entity, error) {
|
func possiblyForwardAliasCreation(ctx context.Context, c *Core, inErr error, auth *logical.Auth, entity *identity.Entity) (*identity.Entity, bool, error) {
|
||||||
return entity, inErr
|
return entity, false, inErr
|
||||||
}
|
}
|
||||||
|
|
||||||
var errCreateEntityUnimplemented = "create entity unimplemented in the server"
|
var errCreateEntityUnimplemented = "create entity unimplemented in the server"
|
||||||
|
|
|
@ -2591,7 +2591,7 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create or fetch entity from entity alias
|
// Create or fetch entity from entity alias
|
||||||
entity, err := ts.core.identityStore.CreateOrFetchEntity(ctx, alias)
|
entity, _, err := ts.core.identityStore.CreateOrFetchEntity(ctx, alias)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue