Add support for auth.oidc.allowed_user_groups (#667) (#668)
Some checks are pending
Docker / Build and Push (push) Waiting to run
Docker / release (push) Blocked by required conditions
github-pages / deploy (push) Waiting to run

Signed-off-by: Michael Tupitsyn <michael.tupitsyn@gmail.com>
This commit is contained in:
Michael Tupitsyn
2026-04-11 09:24:18 -07:00
committed by GitHub
parent 401642701a
commit 9b437205b1
10 changed files with 106 additions and 1 deletions

View File

@@ -65,6 +65,9 @@ type AuthenticatorOauth interface {
RegistrationEnabled() bool
// GetAllowedDomains returns the list of whitelisted domains
GetAllowedDomains() []string
// GetAllowedUserGroups returns the list of whitelisted user groups.
// If non-empty, at least one user group must match.
GetAllowedUserGroups() []string
}
// AuthenticatorLdap is the interface for all LDAP authenticators.
@@ -497,6 +500,33 @@ func isDomainAllowed(email string, allowedDomains []string) bool {
return false
}
func isAnyAllowedUserGroup(userGroups, allowedUserGroups []string) bool {
if len(allowedUserGroups) == 0 {
return true
}
allowed := make(map[string]struct{}, len(allowedUserGroups))
for _, group := range allowedUserGroups {
trimmed := strings.TrimSpace(group)
if trimmed == "" {
continue
}
allowed[trimmed] = struct{}{}
}
if len(allowed) == 0 {
return false
}
for _, group := range userGroups {
if _, ok := allowed[strings.TrimSpace(group)]; ok {
return true
}
}
return false
}
// OauthLoginStep2 finishes the oauth authentication flow by exchanging the code for an access token and
// fetching the user information.
func (a *Authenticator) OauthLoginStep2(ctx context.Context, providerId, nonce, code string) (*domain.User, error) {
@@ -524,6 +554,10 @@ func (a *Authenticator) OauthLoginStep2(ctx context.Context, providerId, nonce,
return nil, fmt.Errorf("user %s is not in allowed domains", userInfo.Email)
}
if !isAnyAllowedUserGroup(userInfo.UserGroups, oauthProvider.GetAllowedUserGroups()) {
return nil, fmt.Errorf("user %s is not in allowed user groups", userInfo.Identifier)
}
ctx = domain.SetUserInfo(ctx,
domain.SystemAdminContextUserInfo()) // switch to admin user context to check if user exists
user, err := a.processUserInfo(ctx, userInfo, domain.UserSourceOauth, oauthProvider.GetName(),