diff --git a/internal/controller/oauth_controller.go b/internal/controller/oauth_controller.go index fd6c2658..b1d770d3 100644 --- a/internal/controller/oauth_controller.go +++ b/internal/controller/oauth_controller.go @@ -224,6 +224,7 @@ func (controller *OAuthController) oauthCallbackHandler(c *gin.Context) { Username: user.PreferredUsername, Email: user.Email, Name: user.Name, + Groups: utils.CoalesceToString(user.Groups), }) sessionCookie := repository.Session{ @@ -231,7 +232,7 @@ func (controller *OAuthController) oauthCallbackHandler(c *gin.Context) { Name: oauthUserInfo.Name, Email: oauthUserInfo.Email, Provider: svc.ID(), - OAuthGroups: utils.CoalesceToString(user.Groups), + OAuthGroups: oauthUserInfo.Groups, OAuthName: svc.Name(), OAuthSub: user.Sub, } @@ -341,6 +342,7 @@ type oauthUserInfo struct { Email string Username string Name string + Groups string } func (controller *OAuthController) createOAuthUserInfo(input oauthUserInfo) oauthUserInfo { @@ -348,8 +350,12 @@ func (controller *OAuthController) createOAuthUserInfo(input oauthUserInfo) oaut Email: input.Email, } + userAttribs := controller.getUserAttributes(input.Email) + if controller.config.Experimental.OAuthBridgeEnabled { - if input.Username != "" { + if userAttribs.PreferredUsername != "" { + info.Username = userAttribs.PreferredUsername + } else if input.Username != "" { info.Username = input.Username } else { parts := strings.SplitN(input.Email, "@", 2) @@ -360,7 +366,9 @@ func (controller *OAuthController) createOAuthUserInfo(input oauthUserInfo) oaut } } - if input.Name != "" { + if userAttribs.Name != "" { + info.Name = userAttribs.Name + } else if input.Name != "" { info.Name = input.Name } else { info.Name = utils.Capitalize(info.Username) @@ -369,7 +377,9 @@ func (controller *OAuthController) createOAuthUserInfo(input oauthUserInfo) oaut return info } - if input.Name != "" { + if userAttribs.Name != "" { + info.Name = userAttribs.Name + } else if input.Name != "" { controller.log.App.Debug().Msg("Using name from OAuth provider") info.Name = input.Name } else { @@ -382,7 +392,10 @@ func (controller *OAuthController) createOAuthUserInfo(input oauthUserInfo) oaut } } - if input.Username != "" { + if userAttribs.PreferredUsername != "" { + controller.log.App.Debug().Msg("Using preferred username from Auth user attributes") + info.Username = userAttribs.PreferredUsername + } else if input.Username != "" { controller.log.App.Debug().Msg("Using preferred username from OAuth provider") info.Username = input.Username } else { @@ -390,5 +403,20 @@ func (controller *OAuthController) createOAuthUserInfo(input oauthUserInfo) oaut info.Username = strings.Replace(info.Email, "@", "_", 1) } + if userAttribs.Groups != nil { + info.Groups = strings.Join(userAttribs.Groups, ",") + controller.log.App.Debug().Msgf("Using groups from Auth user attributes: %s", userAttribs.Groups) + } else if input.Groups != "" { + controller.log.App.Debug().Msg("Using groups from OAuth provider") + info.Groups = input.Groups + } + return info } + +func (controller *OAuthController) getUserAttributes(email string) model.UserAttributes { + email = strings.ReplaceAll(email, "@", "-") + email = strings.ReplaceAll(email, ".", "-") + attribs := controller.config.Auth.UserAttributes[email] + return attribs +} diff --git a/internal/model/config.go b/internal/model/config.go index 5b077fc5..c2aec45b 100644 --- a/internal/model/config.go +++ b/internal/model/config.go @@ -156,21 +156,23 @@ type AuthConfig struct { } type UserAttributes struct { - Name string `description:"Full name of the user." yaml:"name,omitempty"` - GivenName string `description:"Given (first) name of the user." yaml:"givenName,omitempty"` - FamilyName string `description:"Family (last) name of the user." yaml:"familyName,omitempty"` - MiddleName string `description:"Middle name of the user." yaml:"middleName,omitempty"` - Nickname string `description:"Nickname of the user." yaml:"nickname,omitempty"` - Profile string `description:"URL of the user's profile page." yaml:"profile,omitempty"` - Picture string `description:"URL of the user's profile picture." yaml:"picture,omitempty"` - Website string `description:"URL of the user's website." yaml:"website,omitempty"` - Email string `description:"Email address of the user." yaml:"email,omitempty"` - Gender string `description:"Gender of the user." yaml:"gender,omitempty"` - Birthdate string `description:"Birthdate of the user (YYYY-MM-DD)." yaml:"birthdate,omitempty"` - Zoneinfo string `description:"Time zone of the user (e.g. Europe/Athens)." yaml:"zoneinfo,omitempty"` - Locale string `description:"Locale of the user (e.g. en-US)." yaml:"locale,omitempty"` - PhoneNumber string `description:"Phone number of the user." yaml:"phoneNumber,omitempty"` - Address AddressClaim `description:"Address of the user." yaml:"address,omitempty"` + Name string `description:"Full name of the user." yaml:"name,omitempty"` + GivenName string `description:"Given (first) name of the user." yaml:"givenName,omitempty"` + FamilyName string `description:"Family (last) name of the user." yaml:"familyName,omitempty"` + MiddleName string `description:"Middle name of the user." yaml:"middleName,omitempty"` + Nickname string `description:"Nickname of the user." yaml:"nickname,omitempty"` + PreferredUsername string `description:"Preferred username of the user." yaml:"preferredUsername,omitempty"` + Groups []string `description:"List of groups the user belongs to." yaml:"groups,omitempty"` + Profile string `description:"URL of the user's profile page." yaml:"profile,omitempty"` + Picture string `description:"URL of the user's profile picture." yaml:"picture,omitempty"` + Website string `description:"URL of the user's website." yaml:"website,omitempty"` + Email string `description:"Email address of the user." yaml:"email,omitempty"` + Gender string `description:"Gender of the user." yaml:"gender,omitempty"` + Birthdate string `description:"Birthdate of the user (YYYY-MM-DD)." yaml:"birthdate,omitempty"` + Zoneinfo string `description:"Time zone of the user (e.g. Europe/Athens)." yaml:"zoneinfo,omitempty"` + Locale string `description:"Locale of the user (e.g. en-US)." yaml:"locale,omitempty"` + PhoneNumber string `description:"Phone number of the user." yaml:"phoneNumber,omitempty"` + Address AddressClaim `description:"Address of the user." yaml:"address,omitempty"` } type AddressClaim struct { diff --git a/internal/service/access_controls_rules.go b/internal/service/access_controls_rules.go index 318894d2..f87965a4 100644 --- a/internal/service/access_controls_rules.go +++ b/internal/service/access_controls_rules.go @@ -117,8 +117,12 @@ func (rule *OAuthGroupRule) Evaluate(ctx *ACLContext) Effect { } if _, ok := model.OverrideProviders[ctx.UserContext.OAuth.ID]; ok { - rule.Log.App.Debug().Str("provider", ctx.UserContext.OAuth.ID).Msg("Provider override detected, skipping group check") - return EffectAllow + if len(ctx.UserContext.OAuth.Groups) == 0 { + rule.Log.App.Debug().Str("provider", ctx.UserContext.OAuth.ID).Msg("Provider override detected, skipping group check") + return EffectAllow + } + + rule.Log.App.Debug().Str("provider", ctx.UserContext.OAuth.ID).Msg("Provider override detected but user has groups, doing group check") } for _, group := range ctx.UserContext.OAuth.Groups {