Add set basic auth param (#413)
* addint redirect capability to sign_out * updating changelog * Add a new param to set the Authorization header to up-stream systems as Basic user:password * Resolving code review * mutual exclusiv changes for Basic and Bearer Authorization header * Fixed the merge mixup and comment error * Updated changelog and fixed typo * Adding the new entry in changelog Co-authored-by: Costel Moraru <costel.moraru-germany@ibm.com>
This commit is contained in:
		
							parent
							
								
									7efc162aaa
								
							
						
					
					
						commit
						b0b87563dc
					
				|  | @ -27,6 +27,7 @@ | ||||||
| - [#432](https://github.com/oauth2-proxy/oauth2-proxy/pull/432) Update ruby dependencies for documentation (@theobarberbany) | - [#432](https://github.com/oauth2-proxy/oauth2-proxy/pull/432) Update ruby dependencies for documentation (@theobarberbany) | ||||||
| - [#471](https://github.com/oauth2-proxy/oauth2-proxy/pull/471) Add logging in case of invalid redirects (@gargath) | - [#471](https://github.com/oauth2-proxy/oauth2-proxy/pull/471) Add logging in case of invalid redirects (@gargath) | ||||||
| - [#462](https://github.com/oauth2-proxy/oauth2-proxy/pull/462) Allow HTML in banner message (@eritikass). | - [#462](https://github.com/oauth2-proxy/oauth2-proxy/pull/462) Allow HTML in banner message (@eritikass). | ||||||
|  | - [#413](https://github.com/oauth2-proxy/oauth2-proxy/pull/413) Add -set-basic-auth param to set the Basic Authorization header for upstreams (@morarucostel). | ||||||
| 
 | 
 | ||||||
| # v5.1.0 | # v5.1.0 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -103,6 +103,7 @@ An example [oauth2-proxy.cfg]({{ site.gitweb }}/contrib/oauth2-proxy.cfg.example | ||||||
| | `-session-store-type` | string | [Session data storage backend](configuration/sessions); redis or cookie | cookie | | | `-session-store-type` | string | [Session data storage backend](configuration/sessions); redis or cookie | cookie | | ||||||
| | `-set-xauthrequest` | bool | set X-Auth-Request-User, X-Auth-Request-Email and X-Auth-Request-Preferred-Username response headers (useful in Nginx auth_request mode) | false | | | `-set-xauthrequest` | bool | set X-Auth-Request-User, X-Auth-Request-Email and X-Auth-Request-Preferred-Username response headers (useful in Nginx auth_request mode) | false | | ||||||
| | `-set-authorization-header` | bool | set Authorization Bearer response header (useful in Nginx auth_request mode) | false | | | `-set-authorization-header` | bool | set Authorization Bearer response header (useful in Nginx auth_request mode) | false | | ||||||
|  | | `-set-basic-auth` | bool | set HTTP Basic Auth information in response (useful in Nginx auth_request mode) | true | | ||||||
| | `-signature-key` | string | GAP-Signature request signature key (algorithm:secretkey) | | | | `-signature-key` | string | GAP-Signature request signature key (algorithm:secretkey) | | | ||||||
| | `-silence-ping-logging` | bool | disable logging of requests to ping endpoint | false | | | `-silence-ping-logging` | bool | disable logging of requests to ping endpoint | false | | ||||||
| | `-skip-auth-preflight` | bool | will skip authentication for OPTIONS requests | false | | | `-skip-auth-preflight` | bool | will skip authentication for OPTIONS requests | false | | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								main.go
								
								
								
								
							
							
						
						
									
										1
									
								
								main.go
								
								
								
								
							|  | @ -43,6 +43,7 @@ func main() { | ||||||
| 	flagSet.Bool("set-xauthrequest", false, "set X-Auth-Request-User and X-Auth-Request-Email response headers (useful in Nginx auth_request mode)") | 	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, file:// paths for static files or static://<status_code> for static response. Routing is based on the path") | 	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") | ||||||
| 	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("set-basic-auth", true, "set HTTP Basic Auth information in response (useful in Nginx auth_request mode)") | ||||||
| 	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") | 	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") | ||||||
| 	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") | ||||||
| 	flagSet.String("basic-auth-password", "", "the password to set when passing the HTTP Basic Auth header") | 	flagSet.String("basic-auth-password", "", "the password to set when passing the HTTP Basic Auth header") | ||||||
|  |  | ||||||
|  | @ -94,6 +94,7 @@ type OAuthProxy struct { | ||||||
| 	serveMux             http.Handler | 	serveMux             http.Handler | ||||||
| 	SetXAuthRequest      bool | 	SetXAuthRequest      bool | ||||||
| 	PassBasicAuth        bool | 	PassBasicAuth        bool | ||||||
|  | 	SetBasicAuth         bool | ||||||
| 	SkipProviderButton   bool | 	SkipProviderButton   bool | ||||||
| 	PassUserHeaders      bool | 	PassUserHeaders      bool | ||||||
| 	BasicAuthPassword    string | 	BasicAuthPassword    string | ||||||
|  | @ -302,6 +303,7 @@ func NewOAuthProxy(opts *Options, validator func(string) bool) *OAuthProxy { | ||||||
| 		compiledRegex:        opts.CompiledRegex, | 		compiledRegex:        opts.CompiledRegex, | ||||||
| 		SetXAuthRequest:      opts.SetXAuthRequest, | 		SetXAuthRequest:      opts.SetXAuthRequest, | ||||||
| 		PassBasicAuth:        opts.PassBasicAuth, | 		PassBasicAuth:        opts.PassBasicAuth, | ||||||
|  | 		SetBasicAuth:         opts.SetBasicAuth, | ||||||
| 		PassUserHeaders:      opts.PassUserHeaders, | 		PassUserHeaders:      opts.PassUserHeaders, | ||||||
| 		BasicAuthPassword:    opts.BasicAuthPassword, | 		BasicAuthPassword:    opts.BasicAuthPassword, | ||||||
| 		PassAccessToken:      opts.PassAccessToken, | 		PassAccessToken:      opts.PassAccessToken, | ||||||
|  | @ -1037,6 +1039,14 @@ func (p *OAuthProxy) addHeadersForProxying(rw http.ResponseWriter, req *http.Req | ||||||
| 			req.Header.Del("Authorization") | 			req.Header.Del("Authorization") | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	if p.SetBasicAuth { | ||||||
|  | 		if session.User != "" { | ||||||
|  | 			authVal := b64.StdEncoding.EncodeToString([]byte(session.User + ":" + p.BasicAuthPassword)) | ||||||
|  | 			rw.Header().Set("Authorization", "Basic "+authVal) | ||||||
|  | 		} else { | ||||||
|  | 			rw.Header().Del("Authorization") | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 	if p.SetAuthorization { | 	if p.SetAuthorization { | ||||||
| 		if session.IDToken != "" { | 		if session.IDToken != "" { | ||||||
| 			rw.Header().Set("Authorization", fmt.Sprintf("Bearer %s", session.IDToken)) | 			rw.Header().Set("Authorization", fmt.Sprintf("Bearer %s", session.IDToken)) | ||||||
|  |  | ||||||
|  | @ -404,6 +404,7 @@ func TestBasicAuthPassword(t *testing.T) { | ||||||
| 	opts.ClientSecret = "alkgret" | 	opts.ClientSecret = "alkgret" | ||||||
| 	opts.CookieSecure = false | 	opts.CookieSecure = false | ||||||
| 	opts.PassBasicAuth = true | 	opts.PassBasicAuth = true | ||||||
|  | 	opts.SetBasicAuth = true | ||||||
| 	opts.PassUserHeaders = true | 	opts.PassUserHeaders = true | ||||||
| 	opts.PreferEmailToUser = true | 	opts.PreferEmailToUser = true | ||||||
| 	opts.BasicAuthPassword = "This is a secure password" | 	opts.BasicAuthPassword = "This is a secure password" | ||||||
|  | @ -1075,6 +1076,71 @@ func TestAuthOnlyEndpointSetXAuthRequestHeaders(t *testing.T) { | ||||||
| 	assert.Equal(t, "oauth_user@example.com", pcTest.rw.HeaderMap["X-Auth-Request-Email"][0]) | 	assert.Equal(t, "oauth_user@example.com", pcTest.rw.HeaderMap["X-Auth-Request-Email"][0]) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func TestAuthOnlyEndpointSetBasicAuthTrueRequestHeaders(t *testing.T) { | ||||||
|  | 	var pcTest ProcessCookieTest | ||||||
|  | 
 | ||||||
|  | 	pcTest.opts = NewOptions() | ||||||
|  | 	pcTest.opts.SetXAuthRequest = true | ||||||
|  | 	pcTest.opts.SetBasicAuth = true | ||||||
|  | 	pcTest.opts.Validate() | ||||||
|  | 
 | ||||||
|  | 	pcTest.proxy = NewOAuthProxy(pcTest.opts, func(email string) bool { | ||||||
|  | 		return pcTest.validateUser | ||||||
|  | 	}) | ||||||
|  | 	pcTest.proxy.provider = &TestProvider{ | ||||||
|  | 		ValidToken: true, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	pcTest.validateUser = true | ||||||
|  | 
 | ||||||
|  | 	pcTest.rw = httptest.NewRecorder() | ||||||
|  | 	pcTest.req, _ = http.NewRequest("GET", | ||||||
|  | 		pcTest.opts.ProxyPrefix+"/auth", nil) | ||||||
|  | 
 | ||||||
|  | 	startSession := &sessions.SessionState{ | ||||||
|  | 		User: "oauth_user", Email: "oauth_user@example.com", AccessToken: "oauth_token", CreatedAt: time.Now()} | ||||||
|  | 	pcTest.SaveSession(startSession) | ||||||
|  | 
 | ||||||
|  | 	pcTest.proxy.ServeHTTP(pcTest.rw, pcTest.req) | ||||||
|  | 	assert.Equal(t, http.StatusAccepted, pcTest.rw.Code) | ||||||
|  | 	assert.Equal(t, "oauth_user", pcTest.rw.HeaderMap["X-Auth-Request-User"][0]) | ||||||
|  | 	assert.Equal(t, "oauth_user@example.com", pcTest.rw.HeaderMap["X-Auth-Request-Email"][0]) | ||||||
|  | 	expectedHeader := "Basic " + base64.StdEncoding.EncodeToString([]byte("oauth_user:"+pcTest.opts.BasicAuthPassword)) | ||||||
|  | 	assert.Equal(t, expectedHeader, pcTest.rw.HeaderMap["Authorization"][0]) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestAuthOnlyEndpointSetBasicAuthFalseRequestHeaders(t *testing.T) { | ||||||
|  | 	var pcTest ProcessCookieTest | ||||||
|  | 
 | ||||||
|  | 	pcTest.opts = NewOptions() | ||||||
|  | 	pcTest.opts.SetXAuthRequest = true | ||||||
|  | 	pcTest.opts.SetBasicAuth = false | ||||||
|  | 	pcTest.opts.Validate() | ||||||
|  | 
 | ||||||
|  | 	pcTest.proxy = NewOAuthProxy(pcTest.opts, func(email string) bool { | ||||||
|  | 		return pcTest.validateUser | ||||||
|  | 	}) | ||||||
|  | 	pcTest.proxy.provider = &TestProvider{ | ||||||
|  | 		ValidToken: true, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	pcTest.validateUser = true | ||||||
|  | 
 | ||||||
|  | 	pcTest.rw = httptest.NewRecorder() | ||||||
|  | 	pcTest.req, _ = http.NewRequest("GET", | ||||||
|  | 		pcTest.opts.ProxyPrefix+"/auth", nil) | ||||||
|  | 
 | ||||||
|  | 	startSession := &sessions.SessionState{ | ||||||
|  | 		User: "oauth_user", Email: "oauth_user@example.com", AccessToken: "oauth_token", CreatedAt: time.Now()} | ||||||
|  | 	pcTest.SaveSession(startSession) | ||||||
|  | 
 | ||||||
|  | 	pcTest.proxy.ServeHTTP(pcTest.rw, pcTest.req) | ||||||
|  | 	assert.Equal(t, http.StatusAccepted, pcTest.rw.Code) | ||||||
|  | 	assert.Equal(t, "oauth_user", pcTest.rw.HeaderMap["X-Auth-Request-User"][0]) | ||||||
|  | 	assert.Equal(t, "oauth_user@example.com", pcTest.rw.HeaderMap["X-Auth-Request-Email"][0]) | ||||||
|  | 	assert.Equal(t, 0, len(pcTest.rw.HeaderMap["Authorization"]), "should not have Authorization header entries") | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func TestAuthSkippedForPreflightRequests(t *testing.T) { | func TestAuthSkippedForPreflightRequests(t *testing.T) { | ||||||
| 	upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | 	upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||||
| 		w.WriteHeader(200) | 		w.WriteHeader(200) | ||||||
|  |  | ||||||
|  | @ -73,6 +73,7 @@ type Options struct { | ||||||
| 	SkipJwtBearerTokens           bool          `flag:"skip-jwt-bearer-tokens" cfg:"skip_jwt_bearer_tokens" env:"OAUTH2_PROXY_SKIP_JWT_BEARER_TOKENS"` | 	SkipJwtBearerTokens           bool          `flag:"skip-jwt-bearer-tokens" cfg:"skip_jwt_bearer_tokens" env:"OAUTH2_PROXY_SKIP_JWT_BEARER_TOKENS"` | ||||||
| 	ExtraJwtIssuers               []string      `flag:"extra-jwt-issuers" cfg:"extra_jwt_issuers" env:"OAUTH2_PROXY_EXTRA_JWT_ISSUERS"` | 	ExtraJwtIssuers               []string      `flag:"extra-jwt-issuers" cfg:"extra_jwt_issuers" env:"OAUTH2_PROXY_EXTRA_JWT_ISSUERS"` | ||||||
| 	PassBasicAuth                 bool          `flag:"pass-basic-auth" cfg:"pass_basic_auth" env:"OAUTH2_PROXY_PASS_BASIC_AUTH"` | 	PassBasicAuth                 bool          `flag:"pass-basic-auth" cfg:"pass_basic_auth" env:"OAUTH2_PROXY_PASS_BASIC_AUTH"` | ||||||
|  | 	SetBasicAuth                  bool          `flag:"set-basic-auth" cfg:"set_basic_auth" env:"OAUTH2_PROXY_SET_BASIC_AUTH"` | ||||||
| 	PreferEmailToUser             bool          `flag:"prefer-email-to-user" cfg:"prefer_email_to_user" env:"OAUTH2_PROXY_PREFER_EMAIL_TO_USER"` | 	PreferEmailToUser             bool          `flag:"prefer-email-to-user" cfg:"prefer_email_to_user" env:"OAUTH2_PROXY_PREFER_EMAIL_TO_USER"` | ||||||
| 	BasicAuthPassword             string        `flag:"basic-auth-password" cfg:"basic_auth_password" env:"OAUTH2_PROXY_BASIC_AUTH_PASSWORD"` | 	BasicAuthPassword             string        `flag:"basic-auth-password" cfg:"basic_auth_password" env:"OAUTH2_PROXY_BASIC_AUTH_PASSWORD"` | ||||||
| 	PassAccessToken               bool          `flag:"pass-access-token" cfg:"pass_access_token" env:"OAUTH2_PROXY_PASS_ACCESS_TOKEN"` | 	PassAccessToken               bool          `flag:"pass-access-token" cfg:"pass_access_token" env:"OAUTH2_PROXY_PASS_ACCESS_TOKEN"` | ||||||
|  | @ -166,6 +167,7 @@ func NewOptions() *Options { | ||||||
| 		SetXAuthRequest:                  false, | 		SetXAuthRequest:                  false, | ||||||
| 		SkipAuthPreflight:                false, | 		SkipAuthPreflight:                false, | ||||||
| 		PassBasicAuth:                    true, | 		PassBasicAuth:                    true, | ||||||
|  | 		SetBasicAuth:                     false, | ||||||
| 		PassUserHeaders:                  true, | 		PassUserHeaders:                  true, | ||||||
| 		PassAccessToken:                  false, | 		PassAccessToken:                  false, | ||||||
| 		PassHostHeader:                   true, | 		PassHostHeader:                   true, | ||||||
|  | @ -243,6 +245,10 @@ func (o *Options) Validate() error { | ||||||
| 			"\n      use email-domain=* to authorize all email addresses") | 			"\n      use email-domain=* to authorize all email addresses") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if o.SetBasicAuth && o.SetAuthorization { | ||||||
|  | 		msgs = append(msgs, "mutually exclusive: set-basic-auth and set-authorization-header can not both be true") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	if o.OIDCIssuerURL != "" { | 	if o.OIDCIssuerURL != "" { | ||||||
| 
 | 
 | ||||||
| 		ctx := context.Background() | 		ctx := context.Background() | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue