From 2ec8a4abfca790369a78a82e23713248854dd073 Mon Sep 17 00:00:00 2001 From: Martyn Ranyard Date: Thu, 19 Oct 2023 12:40:04 +0200 Subject: [PATCH 1/4] Initial attempt to enable JWT auth to look at a configurable header instead of `Authorization` --- oauthproxy.go | 2 +- pkg/apis/options/options.go | 1 + pkg/middleware/jwt_session.go | 10 ++++++++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/oauthproxy.go b/oauthproxy.go index 10a69b311d..335e5a6420 100644 --- a/oauthproxy.go +++ b/oauthproxy.go @@ -388,7 +388,7 @@ func buildSessionChain(opts *options.Options, provider providers.Provider, sessi middlewareapi.CreateTokenToSessionFunc(verifier.Verify)) } - chain = chain.Append(middleware.NewJwtSessionLoader(sessionLoaders)) + chain = chain.Append(middleware.NewJwtSessionLoader(sessionLoaders, opts.JWTAuthHeader)) } if validator != nil { diff --git a/pkg/apis/options/options.go b/pkg/apis/options/options.go index 0af8df3fc6..42fee06dbc 100644 --- a/pkg/apis/options/options.go +++ b/pkg/apis/options/options.go @@ -27,6 +27,7 @@ type Options struct { TrustedIPs []string `flag:"trusted-ip" cfg:"trusted_ips"` ForceHTTPS bool `flag:"force-https" cfg:"force_https"` RawRedirectURL string `flag:"redirect-url" cfg:"redirect_url"` + JWTAuthHeader string `flag:"jwt-auth-header" cfg:"jwt_auth_header"` AuthenticatedEmailsFile string `flag:"authenticated-emails-file" cfg:"authenticated_emails_file"` EmailDomains []string `flag:"email-domain" cfg:"email_domains"` diff --git a/pkg/middleware/jwt_session.go b/pkg/middleware/jwt_session.go index 78ef540052..8c8988c72e 100644 --- a/pkg/middleware/jwt_session.go +++ b/pkg/middleware/jwt_session.go @@ -15,9 +15,10 @@ import ( const jwtRegexFormat = `^ey[IJ][a-zA-Z0-9_-]*\.ey[IJ][a-zA-Z0-9_-]*\.[a-zA-Z0-9_-]+$` -func NewJwtSessionLoader(sessionLoaders []middlewareapi.TokenToSessionFunc) alice.Constructor { +func NewJwtSessionLoader(sessionLoaders []middlewareapi.TokenToSessionFunc, jwtAuthHeader string) alice.Constructor { js := &jwtSessionLoader{ jwtRegex: regexp.MustCompile(jwtRegexFormat), + jwtAuthHeader: jwtAuthHeader, sessionLoaders: sessionLoaders, } return js.loadSession @@ -27,6 +28,7 @@ func NewJwtSessionLoader(sessionLoaders []middlewareapi.TokenToSessionFunc) alic // Authorization headers. type jwtSessionLoader struct { jwtRegex *regexp.Regexp + jwtAuthHeader string sessionLoaders []middlewareapi.TokenToSessionFunc } @@ -60,7 +62,11 @@ func (j *jwtSessionLoader) loadSession(next http.Handler) http.Handler { // getJwtSession loads a session based on a JWT token in the authorization header. // (see the config options skip-jwt-bearer-tokens and extra-jwt-issuers) func (j *jwtSessionLoader) getJwtSession(req *http.Request) (*sessionsapi.SessionState, error) { - auth := req.Header.Get("Authorization") + authHeader := "Authorization" + if j.jwtAuthHeader == "" { + authHeader = jwtAuthHeader + } + auth := req.Header.Get(authHeader) if auth == "" { // No auth header provided, so don't attempt to load a session return nil, nil From 5f413d092203acdaa52f74776f126ff8f8c5a54d Mon Sep 17 00:00:00 2001 From: Martyn Ranyard Date: Thu, 19 Oct 2023 12:40:04 +0200 Subject: [PATCH 2/4] Initial attempt to enable JWT auth to look at a configurable header instead of `Authorization` --- pkg/middleware/jwt_session.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/middleware/jwt_session.go b/pkg/middleware/jwt_session.go index 8c8988c72e..d4aee53395 100644 --- a/pkg/middleware/jwt_session.go +++ b/pkg/middleware/jwt_session.go @@ -63,8 +63,8 @@ func (j *jwtSessionLoader) loadSession(next http.Handler) http.Handler { // (see the config options skip-jwt-bearer-tokens and extra-jwt-issuers) func (j *jwtSessionLoader) getJwtSession(req *http.Request) (*sessionsapi.SessionState, error) { authHeader := "Authorization" - if j.jwtAuthHeader == "" { - authHeader = jwtAuthHeader + if j.jwtAuthHeader != "" { + authHeader = j.jwtAuthHeader } auth := req.Header.Get(authHeader) if auth == "" { From f7b184a90b90c8a054cfed9728f7e05bc8d771df Mon Sep 17 00:00:00 2001 From: Martyn Ranyard Date: Thu, 19 Oct 2023 15:09:55 +0200 Subject: [PATCH 3/4] Missed a bit and fix the test --- pkg/apis/options/options.go | 1 + pkg/middleware/jwt_session.go | 2 +- pkg/middleware/jwt_session_test.go | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/apis/options/options.go b/pkg/apis/options/options.go index 42fee06dbc..74a9ecab51 100644 --- a/pkg/apis/options/options.go +++ b/pkg/apis/options/options.go @@ -127,6 +127,7 @@ func NewFlagSet() *pflag.FlagSet { flagSet.Bool("skip-jwt-bearer-tokens", false, "will skip requests that have verified JWT bearer tokens (default false)") flagSet.Bool("force-json-errors", false, "will force JSON errors instead of HTTP error pages or redirects") flagSet.StringSlice("extra-jwt-issuers", []string{}, "if skip-jwt-bearer-tokens is set, a list of extra JWT issuer=audience pairs (where the issuer URL has a .well-known/openid-configuration or a .well-known/jwks.json)") + flagSet.String("jwt-auth-header", "Authorization", "alternate Authorization header for jwt, so that you can say something like -jwt-header=\"X-Oauth2-proxy-Authorization\": required for some clashes of Authorization header") flagSet.StringSlice("email-domain", []string{}, "authenticate emails with the specified domain (may be given multiple times). Use * to authenticate any email") flagSet.StringSlice("whitelist-domain", []string{}, "allowed domains for redirection after authentication. Prefix domain with a . or a *. to allow subdomains (eg .example.com, *.example.com)") diff --git a/pkg/middleware/jwt_session.go b/pkg/middleware/jwt_session.go index d4aee53395..53495cca63 100644 --- a/pkg/middleware/jwt_session.go +++ b/pkg/middleware/jwt_session.go @@ -64,7 +64,7 @@ func (j *jwtSessionLoader) loadSession(next http.Handler) http.Handler { func (j *jwtSessionLoader) getJwtSession(req *http.Request) (*sessionsapi.SessionState, error) { authHeader := "Authorization" if j.jwtAuthHeader != "" { - authHeader = j.jwtAuthHeader + authHeader = j.jwtAuthHeader } auth := req.Header.Get(authHeader) if auth == "" { diff --git a/pkg/middleware/jwt_session_test.go b/pkg/middleware/jwt_session_test.go index 2d056a7833..2b15610371 100644 --- a/pkg/middleware/jwt_session_test.go +++ b/pkg/middleware/jwt_session_test.go @@ -114,7 +114,7 @@ Nnc3a3lGVWFCNUMxQnNJcnJMTWxka1dFaHluYmI4Ongtb2F1dGgtYmFzaWM=` // Create the handler with a next handler that will capture the session // from the scope var gotSession *sessionsapi.SessionState - handler := NewJwtSessionLoader(sessionLoaders)(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + handler := NewJwtSessionLoader(sessionLoaders, "Authorization")(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { gotSession = middlewareapi.GetRequestScope(r).Session })) handler.ServeHTTP(rw, req) From 71e516043bf4bf43c46e5968552f60706e799338 Mon Sep 17 00:00:00 2001 From: Martyn Ranyard Date: Thu, 19 Oct 2023 17:12:10 +0200 Subject: [PATCH 4/4] Adds the option to the doc --- docs/docs/configuration/overview.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docs/configuration/overview.md b/docs/docs/configuration/overview.md index e7fcc24415..7c97fee531 100644 --- a/docs/docs/configuration/overview.md +++ b/docs/docs/configuration/overview.md @@ -133,6 +133,7 @@ An example [oauth2-proxy.cfg](https://github.com/oauth2-proxy/oauth2-proxy/blob/ | `--logging-max-size` | int | Maximum size in megabytes of the log file before rotation | 100 | | `--jwt-key` | string | private key in PEM format used to sign JWT, so that you can say something like `--jwt-key="${OAUTH2_PROXY_JWT_KEY}"`: required by login.gov | | | `--jwt-key-file` | string | path to the private key file in PEM format used to sign the JWT so that you can say something like `--jwt-key-file=/etc/ssl/private/jwt_signing_key.pem`: required by login.gov | | +> `--jwt-auth-header` | string | alternate Authorization header for jwt, so that you can say something like `--jwt-header="X-Oauth2-proxy-Authorization"`: required for some clashes of Authorization header | "Authorization" | | `--login-url` | string | Authentication endpoint | | | `--insecure-oidc-allow-unverified-email` | bool | don't fail if an email address in an id_token is not verified | false | | `--insecure-oidc-skip-issuer-verification` | bool | allow the OIDC issuer URL to differ from the expected (currently required for Azure multi-tenant compatibility) | false |