From 829b442302f7db79929b679a01a6a3f41388bc4b Mon Sep 17 00:00:00 2001 From: Lukasz Siudut Date: Thu, 20 Oct 2016 17:49:59 +0530 Subject: [PATCH 1/3] add --set-xauthrequest flag for use in Nginx auth_request mode This is enhancement of #173 to use "Auth Request" consistently in the command-line option, configuration file and response headers. It always sets the X-Auth-Request-User response header and if the email is available, sets X-Auth-Request-Email as well. --- main.go | 1 + oauthproxy.go | 8 ++++++++ oauthproxy_test.go | 30 ++++++++++++++++++++++++++++++ options.go | 2 ++ 4 files changed, 41 insertions(+) diff --git a/main.go b/main.go index bf1bba8..b5ed971 100644 --- a/main.go +++ b/main.go @@ -30,6 +30,7 @@ func main() { flagSet.String("tls-cert", "", "path to certificate file") flagSet.String("tls-key", "", "path to private key file") flagSet.String("redirect-url", "", "the OAuth Redirect URL. ie: \"https://internalapp.yourcompany.com/oauth2/callback\"") + flagSet.Bool("set-xauthrequest", false, "set X-Auth-Request-User and X-Auth-Request-Email response headers (useful in Nginx auth_request mode)") flagSet.Var(&upstreams, "upstream", "the http url(s) of the upstream endpoint or file:// paths for static files. Routing is based on the path") flagSet.Bool("pass-basic-auth", true, "pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream") flagSet.Bool("pass-user-headers", true, "pass X-Forwarded-User and X-Forwarded-Email information to upstream") diff --git a/oauthproxy.go b/oauthproxy.go index 5ce9559..5cf9b44 100644 --- a/oauthproxy.go +++ b/oauthproxy.go @@ -60,6 +60,7 @@ type OAuthProxy struct { HtpasswdFile *HtpasswdFile DisplayHtpasswdForm bool serveMux http.Handler + SetXAuthRequest bool PassBasicAuth bool SkipProviderButton bool PassUserHeaders bool @@ -198,6 +199,7 @@ func NewOAuthProxy(opts *Options, validator func(string) bool) *OAuthProxy { redirectURL: redirectURL, skipAuthRegex: opts.SkipAuthRegex, compiledRegex: opts.CompiledRegex, + SetXAuthRequest: opts.SetXAuthRequest, PassBasicAuth: opts.PassBasicAuth, PassUserHeaders: opts.PassUserHeaders, BasicAuthPassword: opts.BasicAuthPassword, @@ -663,6 +665,12 @@ func (p *OAuthProxy) Authenticate(rw http.ResponseWriter, req *http.Request) int req.Header["X-Forwarded-Email"] = []string{session.Email} } } + if p.SetXAuthRequest { + rw.Header().Set("X-Auth-Request-User", session.User) + if session.Email != "" { + rw.Header().Set("X-Auth-Request-Email", session.Email) + } + } if p.PassAccessToken && session.AccessToken != "" { req.Header["X-Forwarded-Access-Token"] = []string{session.AccessToken} } diff --git a/oauthproxy_test.go b/oauthproxy_test.go index 26a942d..0689424 100644 --- a/oauthproxy_test.go +++ b/oauthproxy_test.go @@ -611,6 +611,36 @@ func TestAuthOnlyEndpointUnauthorizedOnEmailValidationFailure(t *testing.T) { assert.Equal(t, "unauthorized request\n", string(bodyBytes)) } +func TestAuthOnlyEndpointSetXAuthRequestHeaders(t *testing.T) { + var pc_test ProcessCookieTest + + pc_test.opts = NewOptions() + pc_test.opts.SetXAuthRequest = true + pc_test.opts.Validate() + + pc_test.proxy = NewOAuthProxy(pc_test.opts, func(email string) bool { + return pc_test.validate_user + }) + pc_test.proxy.provider = &TestProvider{ + ValidToken: true, + } + + pc_test.validate_user = true + + pc_test.rw = httptest.NewRecorder() + pc_test.req, _ = http.NewRequest("GET", + pc_test.opts.ProxyPrefix+"/auth", nil) + + startSession := &providers.SessionState{ + User: "oauth_user", Email: "oauth_user@example.com", AccessToken: "oauth_token"} + pc_test.SaveSession(startSession, time.Now()) + + pc_test.proxy.ServeHTTP(pc_test.rw, pc_test.req) + assert.Equal(t, http.StatusAccepted, pc_test.rw.Code) + assert.Equal(t, "oauth_user", pc_test.rw.HeaderMap["X-Auth-Request-User"][0]) + assert.Equal(t, "oauth_user@example.com", pc_test.rw.HeaderMap["X-Auth-Request-Email"][0]) +} + type SignatureAuthenticator struct { auth hmacauth.HmacAuth } diff --git a/options.go b/options.go index e8f242a..63f23c6 100644 --- a/options.go +++ b/options.go @@ -57,6 +57,7 @@ type Options struct { SkipProviderButton bool `flag:"skip-provider-button" cfg:"skip_provider_button"` PassUserHeaders bool `flag:"pass-user-headers" cfg:"pass_user_headers"` SSLInsecureSkipVerify bool `flag:"ssl-insecure-skip-verify" cfg:"ssl_insecure_skip_verify"` + SetXAuthRequest bool `flag:"set-xauthrequest" cfg:"set_xauthrequest"` // These options allow for other providers besides Google, with // potential overrides. @@ -97,6 +98,7 @@ func NewOptions() *Options { CookieHttpOnly: true, CookieExpire: time.Duration(168) * time.Hour, CookieRefresh: time.Duration(0), + SetXAuthRequest: false, PassBasicAuth: true, PassUserHeaders: true, PassAccessToken: false, From 90a22b2f39a31af37c8d8e7f7c47f475e0d70933 Mon Sep 17 00:00:00 2001 From: Sjoerd Mulder Date: Wed, 16 Nov 2016 12:06:18 +0530 Subject: [PATCH 2/3] Use X-Auth-Request-Redirect request header in sign-in page This is useful in Nginx auth_request mode, if a 401 handler is configured to redirect to the sign-in page. As the request URL does not reflect the actual URL, the value is taken from the header "X-Auth-Request-Redirect" instead. Based on #247 --- oauthproxy.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/oauthproxy.go b/oauthproxy.go index 5cf9b44..f4cd577 100644 --- a/oauthproxy.go +++ b/oauthproxy.go @@ -363,6 +363,9 @@ func (p *OAuthProxy) SignInPage(rw http.ResponseWriter, req *http.Request, code rw.WriteHeader(code) redirect_url := req.URL.RequestURI() + if req.Header.Get("X-Auth-Request-Redirect") != "" { + redirect_url = req.Header.Get("X-Auth-Request-Redirect") + } if redirect_url == p.SignInPath { redirect_url = "/" } From fe44b89f574a3c8174b18a3cf458217e3b281544 Mon Sep 17 00:00:00 2001 From: Ashish Kulkarni Date: Wed, 16 Nov 2016 13:25:07 +0530 Subject: [PATCH 3/3] update documentation for Nginx auth_request mode --- README.md | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fd4ee71..9333a66 100644 --- a/README.md +++ b/README.md @@ -359,10 +359,25 @@ server { } location /oauth2/ { - proxy_pass http://127.0.0.1:4180; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Scheme $scheme; + proxy_pass http://127.0.0.1:4180; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Scheme $scheme; + proxy_set_header X-Auth-Request-Redirect $request_uri; + } + + location /upstream/ { + auth_request /oauth2/auth; + error_page 401 = /oauth2/sign_in; + + # pass information via X-User and X-Email headers to backend, + # requires running with --set-xauthrequest flag + auth_request_set $user $upstream_http_x_auth_request_user; + auth_request_set $email $upstream_http_x_auth_request_email; + proxy_set_header X-User $user; + proxy_set_header X-Email $email; + + proxy_pass http://backend/; } location / {