From 79eaedb9ca7c9cd55ccbfa98254c04e8e0ae8a6b Mon Sep 17 00:00:00 2001 From: Christoph Haas Date: Mon, 19 Jan 2026 23:17:56 +0100 Subject: [PATCH] only override isAdmin flag if it is provided by the authentication source --- internal/app/auth/auth.go | 9 +++++++-- internal/app/auth/auth_ldap.go | 28 ++++++++++++++++++---------- internal/app/auth/oauth_common.go | 18 +++++++++++------- internal/domain/auth.go | 15 ++++++++------- 4 files changed, 44 insertions(+), 26 deletions(-) diff --git a/internal/app/auth/auth.go b/internal/app/auth/auth.go index c1fc0c2..0572324 100644 --- a/internal/app/auth/auth.go +++ b/internal/app/auth/auth.go @@ -605,7 +605,7 @@ func (a *Authenticator) registerNewUser( user := &domain.User{ Identifier: userInfo.Identifier, Email: userInfo.Email, - IsAdmin: userInfo.IsAdmin, + IsAdmin: false, Firstname: userInfo.Firstname, Lastname: userInfo.Lastname, Phone: userInfo.Phone, @@ -624,6 +624,9 @@ func (a *Authenticator) registerNewUser( }, }, } + if userInfo.AdminInfoAvailable && userInfo.IsAdmin { + user.IsAdmin = true + } err := a.users.RegisterUser(ctx, user) if err != nil { @@ -632,6 +635,7 @@ func (a *Authenticator) registerNewUser( slog.Debug("registered user from external authentication provider", "user", user.Identifier, + "adminInfoAvailable", userInfo.AdminInfoAvailable, "isAdmin", user.IsAdmin, "provider", source) @@ -719,7 +723,7 @@ func (a *Authenticator) updateExternalUser( existingUser.Department = userInfo.Department isChanged = true } - if existingUser.IsAdmin != userInfo.IsAdmin { + if userInfo.AdminInfoAvailable && existingUser.IsAdmin != userInfo.IsAdmin { existingUser.IsAdmin = userInfo.IsAdmin isChanged = true } @@ -732,6 +736,7 @@ func (a *Authenticator) updateExternalUser( slog.Debug("updated user with data from external authentication provider", "user", existingUser.Identifier, + "adminInfoAvailable", userInfo.AdminInfoAvailable, "isAdmin", existingUser.IsAdmin, "provider", source) } diff --git a/internal/app/auth/auth_ldap.go b/internal/app/auth/auth_ldap.go index faca76a..ddcca83 100644 --- a/internal/app/auth/auth_ldap.go +++ b/internal/app/auth/auth_ldap.go @@ -127,18 +127,26 @@ func (l LdapAuthenticator) GetUserInfo(_ context.Context, userId domain.UserIden // ParseUserInfo parses the user information from the LDAP server into a domain.AuthenticatorUserInfo struct. func (l LdapAuthenticator) ParseUserInfo(raw map[string]any) (*domain.AuthenticatorUserInfo, error) { - isAdmin, err := internal.LdapIsMemberOf(raw[l.cfg.FieldMap.GroupMembership].([][]byte), l.cfg.ParsedAdminGroupDN) - if err != nil { - return nil, fmt.Errorf("failed to check admin group: %w", err) + isAdmin := false + adminInfoAvailable := false + if l.cfg.FieldMap.GroupMembership != "" { + adminInfoAvailable = true + var err error + isAdmin, err = internal.LdapIsMemberOf(raw[l.cfg.FieldMap.GroupMembership].([][]byte), l.cfg.ParsedAdminGroupDN) + if err != nil { + return nil, fmt.Errorf("failed to check admin group: %w", err) + } } + userInfo := &domain.AuthenticatorUserInfo{ - Identifier: domain.UserIdentifier(internal.MapDefaultString(raw, l.cfg.FieldMap.UserIdentifier, "")), - Email: internal.MapDefaultString(raw, l.cfg.FieldMap.Email, ""), - Firstname: internal.MapDefaultString(raw, l.cfg.FieldMap.Firstname, ""), - Lastname: internal.MapDefaultString(raw, l.cfg.FieldMap.Lastname, ""), - Phone: internal.MapDefaultString(raw, l.cfg.FieldMap.Phone, ""), - Department: internal.MapDefaultString(raw, l.cfg.FieldMap.Department, ""), - IsAdmin: isAdmin, + Identifier: domain.UserIdentifier(internal.MapDefaultString(raw, l.cfg.FieldMap.UserIdentifier, "")), + Email: internal.MapDefaultString(raw, l.cfg.FieldMap.Email, ""), + Firstname: internal.MapDefaultString(raw, l.cfg.FieldMap.Firstname, ""), + Lastname: internal.MapDefaultString(raw, l.cfg.FieldMap.Lastname, ""), + Phone: internal.MapDefaultString(raw, l.cfg.FieldMap.Phone, ""), + Department: internal.MapDefaultString(raw, l.cfg.FieldMap.Department, ""), + IsAdmin: isAdmin, + AdminInfoAvailable: adminInfoAvailable, } return userInfo, nil diff --git a/internal/app/auth/oauth_common.go b/internal/app/auth/oauth_common.go index b5927cc..a66b1ce 100644 --- a/internal/app/auth/oauth_common.go +++ b/internal/app/auth/oauth_common.go @@ -15,9 +15,11 @@ func parseOauthUserInfo( raw map[string]any, ) (*domain.AuthenticatorUserInfo, error) { var isAdmin bool + var adminInfoAvailable bool // first try to match the is_admin field against the given regex if mapping.IsAdmin != "" { + adminInfoAvailable = true re := adminMapping.GetAdminValueRegex() if re.MatchString(strings.TrimSpace(internal.MapDefaultString(raw, mapping.IsAdmin, ""))) { isAdmin = true @@ -26,6 +28,7 @@ func parseOauthUserInfo( // next try to parse the user's groups if !isAdmin && mapping.UserGroups != "" && adminMapping.AdminGroupRegex != "" { + adminInfoAvailable = true userGroups := internal.MapDefaultStringSlice(raw, mapping.UserGroups, nil) re := adminMapping.GetAdminGroupRegex() for _, group := range userGroups { @@ -37,13 +40,14 @@ func parseOauthUserInfo( } userInfo := &domain.AuthenticatorUserInfo{ - Identifier: domain.UserIdentifier(internal.MapDefaultString(raw, mapping.UserIdentifier, "")), - Email: internal.MapDefaultString(raw, mapping.Email, ""), - Firstname: internal.MapDefaultString(raw, mapping.Firstname, ""), - Lastname: internal.MapDefaultString(raw, mapping.Lastname, ""), - Phone: internal.MapDefaultString(raw, mapping.Phone, ""), - Department: internal.MapDefaultString(raw, mapping.Department, ""), - IsAdmin: isAdmin, + Identifier: domain.UserIdentifier(internal.MapDefaultString(raw, mapping.UserIdentifier, "")), + Email: internal.MapDefaultString(raw, mapping.Email, ""), + Firstname: internal.MapDefaultString(raw, mapping.Firstname, ""), + Lastname: internal.MapDefaultString(raw, mapping.Lastname, ""), + Phone: internal.MapDefaultString(raw, mapping.Phone, ""), + Department: internal.MapDefaultString(raw, mapping.Department, ""), + IsAdmin: isAdmin, + AdminInfoAvailable: adminInfoAvailable, } return userInfo, nil diff --git a/internal/domain/auth.go b/internal/domain/auth.go index 817d66d..bed6219 100644 --- a/internal/domain/auth.go +++ b/internal/domain/auth.go @@ -10,11 +10,12 @@ type LoginProviderInfo struct { } type AuthenticatorUserInfo struct { - Identifier UserIdentifier - Email string - Firstname string - Lastname string - Phone string - Department string - IsAdmin bool + Identifier UserIdentifier + Email string + Firstname string + Lastname string + Phone string + Department string + IsAdmin bool + AdminInfoAvailable bool // true if the IsAdmin flag is valid }