1
0
mirror of https://github.com/oauth2-proxy/oauth2-proxy.git synced 2025-04-23 12:18:50 +02:00

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.
This commit is contained in:
Nick Meves 2020-05-30 14:16:26 -07:00
parent 5817028bb1
commit 788d8ecc1b
No known key found for this signature in database
GPG Key ID: 93BA8A3CEDCDD1CF
4 changed files with 106 additions and 64 deletions

View File

@ -88,35 +88,36 @@ type OAuthProxy struct {
AuthOnlyPath string AuthOnlyPath string
UserInfoPath string UserInfoPath string
redirectURL *url.URL // the url to receive requests at redirectURL *url.URL // the url to receive requests at
whitelistDomains []string whitelistDomains []string
provider providers.Provider provider providers.Provider
providerNameOverride string providerNameOverride string
sessionStore sessionsapi.SessionStore sessionStore sessionsapi.SessionStore
ProxyPrefix string ProxyPrefix string
SignInMessage string SignInMessage string
HtpasswdFile *HtpasswdFile HtpasswdFile *HtpasswdFile
DisplayHtpasswdForm bool DisplayHtpasswdForm bool
serveMux http.Handler serveMux http.Handler
SetXAuthRequest bool SetXAuthRequest bool
PassBasicAuth bool PassBasicAuth bool
SetBasicAuth bool SetBasicAuth bool
SkipProviderButton bool SkipProviderButton bool
PassUserHeaders bool PassUserHeaders bool
BasicAuthPassword string BasicAuthPassword string
PassAccessToken bool PassAccessToken bool
SetAuthorization bool SetAuthorization bool
PassAuthorization bool PassAuthorization bool
PreferEmailToUser bool PreferEmailToUser bool
skipAuthRegex []string skipAuthRegex []string
skipAuthPreflight bool skipAuthPreflight bool
skipJwtBearerTokens bool skipJwtBearerTokens bool
jwtBearerVerifiers []*oidc.IDTokenVerifier mainJwtBearerVerifier *oidc.IDTokenVerifier
compiledRegex []*regexp.Regexp extraJwtBearerVerifiers []*oidc.IDTokenVerifier
templates *template.Template compiledRegex []*regexp.Regexp
realClientIPParser ipapi.RealClientIPParser templates *template.Template
Banner string realClientIPParser ipapi.RealClientIPParser
Footer string Banner string
Footer string
} }
// UpstreamProxy represents an upstream server to proxy to // UpstreamProxy represents an upstream server to proxy to
@ -317,32 +318,33 @@ func NewOAuthProxy(opts *options.Options, validator func(string) bool) *OAuthPro
AuthOnlyPath: fmt.Sprintf("%s/auth", opts.ProxyPrefix), AuthOnlyPath: fmt.Sprintf("%s/auth", opts.ProxyPrefix),
UserInfoPath: fmt.Sprintf("%s/userinfo", opts.ProxyPrefix), UserInfoPath: fmt.Sprintf("%s/userinfo", opts.ProxyPrefix),
ProxyPrefix: opts.ProxyPrefix, ProxyPrefix: opts.ProxyPrefix,
provider: opts.GetProvider(), provider: opts.GetProvider(),
providerNameOverride: opts.ProviderName, providerNameOverride: opts.ProviderName,
sessionStore: opts.GetSessionStore(), sessionStore: opts.GetSessionStore(),
serveMux: serveMux, serveMux: serveMux,
redirectURL: redirectURL, redirectURL: redirectURL,
whitelistDomains: opts.WhitelistDomains, whitelistDomains: opts.WhitelistDomains,
skipAuthRegex: opts.SkipAuthRegex, skipAuthRegex: opts.SkipAuthRegex,
skipAuthPreflight: opts.SkipAuthPreflight, skipAuthPreflight: opts.SkipAuthPreflight,
skipJwtBearerTokens: opts.SkipJwtBearerTokens, skipJwtBearerTokens: opts.SkipJwtBearerTokens,
jwtBearerVerifiers: opts.GetJWTBearerVerifiers(), mainJwtBearerVerifier: opts.GetOIDCVerifier(),
compiledRegex: opts.GetCompiledRegex(), extraJwtBearerVerifiers: opts.GetJWTBearerVerifiers(),
realClientIPParser: opts.GetRealClientIPParser(), compiledRegex: opts.GetCompiledRegex(),
SetXAuthRequest: opts.SetXAuthRequest, realClientIPParser: opts.GetRealClientIPParser(),
PassBasicAuth: opts.PassBasicAuth, SetXAuthRequest: opts.SetXAuthRequest,
SetBasicAuth: opts.SetBasicAuth, PassBasicAuth: opts.PassBasicAuth,
PassUserHeaders: opts.PassUserHeaders, SetBasicAuth: opts.SetBasicAuth,
BasicAuthPassword: opts.BasicAuthPassword, PassUserHeaders: opts.PassUserHeaders,
PassAccessToken: opts.PassAccessToken, BasicAuthPassword: opts.BasicAuthPassword,
SetAuthorization: opts.SetAuthorization, PassAccessToken: opts.PassAccessToken,
PassAuthorization: opts.PassAuthorization, SetAuthorization: opts.SetAuthorization,
PreferEmailToUser: opts.PreferEmailToUser, PassAuthorization: opts.PassAuthorization,
SkipProviderButton: opts.SkipProviderButton, PreferEmailToUser: opts.PreferEmailToUser,
templates: loadTemplates(opts.CustomTemplatesDir), SkipProviderButton: opts.SkipProviderButton,
Banner: opts.Banner, templates: loadTemplates(opts.CustomTemplatesDir),
Footer: opts.Footer, Banner: opts.Banner,
Footer: opts.Footer,
} }
} }
@ -1139,15 +1141,24 @@ func (p *OAuthProxy) GetJwtSession(req *http.Request) (*sessionsapi.SessionState
return nil, err return nil, err
} }
for _, verifier := range p.jwtBearerVerifiers { // If we are using an oidc provider, go ahead and try that provider first with its Verifier
bearerToken, err := verifier.Verify(req.Context(), rawBearerToken) // and Bearer Token -> Session converter
if p.mainJwtBearerVerifier != nil {
bearerToken, err := p.mainJwtBearerVerifier.Verify(req.Context(), rawBearerToken)
if err == nil {
return p.provider.CreateSessionStateFromBearerToken(req.Context(), rawBearerToken, bearerToken)
}
}
// Otherwise, attempt to verify against the extra JWT issuers and use a more generic
// Bearer Token -> Session converter
for _, verifier := range p.extraJwtBearerVerifiers {
bearerToken, err := verifier.Verify(req.Context(), rawBearerToken)
if err != nil { if err != nil {
logger.Printf("failed to verify bearer token: %v", err)
continue continue
} }
return p.provider.CreateSessionStateFromBearerToken(req.Context(), rawBearerToken, bearerToken) return (*providers.ProviderData)(nil).CreateSessionStateFromBearerToken(req.Context(), rawBearerToken, bearerToken)
} }
return nil, fmt.Errorf("unable to verify jwt token %s", req.Header.Get("Authorization")) return nil, fmt.Errorf("unable to verify jwt token %s", req.Header.Get("Authorization"))
} }

View File

@ -178,10 +178,6 @@ func Validate(o *options.Options) error {
} }
if o.SkipJwtBearerTokens { if o.SkipJwtBearerTokens {
// If we are using an oidc provider, go ahead and add that provider to the list
if o.GetOIDCVerifier() != nil {
o.SetJWTBearerVerifiers(append(o.GetJWTBearerVerifiers(), o.GetOIDCVerifier()))
}
// Configure extra issuers // Configure extra issuers
if len(o.ExtraJwtIssuers) > 0 { if len(o.ExtraJwtIssuers) > 0 {
var jwtIssuers []jwtIssuer var jwtIssuers []jwtIssuer

View File

@ -124,7 +124,6 @@ func newOIDCServer(body []byte) (*url.URL, *httptest.Server) {
} }
func newSignedTestIDToken(tokenClaims idTokenClaims) (string, error) { func newSignedTestIDToken(tokenClaims idTokenClaims) (string, error) {
key, _ := rsa.GenerateKey(rand.Reader, 2048) key, _ := rsa.GenerateKey(rand.Reader, 2048)
standardClaims := jwt.NewWithClaims(jwt.SigningMethodRS256, tokenClaims) standardClaims := jwt.NewWithClaims(jwt.SigningMethodRS256, tokenClaims)
return standardClaims.SignedString(key) return standardClaims.SignedString(key)

View File

@ -2,6 +2,10 @@ package providers
import ( import (
"context" "context"
"crypto/rand"
"crypto/rsa"
"github.com/coreos/go-oidc"
"github.com/dgrijalva/jwt-go"
"net/url" "net/url"
"testing" "testing"
"time" "time"
@ -47,3 +51,35 @@ func TestAcrValuesConfigured(t *testing.T) {
result := p.GetLoginURL("https://my.test.app/oauth", "") result := p.GetLoginURL("https://my.test.app/oauth", "")
assert.Contains(t, result, "acr_values=testValue") assert.Contains(t, result, "acr_values=testValue")
} }
func TestCreateSessionStateFromBearerToken(t *testing.T) {
minimalIDToken := jwt.StandardClaims{
Audience: "asdf1234",
ExpiresAt: time.Now().Add(time.Duration(5) * time.Minute).Unix(),
Id: "id-some-id",
IssuedAt: time.Now().Unix(),
Issuer: "https://issuer.example.com",
NotBefore: 0,
Subject: "123456789",
}
// From oidc_test.go
verifier := oidc.NewVerifier(
"https://issuer.example.com",
fakeKeySetStub{},
&oidc.Config{ClientID: "asdf1234"},
)
key, _ := rsa.GenerateKey(rand.Reader, 2048)
rawIDToken, _ := jwt.NewWithClaims(jwt.SigningMethodRS256, minimalIDToken).SignedString(key)
idToken, err := verifier.Verify(context.Background(), rawIDToken)
session, err := (*ProviderData)(nil).CreateSessionStateFromBearerToken(context.Background(), rawIDToken, idToken)
assert.Equal(t, nil, err)
assert.Equal(t, rawIDToken, session.AccessToken)
assert.Equal(t, rawIDToken, session.IDToken)
assert.Equal(t, "", session.RefreshToken)
assert.Equal(t, "123456789", session.Email)
assert.Equal(t, "123456789", session.User)
assert.Equal(t, "", session.PreferredUsername)
}