Skip to content

Commit

Permalink
feat: list consent sessions by session id (#2853)
Browse files Browse the repository at this point in the history
  • Loading branch information
aarmam committed Dec 7, 2022
1 parent f2925ee commit d275ad6
Show file tree
Hide file tree
Showing 10 changed files with 150 additions and 10 deletions.
15 changes: 14 additions & 1 deletion consent/handler.go
Expand Up @@ -149,6 +149,11 @@ type listOAuth2ConsentSessions struct {
// in: query
// required: true
Subject string `json:"subject"`
// The login session id to list the consent sessions for.
//
// in: query
// required: false
LoginSessionId string `json:"login_session_id"`
}

// swagger:route GET /admin/oauth2/auth/sessions/consent oAuth2 listOAuth2ConsentSessions
Expand Down Expand Up @@ -176,9 +181,17 @@ func (h *Handler) listOAuth2ConsentSessions(w http.ResponseWriter, r *http.Reque
h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithHint(`Query parameter 'subject' is not defined but should have been.`)))
return
}
loginSessionId := r.URL.Query().Get("login_session_id")

page, itemsPerPage := x.ParsePagination(r)
s, err := h.r.ConsentManager().FindSubjectsGrantedConsentRequests(r.Context(), subject, itemsPerPage, itemsPerPage*page)

var s []AcceptOAuth2ConsentRequest
var err error
if len(loginSessionId) == 0 {
s, err = h.r.ConsentManager().FindSubjectsGrantedConsentRequests(r.Context(), subject, itemsPerPage, itemsPerPage*page)
} else {
s, err = h.r.ConsentManager().FindSubjectsSessionGrantedConsentRequests(r.Context(), subject, loginSessionId, itemsPerPage, itemsPerPage*page)
}
if errors.Is(err, ErrNoPreviousConsentFound) {
h.r.Writer().Write(w, r, []OAuth2ConsentSession{})
return
Expand Down
1 change: 1 addition & 0 deletions consent/manager.go
Expand Up @@ -33,6 +33,7 @@ type Manager interface {
VerifyAndInvalidateConsentRequest(ctx context.Context, verifier string) (*AcceptOAuth2ConsentRequest, error)
FindGrantedAndRememberedConsentRequests(ctx context.Context, client, user string) ([]AcceptOAuth2ConsentRequest, error)
FindSubjectsGrantedConsentRequests(ctx context.Context, user string, limit, offset int) ([]AcceptOAuth2ConsentRequest, error)
FindSubjectsSessionGrantedConsentRequests(ctx context.Context, user, sid string, limit, offset int) ([]AcceptOAuth2ConsentRequest, error)
CountSubjectsGrantedConsentRequests(ctx context.Context, user string) (int, error)

// Cookie management
Expand Down
47 changes: 47 additions & 0 deletions consent/manager_test_helpers.go
Expand Up @@ -314,6 +314,7 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit
lr[k] = &LoginRequest{
ID: makeID("fk-login-challenge", network, k),
Subject: fmt.Sprintf("subject%s", k),
SessionID: sqlxx.NullString(makeID("fk-login-session", network, k)),
Verifier: makeID("fk-login-verifier", network, k),
Client: &client.Client{LegacyClientID: fmt.Sprintf("fk-client-%s", k)},
AuthenticatedAt: sqlxx.NullTime(time.Now()),
Expand Down Expand Up @@ -668,6 +669,52 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit
_, err = m.HandleConsentRequest(context.Background(), hcr2)
require.NoError(t, err)

for i, tc := range []struct {
subject string
sid string
challenges []string
clients []string
}{
{
subject: cr1.Subject,
sid: makeID("fk-login-session", network, "rv1"),
challenges: []string{challengerv1},
clients: []string{"fk-client-rv1"},
},
{
subject: cr2.Subject,
sid: makeID("fk-login-session", network, "rv2"),
challenges: []string{challengerv2},
clients: []string{"fk-client-rv2"},
},
{
subject: "subjectrv3",
sid: makeID("fk-login-session", network, "rv2"),
challenges: []string{},
clients: []string{},
},
} {
t.Run(fmt.Sprintf("case=%d/subject=%s/session=%s", i, tc.subject, tc.sid), func(t *testing.T) {
consents, err := m.FindSubjectsSessionGrantedConsentRequests(context.Background(), tc.subject, tc.sid, 100, 0)
assert.Equal(t, len(tc.challenges), len(consents))

if len(tc.challenges) == 0 {
assert.EqualError(t, err, ErrNoPreviousConsentFound.Error())
} else {
require.NoError(t, err)
for _, consent := range consents {
assert.Contains(t, tc.challenges, consent.ID)
assert.Contains(t, tc.clients, consent.ConsentRequest.Client.GetID())
}
}

n, err := m.CountSubjectsGrantedConsentRequests(context.Background(), tc.subject)
require.NoError(t, err)
assert.Equal(t, n, len(tc.challenges))

})
}

for i, tc := range []struct {
subject string
challenges []string
Expand Down
14 changes: 12 additions & 2 deletions consent/sdk_test.go
Expand Up @@ -77,10 +77,10 @@ func TestSDK(t *testing.T) {
require.NoError(t, reg.ClientManager().CreateClient(context.Background(), cr4.Client))
require.NoError(t, m.CreateLoginRequest(context.Background(), &LoginRequest{ID: cr1.LoginChallenge.String(), Subject: cr1.Subject, Client: cr1.Client, Verifier: cr1.ID}))
require.NoError(t, m.CreateLoginRequest(context.Background(), &LoginRequest{ID: cr2.LoginChallenge.String(), Subject: cr2.Subject, Client: cr2.Client, Verifier: cr2.ID}))
require.NoError(t, m.CreateLoginRequest(context.Background(), &LoginRequest{ID: cr3.LoginChallenge.String(), Subject: cr3.Subject, Client: cr3.Client, Verifier: cr3.ID, RequestedAt: hcr3.RequestedAt}))
require.NoError(t, m.CreateLoginSession(context.Background(), &LoginSession{ID: cr3.LoginSessionID.String()}))
require.NoError(t, m.CreateLoginRequest(context.Background(), &LoginRequest{ID: cr4.LoginChallenge.String(), Client: cr4.Client, Verifier: cr4.ID}))
require.NoError(t, m.CreateLoginRequest(context.Background(), &LoginRequest{ID: cr3.LoginChallenge.String(), Subject: cr3.Subject, Client: cr3.Client, Verifier: cr3.ID, RequestedAt: hcr3.RequestedAt, SessionID: cr3.LoginSessionID}))
require.NoError(t, m.CreateLoginSession(context.Background(), &LoginSession{ID: cr4.LoginSessionID.String()}))
require.NoError(t, m.CreateLoginRequest(context.Background(), &LoginRequest{ID: cr4.LoginChallenge.String(), Client: cr4.Client, Verifier: cr4.ID, SessionID: cr4.LoginSessionID}))
require.NoError(t, m.CreateConsentRequest(context.Background(), cr1))
require.NoError(t, m.CreateConsentRequest(context.Background(), cr2))
require.NoError(t, m.CreateConsentRequest(context.Background(), cr3))
Expand Down Expand Up @@ -152,6 +152,16 @@ func TestSDK(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, 0, len(csGot))

csGot, _, err = sdk.OAuth2Api.ListOAuth2ConsentSessions(ctx).Subject("subject3").LoginSessionId("fk-login-session-t1-3").Execute()
require.NoError(t, err)
assert.Equal(t, 1, len(csGot))
cs = csGot[0]
assert.Equal(t, makeID("challenge", network, "3"), cs.ConsentRequest.Challenge)

csGot, _, err = sdk.OAuth2Api.ListOAuth2ConsentSessions(ctx).Subject("subject3").LoginSessionId("fk-login-session-t1-X").Execute()
require.NoError(t, err)
assert.Equal(t, 0, len(csGot))

luGot, _, err := sdk.OAuth2Api.GetOAuth2LogoutRequest(ctx).LogoutChallenge(makeID("challenge", network, "testsdk-1")).Execute()
require.NoError(t, err)
compareSDKLogoutRequest(t, lur1, luGot)
Expand Down
8 changes: 8 additions & 0 deletions internal/httpclient/api/openapi.yaml
Expand Up @@ -1104,6 +1104,14 @@ paths:
schema:
type: string
style: form
- description: The login session id to list the consent sessions for.
explode: true
in: query
name: login_session_id
required: false
schema:
type: string
style: form
responses:
"200":
content:
Expand Down
20 changes: 15 additions & 5 deletions internal/httpclient/api_o_auth2.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions internal/httpclient/docs/OAuth2Api.md
Expand Up @@ -983,7 +983,7 @@ No authorization required

## ListOAuth2ConsentSessions

> []OAuth2ConsentSession ListOAuth2ConsentSessions(ctx).Subject(subject).PageSize(pageSize).PageToken(pageToken).Execute()
> []OAuth2ConsentSession ListOAuth2ConsentSessions(ctx).Subject(subject).PageSize(pageSize).PageToken(pageToken).LoginSessionId(loginSessionId).Execute()
List OAuth 2.0 Consent Sessions of a Subject

Expand All @@ -1005,10 +1005,11 @@ func main() {
subject := "subject_example" // string | The subject to list the consent sessions for.
pageSize := int64(789) // int64 | Items per Page This is the number of items per page to return. For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). (optional) (default to 250)
pageToken := "pageToken_example" // string | Next Page Token The next page token. For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). (optional) (default to "1")
loginSessionId := "loginSessionId_example" // string | The login session id to list the consent sessions for. (optional)

configuration := openapiclient.NewConfiguration()
apiClient := openapiclient.NewAPIClient(configuration)
resp, r, err := apiClient.OAuth2Api.ListOAuth2ConsentSessions(context.Background()).Subject(subject).PageSize(pageSize).PageToken(pageToken).Execute()
resp, r, err := apiClient.OAuth2Api.ListOAuth2ConsentSessions(context.Background()).Subject(subject).PageSize(pageSize).PageToken(pageToken).LoginSessionId(loginSessionId).Execute()
if err != nil {
fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.ListOAuth2ConsentSessions``: %v\n", err)
fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r)
Expand All @@ -1032,6 +1033,7 @@ Name | Type | Description | Notes
**subject** | **string** | The subject to list the consent sessions for. |
**pageSize** | **int64** | Items per Page This is the number of items per page to return. For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). | [default to 250]
**pageToken** | **string** | Next Page Token The next page token. For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). | [default to "1"]
**loginSessionId** | **string** | The login session id to list the consent sessions for. |

### Return type

Expand Down
35 changes: 35 additions & 0 deletions persistence/sql/persister_consent.go
Expand Up @@ -465,6 +465,41 @@ nid = ?`, flow.FlowStateConsentUsed, flow.FlowStateConsentUnused,
return p.filterExpiredConsentRequests(ctx, rs)
}

func (p *Persister) FindSubjectsSessionGrantedConsentRequests(ctx context.Context, subject, sid string, limit, offset int) ([]consent.AcceptOAuth2ConsentRequest, error) {
ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FindSubjectsSessionGrantedConsentRequests")
defer span.End()

var fs []flow.Flow
c := p.Connection(ctx)

if err := c.
Where(
strings.TrimSpace(fmt.Sprintf(`
(state = %d OR state = %d) AND
subject = ? AND
login_session_id = ? AND
consent_skip=FALSE AND
consent_error='{}' AND
nid = ?`, flow.FlowStateConsentUsed, flow.FlowStateConsentUnused,
)),
subject, sid, p.NetworkID(ctx)).
Order("requested_at DESC").
Paginate(offset/limit+1, limit).
All(&fs); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, errorsx.WithStack(consent.ErrNoPreviousConsentFound)
}
return nil, sqlcon.HandleError(err)
}

var rs []consent.AcceptOAuth2ConsentRequest
for _, f := range fs {
rs = append(rs, *f.GetHandledConsentRequest())
}

return p.filterExpiredConsentRequests(ctx, rs)
}

func (p *Persister) CountSubjectsGrantedConsentRequests(ctx context.Context, subject string) (int, error) {
ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CountSubjectsGrantedConsentRequests")
defer span.End()
Expand Down
8 changes: 8 additions & 0 deletions spec/api.json
Expand Up @@ -2796,6 +2796,14 @@
"schema": {
"type": "string"
}
},
{
"description": "The login session id to list the consent sessions for.",
"in": "query",
"name": "login_session_id",
"schema": {
"type": "string"
}
}
],
"responses": {
Expand Down
6 changes: 6 additions & 0 deletions spec/swagger.json
Expand Up @@ -1204,6 +1204,12 @@
"name": "subject",
"in": "query",
"required": true
},
{
"type": "string",
"description": "The login session id to list the consent sessions for.",
"name": "login_session_id",
"in": "query"
}
],
"responses": {
Expand Down

0 comments on commit d275ad6

Please sign in to comment.