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 1 commit
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
Prev Previous commit
Next Next commit
feat: update to plural and lowercase domain
  • Loading branch information
Daniel Carrion committed Dec 1, 2022
commit 865710a7991377d603539ac33eac66e1e141552c
6 changes: 3 additions & 3 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]{
Name: "OIDC Email Domain",
Usage: "Email domain that clients logging in with OIDC must match.",
EmailDomains: &codersdk.DeploymentConfigField[[]string]{
Name: "OIDC Email Domains",
Usage: "Email domains that clients logging in with OIDC must match.",
Flag: "oidc-email-domain",
},
IssuerURL: &codersdk.DeploymentConfigField[string]{
Expand Down
4 changes: 2 additions & 2 deletions cli/deployment/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func TestConfig(t *testing.T) {
Env: map[string]string{},
Valid: func(config *codersdk.DeploymentConfig) {
require.Empty(t, config.OIDC.IssuerURL.Value)
require.Empty(t, config.OIDC.EmailDomain.Value)
require.Empty(t, config.OIDC.EmailDomains.Value)
require.Empty(t, config.OIDC.ClientID.Value)
require.Empty(t, config.OIDC.ClientSecret.Value)
require.True(t, config.OIDC.AllowSignups.Value)
Expand All @@ -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.EmailDomains.Value, "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
2 changes: 1 addition & 1 deletion cli/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
Verifier: oidcProvider.Verifier(&oidc.Config{
ClientID: cfg.OIDC.ClientID.Value,
}),
EmailDomain: cfg.OIDC.EmailDomain.Value,
EmailDomains: cfg.OIDC.EmailDomains.Value,
AllowSignups: cfg.OIDC.AllowSignups.Value,
}
}
Expand Down
2 changes: 1 addition & 1 deletion cli/testdata/coder_server_--help.golden
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ 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-email-domain string 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
Expand Down
12 changes: 6 additions & 6 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 is the domain to enforce when a user authenticates.
EmailDomains []string
AllowSignups bool
// IgnoreEmailVerified allows ignoring the email_verified claim
// from an upstream OIDC provider. See #5065 for context.
Expand Down Expand Up @@ -291,17 +291,17 @@ func (api *API) userOIDC(rw http.ResponseWriter, r *http.Request) {
}
// Check if one or comma delimited list of allowed domains is provided.
// If a suffix matches, break and continue, otherwise error.
if api.OIDCConfig.EmailDomain != "" {
if len(api.OIDCConfig.EmailDomains) != 0 {
ok = false
for _, domain := range strings.Split(api.OIDCConfig.EmailDomain, ",") {
if strings.HasSuffix(strings.ToLower(email), domain) {
for _, domain := range api.OIDCConfig.EmailDomains {
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.EmailDomains),
})
return
}
Expand Down
16 changes: 10 additions & 6 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
EmailDomains []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,
EmailDomains: []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,
EmailDomains: []string{
"kwc.io",
},
StatusCode: http.StatusTemporaryRedirect,
}, {
Name: "EmptyClaims",
Claims: jwt.MapClaims{},
Expand Down Expand Up @@ -611,7 +615,7 @@ func TestUserOIDC(t *testing.T) {

config := conf.OIDCConfig()
config.AllowSignups = tc.AllowSignups
config.EmailDomain = tc.EmailDomain
config.EmailDomains = tc.EmailDomains
config.IgnoreEmailVerified = tc.IgnoreEmailVerified

client := coderdtest.New(t, &coderdtest.Options{
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"`
EmailDomains *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