Skip to content

feat: Allow multiple OIDC domains #5210

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Dec 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cli/deployment/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,9 @@ func newConfig() *codersdk.DeploymentConfig {
Flag: "oidc-client-secret",
Secret: true,
},
EmailDomain: &codersdk.DeploymentConfigField[string]{
EmailDomain: &codersdk.DeploymentConfigField[[]string]{
Name: "OIDC Email Domain",
Usage: "Email domain that clients logging in with OIDC must match.",
Usage: "Email domains that clients logging in with OIDC must match.",
Flag: "oidc-email-domain",
},
IssuerURL: &codersdk.DeploymentConfigField[string]{
Expand Down
2 changes: 1 addition & 1 deletion cli/deployment/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ func TestConfig(t *testing.T) {
},
Valid: func(config *codersdk.DeploymentConfig) {
require.Equal(t, config.OIDC.IssuerURL.Value, "https://accounts.google.com")
require.Equal(t, config.OIDC.EmailDomain.Value, "coder.com")
require.Equal(t, config.OIDC.EmailDomain.Value, []string{"coder.com"})
require.Equal(t, config.OIDC.ClientID.Value, "client")
require.Equal(t, config.OIDC.ClientSecret.Value, "secret")
require.False(t, config.OIDC.AllowSignups.Value)
Expand Down
4 changes: 2 additions & 2 deletions cli/testdata/coder_server_--help.golden
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ Flags:
Consumes $CODER_OIDC_CLIENT_ID
--oidc-client-secret string Client secret to use for Login with OIDC.
Consumes $CODER_OIDC_CLIENT_SECRET
--oidc-email-domain string Email domain that clients logging in with
OIDC must match.
--oidc-email-domain strings Email domains that clients logging in
with OIDC must match.
Consumes $CODER_OIDC_EMAIL_DOMAIN
--oidc-ignore-email-verified Ignore the email_verified claim from the
upstream provider.
Expand Down
17 changes: 12 additions & 5 deletions coderd/userauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,8 @@ type OIDCConfig struct {
httpmw.OAuth2Config

Verifier *oidc.IDTokenVerifier
// EmailDomain is the domain to enforce when a user authenticates.
EmailDomain string
// EmailDomains are the domains to enforce when a user authenticates.
EmailDomain []string
AllowSignups bool
// IgnoreEmailVerified allows ignoring the email_verified claim
// from an upstream OIDC provider. See #5065 for context.
Expand Down Expand Up @@ -289,10 +289,17 @@ func (api *API) userOIDC(rw http.ResponseWriter, r *http.Request) {
}
username = httpapi.UsernameFrom(username)
}
if api.OIDCConfig.EmailDomain != "" {
if !strings.HasSuffix(strings.ToLower(email), strings.ToLower(api.OIDCConfig.EmailDomain)) {
if len(api.OIDCConfig.EmailDomain) > 0 {
ok = false
for _, domain := range api.OIDCConfig.EmailDomain {
if strings.HasSuffix(strings.ToLower(email), strings.ToLower(domain)) {
ok = true
break
}
}
if !ok {
httpapi.Write(ctx, rw, http.StatusForbidden, codersdk.Response{
Message: fmt.Sprintf("Your email %q is not a part of the %q domain!", email, api.OIDCConfig.EmailDomain),
Message: fmt.Sprintf("Your email %q is not in domains %q !", email, api.OIDCConfig.EmailDomain),
})
return
}
Expand Down
14 changes: 9 additions & 5 deletions coderd/userauth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ func TestUserOIDC(t *testing.T) {
Name string
Claims jwt.MapClaims
AllowSignups bool
EmailDomain string
EmailDomain []string
Username string
AvatarURL string
StatusCode int
Expand Down Expand Up @@ -528,17 +528,21 @@ func TestUserOIDC(t *testing.T) {
"email_verified": true,
},
AllowSignups: true,
EmailDomain: "coder.com",
StatusCode: http.StatusForbidden,
EmailDomain: []string{
"coder.com",
},
StatusCode: http.StatusForbidden,
}, {
Name: "EmailDomainCaseInsensitive",
Claims: jwt.MapClaims{
"email": "kyle@KWC.io",
"email_verified": true,
},
AllowSignups: true,
EmailDomain: "kwc.io",
StatusCode: http.StatusTemporaryRedirect,
EmailDomain: []string{
"kwc.io",
},
StatusCode: http.StatusTemporaryRedirect,
}, {
Name: "EmptyClaims",
Claims: jwt.MapClaims{},
Expand Down
2 changes: 1 addition & 1 deletion codersdk/deploymentconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ type OIDCConfig struct {
AllowSignups *DeploymentConfigField[bool] `json:"allow_signups" typescript:",notnull"`
ClientID *DeploymentConfigField[string] `json:"client_id" typescript:",notnull"`
ClientSecret *DeploymentConfigField[string] `json:"client_secret" typescript:",notnull"`
EmailDomain *DeploymentConfigField[string] `json:"email_domain" typescript:",notnull"`
EmailDomain *DeploymentConfigField[[]string] `json:"email_domain" typescript:",notnull"`
IssuerURL *DeploymentConfigField[string] `json:"issuer_url" typescript:",notnull"`
Scopes *DeploymentConfigField[[]string] `json:"scopes" typescript:",notnull"`
IgnoreEmailVerified *DeploymentConfigField[bool] `json:"ignore_email_verified" typescript:",notnull"`
Expand Down
4 changes: 2 additions & 2 deletions docs/admin/auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ Navigate to your Coder host and run the following command to start up the Coder
server:

```console
coder server --oidc-issuer-url="https://accounts.google.com" --oidc-email-domain="your-domain" --oidc-client-id="533...ent.com" --oidc-client-secret="G0CSP...7qSM"
coder server --oidc-issuer-url="https://accounts.google.com" --oidc-email-domain="your-domain-1,your-domain-2" --oidc-client-id="533...ent.com" --oidc-client-secret="G0CSP...7qSM"
```

Alternatively, if you are running Coder as a system service, you can achieve the
Expand All @@ -72,7 +72,7 @@ to the `/etc/coder.d/coder.env` file:

```console
CODER_OIDC_ISSUER_URL="https://accounts.google.com"
CODER_OIDC_EMAIL_DOMAIN="your-domain"
CODER_OIDC_EMAIL_DOMAIN="your-domain-1,your-domain-2"
CODER_OIDC_CLIENT_ID="533...ent.com"
CODER_OIDC_CLIENT_SECRET="G0CSP...7qSM"
```
Expand Down
2 changes: 1 addition & 1 deletion site/src/api/typesGenerated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ export interface OIDCConfig {
readonly allow_signups: DeploymentConfigField<boolean>
readonly client_id: DeploymentConfigField<string>
readonly client_secret: DeploymentConfigField<string>
readonly email_domain: DeploymentConfigField<string>
readonly email_domain: DeploymentConfigField<string[]>
readonly issuer_url: DeploymentConfigField<string>
readonly scopes: DeploymentConfigField<string[]>
readonly ignore_email_verified: DeploymentConfigField<boolean>
Expand Down