diff --git a/main.go b/main.go index a8d3f1b6f..f27963c56 100644 --- a/main.go +++ b/main.go @@ -31,6 +31,7 @@ func main() { 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.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("return-authenticated-email", false, "return X-Authorized-Email header (useful when used as authenticator only)") flagSet.Bool("pass-basic-auth", true, "pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream") flagSet.String("basic-auth-password", "", "the password to set when passing the HTTP Basic Auth header") flagSet.Bool("pass-access-token", false, "pass OAuth access_token to upstream via X-Forwarded-Access-Token header") diff --git a/oauthproxy.go b/oauthproxy.go index dd69d6a41..c06201c9b 100644 --- a/oauthproxy.go +++ b/oauthproxy.go @@ -51,20 +51,21 @@ type OAuthProxy struct { OAuthCallbackPath string AuthOnlyPath string - redirectURL *url.URL // the url to receive requests at - provider providers.Provider - ProxyPrefix string - SignInMessage string - HtpasswdFile *HtpasswdFile - DisplayHtpasswdForm bool - serveMux http.Handler - PassBasicAuth bool - BasicAuthPassword string - PassAccessToken bool - CookieCipher *cookie.Cipher - skipAuthRegex []string - compiledRegex []*regexp.Regexp - templates *template.Template + redirectURL *url.URL // the url to receive requests at + provider providers.Provider + ProxyPrefix string + SignInMessage string + HtpasswdFile *HtpasswdFile + DisplayHtpasswdForm bool + serveMux http.Handler + PassBasicAuth bool + ReturnAuthenticatedEmail bool + BasicAuthPassword string + PassAccessToken bool + CookieCipher *cookie.Cipher + skipAuthRegex []string + compiledRegex []*regexp.Regexp + templates *template.Template } type UpstreamProxy struct { @@ -186,17 +187,18 @@ func NewOAuthProxy(opts *Options, validator func(string) bool) *OAuthProxy { OAuthCallbackPath: fmt.Sprintf("%s/callback", opts.ProxyPrefix), AuthOnlyPath: fmt.Sprintf("%s/auth", opts.ProxyPrefix), - ProxyPrefix: opts.ProxyPrefix, - provider: opts.provider, - serveMux: serveMux, - redirectURL: redirectURL, - skipAuthRegex: opts.SkipAuthRegex, - compiledRegex: opts.CompiledRegex, - PassBasicAuth: opts.PassBasicAuth, - BasicAuthPassword: opts.BasicAuthPassword, - PassAccessToken: opts.PassAccessToken, - CookieCipher: cipher, - templates: loadTemplates(opts.CustomTemplatesDir), + ProxyPrefix: opts.ProxyPrefix, + provider: opts.provider, + serveMux: serveMux, + redirectURL: redirectURL, + skipAuthRegex: opts.SkipAuthRegex, + compiledRegex: opts.CompiledRegex, + PassBasicAuth: opts.PassBasicAuth, + ReturnAuthenticatedEmail: opts.ReturnAuthenticatedEmail, + BasicAuthPassword: opts.BasicAuthPassword, + PassAccessToken: opts.PassAccessToken, + CookieCipher: cipher, + templates: loadTemplates(opts.CustomTemplatesDir), } } @@ -593,6 +595,9 @@ func (p *OAuthProxy) Authenticate(rw http.ResponseWriter, req *http.Request) int req.Header["X-Forwarded-Email"] = []string{session.Email} } } + if p.ReturnAuthenticatedEmail { + rw.Header().Set("X-Authenticated-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 7af1de18b..a77eb13fe 100644 --- a/oauthproxy_test.go +++ b/oauthproxy_test.go @@ -595,6 +595,35 @@ func TestAuthOnlyEndpointUnauthorizedOnEmailValidationFailure(t *testing.T) { assert.Equal(t, "unauthorized request\n", string(bodyBytes)) } +func TestAuthOnlyEndpointReturnAuthenticatedEmail(t *testing.T) { + var pc_test ProcessCookieTest + + pc_test.opts = NewOptions() + pc_test.opts.ReturnAuthenticatedEmail = 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{ + Email: "michael.bland@gsa.gov", AccessToken: "my_access_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, "michael.bland@gsa.gov", pc_test.rw.HeaderMap["X-Authenticated-Email"][0]) +} + type SignatureAuthenticator struct { auth hmacauth.HmacAuth } diff --git a/options.go b/options.go index b64396cbc..e72f75c9a 100644 --- a/options.go +++ b/options.go @@ -43,12 +43,13 @@ type Options struct { CookieSecure bool `flag:"cookie-secure" cfg:"cookie_secure"` CookieHttpOnly bool `flag:"cookie-httponly" cfg:"cookie_httponly"` - Upstreams []string `flag:"upstream" cfg:"upstreams"` - SkipAuthRegex []string `flag:"skip-auth-regex" cfg:"skip_auth_regex"` - PassBasicAuth bool `flag:"pass-basic-auth" cfg:"pass_basic_auth"` - BasicAuthPassword string `flag:"basic-auth-password" cfg:"basic_auth_password"` - PassAccessToken bool `flag:"pass-access-token" cfg:"pass_access_token"` - PassHostHeader bool `flag:"pass-host-header" cfg:"pass_host_header"` + Upstreams []string `flag:"upstream" cfg:"upstreams"` + SkipAuthRegex []string `flag:"skip-auth-regex" cfg:"skip_auth_regex"` + ReturnAuthenticatedEmail bool `flag:"return-authenticated-email" cfg:"return_authenticated_email"` + PassBasicAuth bool `flag:"pass-basic-auth" cfg:"pass_basic_auth"` + BasicAuthPassword string `flag:"basic-auth-password" cfg:"basic_auth_password"` + PassAccessToken bool `flag:"pass-access-token" cfg:"pass_access_token"` + PassHostHeader bool `flag:"pass-host-header" cfg:"pass_host_header"` // These options allow for other providers besides Google, with // potential overrides. @@ -79,20 +80,21 @@ type SignatureData struct { func NewOptions() *Options { return &Options{ - ProxyPrefix: "/oauth2", - HttpAddress: "127.0.0.1:4180", - HttpsAddress: ":443", - DisplayHtpasswdForm: true, - CookieName: "_oauth2_proxy", - CookieSecure: true, - CookieHttpOnly: true, - CookieExpire: time.Duration(168) * time.Hour, - CookieRefresh: time.Duration(0), - PassBasicAuth: true, - PassAccessToken: false, - PassHostHeader: true, - ApprovalPrompt: "force", - RequestLogging: true, + ProxyPrefix: "/oauth2", + HttpAddress: "127.0.0.1:4180", + HttpsAddress: ":443", + DisplayHtpasswdForm: true, + CookieName: "_oauth2_proxy", + CookieSecure: true, + CookieHttpOnly: true, + CookieExpire: time.Duration(168) * time.Hour, + CookieRefresh: time.Duration(0), + ReturnAuthenticatedEmail: false, + PassBasicAuth: true, + PassAccessToken: false, + PassHostHeader: true, + ApprovalPrompt: "force", + RequestLogging: true, } }