Skip to content

Commit

Permalink
Enable forward-auth also for Oauth code flow (#240)
Browse files Browse the repository at this point in the history
* Enable forward-auth also for Oauth code flow

* Move nolint comment

* Change testing k8s yaml gatekeeper image
  • Loading branch information
p53 committed Dec 15, 2022
1 parent 11ec1be commit 0ba1661
Show file tree
Hide file tree
Showing 11 changed files with 2,785 additions and 28 deletions.
14 changes: 10 additions & 4 deletions common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ type fakeRequest struct {
Groups []string
HasCookieToken bool
HasLogin bool
LoginXforwarded bool
HasToken bool
Headers map[string]string
Method string
Expand Down Expand Up @@ -278,7 +279,7 @@ func (f *fakeProxy) RunTests(t *testing.T, requests []fakeRequest) {

// are we performing a oauth login beforehand
if reqCfg.HasLogin {
if err := f.performUserLogin(reqCfg.URI); err != nil {
if err := f.performUserLogin(&reqCfg); err != nil {
t.Errorf(
"case %d, unable to login to oauth server, error: %s",
idx,
Expand Down Expand Up @@ -627,8 +628,8 @@ func (f *fakeProxy) RunTests(t *testing.T, requests []fakeRequest) {
}
}

func (f *fakeProxy) performUserLogin(uri string) error {
resp, flowCookies, err := makeTestCodeFlowLogin(f.getServiceURL() + uri)
func (f *fakeProxy) performUserLogin(reqCfg *fakeRequest) error {
resp, flowCookies, err := makeTestCodeFlowLogin(f.getServiceURL()+reqCfg.URI, reqCfg.LoginXforwarded)
if err != nil {
return err
}
Expand Down Expand Up @@ -781,7 +782,7 @@ func newFakeKeycloakConfig() *Config {
}
}

func makeTestCodeFlowLogin(location string) (*http.Response, []*http.Cookie, error) {
func makeTestCodeFlowLogin(location string, xforwarded bool) (*http.Response, []*http.Cookie, error) {
flowCookies := make([]*http.Cookie, 0)

uri, err := url.Parse(location)
Expand All @@ -794,6 +795,11 @@ func makeTestCodeFlowLogin(location string) (*http.Response, []*http.Cookie, err
for count := 0; count < 4; count++ {
req, err := http.NewRequest(http.MethodGet, location, nil)

if xforwarded {
req.Header.Add("X-Forwarded-Host", uri.Host)
req.Header.Add("X-Forwarded-Proto", uri.Scheme)
}

if err != nil {
return nil, nil, err
}
Expand Down
7 changes: 5 additions & 2 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -432,8 +432,11 @@ func (r *Config) isTokenVerificationSettingsValid() error {
}

func (r *Config) isNoProxyValid() error {
if r.NoProxy && !r.NoRedirects {
return errors.New("noproxy option must be used with noredirects")
if r.NoProxy && !r.NoRedirects && r.RedirectionURL != "" {
return errors.New("when in forward-auth mode - " +
"noproxy=true with noredirect=false, redirectionURL " +
"should not be set, will be composed from X-FORWARDED-* headers",
)
}
return nil
}
Expand Down
11 changes: 10 additions & 1 deletion config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1275,11 +1275,20 @@ func TestIsNoProxyValid(t *testing.T) {
Valid: true,
},
{
Name: "InValidNoProxy",
Name: "ValidNoProxy",
Config: &Config{
NoProxy: true,
NoRedirects: false,
},
Valid: true,
},
{
Name: "InValidNoProxy",
Config: &Config{
NoProxy: true,
NoRedirects: false,
RedirectionURL: "http://some",
},
Valid: false,
},
}
Expand Down
11 changes: 9 additions & 2 deletions cookies.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,16 @@ func (r *oauthProxy) writeStateParameterCookie(req *http.Request, wrt http.Respo
wrt.WriteHeader(http.StatusInternalServerError)
}

requestURI := base64.StdEncoding.EncodeToString([]byte(req.URL.RequestURI()))
requestURI := req.URL.RequestURI()

r.dropCookie(wrt, req.Host, r.config.CookieRequestURIName, requestURI, 0)
if r.config.NoProxy && !r.config.NoRedirects {
xReqURI := req.Header.Get("X-Forwarded-Uri")
requestURI = xReqURI
}

encRequestURI := base64.StdEncoding.EncodeToString([]byte(requestURI))

r.dropCookie(wrt, req.Host, r.config.CookieRequestURIName, encRequestURI, 0)
r.dropCookie(wrt, req.Host, r.config.CookieOAuthStateName, uuid.String(), 0)

return uuid.String()
Expand Down
8 changes: 4 additions & 4 deletions cookies_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import (

func TestCookieDomainHostHeader(t *testing.T) {
svc := newTestService()
resp, _, err := makeTestCodeFlowLogin(svc + "/admin")
resp, _, err := makeTestCodeFlowLogin(svc+"/admin", false)
assert.NoError(t, err)
assert.NotNil(t, resp)

Expand All @@ -53,7 +53,7 @@ func TestCookieBasePath(t *testing.T) {

_, _, svc := newTestProxyService(cfg)

resp, _, err := makeTestCodeFlowLogin(svc + "/admin")
resp, _, err := makeTestCodeFlowLogin(svc+"/admin", false)
assert.NoError(t, err)
assert.NotNil(t, resp)

Expand All @@ -74,7 +74,7 @@ func TestCookieWithoutBasePath(t *testing.T) {

_, _, svc := newTestProxyService(cfg)

resp, _, err := makeTestCodeFlowLogin(svc + "/admin")
resp, _, err := makeTestCodeFlowLogin(svc+"/admin", false)
assert.NoError(t, err)
assert.NotNil(t, resp)

Expand All @@ -93,7 +93,7 @@ func TestCookieWithoutBasePath(t *testing.T) {
func TestCookieDomain(t *testing.T) {
p, _, svc := newTestProxyService(nil)
p.config.CookieDomain = "domain.com"
resp, _, err := makeTestCodeFlowLogin(svc + "/admin")
resp, _, err := makeTestCodeFlowLogin(svc+"/admin", false)
assert.NoError(t, err)
assert.NotNil(t, resp)

Expand Down
6 changes: 5 additions & 1 deletion docs/user-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -665,7 +665,11 @@ the store.
There are 3 possibilities how to logout:

1. Calling **/oauth/logout** with token and `redirection-url` parameter set in gatekeeper config.
This is gatekeeper own mechanism, which revokes token and redirects to provided url.
This is gatekeeper own mechanism, which revokes token and redirects to provided url.
**IMPORTANT:** You will want to use `--enable-refresh-tokens=true` for this logout mechanism, this ensures
that all access-tokens related to this refresh token will be invalidated, in case this option is not
enabled it will only revoke current access-token, that means that after next request and use of refresh
token stored in cookie user will retrieve new access token and still will have access.

2. There is also option `--enable-logout-redirect` which uses keycloak logout mechanism
and this logout url <https://keycloak.example.com/auth/realms/REALM_NAME/protocol/openid-connect/logout>.
Expand Down

0 comments on commit 0ba1661

Please sign in to comment.