Merge pull request #319 from advarisk/auth-request
various fixes for getting Nginx auth_request mode working
This commit is contained in:
		
						commit
						af7be2d622
					
				
							
								
								
									
										15
									
								
								README.md
								
								
								
								
							
							
						
						
									
										15
									
								
								README.md
								
								
								
								
							|  | @ -363,6 +363,21 @@ server { | ||||||
|     proxy_set_header Host                    $host; |     proxy_set_header Host                    $host; | ||||||
|     proxy_set_header X-Real-IP               $remote_addr; |     proxy_set_header X-Real-IP               $remote_addr; | ||||||
|     proxy_set_header X-Scheme                $scheme; |     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 / { |   location / { | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								main.go
								
								
								
								
							
							
						
						
									
										1
									
								
								main.go
								
								
								
								
							|  | @ -30,6 +30,7 @@ func main() { | ||||||
| 	flagSet.String("tls-cert", "", "path to certificate file") | 	flagSet.String("tls-cert", "", "path to certificate file") | ||||||
| 	flagSet.String("tls-key", "", "path to private key 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.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.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-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") | 	flagSet.Bool("pass-user-headers", true, "pass X-Forwarded-User and X-Forwarded-Email information to upstream") | ||||||
|  |  | ||||||
|  | @ -60,6 +60,7 @@ type OAuthProxy struct { | ||||||
| 	HtpasswdFile        *HtpasswdFile | 	HtpasswdFile        *HtpasswdFile | ||||||
| 	DisplayHtpasswdForm bool | 	DisplayHtpasswdForm bool | ||||||
| 	serveMux            http.Handler | 	serveMux            http.Handler | ||||||
|  | 	SetXAuthRequest     bool | ||||||
| 	PassBasicAuth       bool | 	PassBasicAuth       bool | ||||||
| 	SkipProviderButton  bool | 	SkipProviderButton  bool | ||||||
| 	PassUserHeaders     bool | 	PassUserHeaders     bool | ||||||
|  | @ -198,6 +199,7 @@ func NewOAuthProxy(opts *Options, validator func(string) bool) *OAuthProxy { | ||||||
| 		redirectURL:        redirectURL, | 		redirectURL:        redirectURL, | ||||||
| 		skipAuthRegex:      opts.SkipAuthRegex, | 		skipAuthRegex:      opts.SkipAuthRegex, | ||||||
| 		compiledRegex:      opts.CompiledRegex, | 		compiledRegex:      opts.CompiledRegex, | ||||||
|  | 		SetXAuthRequest:    opts.SetXAuthRequest, | ||||||
| 		PassBasicAuth:      opts.PassBasicAuth, | 		PassBasicAuth:      opts.PassBasicAuth, | ||||||
| 		PassUserHeaders:    opts.PassUserHeaders, | 		PassUserHeaders:    opts.PassUserHeaders, | ||||||
| 		BasicAuthPassword:  opts.BasicAuthPassword, | 		BasicAuthPassword:  opts.BasicAuthPassword, | ||||||
|  | @ -361,6 +363,9 @@ func (p *OAuthProxy) SignInPage(rw http.ResponseWriter, req *http.Request, code | ||||||
| 	rw.WriteHeader(code) | 	rw.WriteHeader(code) | ||||||
| 
 | 
 | ||||||
| 	redirect_url := req.URL.RequestURI() | 	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 { | 	if redirect_url == p.SignInPath { | ||||||
| 		redirect_url = "/" | 		redirect_url = "/" | ||||||
| 	} | 	} | ||||||
|  | @ -663,6 +668,12 @@ func (p *OAuthProxy) Authenticate(rw http.ResponseWriter, req *http.Request) int | ||||||
| 			req.Header["X-Forwarded-Email"] = []string{session.Email} | 			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 != "" { | 	if p.PassAccessToken && session.AccessToken != "" { | ||||||
| 		req.Header["X-Forwarded-Access-Token"] = []string{session.AccessToken} | 		req.Header["X-Forwarded-Access-Token"] = []string{session.AccessToken} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -611,6 +611,36 @@ func TestAuthOnlyEndpointUnauthorizedOnEmailValidationFailure(t *testing.T) { | ||||||
| 	assert.Equal(t, "unauthorized request\n", string(bodyBytes)) | 	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 { | type SignatureAuthenticator struct { | ||||||
| 	auth hmacauth.HmacAuth | 	auth hmacauth.HmacAuth | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -57,6 +57,7 @@ type Options struct { | ||||||
| 	SkipProviderButton    bool     `flag:"skip-provider-button" cfg:"skip_provider_button"` | 	SkipProviderButton    bool     `flag:"skip-provider-button" cfg:"skip_provider_button"` | ||||||
| 	PassUserHeaders       bool     `flag:"pass-user-headers" cfg:"pass_user_headers"` | 	PassUserHeaders       bool     `flag:"pass-user-headers" cfg:"pass_user_headers"` | ||||||
| 	SSLInsecureSkipVerify bool     `flag:"ssl-insecure-skip-verify" cfg:"ssl_insecure_skip_verify"` | 	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
 | 	// These options allow for other providers besides Google, with
 | ||||||
| 	// potential overrides.
 | 	// potential overrides.
 | ||||||
|  | @ -97,6 +98,7 @@ func NewOptions() *Options { | ||||||
| 		CookieHttpOnly:      true, | 		CookieHttpOnly:      true, | ||||||
| 		CookieExpire:        time.Duration(168) * time.Hour, | 		CookieExpire:        time.Duration(168) * time.Hour, | ||||||
| 		CookieRefresh:       time.Duration(0), | 		CookieRefresh:       time.Duration(0), | ||||||
|  | 		SetXAuthRequest:     false, | ||||||
| 		PassBasicAuth:       true, | 		PassBasicAuth:       true, | ||||||
| 		PassUserHeaders:     true, | 		PassUserHeaders:     true, | ||||||
| 		PassAccessToken:     false, | 		PassAccessToken:     false, | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue