git.iko.soy/typeable/oauth2-proxy
on master help sign in
Add OIDC support for UserInfo Endpoint Email Verification

* 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 * First, attempt to retrieve email from JWT token claims. Then fall back to requesting email from userinfo endpoint. * Don't fallback to subject for email https://github.com/bitly/oauth2_proxy/pull/481

commit2eecf756e43a2d77e489d41251af4ab2f419aa06 authorRyan Luckie <rluckie@cisco.com> dateFri 3 May 2019, 17:33 (7 years ago) parent8635391
1 file changed+36−2
providers/oidc.go+36−2
providers/oidc.go+36−2
@@ -3,11 +3,15 @@ package providers
33import (
44 "context"
55 "fmt"
6+ "net/http"
67 "time"
78
89 oidc "github.com/coreos/go-oidc"
910 "github.com/pusher/oauth2_proxy/pkg/apis/sessions"
11+ "github.com/pusher/oauth2_proxy/pkg/requests"
12+
1013 "golang.org/x/oauth2"
14+
1115)
1216
1317// OIDCProvider represents an OIDC based Identity Provider
@@ -117,8 +121,31 @@ func (p *OIDCProvider) createSessionState(ctx context.Context, token *oauth2.Tok
117121 }
118122
119123 if claims.Email == "" {
120− // TODO: Try getting email from /userinfo before falling back to Subject
121− claims.Email = claims.Subject
124+ if p.ProfileURL.String() == "" {
125+ return nil, fmt.Errorf("id_token did not contain an email")
126+ }
127+
128+ // If the userinfo endpoint profileURL is defined, then there is a chance the userinfo
129+ // contents at the profileURL contains the email.
130+ // Make a query to the userinfo endpoint, and attempt to locate the email from there.
131+
132+ req, err := http.NewRequest("GET", p.ProfileURL.String(), nil)
133+ if err != nil {
134+ return nil, err
135+ }
136+ req.Header = getOIDCHeader(token.AccessToken)
137+
138+ json, err := requests.Request(req)
139+ if err != nil {
140+ return nil, err
141+ }
142+
143+ email, err := json.Get("email").String()
144+ if err != nil {
145+ return nil, fmt.Errorf("id_token nor userinfo endpoint did not contain an email")
146+ }
147+
148+ claims.Email = email
122149 }
123150 if !p.AllowUnverifiedEmail && claims.Verified != nil && !*claims.Verified {
124151 return nil, fmt.Errorf("email in id_token (%s) isn't verified", claims.Email)
@@ -145,3 +172,10 @@ func (p *OIDCProvider) ValidateSessionState(s *sessions.SessionState) bool {
145172
146173 return true
147174}
175+
176+func getOIDCHeader(access_token string) http.Header {
177+ header := make(http.Header)
178+ header.Set("Accept", "application/json")
179+ header.Set("Authorization", fmt.Sprintf("Bearer %s", access_token))
180+ return header
181+}