Skip to content

Commit

Permalink
feat: add support for additional headers in check_session and bearer …
Browse files Browse the repository at this point in the history
…token
  • Loading branch information
aeneasr committed Jul 19, 2021
1 parent 74bc0ca commit 390abe3
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 10 deletions.
14 changes: 14 additions & 0 deletions .schema/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,14 @@
"type": "boolean",
"description": "When set to true the HTTP Header X-Forwarded-Host will be set to the original HTTP host."
},
"additional_headers": {
"title": "Set Additional HTTP Headers",
"type": "object",
"description": "Set additional HTTP Headers for the Session Check URL.",
"additionalProperties": {
"type": "string"
}
},
"extra_from": {
"title": "Extra JSON Path",
"description": "The `extra` field in the ORY Oathkeeper authentication session is set using this JSON Path. Defaults to `extra`, and could be `@this` (for the root element), `foo.bar` (for key foo.bar), or any other valid GJSON path. See [GSJON Syntax](https://github.com/tidwall/gjson/blob/master/SYNTAX.md) for reference.",
Expand Down Expand Up @@ -514,6 +522,12 @@
"type": "boolean",
"description": "When set to true the HTTP Header X-Forwarded-Host will be set to the original HTTP host."
},
"additional_headers": {
"title": "Set Additional HTTP Headers",
"type": "object",
"description": "Set additional HTTP Headers for the Session Check URL.",
"additionalProperties": { "type": "string" }
},
"extra_from": {
"title": "Extra JSON Path",
"description": "The `extra` field in the ORY Oathkeeper authentication session is set using this JSON Path. Defaults to `extra`, and could be `@this` (for the root element), `foo.bar` (for key foo.bar), or any other valid GJSON path. See [GSJON Syntax](https://github.com/tidwall/gjson/blob/master/SYNTAX.md) for reference.",
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ require (
github.com/aws/aws-sdk-go v1.31.13
github.com/blang/semver v3.5.1+incompatible
github.com/bxcodec/faker v2.0.1+incompatible
github.com/davecgh/go-spew v1.1.1
github.com/dgraph-io/ristretto v0.0.2
github.com/dlclark/regexp2 v1.2.0
github.com/form3tech-oss/jwt-go v3.2.2+incompatible
Expand Down
3 changes: 2 additions & 1 deletion pipeline/authn/authenticator_bearer_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type AuthenticatorBearerTokenConfiguration struct {
PreserveHost bool `json:"preserve_host"`
ExtraFrom string `json:"extra_from"`
SubjectFrom string `json:"subject_from"`
SetHeaders map[string]string `json:"additional_headers"`
}

type AuthenticatorBearerToken struct {
Expand Down Expand Up @@ -83,7 +84,7 @@ func (a *AuthenticatorBearerToken) Authenticate(r *http.Request, session *Authen
return errors.WithStack(ErrAuthenticatorNotResponsible)
}

body, err := forwardRequestToSessionStore(r, cf.CheckSessionURL, cf.PreservePath, cf.PreserveHost)
body, err := forwardRequestToSessionStore(r, cf.CheckSessionURL, cf.PreservePath, cf.PreserveHost, cf.SetHeaders)
if err != nil {
return err
}
Expand Down
19 changes: 18 additions & 1 deletion pipeline/authn/authenticator_bearer_token_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func TestAuthenticatorBearerToken(t *testing.T) {
},
},
{
d: "should pass through method and headers ONLY to auth server when PreserveHost is true",
d: "should pass and set host when preserve_host is true",
r: &http.Request{Host: "some-host", Header: http.Header{"Authorization": {"bearer zyx"}}, URL: &url.URL{Path: "/users/123?query=string"}, Method: "PUT"},
router: func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, r.Method, "PUT")
Expand All @@ -130,6 +130,23 @@ func TestAuthenticatorBearerToken(t *testing.T) {
Subject: "123",
},
},
{
d: "should pass and set additional hosts but not overwrite x-forwarded-host",
r: &http.Request{Host: "some-host", Header: http.Header{"Authorization": {"bearer zyx"}}, URL: &url.URL{Path: "/users/123?query=string"}, Method: "PUT"},
router: func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, r.Method, "PUT")
assert.Equal(t, "some-host", r.Header.Get("X-Forwarded-Host"))
assert.Equal(t, "bar", r.Header.Get("X-Foo"))
assert.Equal(t, r.Header.Get("Authorization"), "bearer zyx")
w.WriteHeader(200)
w.Write([]byte(`{"sub": "123"}`))
},
config: []byte(`{"preserve_host": true, "additional_headers": {"X-Foo": "bar","X-Forwarded-For": "not-some-host"}}`),
expectErr: false,
expectSess: &AuthenticationSession{
Subject: "123",
},
},
{
d: "does not pass request body through to auth server",
r: &http.Request{
Expand Down
21 changes: 13 additions & 8 deletions pipeline/authn/authenticator_cookie_session.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,13 @@ type AuthenticatorCookieSessionFilter struct {
}

type AuthenticatorCookieSessionConfiguration struct {
Only []string `json:"only"`
CheckSessionURL string `json:"check_session_url"`
PreservePath bool `json:"preserve_path"`
ExtraFrom string `json:"extra_from"`
SubjectFrom string `json:"subject_from"`
PreserveHost bool `json:"preserve_host"`
Only []string `json:"only"`
CheckSessionURL string `json:"check_session_url"`
PreservePath bool `json:"preserve_path"`
ExtraFrom string `json:"extra_from"`
SubjectFrom string `json:"subject_from"`
PreserveHost bool `json:"preserve_host"`
SetHeaders map[string]string `json:"additional_headers"`
}

type AuthenticatorCookieSession struct {
Expand Down Expand Up @@ -86,7 +87,7 @@ func (a *AuthenticatorCookieSession) Authenticate(r *http.Request, session *Auth
return errors.WithStack(ErrAuthenticatorNotResponsible)
}

body, err := forwardRequestToSessionStore(r, cf.CheckSessionURL, cf.PreservePath, cf.PreserveHost)
body, err := forwardRequestToSessionStore(r, cf.CheckSessionURL, cf.PreservePath, cf.PreserveHost, cf.SetHeaders)
if err != nil {
return err
}
Expand Down Expand Up @@ -126,7 +127,7 @@ func cookieSessionResponsible(r *http.Request, only []string) bool {
return false
}

func forwardRequestToSessionStore(r *http.Request, checkSessionURL string, preservePath bool, preserveHost bool) (json.RawMessage, error) {
func forwardRequestToSessionStore(r *http.Request, checkSessionURL string, preservePath bool, preserveHost bool, setHeaders map[string]string) (json.RawMessage, error) {
reqUrl, err := url.Parse(checkSessionURL)
if err != nil {
return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Unable to parse session check URL: %s", err))
Expand All @@ -142,6 +143,10 @@ func forwardRequestToSessionStore(r *http.Request, checkSessionURL string, prese
Header: r.Header,
}

for k, v := range setHeaders {
req.Header.Set(k, v)
}

if preserveHost {
req.Header.Set("X-Forwarded-Host", r.Host)
}
Expand Down
21 changes: 21 additions & 0 deletions pipeline/authn/authenticator_cookie_session_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,27 @@ func TestAuthenticatorCookieSession(t *testing.T) {
assert.Equal(t, &AuthenticationSession{Subject: "123"}, session)
})

t.Run("description=should pass not override x-forwarded-host in set_headers", func(t *testing.T) {
testServer, requestRecorder := makeServer(200, `{"subject": "123"}`)
req := makeRequest("PUT", "/users/123?query=string", map[string]string{"sessionid": "zyx"}, "")
expectedHost := "some-host"
req.Host = expectedHost
err := pipelineAuthenticator.Authenticate(
req,
session,
json.RawMessage(fmt.Sprintf(`{"check_session_url": "%s", "additional_headers": {"X-Forwarded-Host": "not-some-host", "X-Foo": "bar"}, "preserve_host": true}`, testServer.URL)),
nil,
)
require.NoError(t, err, "%#v", errors.Cause(err))
assert.Len(t, requestRecorder.requests, 1)
r := requestRecorder.requests[0]
assert.Equal(t, r.Method, "PUT")
assert.Equal(t, expectedHost, r.Header.Get("X-Forwarded-Host"))
assert.Equal(t, "bar", r.Header.Get("X-Foo"), "%+v", r.Header)
assert.Equal(t, r.Header.Get("Cookie"), "sessionid=zyx")
assert.Equal(t, &AuthenticationSession{Subject: "123"}, session)
})

t.Run("description=does not pass request body through to auth server", func(t *testing.T) {
testServer, requestRecorder := makeServer(200, `{}`)
pipelineAuthenticator.Authenticate(
Expand Down

0 comments on commit 390abe3

Please sign in to comment.