Skip to content

Commit

Permalink
authn/cookie_session: Add subject_from modifier (#336)
Browse files Browse the repository at this point in the history
The subject_from modifier is a GJSON path that points to the `subject` field. Useful if the upstream API does not return a `{"subject": "..."}` format.

Signed-off-by: aeneasr <[email protected]>
  • Loading branch information
aeneasr authored Jan 13, 2020
1 parent d084c39 commit 6723fb8
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 20 deletions.
6 changes: 6 additions & 0 deletions .schemas/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,12 @@
"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.",
"type": "string",
"default": "extra"
},
"subject_from": {
"title": "Subject JSON Path",
"description": "The `subject` field in the ORY Oathkeeper authentication session is set using this JSON Path. Defaults to `subject`. See [GSJON Syntax](https://github.com/tidwall/gjson/blob/master/SYNTAX.md) for reference.",
"type": "string",
"default": "subject"
}
},
"required": [
Expand Down
36 changes: 20 additions & 16 deletions pipeline/authn/authenticator_cookie_session.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"github.com/pkg/errors"
"github.com/tidwall/gjson"

"github.com/ory/go-convenience/stringsx"

"github.com/ory/herodot"

"github.com/ory/oathkeeper/driver/configuration"
Expand All @@ -30,6 +32,7 @@ type AuthenticatorCookieSessionConfiguration struct {
CheckSessionURL string `json:"check_session_url"`
PreservePath bool `json:"preserve_path"`
ExtraFrom string `json:"extra_from"`
SubjectFrom string `json:"subject_from"`
}

type AuthenticatorCookieSession struct {
Expand Down Expand Up @@ -65,6 +68,10 @@ func (a *AuthenticatorCookieSession) Config(config json.RawMessage) (*Authentica
c.ExtraFrom = "extra"
}

if len(c.SubjectFrom) == 0 {
c.SubjectFrom = "subject"
}

return &c, nil
}

Expand All @@ -78,32 +85,29 @@ func (a *AuthenticatorCookieSession) Authenticate(r *http.Request, config json.R
return nil, errors.WithStack(ErrAuthenticatorNotResponsible)
}

origin := cf.CheckSessionURL
preservePath := cf.PreservePath
body, err := forwardRequestToSessionStore(r, origin, preservePath)
body, err := forwardRequestToSessionStore(r, cf.CheckSessionURL, cf.PreservePath)
if err != nil {
return nil, err
}

var session struct {
Subject string `json:"subject"`
}
if err = json.Unmarshal(body, &session); err != nil {
return nil, helper.ErrForbidden.WithReason(err.Error()).WithTrace(err)
}
var (
subject string
extra map[string]interface{}

subjectRaw = []byte(stringsx.Coalesce(gjson.GetBytes(body, cf.SubjectFrom).Raw, "null"))
extraRaw = []byte(stringsx.Coalesce(gjson.GetBytes(body, cf.ExtraFrom).Raw, "null"))
)

extra := map[string]interface{}{}
rawExtra := gjson.GetBytes(body, cf.ExtraFrom).Raw
if rawExtra == "" {
rawExtra = "null"
if err = json.Unmarshal(subjectRaw, &subject); err != nil {
return nil, helper.ErrForbidden.WithReasonf("The configured subject_from GJSON path returned an error on JSON output: %s", err.Error()).WithDebugf("GJSON path: %s\nBody: %s\nResult: %s", cf.SubjectFrom, body, subjectRaw).WithTrace(err)
}

if err = json.Unmarshal([]byte(rawExtra), &extra); err != nil {
return nil, helper.ErrForbidden.WithReasonf("The configured GJSON path returned an error on JSON output: %s", err.Error()).WithDebugf("GJSON path: %s\nBody: %s\nResult: %s", cf.ExtraFrom, body, rawExtra).WithTrace(err)
if err = json.Unmarshal(extraRaw, &extra); err != nil {
return nil, helper.ErrForbidden.WithReasonf("The configured extra_from GJSON path returned an error on JSON output: %s", err.Error()).WithDebugf("GJSON path: %s\nBody: %s\nResult: %s", cf.ExtraFrom, body, extraRaw).WithTrace(err)
}

return &AuthenticationSession{
Subject: session.Subject,
Subject: subject,
Extra: extra,
}, nil
}
Expand Down
8 changes: 4 additions & 4 deletions pipeline/authn/authenticator_cookie_session_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,17 +133,17 @@ func TestAuthenticatorCookieSession(t *testing.T) {
}, session)
})

t.Run("description=should work with the root key", func(t *testing.T) {
testServer, _ := makeServer(200, `{"subject": "123", "session": {"foo": "bar"}}`)
t.Run("description=should work with the root key for extra and a custom subject key", func(t *testing.T) {
testServer, _ := makeServer(200, `{"identity": {"id": "123"}, "session": {"foo": "bar"}}`)
session, err := pipelineAuthenticator.Authenticate(
makeRequest("GET", "/", map[string]string{"sessionid": "zyx"}, ""),
json.RawMessage(fmt.Sprintf(`{"check_session_url": "%s", "extra_from": "@this"}`, testServer.URL)),
json.RawMessage(fmt.Sprintf(`{"check_session_url": "%s", "subject_from": "identity.id", "extra_from": "@this"}`, testServer.URL)),
nil,
)
require.NoError(t, err, "%#v", errors.Cause(err))
assert.Equal(t, &AuthenticationSession{
Subject: "123",
Extra: map[string]interface{}{"session": map[string]interface{}{"foo": "bar"}, "subject": "123"},
Extra: map[string]interface{}{"session": map[string]interface{}{"foo": "bar"}, "identity": map[string]interface{}{"id": "123"}},
}, session)
})
})
Expand Down

0 comments on commit 6723fb8

Please sign in to comment.