Skip to content

Commit

Permalink
fix: reduce db lookups in whoami for aal check
Browse files Browse the repository at this point in the history
  • Loading branch information
aeneasr committed Jul 6, 2023
1 parent 33ac6ae commit 48f56b2
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 17 deletions.
4 changes: 4 additions & 0 deletions identity/identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ type Identity struct {
// Credentials represents all credentials that can be used for authenticating this identity.
Credentials map[CredentialsType]Credentials `json:"credentials,omitempty" faker:"-" db:"-"`

// AvailableAAL defines the maximum available AAL for this identity. If the user has only a password
// configured, the AAL will be 1. If the user has a password and a TOTP configured, the AAL will be 2.
AvailableAAL AuthenticatorAssuranceLevel `json:"available_aal" faker:"-" db:"available_aal"`

// // IdentifierCredentials contains the access and refresh token for oidc identifier
// IdentifierCredentials []IdentifierCredential `json:"identifier_credentials,omitempty" faker:"-" db:"-"`

Expand Down
33 changes: 33 additions & 0 deletions identity/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ func (m *Manager) Create(ctx context.Context, i *Identity, opts ...ManagerOption
return err
}

if err := m.setAAL(ctx, i); err != nil {
return err
}

if err := m.r.PrivilegedIdentityPool().CreateIdentity(ctx, i); err != nil {
return err
}
Expand All @@ -107,6 +111,10 @@ func (m *Manager) CreateIdentities(ctx context.Context, identities []*Identity,
i.SchemaID = m.r.Config().DefaultIdentityTraitsSchemaID(ctx)
}

if err := m.setAAL(ctx, i); err != nil {
return err
}

o := newManagerOptions(opts)
if err := m.ValidateIdentity(ctx, i, o); err != nil {
return err
Expand Down Expand Up @@ -164,9 +172,34 @@ func (m *Manager) Update(ctx context.Context, updated *Identity, opts ...Manager
return err
}

if err := m.setAAL(ctx, updated); err != nil {
return err
}

return m.r.PrivilegedIdentityPool().UpdateIdentity(ctx, updated)
}

func (m *Manager) setAAL(ctx context.Context, i *Identity) (err error) {
i.AvailableAAL = NoAuthenticatorAssuranceLevel
if c, err := m.CountActiveFirstFactorCredentials(ctx, i); err != nil {
return err
} else if c == 0 {
// No first factor set up - AAL is 0
return nil
}

i.AvailableAAL = AuthenticatorAssuranceLevel1
if c, err := m.CountActiveMultiFactorCredentials(ctx, i); err != nil {
return err
} else if c == 0 {
// No second factor set up - AAL is 1
return nil
}

i.AvailableAAL = AuthenticatorAssuranceLevel2
return nil
}

func (m *Manager) UpdateSchemaID(ctx context.Context, id uuid.UUID, schemaID string, opts ...ManagerOption) (err error) {
ctx, span := m.r.Tracer(ctx).Tracer().Start(ctx, "identity.Manager.UpdateSchemaID")
defer otelx.End(span, &err)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE identities DROP COLUMN available_aal;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE identities ADD COLUMN available_aal TYPE VARCHAR(4) NOT NULL DEFAULT "aal0";
36 changes: 19 additions & 17 deletions session/manager_http.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,31 +295,33 @@ func (s *ManagerHTTP) DoesSessionSatisfy(r *http.Request, sess *Session, request
return nil
}
case config.HighestAvailableAAL:
i := sess.Identity
if i == nil {
i, err = s.r.IdentityPool().GetIdentity(ctx, sess.IdentityID, identity.ExpandCredentials)
if sess.Identity == nil {
sess.Identity, err = s.r.IdentityPool().GetIdentity(ctx, sess.IdentityID, identity.ExpandNothing)
if err != nil {
return err
}
sess.Identity = i
} else if len(i.Credentials) == 0 {
// If credentials are not expanded, we load them here.
}

i := sess.Identity
available := i.AvailableAAL
if available == identity.NoAuthenticatorAssuranceLevel && len(i.Credentials) == 0 {
// Indicates that the database state is not up-to-date. Most likely because the SQL migrations did not catch this case.
if err := s.r.PrivilegedIdentityPool().HydrateIdentityAssociations(ctx, i, identity.ExpandCredentials); err != nil {
return err
}
}

available := identity.NoAuthenticatorAssuranceLevel
if firstCount, err := s.r.IdentityManager().CountActiveFirstFactorCredentials(ctx, i); err != nil {
return err
} else if firstCount > 0 {
available = identity.AuthenticatorAssuranceLevel1
}
available = identity.NoAuthenticatorAssuranceLevel
if firstCount, err := s.r.IdentityManager().CountActiveFirstFactorCredentials(ctx, i); err != nil {
return err
} else if firstCount > 0 {
available = identity.AuthenticatorAssuranceLevel1
}

if secondCount, err := s.r.IdentityManager().CountActiveMultiFactorCredentials(ctx, i); err != nil {
return err
} else if secondCount > 0 {
available = identity.AuthenticatorAssuranceLevel2
if secondCount, err := s.r.IdentityManager().CountActiveMultiFactorCredentials(ctx, i); err != nil {
return err
} else if secondCount > 0 {
available = identity.AuthenticatorAssuranceLevel2
}
}

if sess.AuthenticatorAssuranceLevel >= available {
Expand Down

0 comments on commit 48f56b2

Please sign in to comment.