-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Added OIDC support for UserInfo Endpoint Email Verification #481
base: master
Are you sure you want to change the base?
Conversation
Hi @jehiah @ericchiang, I noticed that the two of you were responsible for adding the most recent OIDC provider. I was hoping for feedback on this patch which was required to make the OIDC provider work for me. I'm new to OIDC/oauth, so feedback is appreciated. Thanks! |
5f42379
to
4f82de3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UserInfo endpoint is optional.[1] Not all providers support it. Why not get the email from the id_token?
[1] https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata
providers/provider_default.go
Outdated
return a.String() | ||
|
||
// Default golang libs Encode space( ) as plus (+) instead of '%20' | ||
// which is more proper. Some OpenID servers do not accept this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which providers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm integrating with the Ping Federate OIDC provider. For some reason, their API is not lenient on this. It'll totally fail with '+' as space. It's totally a purist golang library encoding thing. Check out golang/go#4013
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding the Email from JWT claims...
I would have preferred JWT, which would have worked with less code, but I don't have access to the Ping Federate admin panel to enable the extensions that set the openid claims in the JWT token. The documentation for the Ping Federate provider is here.
Regardless, I think the OIDC spec allows for email to be returned in either JWT claims OR the UserInfo endpoint. The code changes involving the UserInfo endpoint follow the same pattern as the LinkedIn, Gitlab, and Azure providers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to remove the rewriting the "+" signs in the next commit. I'll put that in a separate PR as a command line option, in hopes of increasing the chances of this PR getting merged.
4f82de3
to
e17f3e3
Compare
Adding this comment hidden by code updates... I think the OIDC spec allows for email to be returned in either JWT claims OR the UserInfo endpoint. The code changes involving the UserInfo endpoint follow the same pattern as the LinkedIn, Gitlab, and Azure providers. It first searches JWT token for the email. If it cannot find it in the JWT token, it falls back to searching the UserInfo endpoint. |
providers/oidc.go
Outdated
if s.AccessToken == "" { | ||
return "", errors.New("missing access token") | ||
} | ||
req, err := http.NewRequest("GET", p.ProfileURL.String(), nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is ProfileURL set? I would have expected this to use the discovery endpoint https://accounts.google.com/.well-known/openid-configuration
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently, the profile_url is hard-coded in each provider.
Facebook: https://github.com/bitly/oauth2_proxy/blob/master/providers/facebook.go#L32
Azure: https://github.com/bitly/oauth2_proxy/blob/master/providers/azure.go#L22
LinkedIn: https://github.com/bitly/oauth2_proxy/blob/master/providers/linkedin.go#L29
For the OIDC provider in its current state (before I submitted this PR... I left it untouched), the profile_url is untouched. In fact, it defaults to empty (""). I feed it in currently through the command line option:
-profile-url string
Profile access endpoint
providers/oidc.go
Outdated
@@ -57,10 +62,10 @@ func (p *OIDCProvider) Redeem(redirectURL, code string) (s *SessionState, err er | |||
} | |||
|
|||
if claims.Email == "" { | |||
return nil, fmt.Errorf("id_token did not contain an email") | |||
log.Printf("id_token did not contain an email. Falling back on userinfo endpoint\n") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perform the request to the user info endpoint here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay. I have no problem changing it.
I think google does it the way that you're suggeting, but they have full control over where email shows up. It will show up only in the token and no other way (as in no userinfo endpoint).
The other providers don't seem to check email in their Redeem functions. They rely on the Redeem function not returning an email, and then common oauthproxy.go:redeemCode function to notice and then hit the UserInfo endpoint.
I kind of think both places are equivalent, and I'm happy to change it if you prefer it here. Let me know your preference (after this additional information), and I can change it on Monday.
Thanks @ericchiang , for the review!
* Current OIDC implementation asserts that user email check must come from JWT token claims. OIDC specification also allows for source of user email to be fetched from userinfo profile endpoint. http://openid.net/specs/openid-connect-core-1_0.html#UserInfo * Modified current code to search for email in JWT token claims first, and then fall back to requesting email from userinfo endpoint. * Modified URL encoding to use '%20' instead of '+' for encoding spaces, which is more proper. Some OpenID servers do not accept '+' encoding for the http query arg "scope" (e.g. bad: "openid+profile+email" good: "openid%20profilie%20email")
* The change was requested by @ericchiang in the pull request comments to PR481.
e277b66
to
eb5b18e
Compare
Hi All, I'd still like to get this pull request in. I've made the changes that @ericchiang had requested. Sorry it took a few months. This PR has been rebased on the latest code. -dave |
Hi @jehiah @ericchiang, Would you mind having a look to review? Thanks! |
@ericchiang I made the changes you've requested. Would you mind reviewing? |
Hello @jehiah @ericchiang, This does resolve my issue: Thanks |
@mbland and I do not have permissions to merge in this repo, sorry |
Current OIDC implementation asserts that user email check must come
from JWT token claims. OIDC specification also allows for source
of user email to be fetched from userinfo profile endpoint.
http://openid.net/specs/openid-connect-core-1_0.html#UserInfo
Modified current code to search for email in JWT token claims
first, and then fall back to requesting email from userinfo
endpoint.