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,