fix: correct conditions for user update after actions in post authent… (#5535)

Correct conditions on when the user gets updated through actions in post-authentication, with an added boolean for checking if anything changed in the actions.
This commit is contained in:
Stefan Benz
2023-03-28 14:53:21 +02:00
committed by GitHub
parent 25c3c17986
commit 12a7c4b994
4 changed files with 24 additions and 14 deletions

View File

@@ -23,7 +23,7 @@ func (l *Login) runPostExternalAuthenticationActions(
httpRequest *http.Request, httpRequest *http.Request,
idpUser idp.User, idpUser idp.User,
authenticationError error, authenticationError error,
) (*domain.ExternalUser, error) { ) (_ *domain.ExternalUser, userChanged bool, err error) {
ctx := httpRequest.Context() ctx := httpRequest.Context()
resourceOwner := authRequest.RequestedOrgID resourceOwner := authRequest.RequestedOrgID
@@ -32,40 +32,50 @@ func (l *Login) runPostExternalAuthenticationActions(
} }
triggerActions, err := l.query.GetActiveActionsByFlowAndTriggerType(ctx, domain.FlowTypeExternalAuthentication, domain.TriggerTypePostAuthentication, resourceOwner, false) triggerActions, err := l.query.GetActiveActionsByFlowAndTriggerType(ctx, domain.FlowTypeExternalAuthentication, domain.TriggerTypePostAuthentication, resourceOwner, false)
if err != nil { if err != nil {
return nil, err return nil, false, err
} }
metadataList := object.MetadataListFromDomain(user.Metadatas) metadataList := object.MetadataListFromDomain(user.Metadatas)
apiFields := actions.WithAPIFields( apiFields := actions.WithAPIFields(
actions.SetFields("setFirstName", func(firstName string) { actions.SetFields("setFirstName", func(firstName string) {
user.FirstName = firstName user.FirstName = firstName
userChanged = true
}), }),
actions.SetFields("setLastName", func(lastName string) { actions.SetFields("setLastName", func(lastName string) {
user.LastName = lastName user.LastName = lastName
userChanged = true
}), }),
actions.SetFields("setNickName", func(nickName string) { actions.SetFields("setNickName", func(nickName string) {
user.NickName = nickName user.NickName = nickName
userChanged = true
}), }),
actions.SetFields("setDisplayName", func(displayName string) { actions.SetFields("setDisplayName", func(displayName string) {
user.DisplayName = displayName user.DisplayName = displayName
userChanged = true
}), }),
actions.SetFields("setPreferredLanguage", func(preferredLanguage string) { actions.SetFields("setPreferredLanguage", func(preferredLanguage string) {
user.PreferredLanguage = language.Make(preferredLanguage) user.PreferredLanguage = language.Make(preferredLanguage)
userChanged = true
}), }),
actions.SetFields("setPreferredUsername", func(username string) { actions.SetFields("setPreferredUsername", func(username string) {
user.PreferredUsername = username user.PreferredUsername = username
userChanged = true
}), }),
actions.SetFields("setEmail", func(email domain.EmailAddress) { actions.SetFields("setEmail", func(email domain.EmailAddress) {
user.Email = email user.Email = email
userChanged = true
}), }),
actions.SetFields("setEmailVerified", func(verified bool) { actions.SetFields("setEmailVerified", func(verified bool) {
user.IsEmailVerified = verified user.IsEmailVerified = verified
userChanged = true
}), }),
actions.SetFields("setPhone", func(phone domain.PhoneNumber) { actions.SetFields("setPhone", func(phone domain.PhoneNumber) {
user.Phone = phone user.Phone = phone
userChanged = true
}), }),
actions.SetFields("setPhoneVerified", func(verified bool) { actions.SetFields("setPhoneVerified", func(verified bool) {
user.IsPhoneVerified = verified user.IsPhoneVerified = verified
userChanged = true
}), }),
actions.SetFields("metadata", func(c *actions.FieldConfig) interface{} { actions.SetFields("metadata", func(c *actions.FieldConfig) interface{} {
return metadataList.MetadataListFromDomain(c.Runtime) return metadataList.MetadataListFromDomain(c.Runtime)
@@ -111,11 +121,11 @@ func (l *Login) runPostExternalAuthenticationActions(
) )
cancel() cancel()
if err != nil { if err != nil {
return nil, err return nil, false, err
} }
} }
user.Metadatas = object.MetadataListToDomain(metadataList) user.Metadatas = object.MetadataListToDomain(metadataList)
return user, err return user, userChanged, err
} }
type authMethod string type authMethod string

View File

@@ -286,7 +286,7 @@ func (l *Login) handleExternalUserAuthenticated(
callback func(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest), callback func(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest),
) { ) {
externalUser := mapIDPUserToExternalUser(user, provider.ID) externalUser := mapIDPUserToExternalUser(user, provider.ID)
externalUser, err := l.runPostExternalAuthenticationActions(externalUser, tokens(session), authReq, r, user, nil) externalUser, externalUserChange, err := l.runPostExternalAuthenticationActions(externalUser, tokens(session), authReq, r, user, nil)
if err != nil { if err != nil {
l.renderError(w, r, authReq, err) l.renderError(w, r, authReq, err)
return return
@@ -300,7 +300,7 @@ func (l *Login) handleExternalUserAuthenticated(
l.externalUserNotExisting(w, r, authReq, provider, externalUser) l.externalUserNotExisting(w, r, authReq, provider, externalUser)
return return
} }
if provider.IsAutoUpdate || len(externalUser.Metadatas) > 0 { if provider.IsAutoUpdate || len(externalUser.Metadatas) > 0 || externalUserChange {
// read current auth request state (incl. authorized user) // read current auth request state (incl. authorized user)
authReq, err = l.authRepo.AuthRequestByID(r.Context(), authReq.ID, authReq.AgentID) authReq, err = l.authRepo.AuthRequestByID(r.Context(), authReq.ID, authReq.AgentID)
if err != nil { if err != nil {
@@ -308,7 +308,7 @@ func (l *Login) handleExternalUserAuthenticated(
return return
} }
} }
if provider.IsAutoUpdate { if provider.IsAutoUpdate || externalUserChange {
err = l.updateExternalUser(r.Context(), authReq, externalUser) err = l.updateExternalUser(r.Context(), authReq, externalUser)
if err != nil { if err != nil {
l.renderError(w, r, authReq, err) l.renderError(w, r, authReq, err)
@@ -558,7 +558,7 @@ func (l *Login) updateExternalUser(ctx context.Context, authReq *domain.AuthRequ
if user.Human == nil { if user.Human == nil {
return errors.ThrowPreconditionFailed(nil, "LOGIN-WLTce", "Errors.User.NotHuman") return errors.ThrowPreconditionFailed(nil, "LOGIN-WLTce", "Errors.User.NotHuman")
} }
if externalUser.Email != "" && externalUser.Email != user.Human.Email && externalUser.IsEmailVerified != user.Human.IsEmailVerified { if externalUser.Email != "" && (externalUser.Email != user.Human.Email || externalUser.IsEmailVerified != user.Human.IsEmailVerified) {
emailCodeGenerator, err := l.query.InitEncryptionGenerator(ctx, domain.SecretGeneratorTypeVerifyEmailCode, l.userCodeAlg) emailCodeGenerator, err := l.query.InitEncryptionGenerator(ctx, domain.SecretGeneratorTypeVerifyEmailCode, l.userCodeAlg)
logging.WithFields("authReq", authReq.ID, "user", authReq.UserID).OnError(err).Error("unable to update email") logging.WithFields("authReq", authReq.ID, "user", authReq.UserID).OnError(err).Error("unable to update email")
if err == nil { if err == nil {
@@ -572,7 +572,7 @@ func (l *Login) updateExternalUser(ctx context.Context, authReq *domain.AuthRequ
logging.WithFields("authReq", authReq.ID, "user", authReq.UserID).OnError(err).Error("unable to update email") logging.WithFields("authReq", authReq.ID, "user", authReq.UserID).OnError(err).Error("unable to update email")
} }
} }
if externalUser.Phone != "" && externalUser.Phone != user.Human.Phone && externalUser.IsPhoneVerified != user.Human.IsPhoneVerified { if externalUser.Phone != "" && (externalUser.Phone != user.Human.Phone || externalUser.IsPhoneVerified != user.Human.IsPhoneVerified) {
phoneCodeGenerator, err := l.query.InitEncryptionGenerator(ctx, domain.SecretGeneratorTypeVerifyPhoneCode, l.userCodeAlg) phoneCodeGenerator, err := l.query.InitEncryptionGenerator(ctx, domain.SecretGeneratorTypeVerifyPhoneCode, l.userCodeAlg)
logging.WithFields("authReq", authReq.ID, "user", authReq.UserID).OnError(err).Error("unable to update phone") logging.WithFields("authReq", authReq.ID, "user", authReq.UserID).OnError(err).Error("unable to update phone")
if err == nil { if err == nil {
@@ -838,7 +838,7 @@ func (l *Login) appendUserGrants(ctx context.Context, userGrants []*domain.UserG
} }
func (l *Login) externalAuthFailed(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, tokens *oidc.Tokens[*oidc.IDTokenClaims], user idp.User, err error) { func (l *Login) externalAuthFailed(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, tokens *oidc.Tokens[*oidc.IDTokenClaims], user idp.User, err error) {
if _, actionErr := l.runPostExternalAuthenticationActions(&domain.ExternalUser{}, tokens, authReq, r, user, err); actionErr != nil { if _, _, actionErr := l.runPostExternalAuthenticationActions(&domain.ExternalUser{}, tokens, authReq, r, user, err); actionErr != nil {
logging.WithError(err).Error("both external user authentication and action post authentication failed") logging.WithError(err).Error("both external user authentication and action post authentication failed")
} }
l.renderLogin(w, r, authReq, err) l.renderLogin(w, r, authReq, err)

View File

@@ -66,7 +66,7 @@ func (l *Login) handleJWTRequest(w http.ResponseWriter, r *http.Request) {
func (l *Login) handleJWTExtraction(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, identityProvider *query.IDPTemplate) { func (l *Login) handleJWTExtraction(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, identityProvider *query.IDPTemplate) {
token, err := getToken(r, identityProvider.JWTIDPTemplate.HeaderName) token, err := getToken(r, identityProvider.JWTIDPTemplate.HeaderName)
if err != nil { if err != nil {
if _, actionErr := l.runPostExternalAuthenticationActions(new(domain.ExternalUser), nil, authReq, r, nil, err); actionErr != nil { if _, _, actionErr := l.runPostExternalAuthenticationActions(new(domain.ExternalUser), nil, authReq, r, nil, err); actionErr != nil {
logging.WithError(err).Error("both external user authentication and action post authentication failed") logging.WithError(err).Error("both external user authentication and action post authentication failed")
} }
@@ -75,7 +75,7 @@ func (l *Login) handleJWTExtraction(w http.ResponseWriter, r *http.Request, auth
} }
provider, err := l.jwtProvider(identityProvider) provider, err := l.jwtProvider(identityProvider)
if err != nil { if err != nil {
if _, actionErr := l.runPostExternalAuthenticationActions(new(domain.ExternalUser), nil, authReq, r, nil, err); actionErr != nil { if _, _, actionErr := l.runPostExternalAuthenticationActions(new(domain.ExternalUser), nil, authReq, r, nil, err); actionErr != nil {
logging.WithError(err).Error("both external user authentication and action post authentication failed") logging.WithError(err).Error("both external user authentication and action post authentication failed")
} }
l.renderError(w, r, authReq, err) l.renderError(w, r, authReq, err)
@@ -84,7 +84,7 @@ func (l *Login) handleJWTExtraction(w http.ResponseWriter, r *http.Request, auth
session := &jwt.Session{Provider: provider, Tokens: &oidc.Tokens[*oidc.IDTokenClaims]{IDToken: token, Token: &oauth2.Token{}}} session := &jwt.Session{Provider: provider, Tokens: &oidc.Tokens[*oidc.IDTokenClaims]{IDToken: token, Token: &oauth2.Token{}}}
user, err := session.FetchUser(r.Context()) user, err := session.FetchUser(r.Context())
if err != nil { if err != nil {
if _, actionErr := l.runPostExternalAuthenticationActions(new(domain.ExternalUser), tokens(session), authReq, r, user, err); actionErr != nil { if _, _, actionErr := l.runPostExternalAuthenticationActions(new(domain.ExternalUser), tokens(session), authReq, r, user, err); actionErr != nil {
logging.WithError(err).Error("both external user authentication and action post authentication failed") logging.WithError(err).Error("both external user authentication and action post authentication failed")
} }
l.renderError(w, r, authReq, err) l.renderError(w, r, authReq, err)

View File

@@ -73,7 +73,7 @@ func (l *Login) handleLDAPCallback(w http.ResponseWriter, r *http.Request) {
user, err := session.FetchUser(r.Context()) user, err := session.FetchUser(r.Context())
if err != nil { if err != nil {
if _, actionErr := l.runPostExternalAuthenticationActions(new(domain.ExternalUser), nil, authReq, r, nil, err); actionErr != nil { if _, _, actionErr := l.runPostExternalAuthenticationActions(new(domain.ExternalUser), nil, authReq, r, nil, err); actionErr != nil {
logging.WithError(err).Error("both external user authentication and action post authentication failed") logging.WithError(err).Error("both external user authentication and action post authentication failed")
} }
l.renderLDAPLogin(w, r, authReq, err) l.renderLDAPLogin(w, r, authReq, err)