git.iko.soy/typeable/oauth2-proxy
on master help sign in
Verify main v extra JWT bearers differently

When using the configured provider JWT Verifier, it makes sense to use the provider `CreateSessionStateFromBearerToken` method. For any extra JWT Issuers, they should use a generic default verifier.

commit788d8ecc1b9661b5bde7846cd008bda74eaf39ed authorNick Meves <nick.meves@greenhouse.io> dateSat 30 May 2020, 14:16 (6 years ago) parent5817028
4 files changed+106−64
oauthproxy.go+70−59 pkg/validation/options.go−4 providers/oidc_test.go−1 providers/provider_default_test.go+36
oauthproxy.go+70−59
@@ -88,35 +88,36 @@ type OAuthProxy struct {
8888 AuthOnlyPath string
8989 UserInfoPath string
9090
91− redirectURL *url.URL // the url to receive requests at
92− whitelistDomains []string
93− provider providers.Provider
94− providerNameOverride string
95− sessionStore sessionsapi.SessionStore
96− ProxyPrefix string
97− SignInMessage string
98− HtpasswdFile *HtpasswdFile
99− DisplayHtpasswdForm bool
100− serveMux http.Handler
101− SetXAuthRequest bool
102− PassBasicAuth bool
103− SetBasicAuth bool
104− SkipProviderButton bool
105− PassUserHeaders bool
106− BasicAuthPassword string
107− PassAccessToken bool
108− SetAuthorization bool
109− PassAuthorization bool
110− PreferEmailToUser bool
111− skipAuthRegex []string
112− skipAuthPreflight bool
113− skipJwtBearerTokens bool
114− jwtBearerVerifiers []*oidc.IDTokenVerifier
115− compiledRegex []*regexp.Regexp
116− templates *template.Template
117− realClientIPParser ipapi.RealClientIPParser
118− Banner string
119− Footer string
91+ redirectURL *url.URL // the url to receive requests at
92+ whitelistDomains []string
93+ provider providers.Provider
94+ providerNameOverride string
95+ sessionStore sessionsapi.SessionStore
96+ ProxyPrefix string
97+ SignInMessage string
98+ HtpasswdFile *HtpasswdFile
99+ DisplayHtpasswdForm bool
100+ serveMux http.Handler
101+ SetXAuthRequest bool
102+ PassBasicAuth bool
103+ SetBasicAuth bool
104+ SkipProviderButton bool
105+ PassUserHeaders bool
106+ BasicAuthPassword string
107+ PassAccessToken bool
108+ SetAuthorization bool
109+ PassAuthorization bool
110+ PreferEmailToUser bool
111+ skipAuthRegex []string
112+ skipAuthPreflight bool
113+ skipJwtBearerTokens bool
114+ mainJwtBearerVerifier *oidc.IDTokenVerifier
115+ extraJwtBearerVerifiers []*oidc.IDTokenVerifier
116+ compiledRegex []*regexp.Regexp
117+ templates *template.Template
118+ realClientIPParser ipapi.RealClientIPParser
119+ Banner string
120+ Footer string
120121}
121122
122123// UpstreamProxy represents an upstream server to proxy to
@@ -317,32 +318,33 @@ func NewOAuthProxy(opts *options.Options, validator func(string) bool) *OAuthPro
317318 AuthOnlyPath: fmt.Sprintf("%s/auth", opts.ProxyPrefix),
318319 UserInfoPath: fmt.Sprintf("%s/userinfo", opts.ProxyPrefix),
319320
320− ProxyPrefix: opts.ProxyPrefix,
321− provider: opts.GetProvider(),
322− providerNameOverride: opts.ProviderName,
323− sessionStore: opts.GetSessionStore(),
324− serveMux: serveMux,
325− redirectURL: redirectURL,
326− whitelistDomains: opts.WhitelistDomains,
327− skipAuthRegex: opts.SkipAuthRegex,
328− skipAuthPreflight: opts.SkipAuthPreflight,
329− skipJwtBearerTokens: opts.SkipJwtBearerTokens,
330− jwtBearerVerifiers: opts.GetJWTBearerVerifiers(),
331− compiledRegex: opts.GetCompiledRegex(),
332− realClientIPParser: opts.GetRealClientIPParser(),
333− SetXAuthRequest: opts.SetXAuthRequest,
334− PassBasicAuth: opts.PassBasicAuth,
335− SetBasicAuth: opts.SetBasicAuth,
336− PassUserHeaders: opts.PassUserHeaders,
337− BasicAuthPassword: opts.BasicAuthPassword,
338− PassAccessToken: opts.PassAccessToken,
339− SetAuthorization: opts.SetAuthorization,
340− PassAuthorization: opts.PassAuthorization,
341− PreferEmailToUser: opts.PreferEmailToUser,
342− SkipProviderButton: opts.SkipProviderButton,
343− templates: loadTemplates(opts.CustomTemplatesDir),
344− Banner: opts.Banner,
345− Footer: opts.Footer,
321+ ProxyPrefix: opts.ProxyPrefix,
322+ provider: opts.GetProvider(),
323+ providerNameOverride: opts.ProviderName,
324+ sessionStore: opts.GetSessionStore(),
325+ serveMux: serveMux,
326+ redirectURL: redirectURL,
327+ whitelistDomains: opts.WhitelistDomains,
328+ skipAuthRegex: opts.SkipAuthRegex,
329+ skipAuthPreflight: opts.SkipAuthPreflight,
330+ skipJwtBearerTokens: opts.SkipJwtBearerTokens,
331+ mainJwtBearerVerifier: opts.GetOIDCVerifier(),
332+ extraJwtBearerVerifiers: opts.GetJWTBearerVerifiers(),
333+ compiledRegex: opts.GetCompiledRegex(),
334+ realClientIPParser: opts.GetRealClientIPParser(),
335+ SetXAuthRequest: opts.SetXAuthRequest,
336+ PassBasicAuth: opts.PassBasicAuth,
337+ SetBasicAuth: opts.SetBasicAuth,
338+ PassUserHeaders: opts.PassUserHeaders,
339+ BasicAuthPassword: opts.BasicAuthPassword,
340+ PassAccessToken: opts.PassAccessToken,
341+ SetAuthorization: opts.SetAuthorization,
342+ PassAuthorization: opts.PassAuthorization,
343+ PreferEmailToUser: opts.PreferEmailToUser,
344+ SkipProviderButton: opts.SkipProviderButton,
345+ templates: loadTemplates(opts.CustomTemplatesDir),
346+ Banner: opts.Banner,
347+ Footer: opts.Footer,
346348 }
347349}
348350
@@ -1139,15 +1141,24 @@ func (p *OAuthProxy) GetJwtSession(req *http.Request) (*sessionsapi.SessionState
11391141 return nil, err
11401142 }
11411143
1142− for _, verifier := range p.jwtBearerVerifiers {
1143− bearerToken, err := verifier.Verify(req.Context(), rawBearerToken)
1144+ // If we are using an oidc provider, go ahead and try that provider first with its Verifier
1145+ // and Bearer Token -> Session converter
1146+ if p.mainJwtBearerVerifier != nil {
1147+ bearerToken, err := p.mainJwtBearerVerifier.Verify(req.Context(), rawBearerToken)
1148+ if err == nil {
1149+ return p.provider.CreateSessionStateFromBearerToken(req.Context(), rawBearerToken, bearerToken)
1150+ }
1151+ }
11441152
1153+ // Otherwise, attempt to verify against the extra JWT issuers and use a more generic
1154+ // Bearer Token -> Session converter
1155+ for _, verifier := range p.extraJwtBearerVerifiers {
1156+ bearerToken, err := verifier.Verify(req.Context(), rawBearerToken)
11451157 if err != nil {
1146− logger.Printf("failed to verify bearer token: %v", err)
11471158 continue
11481159 }
11491160
1150− return p.provider.CreateSessionStateFromBearerToken(req.Context(), rawBearerToken, bearerToken)
1161+ return (*providers.ProviderData)(nil).CreateSessionStateFromBearerToken(req.Context(), rawBearerToken, bearerToken)
11511162 }
11521163 return nil, fmt.Errorf("unable to verify jwt token %s", req.Header.Get("Authorization"))
11531164}
pkg/validation/options.go−4
@@ -178,10 +178,6 @@ func Validate(o *options.Options) error {
178178 }
179179
180180 if o.SkipJwtBearerTokens {
181− // If we are using an oidc provider, go ahead and add that provider to the list
182− if o.GetOIDCVerifier() != nil {
183− o.SetJWTBearerVerifiers(append(o.GetJWTBearerVerifiers(), o.GetOIDCVerifier()))
184− }
185181 // Configure extra issuers
186182 if len(o.ExtraJwtIssuers) > 0 {
187183 var jwtIssuers []jwtIssuer
providers/oidc_test.go−1
@@ -124,7 +124,6 @@ func newOIDCServer(body []byte) (*url.URL, *httptest.Server) {
124124}
125125
126126func newSignedTestIDToken(tokenClaims idTokenClaims) (string, error) {
127−
128127 key, _ := rsa.GenerateKey(rand.Reader, 2048)
129128 standardClaims := jwt.NewWithClaims(jwt.SigningMethodRS256, tokenClaims)
130129 return standardClaims.SignedString(key)
providers/provider_default_test.go+36
@@ -2,6 +2,10 @@ package providers
22
33import (
44 "context"
5+ "crypto/rand"
6+ "crypto/rsa"
7+ "github.com/coreos/go-oidc"
8+ "github.com/dgrijalva/jwt-go"
59 "net/url"
610 "testing"
711 "time"
@@ -47,3 +51,35 @@ func TestAcrValuesConfigured(t *testing.T) {
4751 result := p.GetLoginURL("https://my.test.app/oauth", "")
4852 assert.Contains(t, result, "acr_values=testValue")
4953}
54+
55+func TestCreateSessionStateFromBearerToken(t *testing.T) {
56+ minimalIDToken := jwt.StandardClaims{
57+ Audience: "asdf1234",
58+ ExpiresAt: time.Now().Add(time.Duration(5) * time.Minute).Unix(),
59+ Id: "id-some-id",
60+ IssuedAt: time.Now().Unix(),
61+ Issuer: "https://issuer.example.com",
62+ NotBefore: 0,
63+ Subject: "123456789",
64+ }
65+ // From oidc_test.go
66+ verifier := oidc.NewVerifier(
67+ "https://issuer.example.com",
68+ fakeKeySetStub{},
69+ &oidc.Config{ClientID: "asdf1234"},
70+ )
71+
72+ key, _ := rsa.GenerateKey(rand.Reader, 2048)
73+ rawIDToken, _ := jwt.NewWithClaims(jwt.SigningMethodRS256, minimalIDToken).SignedString(key)
74+ idToken, err := verifier.Verify(context.Background(), rawIDToken)
75+
76+ session, err := (*ProviderData)(nil).CreateSessionStateFromBearerToken(context.Background(), rawIDToken, idToken)
77+
78+ assert.Equal(t, nil, err)
79+ assert.Equal(t, rawIDToken, session.AccessToken)
80+ assert.Equal(t, rawIDToken, session.IDToken)
81+ assert.Equal(t, "", session.RefreshToken)
82+ assert.Equal(t, "123456789", session.Email)
83+ assert.Equal(t, "123456789", session.User)
84+ assert.Equal(t, "", session.PreferredUsername)
85+}