diff --git a/internal/api/ui/login/custom_action.go b/internal/api/ui/login/custom_action.go index 970391348..772017277 100644 --- a/internal/api/ui/login/custom_action.go +++ b/internal/api/ui/login/custom_action.go @@ -23,7 +23,7 @@ func (l *Login) runPostExternalAuthenticationActions( httpRequest *http.Request, idpUser idp.User, authenticationError error, -) (*domain.ExternalUser, error) { +) (_ *domain.ExternalUser, userChanged bool, err error) { ctx := httpRequest.Context() resourceOwner := authRequest.RequestedOrgID @@ -32,40 +32,50 @@ func (l *Login) runPostExternalAuthenticationActions( } triggerActions, err := l.query.GetActiveActionsByFlowAndTriggerType(ctx, domain.FlowTypeExternalAuthentication, domain.TriggerTypePostAuthentication, resourceOwner, false) if err != nil { - return nil, err + return nil, false, err } metadataList := object.MetadataListFromDomain(user.Metadatas) apiFields := actions.WithAPIFields( actions.SetFields("setFirstName", func(firstName string) { user.FirstName = firstName + userChanged = true }), actions.SetFields("setLastName", func(lastName string) { user.LastName = lastName + userChanged = true }), actions.SetFields("setNickName", func(nickName string) { user.NickName = nickName + userChanged = true }), actions.SetFields("setDisplayName", func(displayName string) { user.DisplayName = displayName + userChanged = true }), actions.SetFields("setPreferredLanguage", func(preferredLanguage string) { user.PreferredLanguage = language.Make(preferredLanguage) + userChanged = true }), actions.SetFields("setPreferredUsername", func(username string) { user.PreferredUsername = username + userChanged = true }), actions.SetFields("setEmail", func(email domain.EmailAddress) { user.Email = email + userChanged = true }), actions.SetFields("setEmailVerified", func(verified bool) { user.IsEmailVerified = verified + userChanged = true }), actions.SetFields("setPhone", func(phone domain.PhoneNumber) { user.Phone = phone + userChanged = true }), actions.SetFields("setPhoneVerified", func(verified bool) { user.IsPhoneVerified = verified + userChanged = true }), actions.SetFields("metadata", func(c *actions.FieldConfig) interface{} { return metadataList.MetadataListFromDomain(c.Runtime) @@ -111,11 +121,11 @@ func (l *Login) runPostExternalAuthenticationActions( ) cancel() if err != nil { - return nil, err + return nil, false, err } } user.Metadatas = object.MetadataListToDomain(metadataList) - return user, err + return user, userChanged, err } type authMethod string diff --git a/internal/api/ui/login/external_provider_handler.go b/internal/api/ui/login/external_provider_handler.go index 4920e9f4f..0012d1f3e 100644 --- a/internal/api/ui/login/external_provider_handler.go +++ b/internal/api/ui/login/external_provider_handler.go @@ -286,7 +286,7 @@ func (l *Login) handleExternalUserAuthenticated( callback func(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest), ) { 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 { l.renderError(w, r, authReq, err) return @@ -300,7 +300,7 @@ func (l *Login) handleExternalUserAuthenticated( l.externalUserNotExisting(w, r, authReq, provider, externalUser) return } - if provider.IsAutoUpdate || len(externalUser.Metadatas) > 0 { + if provider.IsAutoUpdate || len(externalUser.Metadatas) > 0 || externalUserChange { // read current auth request state (incl. authorized user) authReq, err = l.authRepo.AuthRequestByID(r.Context(), authReq.ID, authReq.AgentID) if err != nil { @@ -308,7 +308,7 @@ func (l *Login) handleExternalUserAuthenticated( return } } - if provider.IsAutoUpdate { + if provider.IsAutoUpdate || externalUserChange { err = l.updateExternalUser(r.Context(), authReq, externalUser) if err != nil { l.renderError(w, r, authReq, err) @@ -558,7 +558,7 @@ func (l *Login) updateExternalUser(ctx context.Context, authReq *domain.AuthRequ if user.Human == nil { 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) logging.WithFields("authReq", authReq.ID, "user", authReq.UserID).OnError(err).Error("unable to update email") 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") } } - 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) logging.WithFields("authReq", authReq.ID, "user", authReq.UserID).OnError(err).Error("unable to update phone") 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) { - 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") } l.renderLogin(w, r, authReq, err) diff --git a/internal/api/ui/login/jwt_handler.go b/internal/api/ui/login/jwt_handler.go index 970b47e12..51b079584 100644 --- a/internal/api/ui/login/jwt_handler.go +++ b/internal/api/ui/login/jwt_handler.go @@ -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) { token, err := getToken(r, identityProvider.JWTIDPTemplate.HeaderName) 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") } @@ -75,7 +75,7 @@ func (l *Login) handleJWTExtraction(w http.ResponseWriter, r *http.Request, auth } provider, err := l.jwtProvider(identityProvider) 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") } 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{}}} user, err := session.FetchUser(r.Context()) 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") } l.renderError(w, r, authReq, err) diff --git a/internal/api/ui/login/ldap_handler.go b/internal/api/ui/login/ldap_handler.go index 1804a4884..3ec49f4a7 100644 --- a/internal/api/ui/login/ldap_handler.go +++ b/internal/api/ui/login/ldap_handler.go @@ -73,7 +73,7 @@ func (l *Login) handleLDAPCallback(w http.ResponseWriter, r *http.Request) { user, err := session.FetchUser(r.Context()) 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") } l.renderLDAPLogin(w, r, authReq, err)