From eb0c3127342ce707483836eeed08a3ac0780a71a Mon Sep 17 00:00:00 2001 From: Moto Ishizawa Date: Fri, 12 Aug 2016 10:45:47 +0900 Subject: [PATCH] connector: add emailClaim setting to OIDC Connector Add emailCiam setting to OIDC Connector for supporting an ID token that does not contain the email claim. --- Documentation/connectors-configuration.md | 1 + connector/connector_oidc.go | 28 +++++++++++++++++++++++ integration/admin_api_test.go | 2 ++ 3 files changed, 31 insertions(+) diff --git a/Documentation/connectors-configuration.md b/Documentation/connectors-configuration.md index 0970f308..63842656 100644 --- a/Documentation/connectors-configuration.md +++ b/Documentation/connectors-configuration.md @@ -48,6 +48,7 @@ This connector config lets users authenticate with other OIDC providers. In addi * clientID: a `string`. The OIDC client ID. * clientSecret: a `string`. The OIDC client secret. * trustedEmailProvider: a `boolean`. If true dex will trust the email address claims from this provider and not require that users verify their emails. +* emailClaim: a `string`. The name of the claim to be treated as an email claim. If empty dex will use a `email` claim. In order to use the `oidc` connector you must register dex as an OIDC client; this mechanism is different from provider to provider. For Google, follow the instructions at their [developer site](https://developers.google.com/identity/protocols/OpenIDConnect?hl=en). Regardless of your provider, registering your client will also provide you with the client ID and secret. diff --git a/connector/connector_oidc.go b/connector/connector_oidc.go index ee320c86..4aa4c33b 100644 --- a/connector/connector_oidc.go +++ b/connector/connector_oidc.go @@ -15,6 +15,7 @@ import ( const ( OIDCConnectorType = "oidc" httpPathCallback = "/callback" + defaultEmailClaim = "email" ) func init() { @@ -27,6 +28,7 @@ type OIDCConnectorConfig struct { ClientID string `json:"clientID"` ClientSecret string `json:"clientSecret"` TrustedEmailProvider bool `json:"trustedEmailProvider"` + EmailClaim string `json:"emailClaim"` } func (cfg *OIDCConnectorConfig) ConnectorID() string { @@ -44,6 +46,7 @@ type OIDCConnector struct { loginFunc oidc.LoginFunc client *oidc.Client trustedEmailProvider bool + emailClaim string } func (cfg *OIDCConnectorConfig) Connector(ns url.URL, lf oidc.LoginFunc, tpls *template.Template) (Connector, error) { @@ -69,6 +72,7 @@ func (cfg *OIDCConnectorConfig) Connector(ns url.URL, lf oidc.LoginFunc, tpls *t loginFunc: lf, client: cl, trustedEmailProvider: cfg.TrustedEmailProvider, + emailClaim: cfg.EmailClaim, } return idpc, nil } @@ -144,6 +148,30 @@ func (c *OIDCConnector) handleCallbackFunc(lf oidc.LoginFunc, errorURL url.URL) return } + // Override the email claim by using the value of the specified claim. + // This is used for the provider (e.g., Azure AD) which returns + // the ID token that does not include a email claim. + if c.emailClaim != "" && c.emailClaim != defaultEmailClaim { + email, ok, err := claims.StringClaim(c.emailClaim) + if err != nil { + log.Errorf("Unable to get value of alternative email claim: %v", err) + q.Set("error", oauth2.ErrorUnsupportedResponseType) + q.Set("error_description", "unable to get value of alternative email claim") + redirectError(w, errorURL, q) + return + } + + if !ok { + log.Errorf("Failed parsing alternative email claim from remote provider: %v", err) + q.Set("error", oauth2.ErrorUnsupportedResponseType) + q.Set("error_description", "failed parsing alternative email claim") + redirectError(w, errorURL, q) + return + } + + claims.Add(defaultEmailClaim, email) + } + ident, err := oidc.IdentityFromClaims(claims) if err != nil { log.Errorf("Failed parsing claims from remote provider: %v", err) diff --git a/integration/admin_api_test.go b/integration/admin_api_test.go index 26fd3b8d..5ecb3aaa 100644 --- a/integration/admin_api_test.go +++ b/integration/admin_api_test.go @@ -337,6 +337,7 @@ func TestConnectors(t *testing.T) { "clientID": "foo", "clientSecret": "bar", "trustedEmailProvider": true, + "emailClaim": "", }, }, }, @@ -353,6 +354,7 @@ func TestConnectors(t *testing.T) { "clientID": "foo", "clientSecret": "bar", "trustedEmailProvider": true, + "emailClaim": "", }, }, },