git.iko.soy/typeable/oauth2-proxy
on master help sign in
Generalize and extend default CreateSessionFromToken
commit22f60e9b63e54e8a0fc6b625280f05159b5560a5 authorNick Meves <nick.meves@greenhouse.io> dateSun 15 Nov 2020, 18:57 (6 years ago) parent44fa831
10 files changed+148−209
oauthproxy.go+49−63 pkg/apis/middleware/session.go+46−14 pkg/middleware/jwt_session.go+3−59 pkg/middleware/jwt_session_test.go+29−38 pkg/validation/options.go+5−6 providers/oidc.go+2−9 providers/oidc_test.go+7−17 providers/provider_data.go+2 providers/provider_default.go+4−1 providers/providers.go+1−2
oauthproxy.go+49−63
@@ -13,7 +13,6 @@ import (
1313 "strings"
1414 "time"
1515
16− "github.com/coreos/go-oidc"
1716 "github.com/justinas/alice"
1817 ipapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/ip"
1918 middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
@@ -78,36 +77,34 @@ type OAuthProxy struct {
7877 AuthOnlyPath string
7978 UserInfoPath string
8079
81− allowedRoutes []allowedRoute
82− redirectURL *url.URL // the url to receive requests at
83− whitelistDomains []string
84− provider providers.Provider
85− providerNameOverride string
86− sessionStore sessionsapi.SessionStore
87− ProxyPrefix string
88− SignInMessage string
89− basicAuthValidator basic.Validator
90− displayHtpasswdForm bool
91− serveMux http.Handler
92− SetXAuthRequest bool
93− PassBasicAuth bool
94− SetBasicAuth bool
95− SkipProviderButton bool
96− PassUserHeaders bool
97− BasicAuthPassword string
98− PassAccessToken bool
99− SetAuthorization bool
100− PassAuthorization bool
101− PreferEmailToUser bool
102− skipAuthPreflight bool
103− skipJwtBearerTokens bool
104− mainJwtBearerVerifier *oidc.IDTokenVerifier
105− extraJwtBearerVerifiers []*oidc.IDTokenVerifier
106− templates *template.Template
107− realClientIPParser ipapi.RealClientIPParser
108− trustedIPs *ip.NetSet
109− Banner string
110− Footer string
80+ allowedRoutes []allowedRoute
81+ redirectURL *url.URL // the url to receive requests at
82+ whitelistDomains []string
83+ provider providers.Provider
84+ providerNameOverride string
85+ sessionStore sessionsapi.SessionStore
86+ ProxyPrefix string
87+ SignInMessage string
88+ basicAuthValidator basic.Validator
89+ displayHtpasswdForm bool
90+ serveMux http.Handler
91+ SetXAuthRequest bool
92+ PassBasicAuth bool
93+ SetBasicAuth bool
94+ SkipProviderButton bool
95+ PassUserHeaders bool
96+ BasicAuthPassword string
97+ PassAccessToken bool
98+ SetAuthorization bool
99+ PassAuthorization bool
100+ PreferEmailToUser bool
101+ skipAuthPreflight bool
102+ skipJwtBearerTokens bool
103+ templates *template.Template
104+ realClientIPParser ipapi.RealClientIPParser
105+ trustedIPs *ip.NetSet
106+ Banner string
107+ Footer string
111108
112109 sessionChain alice.Chain
113110 headersChain alice.Chain
@@ -202,25 +199,23 @@ func NewOAuthProxy(opts *options.Options, validator func(string) bool) (*OAuthPr
202199 AuthOnlyPath: fmt.Sprintf("%s/auth", opts.ProxyPrefix),
203200 UserInfoPath: fmt.Sprintf("%s/userinfo", opts.ProxyPrefix),
204201
205− ProxyPrefix: opts.ProxyPrefix,
206− provider: opts.GetProvider(),
207− providerNameOverride: opts.ProviderName,
208− sessionStore: sessionStore,
209− serveMux: upstreamProxy,
210− redirectURL: redirectURL,
211− allowedRoutes: allowedRoutes,
212− whitelistDomains: opts.WhitelistDomains,
213− skipAuthPreflight: opts.SkipAuthPreflight,
214− skipJwtBearerTokens: opts.SkipJwtBearerTokens,
215− mainJwtBearerVerifier: opts.GetOIDCVerifier(),
216− extraJwtBearerVerifiers: opts.GetJWTBearerVerifiers(),
217− realClientIPParser: opts.GetRealClientIPParser(),
218− SkipProviderButton: opts.SkipProviderButton,
219− templates: templates,
220− trustedIPs: trustedIPs,
221− Banner: opts.Banner,
222− Footer: opts.Footer,
223− SignInMessage: buildSignInMessage(opts),
202+ ProxyPrefix: opts.ProxyPrefix,
203+ provider: opts.GetProvider(),
204+ providerNameOverride: opts.ProviderName,
205+ sessionStore: sessionStore,
206+ serveMux: upstreamProxy,
207+ redirectURL: redirectURL,
208+ allowedRoutes: allowedRoutes,
209+ whitelistDomains: opts.WhitelistDomains,
210+ skipAuthPreflight: opts.SkipAuthPreflight,
211+ skipJwtBearerTokens: opts.SkipJwtBearerTokens,
212+ realClientIPParser: opts.GetRealClientIPParser(),
213+ SkipProviderButton: opts.SkipProviderButton,
214+ templates: templates,
215+ trustedIPs: trustedIPs,
216+ Banner: opts.Banner,
217+ Footer: opts.Footer,
218+ SignInMessage: buildSignInMessage(opts),
224219
225220 basicAuthValidator: basicAuthValidator,
226221 displayHtpasswdForm: basicAuthValidator != nil && opts.DisplayHtpasswdForm,
@@ -266,22 +261,13 @@ func buildSessionChain(opts *options.Options, sessionStore sessionsapi.SessionSt
266261 chain := alice.New()
267262
268263 if opts.SkipJwtBearerTokens {
269− sessionLoaders := []middlewareapi.TokenToSessionLoader{}
270− if opts.GetOIDCVerifier() != nil {
271− sessionLoaders = append(sessionLoaders, middlewareapi.TokenToSessionLoader{
272− Verifier: func(ctx context.Context, token string) (interface{}, error) {
273− return opts.GetOIDCVerifier().Verify(ctx, token)
274− },
275− TokenToSession: opts.GetProvider().CreateSessionFromToken,
276− })
264+ sessionLoaders := []middlewareapi.TokenToSessionFunc{
265+ opts.GetProvider().CreateSessionFromToken,
277266 }
278267
279268 for _, verifier := range opts.GetJWTBearerVerifiers() {
280− sessionLoaders = append(sessionLoaders, middlewareapi.TokenToSessionLoader{
281− Verifier: func(ctx context.Context, token string) (interface{}, error) {
282− return verifier.Verify(ctx, token)
283− },
284− })
269+ sessionLoaders = append(sessionLoaders,
270+ middlewareapi.CreateTokenToSessionFunc(verifier.Verify))
285271 }
286272
287273 chain = chain.Append(middleware.NewJwtSessionLoader(sessionLoaders))
pkg/apis/middleware/session.go+46−14
@@ -2,25 +2,57 @@ package middleware
22
33import (
44 "context"
5+ "fmt"
56
7+ "github.com/coreos/go-oidc"
68 sessionsapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
79)
810
9−// TokenToSessionFunc takes a rawIDToken and an idToken and converts it into a
10−// SessionState.
11−type TokenToSessionFunc func(ctx context.Context, token string, verify VerifyFunc) (*sessionsapi.SessionState, error)
11+// TokenToSessionFunc takes a raw ID Token and converts it into a SessionState.
12+type TokenToSessionFunc func(ctx context.Context, token string) (*sessionsapi.SessionState, error)
1213
13−// VerifyFunc takes a raw bearer token and verifies it
14−type VerifyFunc func(ctx context.Context, token string) (interface{}, error)
14+// VerifyFunc takes a raw bearer token and verifies it returning the converted
15+// oidc.IDToken representation of the token.
16+type VerifyFunc func(ctx context.Context, token string) (*oidc.IDToken, error)
1517
16−// TokenToSessionLoader pairs a token verifier with the correct converter function
17−// to convert the ID Token to a SessionState.
18−type TokenToSessionLoader struct {
19− // Verifier is used to verify that the ID Token was signed by the claimed issuer
20− // and that the token has not been tampered with.
21− Verifier VerifyFunc
18+// CreateTokenToSessionFunc provides a handler that is a default implementation
19+// for converting a JWT into a session.
20+func CreateTokenToSessionFunc(verify VerifyFunc) TokenToSessionFunc {
21+ return func(ctx context.Context, token string) (*sessionsapi.SessionState, error) {
22+ var claims struct {
23+ Subject string `json:"sub"`
24+ Email string `json:"email"`
25+ Verified *bool `json:"email_verified"`
26+ PreferredUsername string `json:"preferred_username"`
27+ }
2228
23− // TokenToSession converts a raw bearer token to a SessionState.
24− // (Optional) If not set a default basic implementation is used.
25− TokenToSession TokenToSessionFunc
29+ idToken, err := verify(ctx, token)
30+ if err != nil {
31+ return nil, err
32+ }
33+
34+ if err := idToken.Claims(&claims); err != nil {
35+ return nil, fmt.Errorf("failed to parse bearer token claims: %v", err)
36+ }
37+
38+ if claims.Email == "" {
39+ claims.Email = claims.Subject
40+ }
41+
42+ if claims.Verified != nil && !*claims.Verified {
43+ return nil, fmt.Errorf("email in id_token (%s) isn't verified", claims.Email)
44+ }
45+
46+ newSession := &sessionsapi.SessionState{
47+ Email: claims.Email,
48+ User: claims.Subject,
49+ PreferredUsername: claims.PreferredUsername,
50+ AccessToken: token,
51+ IDToken: token,
52+ RefreshToken: "",
53+ ExpiresOn: &idToken.Expiry,
54+ }
55+
56+ return newSession, nil
57+ }
2658}
pkg/middleware/jwt_session.go+3−59
@@ -1,12 +1,10 @@
11package middleware
22
33import (
4− "context"
54 "fmt"
65 "net/http"
76 "regexp"
87
9− "github.com/coreos/go-oidc"
108 "github.com/justinas/alice"
119 middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
1210 sessionsapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
@@ -16,16 +14,7 @@ import (
1614
1715const jwtRegexFormat = `^ey[IJ][a-zA-Z0-9_-]*\.ey[IJ][a-zA-Z0-9_-]*\.[a-zA-Z0-9_-]+$`
1816
19−func NewJwtSessionLoader(sessionLoaders []middlewareapi.TokenToSessionLoader) alice.Constructor {
20− for i, loader := range sessionLoaders {
21− if loader.TokenToSession == nil {
22− sessionLoaders[i] = middlewareapi.TokenToSessionLoader{
23− Verifier: loader.Verifier,
24− TokenToSession: createSessionFromToken,
25− }
26− }
27− }
28−
17+func NewJwtSessionLoader(sessionLoaders []middlewareapi.TokenToSessionFunc) alice.Constructor {
2918 js := &jwtSessionLoader{
3019 jwtRegex: regexp.MustCompile(jwtRegexFormat),
3120 sessionLoaders: sessionLoaders,
@@ -37,7 +26,7 @@ func NewJwtSessionLoader(sessionLoaders []middlewareapi.TokenToSessionLoader) al
3726// Authorization headers.
3827type jwtSessionLoader struct {
3928 jwtRegex *regexp.Regexp
40− sessionLoaders []middlewareapi.TokenToSessionLoader
29+ sessionLoaders []middlewareapi.TokenToSessionFunc
4130}
4231
4332// loadSession attempts to load a session from a JWT stored in an Authorization
@@ -83,7 +72,7 @@ func (j *jwtSessionLoader) getJwtSession(req *http.Request) (*sessionsapi.Sessio
8372
8473 errs := []error{fmt.Errorf("unable to verify jwt token: %q", req.Header.Get("Authorization"))}
8574 for _, loader := range j.sessionLoaders {
86− session, err := loader.TokenToSession(req.Context(), token, loader.Verifier)
75+ session, err := loader(req.Context(), token)
8776 if err == nil {
8877 return session, nil
8978 } else {
@@ -135,48 +124,3 @@ func (j *jwtSessionLoader) getBasicToken(token string) (string, error) {
135124
136125 return "", fmt.Errorf("invalid basic auth token found in authorization header")
137126}
138−
139−// createSessionFromToken is a default implementation for converting
140−// a JWT into a session state.
141−func createSessionFromToken(ctx context.Context, token string, verify middlewareapi.VerifyFunc) (*sessionsapi.SessionState, error) {
142− var claims struct {
143− Subject string `json:"sub"`
144− Email string `json:"email"`
145− Verified *bool `json:"email_verified"`
146− PreferredUsername string `json:"preferred_username"`
147− }
148−
149− verifiedToken, err := verify(ctx, token)
150− if err != nil {
151− return nil, err
152− }
153−
154− idToken, ok := verifiedToken.(*oidc.IDToken)
155− if !ok {
156− return nil, fmt.Errorf("failed to create IDToken from bearer token: %s", token)
157− }
158−
159− if err := idToken.Claims(&claims); err != nil {
160− return nil, fmt.Errorf("failed to parse bearer token claims: %v", err)
161− }
162−
163− if claims.Email == "" {
164− claims.Email = claims.Subject
165− }
166−
167− if claims.Verified != nil && !*claims.Verified {
168− return nil, fmt.Errorf("email in id_token (%s) isn't verified", claims.Email)
169− }
170−
171− newSession := &sessionsapi.SessionState{
172− Email: claims.Email,
173− User: claims.Subject,
174− PreferredUsername: claims.PreferredUsername,
175− AccessToken: token,
176− IDToken: token,
177− RefreshToken: "",
178− ExpiresOn: &idToken.Expiry,
179− }
180−
181− return newSession, nil
182−}
pkg/middleware/jwt_session_test.go+29−38
@@ -26,7 +26,7 @@ import (
2626type noOpKeySet struct {
2727}
2828
29−func (noOpKeySet) VerifySignature(ctx context.Context, jwt string) (payload []byte, err error) {
29+func (noOpKeySet) VerifySignature(_ context.Context, jwt string) (payload []byte, err error) {
3030 splitStrings := strings.Split(jwt, ".")
3131 payloadString := splitStrings[1]
3232 return base64.RawURLEncoding.DecodeString(payloadString)
@@ -78,16 +78,14 @@ Nnc3a3lGVWFCNUMxQnNJcnJMTWxka1dFaHluYmI4Ongtb2F1dGgtYmFzaWM=`
7878 const nonVerifiedToken = validToken
7979
8080 BeforeEach(func() {
81− verifier = func(ctx context.Context, token string) (interface{}, error) {
82− return oidc.NewVerifier(
83− "https://issuer.example.com",
84− noOpKeySet{},
85− &oidc.Config{
86− ClientID: "https://test.myapp.com",
87− SkipExpiryCheck: true,
88− },
89− ).Verify(ctx, token)
90− }
81+ verifier = oidc.NewVerifier(
82+ "https://issuer.example.com",
83+ noOpKeySet{},
84+ &oidc.Config{
85+ ClientID: "https://test.myapp.com",
86+ SkipExpiryCheck: true,
87+ },
88+ ).Verify
9189 })
9290
9391 type jwtSessionLoaderTableInput struct {
@@ -110,10 +108,8 @@ Nnc3a3lGVWFCNUMxQnNJcnJMTWxka1dFaHluYmI4Ongtb2F1dGgtYmFzaWM=`
110108
111109 rw := httptest.NewRecorder()
112110
113− sessionLoaders := []middlewareapi.TokenToSessionLoader{
114− {
115− Verifier: verifier,
116− },
111+ sessionLoaders := []middlewareapi.TokenToSessionFunc{
112+ middlewareapi.CreateTokenToSessionFunc(verifier),
117113 }
118114
119115 // Create the handler with a next handler that will capture the session
@@ -175,24 +171,19 @@ Nnc3a3lGVWFCNUMxQnNJcnJMTWxka1dFaHluYmI4Ongtb2F1dGgtYmFzaWM=`
175171 const nonVerifiedToken = validToken
176172
177173 BeforeEach(func() {
178− verifier := func(ctx context.Context, token string) (interface{}, error) {
179− return oidc.NewVerifier(
180− "https://issuer.example.com",
181− noOpKeySet{},
182− &oidc.Config{
183− ClientID: "https://test.myapp.com",
184− SkipExpiryCheck: true,
185− },
186− ).Verify(ctx, token)
187− }
174+ verifier := oidc.NewVerifier(
175+ "https://issuer.example.com",
176+ noOpKeySet{},
177+ &oidc.Config{
178+ ClientID: "https://test.myapp.com",
179+ SkipExpiryCheck: true,
180+ },
181+ ).Verify
188182
189183 j = &jwtSessionLoader{
190184 jwtRegex: regexp.MustCompile(jwtRegexFormat),
191− sessionLoaders: []middlewareapi.TokenToSessionLoader{
192− {
193− Verifier: verifier,
194− TokenToSession: createSessionFromToken,
195− },
185+ sessionLoaders: []middlewareapi.TokenToSessionFunc{
186+ middlewareapi.CreateTokenToSessionFunc(verifier),
196187 },
197188 }
198189 })
@@ -402,7 +393,7 @@ Nnc3a3lGVWFCNUMxQnNJcnJMTWxka1dFaHluYmI4Ongtb2F1dGgtYmFzaWM=`
402393 )
403394 })
404395
405− Context("createSessionFromToken", func() {
396+ Context("CreateTokenToSessionFunc", func() {
406397 ctx := context.Background()
407398 expiresFuture := time.Now().Add(time.Duration(5) * time.Minute)
408399 verified := true
@@ -414,7 +405,7 @@ Nnc3a3lGVWFCNUMxQnNJcnJMTWxka1dFaHluYmI4Ongtb2F1dGgtYmFzaWM=`
414405 jwt.StandardClaims
415406 }
416407
417− type createSessionStateTableInput struct {
408+ type tokenToSessionTableInput struct {
418409 idToken idTokenClaims
419410 expectedErr error
420411 expectedUser string
@@ -423,8 +414,8 @@ Nnc3a3lGVWFCNUMxQnNJcnJMTWxka1dFaHluYmI4Ongtb2F1dGgtYmFzaWM=`
423414 }
424415
425416 DescribeTable("when creating a session from an IDToken",
426− func(in createSessionStateTableInput) {
427− verifier := func(ctx context.Context, token string) (interface{}, error) {
417+ func(in tokenToSessionTableInput) {
418+ verifier := func(ctx context.Context, token string) (*oidc.IDToken, error) {
428419 oidcVerifier := oidc.NewVerifier(
429420 "https://issuer.example.com",
430421 noOpKeySet{},
@@ -443,7 +434,7 @@ Nnc3a3lGVWFCNUMxQnNJcnJMTWxka1dFaHluYmI4Ongtb2F1dGgtYmFzaWM=`
443434 rawIDToken, err := jwt.NewWithClaims(jwt.SigningMethodRS256, in.idToken).SignedString(key)
444435 Expect(err).ToNot(HaveOccurred())
445436
446− session, err := createSessionFromToken(ctx, rawIDToken, verifier)
437+ session, err := middlewareapi.CreateTokenToSessionFunc(verifier)(ctx, rawIDToken)
447438 if in.expectedErr != nil {
448439 Expect(err).To(MatchError(in.expectedErr))
449440 Expect(session).To(BeNil())
@@ -459,7 +450,7 @@ Nnc3a3lGVWFCNUMxQnNJcnJMTWxka1dFaHluYmI4Ongtb2F1dGgtYmFzaWM=`
459450 Expect(session.RefreshToken).To(BeEmpty())
460451 Expect(session.PreferredUsername).To(BeEmpty())
461452 },
462− Entry("with no email", createSessionStateTableInput{
453+ Entry("with no email", tokenToSessionTableInput{
463454 idToken: idTokenClaims{
464455 StandardClaims: jwt.StandardClaims{
465456 Audience: "asdf1234",
@@ -476,7 +467,7 @@ Nnc3a3lGVWFCNUMxQnNJcnJMTWxka1dFaHluYmI4Ongtb2F1dGgtYmFzaWM=`
476467 expectedEmail: "123456789",
477468 expectedExpires: &expiresFuture,
478469 }),
479− Entry("with a verified email", createSessionStateTableInput{
470+ Entry("with a verified email", tokenToSessionTableInput{
480471 idToken: idTokenClaims{
481472 StandardClaims: jwt.StandardClaims{
482473 Audience: "asdf1234",
@@ -495,7 +486,7 @@ Nnc3a3lGVWFCNUMxQnNJcnJMTWxka1dFaHluYmI4Ongtb2F1dGgtYmFzaWM=`
495486 expectedEmail: "foo@example.com",
496487 expectedExpires: &expiresFuture,
497488 }),
498− Entry("with a non-verified email", createSessionStateTableInput{
489+ Entry("with a non-verified email", tokenToSessionTableInput{
499490 idToken: idTokenClaims{
500491 StandardClaims: jwt.StandardClaims{
501492 Audience: "asdf1234",
pkg/validation/options.go+5−6
@@ -233,6 +233,9 @@ func parseProviderInfo(o *options.Options, msgs []string) []string {
233233 p.ValidateURL, msgs = parseURL(o.ValidateURL, "validate", msgs)
234234 p.ProtectedResource, msgs = parseURL(o.ProtectedResource, "resource", msgs)
235235
236+ // Make the OIDC Verifier accessible to all providers that can support it
237+ p.Verifier = o.GetOIDCVerifier()
238+
236239 p.SetAllowedGroups(o.AllowedGroups)
237240
238241 provider := providers.New(o.ProviderType, p)
@@ -273,18 +276,14 @@ func parseProviderInfo(o *options.Options, msgs []string) []string {
273276 p.AllowUnverifiedEmail = o.InsecureOIDCAllowUnverifiedEmail
274277 p.UserIDClaim = o.UserIDClaim
275278 p.GroupsClaim = o.OIDCGroupsClaim
276− if o.GetOIDCVerifier() == nil {
279+ if p.Verifier == nil {
277280 msgs = append(msgs, "oidc provider requires an oidc issuer URL")
278− } else {
279− p.Verifier = o.GetOIDCVerifier()
280281 }
281282 case *providers.GitLabProvider:
282283 p.AllowUnverifiedEmail = o.InsecureOIDCAllowUnverifiedEmail
283284 p.Groups = o.GitLabGroup
284285
285− if o.GetOIDCVerifier() != nil {
286− p.Verifier = o.GetOIDCVerifier()
287− } else {
286+ if p.Verifier == nil {
288287 // Initialize with default verifier for gitlab.com
289288 ctx := context.Background()
290289
providers/oidc.go+2−9
@@ -11,7 +11,6 @@ import (
1111 oidc "github.com/coreos/go-oidc"
1212 "golang.org/x/oauth2"
1313
14− "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
1514 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
1615 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
1716 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests"
@@ -23,7 +22,6 @@ const emailClaim = "email"
2322type OIDCProvider struct {
2423 *ProviderData
2524
26− Verifier *oidc.IDTokenVerifier
2725 AllowUnverifiedEmail bool
2826 UserIDClaim string
2927 GroupsClaim string
@@ -176,17 +174,12 @@ func (p *OIDCProvider) createSessionState(ctx context.Context, token *oauth2.Tok
176174 return newSession, nil
177175}
178176
179−func (p *OIDCProvider) CreateSessionFromToken(ctx context.Context, token string, verify middleware.VerifyFunc) (*sessions.SessionState, error) {
180− verifiedToken, err := verify(ctx, token)
177+func (p *OIDCProvider) CreateSessionFromToken(ctx context.Context, token string) (*sessions.SessionState, error) {
178+ idToken, err := p.Verifier.Verify(ctx, token)
181179 if err != nil {
182180 return nil, err
183181 }
184182
185− idToken, ok := verifiedToken.(*oidc.IDToken)
186− if !ok {
187− return nil, fmt.Errorf("failed to create IDToken from bearer token: %s", token)
188− }
189−
190183 newSession, err := p.createSessionStateInternal(ctx, idToken, nil)
191184 if err != nil {
192185 return nil, err
providers/oidc_test.go+7−17
@@ -144,16 +144,17 @@ func newOIDCProvider(serverURL *url.URL) *OIDCProvider {
144144 Scheme: serverURL.Scheme,
145145 Host: serverURL.Host,
146146 Path: "/api"},
147− Scope: "openid profile offline_access"}
148−
149− p := &OIDCProvider{
150− ProviderData: providerData,
147+ Scope: "openid profile offline_access",
151148 Verifier: oidc.NewVerifier(
152149 "https://issuer.example.com",
153150 fakeKeySetStub{},
154151 &oidc.Config{ClientID: clientID},
155152 ),
156− UserIDClaim: "email",
153+ }
154+
155+ p := &OIDCProvider{
156+ ProviderData: providerData,
157+ UserIDClaim: "email",
157158 }
158159
159160 return p
@@ -347,18 +348,7 @@ func TestCreateSessionStateFromBearerToken(t *testing.T) {
347348 rawIDToken, err := newSignedTestIDToken(tc.IDToken)
348349 assert.NoError(t, err)
349350
350− verifyFunc := func(ctx context.Context, token string) (interface{}, error) {
351− keyset := fakeKeySetStub{}
352− verifier := oidc.NewVerifier("https://issuer.example.com", keyset,
353− &oidc.Config{ClientID: "https://test.myapp.com", SkipExpiryCheck: true})
354−
355− idToken, err := verifier.Verify(ctx, token)
356− assert.NoError(t, err)
357−
358− return idToken, nil
359− }
360−
361− ss, err := provider.CreateSessionFromToken(context.Background(), rawIDToken, verifyFunc)
351+ ss, err := provider.CreateSessionFromToken(context.Background(), rawIDToken)
362352 assert.NoError(t, err)
363353
364354 assert.Equal(t, tc.ExpectedUser, ss.User)
providers/provider_data.go+2
@@ -5,6 +5,7 @@ import (
55 "io/ioutil"
66 "net/url"
77
8+ "github.com/coreos/go-oidc"
89 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
910)
1011
@@ -26,6 +27,7 @@ type ProviderData struct {
2627 ClientSecretFile string
2728 Scope string
2829 Prompt string
30+ Verifier *oidc.IDTokenVerifier
2931
3032 // Universal Group authorization data structure
3133 // any provider can set to consume
providers/provider_default.go+4−1
@@ -126,6 +126,9 @@ func (p *ProviderData) RefreshSessionIfNeeded(_ context.Context, _ *sessions.Ses
126126
127127// CreateSessionStateFromBearerToken should be implemented to allow providers
128128// to convert ID tokens into sessions
129−func (p *ProviderData) CreateSessionFromToken(_ context.Context, _ string, _ middleware.VerifyFunc) (*sessions.SessionState, error) {
129+func (p *ProviderData) CreateSessionFromToken(ctx context.Context, token string) (*sessions.SessionState, error) {
130+ if p.Verifier != nil {
131+ return middleware.CreateTokenToSessionFunc(p.Verifier.Verify)(ctx, token)
132+ }
130133 return nil, ErrNotImplemented
131134}
providers/providers.go+1−2
@@ -3,7 +3,6 @@ package providers
33import (
44 "context"
55
6− "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
76 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
87)
98
@@ -18,7 +17,7 @@ type Provider interface {
1817 ValidateSession(ctx context.Context, s *sessions.SessionState) bool
1918 GetLoginURL(redirectURI, finalRedirect string) string
2019 RefreshSessionIfNeeded(ctx context.Context, s *sessions.SessionState) (bool, error)
21− CreateSessionFromToken(ctx context.Context, token string, verify middleware.VerifyFunc) (*sessions.SessionState, error)
20+ CreateSessionFromToken(ctx context.Context, token string) (*sessions.SessionState, error)
2221}
2322
2423// New provides a new Provider based on the configured provider string