Enable allowed_domains in oauth and oidc providers (#416)

* Enable allowed_domains in oauth and oidc providers

Signed-off-by: Vladimir DOMBROVSKI <vladimir.dombrovski@bso.co>

* Domain check code cleanup

* Run gofmt on domain validation code

---------

Signed-off-by: Vladimir DOMBROVSKI <vladimir.dombrovski@bso.co>
This commit is contained in:
Vladimir Dombrovski 2025-05-05 18:26:19 +02:00 committed by GitHub
parent d8a57edef9
commit 3eb84f0ee9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 41 additions and 0 deletions

View File

@ -63,6 +63,8 @@ type AuthenticatorOauth interface {
ParseUserInfo(raw map[string]any) (*domain.AuthenticatorUserInfo, error)
// RegistrationEnabled returns whether registration is enabled for the OAuth authenticator.
RegistrationEnabled() bool
// GetAllowedDomains returns the list of whitelisted domains
GetAllowedDomains() []string
}
// AuthenticatorLdap is the interface for all LDAP authenticators.
@ -392,6 +394,23 @@ func (a *Authenticator) randString(nByte int) (string, error) {
return base64.RawURLEncoding.EncodeToString(b), nil
}
func isDomainAllowed(email string, allowedDomains []string) bool {
if len(allowedDomains) == 0 {
return true
}
parts := strings.Split(email, "@")
if len(parts) != 2 {
return false
}
domain := strings.ToLower(parts[1])
for _, allowed := range allowedDomains {
if domain == strings.ToLower(allowed) {
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) {
@ -431,6 +450,10 @@ func (a *Authenticator) OauthLoginStep2(ctx context.Context, providerId, nonce,
return nil, fmt.Errorf("unable to process user information: %w", err)
}
if !isDomainAllowed(userInfo.Email, oauthProvider.GetAllowedDomains()) {
return nil, fmt.Errorf("user is not in allowed domains: %w", err)
}
if user.IsLocked() || user.IsDisabled() {
a.bus.Publish(app.TopicAuditLoginFailed, domain.AuditEventWrapper[audit.AuthEvent]{
Ctx: ctx,

View File

@ -27,6 +27,7 @@ type PlainOauthAuthenticator struct {
userAdminMapping *config.OauthAdminMapping
registrationEnabled bool
userInfoLogging bool
allowedDomains []string
}
func newPlainOauthAuthenticator(
@ -56,6 +57,7 @@ func newPlainOauthAuthenticator(
provider.userAdminMapping = &cfg.AdminMapping
provider.registrationEnabled = cfg.RegistrationEnabled
provider.userInfoLogging = cfg.LogUserInfo
provider.allowedDomains = cfg.AllowedDomains
return provider, nil
}
@ -65,6 +67,10 @@ func (p PlainOauthAuthenticator) GetName() string {
return p.name
}
func (p PlainOauthAuthenticator) GetAllowedDomains() []string {
return p.allowedDomains
}
// RegistrationEnabled returns whether registration is enabled for the OAuth authenticator.
func (p PlainOauthAuthenticator) RegistrationEnabled() bool {
return p.registrationEnabled

View File

@ -24,6 +24,7 @@ type OidcAuthenticator struct {
userAdminMapping *config.OauthAdminMapping
registrationEnabled bool
userInfoLogging bool
allowedDomains []string
}
func newOidcAuthenticator(
@ -57,6 +58,7 @@ func newOidcAuthenticator(
provider.userAdminMapping = &cfg.AdminMapping
provider.registrationEnabled = cfg.RegistrationEnabled
provider.userInfoLogging = cfg.LogUserInfo
provider.allowedDomains = cfg.AllowedDomains
return provider, nil
}
@ -66,6 +68,10 @@ func (o OidcAuthenticator) GetName() string {
return o.name
}
func (o OidcAuthenticator) GetAllowedDomains() []string {
return o.allowedDomains
}
// RegistrationEnabled returns whether registration is enabled for this authenticator.
func (o OidcAuthenticator) RegistrationEnabled() bool {
return o.registrationEnabled

View File

@ -188,6 +188,9 @@ type OpenIDConnectProvider struct {
// ExtraScopes specifies optional requested permissions.
ExtraScopes []string `yaml:"extra_scopes"`
// AllowedDomains defines the list of allowed domains
AllowedDomains []string `yaml:"allowed_domains"`
// FieldMap is used to map the names of the user-info endpoint fields to wg-portal fields
FieldMap OauthFields `yaml:"field_map"`
@ -226,6 +229,9 @@ type OAuthProvider struct {
// Scope specifies optional requested permissions.
Scopes []string `yaml:"scopes"`
// AllowedDomains defines the list of allowed domains
AllowedDomains []string `yaml:"allowed_domains"`
// FieldMap is used to map the names of the user-info endpoint fields to wg-portal fields
FieldMap OauthFields `yaml:"field_map"`