Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: improve context #3656

Merged
merged 3 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion consent/csrf.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"strings"
"time"

"github.com/ory/hydra/v2/flow"

"github.com/gorilla/sessions"

"github.com/ory/fosite"
Expand All @@ -18,6 +20,8 @@ import (
"github.com/ory/x/mapx"
)

// WARNING - changes in this file need to be mirrored elsewhere.

func createCsrfSession(w http.ResponseWriter, r *http.Request, conf x.CookieConfigProvider, store sessions.Store, name string, csrfValue string, maxAge time.Duration) error {
// Errors can be ignored here, because we always get a session back. Error typically means that the
// session doesn't exist yet.
Expand Down Expand Up @@ -45,7 +49,7 @@ func createCsrfSession(w http.ResponseWriter, r *http.Request, conf x.CookieConf
return nil
}

func validateCsrfSession(r *http.Request, conf x.CookieConfigProvider, store sessions.Store, name, expectedCSRF string) error {
func ValidateCsrfSession(r *http.Request, conf x.CookieConfigProvider, store sessions.Store, name, expectedCSRF string, f *flow.Flow) error {
if cookie, err := getCsrfSession(r, store, conf, name); err != nil {
return errorsx.WithStack(fosite.ErrRequestForbidden.WithHint("CSRF session cookie could not be decoded."))
} else if csrf, err := mapx.GetString(cookie.Values, "csrf"); err != nil {
Expand Down
1 change: 0 additions & 1 deletion consent/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,6 @@ func (h *Handler) acceptOAuth2LoginRequest(w http.ResponseWriter, r *http.Reques
}

events.Trace(ctx, events.LoginAccepted, events.WithClientID(request.Client.GetID()), events.WithSubject(request.Subject))

h.r.Writer().Write(w, r, &flow.OAuth2RedirectTo{
RedirectTo: urlx.SetQuery(ru, url.Values{"login_verifier": {verifier}}).String(),
})
Expand Down
2 changes: 1 addition & 1 deletion consent/helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ func TestValidateCsrfSession(t *testing.T) {
assert.NoError(t, err, "failed to save cookie %s", c.name)
}

err := validateCsrfSession(r, config, store, name, tc.csrfValue)
err := ValidateCsrfSession(r, config, store, name, tc.csrfValue, new(flow.Flow))
if tc.expectError {
assert.Error(t, err)
} else {
Expand Down
4 changes: 2 additions & 2 deletions consent/strategy_default.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ func (s *DefaultStrategy) verifyAuthentication(
}

clientSpecificCookieNameLoginCSRF := fmt.Sprintf("%s_%s", s.r.Config().CookieNameLoginCSRF(ctx), session.LoginRequest.Client.CookieSuffix())
if err := validateCsrfSession(r, s.r.Config(), store, clientSpecificCookieNameLoginCSRF, session.LoginRequest.CSRF); err != nil {
if err := ValidateCsrfSession(r, s.r.Config(), store, clientSpecificCookieNameLoginCSRF, session.LoginRequest.CSRF, f); err != nil {
return nil, err
}

Expand Down Expand Up @@ -684,7 +684,7 @@ func (s *DefaultStrategy) verifyConsent(ctx context.Context, _ http.ResponseWrit
}

clientSpecificCookieNameConsentCSRF := fmt.Sprintf("%s_%s", s.r.Config().CookieNameConsentCSRF(ctx), session.ConsentRequest.Client.CookieSuffix())
if err := validateCsrfSession(r, s.r.Config(), store, clientSpecificCookieNameConsentCSRF, session.ConsentRequest.CSRF); err != nil {
if err := ValidateCsrfSession(r, s.r.Config(), store, clientSpecificCookieNameConsentCSRF, session.ConsentRequest.CSRF, f); err != nil {
return nil, nil, err
}

Expand Down
10 changes: 10 additions & 0 deletions flow/consent_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,11 @@ type AcceptOAuth2ConsentRequest struct {
// the flow.
WasHandled bool `json:"-"`

// Context is an optional object which can hold arbitrary data. The data will be made available when fetching the
// consent request under the "context" field. This is useful in scenarios where login and consent endpoints share
// data.
Context sqlxx.JSONRawMessage `json:"context"`

ConsentRequest *OAuth2ConsentRequest `json:"-"`
Error *RequestDeniedError `json:"-"`
RequestedAt time.Time `json:"-"`
Expand Down Expand Up @@ -240,6 +245,11 @@ type OAuth2ConsentSession struct {
// the flow.
WasHandled bool `json:"-" db:"was_used"`

// Context is an optional object which can hold arbitrary data. The data will be made available when fetching the
// consent request under the "context" field. This is useful in scenarios where login and consent endpoints share
// data.
Context sqlxx.JSONRawMessage `json:"context"`

// Consent Request
//
// The consent request that lead to this consent session.
Expand Down
10 changes: 9 additions & 1 deletion flow/flow.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,11 @@ func (f *Flow) HandleLoginRequest(h *HandledLoginRequest) error {
} else {
f.State = FlowStateLoginUnused
}

if f.Context != nil {
f.Context = h.Context
}

f.ID = h.ID
f.Subject = h.Subject
f.ForceSubjectIdentifier = h.ForceSubjectIdentifier
Expand All @@ -301,7 +306,6 @@ func (f *Flow) HandleLoginRequest(h *HandledLoginRequest) error {
f.LoginExtendSessionLifespan = h.ExtendSessionLifespan
f.ACR = h.ACR
f.AMR = h.AMR
f.Context = h.Context
f.LoginWasUsed = h.WasHandled
f.LoginAuthenticatedAt = h.AuthenticatedAt
return nil
Expand Down Expand Up @@ -394,6 +398,9 @@ func (f *Flow) HandleConsentRequest(r *AcceptOAuth2ConsentRequest) error {
f.ConsentHandledAt = r.HandledAt
f.ConsentWasHandled = r.WasHandled
f.ConsentError = r.Error
if r.Context != nil {
f.Context = r.Context
}

if r.Session != nil {
f.SessionIDToken = r.Session.IDToken
Expand Down Expand Up @@ -458,6 +465,7 @@ func (f *Flow) GetHandledConsentRequest() *AcceptOAuth2ConsentRequest {
RememberFor: crf,
HandledAt: f.ConsentHandledAt,
WasHandled: f.ConsentWasHandled,
Context: f.Context,
ConsentRequest: f.GetConsentRequest(),
Error: f.ConsentError,
RequestedAt: f.RequestedAt,
Expand Down
3 changes: 3 additions & 0 deletions flow/flow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ func (f *Flow) setHandledConsentRequest(r AcceptOAuth2ConsentRequest) {
f.LoginAuthenticatedAt = r.AuthenticatedAt
f.SessionIDToken = r.SessionIDToken
f.SessionAccessToken = r.SessionAccessToken
if r.Context != nil {
f.Context = r.Context
}
}

func TestFlow_GetLoginRequest(t *testing.T) {
Expand Down
7 changes: 7 additions & 0 deletions internal/httpclient/api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1926,6 +1926,9 @@ components:
type: object
acceptOAuth2ConsentRequest:
properties:
context:
title: "JSONRawMessage represents a json.RawMessage that works well with\
\ JSON, SQL, and Swagger."
grant_access_token_audience:
items:
type: string
Expand Down Expand Up @@ -3341,6 +3344,7 @@ components:
session:
access_token: ""
id_token: ""
context: ""
grant_access_token_audience:
- grant_access_token_audience
- grant_access_token_audience
Expand All @@ -3352,6 +3356,9 @@ components:
properties:
consent_request:
$ref: '#/components/schemas/oAuth2ConsentRequest'
context:
title: "JSONRawMessage represents a json.RawMessage that works well with\
\ JSON, SQL, and Swagger."
expires_at:
$ref: '#/components/schemas/oAuth2ConsentSession_expires_at'
grant_access_token_audience:
Expand Down
36 changes: 36 additions & 0 deletions internal/httpclient/docs/AcceptOAuth2ConsentRequest.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**Context** | Pointer to **interface{}** | | [optional]
**GrantAccessTokenAudience** | Pointer to **[]string** | | [optional]
**GrantScope** | Pointer to **[]string** | | [optional]
**HandledAt** | Pointer to **time.Time** | | [optional]
Expand All @@ -30,6 +31,41 @@ NewAcceptOAuth2ConsentRequestWithDefaults instantiates a new AcceptOAuth2Consent
This constructor will only assign default values to properties that have it defined,
but it doesn't guarantee that properties required by API are set

### GetContext

`func (o *AcceptOAuth2ConsentRequest) GetContext() interface{}`

GetContext returns the Context field if non-nil, zero value otherwise.

### GetContextOk

`func (o *AcceptOAuth2ConsentRequest) GetContextOk() (*interface{}, bool)`

GetContextOk returns a tuple with the Context field if it's non-nil, zero value otherwise
and a boolean to check if the value has been set.

### SetContext

`func (o *AcceptOAuth2ConsentRequest) SetContext(v interface{})`

SetContext sets Context field to given value.

### HasContext

`func (o *AcceptOAuth2ConsentRequest) HasContext() bool`

HasContext returns a boolean if a field has been set.

### SetContextNil

`func (o *AcceptOAuth2ConsentRequest) SetContextNil(b bool)`

SetContextNil sets the value for Context to be an explicit nil

### UnsetContext
`func (o *AcceptOAuth2ConsentRequest) UnsetContext()`

UnsetContext ensures that no value is present for Context, not even an explicit nil
### GetGrantAccessTokenAudience

`func (o *AcceptOAuth2ConsentRequest) GetGrantAccessTokenAudience() []string`
Expand Down
36 changes: 36 additions & 0 deletions internal/httpclient/docs/OAuth2ConsentSession.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**ConsentRequest** | Pointer to [**OAuth2ConsentRequest**](OAuth2ConsentRequest.md) | | [optional]
**Context** | Pointer to **interface{}** | | [optional]
**ExpiresAt** | Pointer to [**OAuth2ConsentSessionExpiresAt**](OAuth2ConsentSessionExpiresAt.md) | | [optional]
**GrantAccessTokenAudience** | Pointer to **[]string** | | [optional]
**GrantScope** | Pointer to **[]string** | | [optional]
Expand Down Expand Up @@ -57,6 +58,41 @@ SetConsentRequest sets ConsentRequest field to given value.

HasConsentRequest returns a boolean if a field has been set.

### GetContext

`func (o *OAuth2ConsentSession) GetContext() interface{}`

GetContext returns the Context field if non-nil, zero value otherwise.

### GetContextOk

`func (o *OAuth2ConsentSession) GetContextOk() (*interface{}, bool)`

GetContextOk returns a tuple with the Context field if it's non-nil, zero value otherwise
and a boolean to check if the value has been set.

### SetContext

`func (o *OAuth2ConsentSession) SetContext(v interface{})`

SetContext sets Context field to given value.

### HasContext

`func (o *OAuth2ConsentSession) HasContext() bool`

HasContext returns a boolean if a field has been set.

### SetContextNil

`func (o *OAuth2ConsentSession) SetContextNil(b bool)`

SetContextNil sets the value for Context to be an explicit nil

### UnsetContext
`func (o *OAuth2ConsentSession) UnsetContext()`

UnsetContext ensures that no value is present for Context, not even an explicit nil
### GetExpiresAt

`func (o *OAuth2ConsentSession) GetExpiresAt() OAuth2ConsentSessionExpiresAt`
Expand Down
6 changes: 6 additions & 0 deletions spec/api.json
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@
},
"acceptOAuth2ConsentRequest": {
"properties": {
"context": {
"$ref": "#/components/schemas/JSONRawMessage"
},
"grant_access_token_audience": {
"$ref": "#/components/schemas/StringSliceJSONFormat"
},
Expand Down Expand Up @@ -918,6 +921,9 @@
"consent_request": {
"$ref": "#/components/schemas/oAuth2ConsentRequest"
},
"context": {
"$ref": "#/components/schemas/JSONRawMessage"
},
"expires_at": {
"properties": {
"access_token": {
Expand Down
6 changes: 6 additions & 0 deletions spec/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -2173,6 +2173,9 @@
"type": "object",
"title": "The request payload used to accept a consent request.",
"properties": {
"context": {
"$ref": "#/definitions/JSONRawMessage"
},
"grant_access_token_audience": {
"$ref": "#/definitions/StringSliceJSONFormat"
},
Expand Down Expand Up @@ -2938,6 +2941,9 @@
"consent_request": {
"$ref": "#/definitions/oAuth2ConsentRequest"
},
"context": {
"$ref": "#/definitions/JSONRawMessage"
},
"grant_access_token_audience": {
"$ref": "#/definitions/StringSliceJSONFormat"
},
Expand Down
Loading