git.iko.soy/typeable/oauth2-proxy
on master help sign in
Support the PreferEmailToUser option on PassUserHeaders

Previously in #401, an option was added to support forwarding the email address as the username to the upstream service when the PassBasicAuth option is used. The PassBasicAuth option is not appropriate for all users, with PassUserHeaders allowing very similar functionality without specifying a basic auth headers. The PreferEmailToUser option has been expanded to support the PassUserHeaders option.

commit4cd43ef39733c9301e286891896d91a868abff1f authorJordan Crawford <jordan@crawford.kiwi> dateWed 4 Mar 2020, 11:27 (7 years ago) parent666d4c3
6 files changed+44−15
CHANGELOG.md+1 docs/configuration/configuration.md+1−1 main.go+1−1 oauthproxy.go+10−4 oauthproxy_test.go+29−7 options.go+2−2
CHANGELOG.md+1
@@ -18,6 +18,7 @@
1818- [#355](https://github.com/pusher/oauth2_proxy/pull/355) Add Client Secret File support for providers that rotate client secret via file system (@pasha-r)
1919- [#401](https://github.com/pusher/oauth2_proxy/pull/401) Give the option to pass email address in the Basic auth header instead of upstream usernames. (@Spindel)
2020- [#405](https://github.com/pusher/oauth2_proxy/pull/405) The `/sign_in` page now honors the `rd` query parameter, fixing the redirect after a successful authentication (@ti-mo)
21+- [#434](https://github.com/pusher/oauth2_proxy/pull/434) Give the option to prefer email address in the username header when using the -pass-user-headers option (@jordancrawfordnz)
2122
2223# v5.0.0
2324
docs/configuration/configuration.md+1−1
@@ -74,7 +74,7 @@ An example [oauth2_proxy.cfg]({{ site.gitweb }}/contrib/oauth2_proxy.cfg.example
7474| `-pass-access-token` | bool | pass OAuth access_token to upstream via X-Forwarded-Access-Token header | false |
7575| `-pass-authorization-header` | bool | pass OIDC IDToken to upstream via Authorization Bearer header | false |
7676| `-pass-basic-auth` | bool | pass HTTP Basic Auth, X-Forwarded-User, X-Forwarded-Email and X-Forwarded-Preferred-Username information to upstream | true |
77−| `-prefer-email-to-user` | bool | Prefer to use the Email address as the Username when passing information to upstream. Will only use Username if Email is unavailable, eg. htaccess authentication. | false |
77+| `-prefer-email-to-user` | bool | Prefer to use the Email address as the Username when passing information to upstream. Will only use Username if Email is unavailable, eg. htaccess authentication. Used in conjunction with `-pass-basic-auth` and `-pass-user-headers` | false |
7878| `-pass-host-header` | bool | pass the request Host Header to upstream | true |
7979| `-pass-user-headers` | bool | pass X-Forwarded-User, X-Forwarded-Email and X-Forwarded-Preferred-Username information to upstream | true |
8080| `-profile-url` | string | Profile access endpoint | |
main.go+1−1
@@ -41,7 +41,7 @@ func main() {
4141 flagSet.Bool("set-xauthrequest", false, "set X-Auth-Request-User and X-Auth-Request-Email response headers (useful in Nginx auth_request mode)")
4242 flagSet.Var(&upstreams, "upstream", "the http url(s) of the upstream endpoint, file:// paths for static files or static://<status_code> for static response. Routing is based on the path")
4343 flagSet.Bool("pass-basic-auth", true, "pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream")
44− flagSet.Bool("prefer-email-to-user", false, "Prefer to use the Email address as the Username when passing information to upstream. Will only use Username if Email is unavailable, eg. htaccess authentication.")
44+ flagSet.Bool("prefer-email-to-user", false, "Prefer to use the Email address as the Username when passing information to upstream. Will only use Username if Email is unavailable, eg. htaccess authentication. Used in conjunction with -pass-basic-auth and -pass-user-headers")
4545 flagSet.Bool("pass-user-headers", true, "pass X-Forwarded-User and X-Forwarded-Email information to upstream")
4646 flagSet.String("basic-auth-password", "", "the password to set when passing the HTTP Basic Auth header")
4747 flagSet.Bool("pass-access-token", false, "pass OAuth access_token to upstream via X-Forwarded-Access-Token header")
oauthproxy.go+10−4
@@ -959,12 +959,18 @@ func (p *OAuthProxy) addHeadersForProxying(rw http.ResponseWriter, req *http.Req
959959 }
960960
961961 if p.PassUserHeaders {
962− req.Header["X-Forwarded-User"] = []string{session.User}
963− if session.Email != "" {
964− req.Header["X-Forwarded-Email"] = []string{session.Email}
965− } else {
962+ if p.PreferEmailToUser && session.Email != "" {
963+ req.Header["X-Forwarded-User"] = []string{session.Email}
966964 req.Header.Del("X-Forwarded-Email")
965+ } else {
966+ req.Header["X-Forwarded-User"] = []string{session.User}
967+ if session.Email != "" {
968+ req.Header["X-Forwarded-Email"] = []string{session.Email}
969+ } else {
970+ req.Header.Del("X-Forwarded-Email")
971+ }
967972 }
973+
968974 if session.PreferredUsername != "" {
969975 req.Header["X-Forwarded-Preferred-Username"] = []string{session.PreferredUsername}
970976 } else {
oauthproxy_test.go+29−7
@@ -511,23 +511,45 @@ func TestBasicAuthWithEmail(t *testing.T) {
511511 assert.Equal(t, expectedEmailHeader, req.Header["Authorization"][0])
512512 assert.Equal(t, emailAddress, req.Header["X-Forwarded-User"][0])
513513 }
514+}
514515
516+func TestPassUserHeadersWithEmail(t *testing.T) {
517+ opts := NewOptions()
518+ opts.PassBasicAuth = false
515519 opts.PassUserHeaders = true
520+ opts.PreferEmailToUser = false
521+ opts.Validate()
522+
523+ const emailAddress = "john.doe@example.com"
524+ const userName = "9fcab5c9b889a557"
525+
526+ session := &sessions.SessionState{
527+ User: userName,
528+ Email: emailAddress,
529+ AccessToken: "oauth_token",
530+ CreatedAt: time.Now(),
531+ }
516532 {
517− // PassUserHeaders takes predecense over the headers added by
518− // PassBasicAuth, thus we expect them to contain something else.
519533 rw := httptest.NewRecorder()
520− req, _ := http.NewRequest("GET", opts.ProxyPrefix+"/testCase2", nil)
534+ req, _ := http.NewRequest("GET", opts.ProxyPrefix+"/testCase0", nil)
521535 proxy := NewOAuthProxy(opts, func(email string) bool {
522536 return email == emailAddress
523537 })
524−
525538 proxy.addHeadersForProxying(rw, req, session)
526− // The user address here should still be an email.
527− assert.Equal(t, expectedEmailHeader, req.Header["Authorization"][0])
528− assert.Equal(t, emailAddress, req.Header["X-Forwarded-Email"][0])
529539 assert.Equal(t, userName, req.Header["X-Forwarded-User"][0])
530540 }
541+
542+ opts.PreferEmailToUser = true
543+ {
544+ rw := httptest.NewRecorder()
545+ req, _ := http.NewRequest("GET", opts.ProxyPrefix+"/testCase1", nil)
546+
547+ proxy := NewOAuthProxy(opts, func(email string) bool {
548+ return email == emailAddress
549+ })
550+ proxy.addHeadersForProxying(rw, req, session)
551+ assert.Equal(t, emailAddress, req.Header["X-Forwarded-User"][0])
552+ }
531553}
532554
533555type PassAccessTokenTest struct {
options.go+2−2
@@ -281,8 +281,8 @@ func (o *Options) Validate() error {
281281 }
282282 }
283283
284− if o.PreferEmailToUser == true && o.PassBasicAuth == false {
285− msgs = append(msgs, "PreferEmailToUser should only be used with PassBasicAuth")
284+ if o.PreferEmailToUser == true && o.PassBasicAuth == false && o.PassUserHeaders == false {
285+ msgs = append(msgs, "PreferEmailToUser should only be used with PassBasicAuth or PassUserHeaders")
286286 }
287287
288288 if o.SkipJwtBearerTokens {