only override isAdmin flag if it is provided by the authentication source

This commit is contained in:
Christoph Haas
2026-01-19 23:17:56 +01:00
parent 70832bfb52
commit 79eaedb9ca
4 changed files with 44 additions and 26 deletions

View File

@@ -605,7 +605,7 @@ func (a *Authenticator) registerNewUser(
user := &domain.User{ user := &domain.User{
Identifier: userInfo.Identifier, Identifier: userInfo.Identifier,
Email: userInfo.Email, Email: userInfo.Email,
IsAdmin: userInfo.IsAdmin, IsAdmin: false,
Firstname: userInfo.Firstname, Firstname: userInfo.Firstname,
Lastname: userInfo.Lastname, Lastname: userInfo.Lastname,
Phone: userInfo.Phone, 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) err := a.users.RegisterUser(ctx, user)
if err != nil { if err != nil {
@@ -632,6 +635,7 @@ func (a *Authenticator) registerNewUser(
slog.Debug("registered user from external authentication provider", slog.Debug("registered user from external authentication provider",
"user", user.Identifier, "user", user.Identifier,
"adminInfoAvailable", userInfo.AdminInfoAvailable,
"isAdmin", user.IsAdmin, "isAdmin", user.IsAdmin,
"provider", source) "provider", source)
@@ -719,7 +723,7 @@ func (a *Authenticator) updateExternalUser(
existingUser.Department = userInfo.Department existingUser.Department = userInfo.Department
isChanged = true isChanged = true
} }
if existingUser.IsAdmin != userInfo.IsAdmin { if userInfo.AdminInfoAvailable && existingUser.IsAdmin != userInfo.IsAdmin {
existingUser.IsAdmin = userInfo.IsAdmin existingUser.IsAdmin = userInfo.IsAdmin
isChanged = true isChanged = true
} }
@@ -732,6 +736,7 @@ func (a *Authenticator) updateExternalUser(
slog.Debug("updated user with data from external authentication provider", slog.Debug("updated user with data from external authentication provider",
"user", existingUser.Identifier, "user", existingUser.Identifier,
"adminInfoAvailable", userInfo.AdminInfoAvailable,
"isAdmin", existingUser.IsAdmin, "isAdmin", existingUser.IsAdmin,
"provider", source) "provider", source)
} }

View File

@@ -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. // 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) { func (l LdapAuthenticator) ParseUserInfo(raw map[string]any) (*domain.AuthenticatorUserInfo, error) {
isAdmin, err := internal.LdapIsMemberOf(raw[l.cfg.FieldMap.GroupMembership].([][]byte), l.cfg.ParsedAdminGroupDN) isAdmin := false
if err != nil { adminInfoAvailable := false
return nil, fmt.Errorf("failed to check admin group: %w", err) 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{ userInfo := &domain.AuthenticatorUserInfo{
Identifier: domain.UserIdentifier(internal.MapDefaultString(raw, l.cfg.FieldMap.UserIdentifier, "")), Identifier: domain.UserIdentifier(internal.MapDefaultString(raw, l.cfg.FieldMap.UserIdentifier, "")),
Email: internal.MapDefaultString(raw, l.cfg.FieldMap.Email, ""), Email: internal.MapDefaultString(raw, l.cfg.FieldMap.Email, ""),
Firstname: internal.MapDefaultString(raw, l.cfg.FieldMap.Firstname, ""), Firstname: internal.MapDefaultString(raw, l.cfg.FieldMap.Firstname, ""),
Lastname: internal.MapDefaultString(raw, l.cfg.FieldMap.Lastname, ""), Lastname: internal.MapDefaultString(raw, l.cfg.FieldMap.Lastname, ""),
Phone: internal.MapDefaultString(raw, l.cfg.FieldMap.Phone, ""), Phone: internal.MapDefaultString(raw, l.cfg.FieldMap.Phone, ""),
Department: internal.MapDefaultString(raw, l.cfg.FieldMap.Department, ""), Department: internal.MapDefaultString(raw, l.cfg.FieldMap.Department, ""),
IsAdmin: isAdmin, IsAdmin: isAdmin,
AdminInfoAvailable: adminInfoAvailable,
} }
return userInfo, nil return userInfo, nil

View File

@@ -15,9 +15,11 @@ func parseOauthUserInfo(
raw map[string]any, raw map[string]any,
) (*domain.AuthenticatorUserInfo, error) { ) (*domain.AuthenticatorUserInfo, error) {
var isAdmin bool var isAdmin bool
var adminInfoAvailable bool
// first try to match the is_admin field against the given regex // first try to match the is_admin field against the given regex
if mapping.IsAdmin != "" { if mapping.IsAdmin != "" {
adminInfoAvailable = true
re := adminMapping.GetAdminValueRegex() re := adminMapping.GetAdminValueRegex()
if re.MatchString(strings.TrimSpace(internal.MapDefaultString(raw, mapping.IsAdmin, ""))) { if re.MatchString(strings.TrimSpace(internal.MapDefaultString(raw, mapping.IsAdmin, ""))) {
isAdmin = true isAdmin = true
@@ -26,6 +28,7 @@ func parseOauthUserInfo(
// next try to parse the user's groups // next try to parse the user's groups
if !isAdmin && mapping.UserGroups != "" && adminMapping.AdminGroupRegex != "" { if !isAdmin && mapping.UserGroups != "" && adminMapping.AdminGroupRegex != "" {
adminInfoAvailable = true
userGroups := internal.MapDefaultStringSlice(raw, mapping.UserGroups, nil) userGroups := internal.MapDefaultStringSlice(raw, mapping.UserGroups, nil)
re := adminMapping.GetAdminGroupRegex() re := adminMapping.GetAdminGroupRegex()
for _, group := range userGroups { for _, group := range userGroups {
@@ -37,13 +40,14 @@ func parseOauthUserInfo(
} }
userInfo := &domain.AuthenticatorUserInfo{ userInfo := &domain.AuthenticatorUserInfo{
Identifier: domain.UserIdentifier(internal.MapDefaultString(raw, mapping.UserIdentifier, "")), Identifier: domain.UserIdentifier(internal.MapDefaultString(raw, mapping.UserIdentifier, "")),
Email: internal.MapDefaultString(raw, mapping.Email, ""), Email: internal.MapDefaultString(raw, mapping.Email, ""),
Firstname: internal.MapDefaultString(raw, mapping.Firstname, ""), Firstname: internal.MapDefaultString(raw, mapping.Firstname, ""),
Lastname: internal.MapDefaultString(raw, mapping.Lastname, ""), Lastname: internal.MapDefaultString(raw, mapping.Lastname, ""),
Phone: internal.MapDefaultString(raw, mapping.Phone, ""), Phone: internal.MapDefaultString(raw, mapping.Phone, ""),
Department: internal.MapDefaultString(raw, mapping.Department, ""), Department: internal.MapDefaultString(raw, mapping.Department, ""),
IsAdmin: isAdmin, IsAdmin: isAdmin,
AdminInfoAvailable: adminInfoAvailable,
} }
return userInfo, nil return userInfo, nil

View File

@@ -10,11 +10,12 @@ type LoginProviderInfo struct {
} }
type AuthenticatorUserInfo struct { type AuthenticatorUserInfo struct {
Identifier UserIdentifier Identifier UserIdentifier
Email string Email string
Firstname string Firstname string
Lastname string Lastname string
Phone string Phone string
Department string Department string
IsAdmin bool IsAdmin bool
AdminInfoAvailable bool // true if the IsAdmin flag is valid
} }