Skip to content

Commit

Permalink
Make authCodeOptions dynamic on OIDC auth filters (#1602)
Browse files Browse the repository at this point in the history
On OIDC auth filters, Auth Code Options will be able to be dynamically set by a query parameter.

Signed-off-by: raraujo <raraujo@jw.org>
  • Loading branch information
rraraujo authored Nov 26, 2020
1 parent 807227a commit 11e4b51
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 7 deletions.
6 changes: 3 additions & 3 deletions docs/reference/filters.md
Original file line number Diff line number Diff line change
Expand Up @@ -1101,7 +1101,7 @@ The filter needs the following parameters:
It can be any value which is a subpath on which the filter is applied.
* **Scopes** The OpenID scopes separated by spaces which need to be specified when requesting the token from the provider.
* **Claims** The claims which should be present in the token returned by the provider.
* **Auth Code Options** (optional) Passes key/value parameters to a provider's authorization endpoint.
* **Auth Code Options** (optional) Passes key/value parameters to a provider's authorization endpoint. The value can be dynamically set by a query parameter with the same key name if the placeholder `skipper-request-query` is used.
* **Upstream Headers** (optional) The upstream endpoint will receive these headers which values are parsed from the OIDC information. The header definition can be one or more header-query pairs, space delimited. The query syntax is [GJSON](https://github.com/tidwall/gjson/blob/master/SYNTAX.md).

## oauthOidcAnyClaims
Expand All @@ -1121,7 +1121,7 @@ The filter needs the following parameters:
It can be any value which is a subpath on which the filter is applied.
* **Scopes** The OpenID scopes separated by spaces which need to be specified when requesting the token from the provider.
* **Claims** Several claims can be specified and the request is allowed as long as at least one of them is present.
* **Auth Code Options** (optional) Passes key/value parameters to a provider's authorization endpoint.
* **Auth Code Options** (optional) Passes key/value parameters to a provider's authorization endpoint. The value can be dynamically set by a query parameter with the same key name if the placeholder `skipper-request-query` is used.
* **Upstream Headers** (optional) The upstream endpoint will receive these headers which values are parsed from the OIDC information. The header definition can be one or more header-query pairs, space delimited. The query syntax is [GJSON](https://github.com/tidwall/gjson/blob/master/SYNTAX.md).

## oauthOidcAllClaims
Expand All @@ -1141,7 +1141,7 @@ The filter needs the following parameters:
It can be any value which is a subpath on which the filter is applied.
* **Scopes** The OpenID scopes separated by spaces which need to be specified when requesting the token from the provider.
* **Claims** Several claims can be specified and the request is allowed only when all claims are present.
* **Auth Code Options** (optional) Passes key/value parameters to a provider's authorization endpoint.
* **Auth Code Options** (optional) Passes key/value parameters to a provider's authorization endpoint. The value can be dynamically set by a query parameter with the same key name if the placeholder `skipper-request-query` is used.
* **Upstream Headers** (optional) The upstream endpoint will receive these headers which values are parsed from the OIDC information. The header definition can be one or more header-query pairs, space delimited. The query syntax is [GJSON](https://github.com/tidwall/gjson/blob/master/SYNTAX.md).

## requestCookie
Expand Down
20 changes: 18 additions & 2 deletions filters/auth/oidc.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ type (
redirectPath string
encrypter secrets.Encryption
authCodeOptions []oauth2.AuthCodeOption
queryParams []string
compressor cookieCompression
upstreamHeaders map[string]string
}
Expand Down Expand Up @@ -205,7 +206,11 @@ func (s *tokenOidcSpec) CreateFilter(args []interface{}) (filters.Filter, error)
if len(splitP) != 2 {
return nil, filters.ErrInvalidFilterParameters
}
f.authCodeOptions = append(f.authCodeOptions, oauth2.SetAuthURLParam(splitP[0], splitP[1]))
if splitP[1] == "skipper-request-query" {
f.queryParams = append(f.queryParams, splitP[0])
} else {
f.authCodeOptions = append(f.authCodeOptions, oauth2.SetAuthURLParam(splitP[0], splitP[1]))
}
}
}
log.Debugf("Auth Code Options: %v", f.authCodeOptions)
Expand Down Expand Up @@ -327,7 +332,18 @@ func (f *tokenOidcFilter) doOauthRedirect(ctx filters.FilterContext) {
return
}

oauth2URL := f.config.AuthCodeURL(fmt.Sprintf("%x", stateEnc), f.authCodeOptions...)
opts := f.authCodeOptions
if f.queryParams != nil {
opts = make([]oauth2.AuthCodeOption, len(f.authCodeOptions), len(f.authCodeOptions)+len(f.queryParams))
copy(opts, f.authCodeOptions)
for _, p := range f.queryParams {
if v := ctx.Request().URL.Query().Get(p); v != "" {
opts = append(opts, oauth2.SetAuthURLParam(p, v))
}
}
}

oauth2URL := f.config.AuthCodeURL(fmt.Sprintf("%x", stateEnc), opts...)
rsp := &http.Response{
Header: http.Header{
"Location": []string{oauth2URL},
Expand Down
30 changes: 28 additions & 2 deletions filters/auth/oidc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,8 @@ func TestOIDCSetup(t *testing.T) {
clientsecret string
scopes []string
claims []string
authCodeOpts []string
queries []string
authType roleCheckType
upstreamheaders string
expected int
Expand Down Expand Up @@ -683,6 +685,22 @@ func TestOIDCSetup(t *testing.T) {
claims: []string{"sub", "uid"},
upstreamheaders: "x-auth-email:claims.email x-auth-something:claims.sub x-auth-groups:claims.groups.#[%\"*-Users\"]",
expectRequest: "X-Auth-Email: someone@example.org\r\nX-Auth-Groups: AppX-Test-Users\r\nX-Auth-Something: somesub",
}, {
msg: "invalid auth code option",
client: validClient,
clientsecret: "mysec",
authType: checkOIDCAnyClaims,
authCodeOpts: []string{"foo"},
expectErr: true,
}, {
msg: "auth code with a placeholder and a regular option",
client: validClient,
clientsecret: "mysec",
authType: checkOIDCAnyClaims,
authCodeOpts: []string{"foo=skipper-request-query", "bar=baz"},
queries: []string{"foo=bar"},
expected: 200,
expectErr: false,
}} {
t.Run(tc.msg, func(t *testing.T) {
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -732,8 +750,16 @@ func TestOIDCSetup(t *testing.T) {

sargs = append(sargs, strings.Join(tc.scopes, " "))
sargs = append(sargs, strings.Join(tc.claims, " "))
// test not implemented for authCodeOptions
sargs = append(sargs, "")
sargs = append(sargs, strings.Join(tc.authCodeOpts, " "))

if tc.queries != nil {
q := reqURL.Query()
for _, rq := range tc.queries {
splitRQ := strings.Split(rq, "=")
q.Add(splitRQ[0], splitRQ[1])
}
reqURL.RawQuery = q.Encode()
}

if tc.upstreamheaders != "" {
sargs = append(sargs, tc.upstreamheaders)
Expand Down

0 comments on commit 11e4b51

Please sign in to comment.