From 52d09a2dfa9707256a922ee90a5f0fec63b761ae Mon Sep 17 00:00:00 2001 From: Thomas Jackson Date: Wed, 24 Apr 2019 13:58:35 -0700 Subject: [PATCH] Add option in oidc to hit the optional userinfo endpoint Some oauth providers return "thin tokens" which won't include all of the claims requested. This simply adds an option which will make the oidc connector use the userinfo endpoint to fetch all the claims. --- Documentation/connectors/oidc.md | 6 ++++++ connector/oidc/oidc.go | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/Documentation/connectors/oidc.md b/Documentation/connectors/oidc.md index 559c0f8c..0f110332 100644 --- a/Documentation/connectors/oidc.md +++ b/Documentation/connectors/oidc.md @@ -60,6 +60,12 @@ connectors: # or if they are acting as a proxy for another IDP etc AWS Cognito with an upstream SAML IDP # This can be overridden with the below option # insecureSkipEmailVerified: true + + # When enabled, the OpenID Connector will query the UserInfo endpoint for additional claims. UserInfo claims + # take priority over claims returned by the IDToken. This option should be used when the IDToken doesn't contain + # all the claims requested. + # https://openid.net/specs/openid-connect-core-1_0.html#UserInfo + # getUserInfo: true ``` [oidc-doc]: openid-connect.md diff --git a/connector/oidc/oidc.go b/connector/oidc/oidc.go index 65f877ee..24d8103e 100644 --- a/connector/oidc/oidc.go +++ b/connector/oidc/oidc.go @@ -39,6 +39,11 @@ type Config struct { // Override the value of email_verifed to true in the returned claims InsecureSkipEmailVerified bool `json:"insecureSkipEmailVerified"` + + // GetUserInfo uses the userinfo endpoint to get additional claims for + // the token. This is especially useful where upstreams return "thin" + // id tokens + GetUserInfo bool `json:"getUserInfo"` } // Domains that don't support basic auth. golang.org/x/oauth2 has an internal @@ -105,6 +110,7 @@ func (c *Config) Open(id string, logger log.Logger) (conn connector.Connector, e clientID := c.ClientID return &oidcConnector{ + provider: provider, redirectURI: c.RedirectURI, oauth2Config: &oauth2.Config{ ClientID: clientID, @@ -120,6 +126,7 @@ func (c *Config) Open(id string, logger log.Logger) (conn connector.Connector, e cancel: cancel, hostedDomains: c.HostedDomains, insecureSkipEmailVerified: c.InsecureSkipEmailVerified, + getUserInfo: c.GetUserInfo, }, nil } @@ -129,6 +136,7 @@ var ( ) type oidcConnector struct { + provider *oidc.Provider redirectURI string oauth2Config *oauth2.Config verifier *oidc.IDTokenVerifier @@ -137,6 +145,7 @@ type oidcConnector struct { logger log.Logger hostedDomains []string insecureSkipEmailVerified bool + getUserInfo bool } func (c *oidcConnector) Close() error { @@ -219,6 +228,16 @@ func (c *oidcConnector) HandleCallback(s connector.Scopes, r *http.Request) (ide } + if c.getUserInfo { + userInfo, err := c.provider.UserInfo(r.Context(), oauth2.StaticTokenSource(token)) + if err != nil { + return identity, fmt.Errorf("oidc: error loading userinfo: %v", err) + } + if err := userInfo.Claims(&claims); err != nil { + return identity, fmt.Errorf("oidc: failed to decode userinfo claims: %v", err) + } + } + identity = connector.Identity{ UserID: idToken.Subject, Username: claims.Username,