Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/ory/hydra
Browse files Browse the repository at this point in the history
  • Loading branch information
arekkas committed Aug 7, 2018
2 parents 8c08f41 + 7aace33 commit ce4e4ef
Show file tree
Hide file tree
Showing 33 changed files with 2,008 additions and 6 deletions.
15 changes: 15 additions & 0 deletions consent/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ type swaggerRevokeUserClientConsentSessionsPayload struct {
Client string `json:"client"`
}

// swagger:parameters listUserConsentSessions
type swaggerListUserConsentSessionsPayload struct {
// in: path
// required: true
User string `json:"user"`
}

// swagger:parameters revokeAuthenticationSession
type swaggerRevokeAuthenticationSessionPayload struct {
// in: path
Expand Down Expand Up @@ -81,3 +88,11 @@ type swaggerRejectRequest struct {
// in: body
Body RequestDeniedError
}

// A list of handled consent requests.
// swagger:response handledConsentRequestList
type swaggerListHandledConsentRequestsResult struct {
// in: body
// type: array
Body []PreviousConsentSession
}
55 changes: 55 additions & 0 deletions consent/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import (
"github.com/ory/fosite"
"github.com/ory/go-convenience/urlx"
"github.com/ory/herodot"
"github.com/ory/pagination"
"github.com/ory/sqlcon"
"github.com/pkg/errors"
)

Expand Down Expand Up @@ -64,6 +66,7 @@ func (h *Handler) SetRoutes(r *httprouter.Router) {
r.PUT(ConsentPath+"/:challenge/reject", h.RejectConsentRequest)

r.DELETE("/oauth2/auth/sessions/login/:user", h.DeleteLoginSession)
r.GET("/oauth2/auth/sessions/consent/:user", h.GetConsentSessions)
r.DELETE("/oauth2/auth/sessions/consent/:user", h.DeleteUserConsentSession)
r.DELETE("/oauth2/auth/sessions/consent/:user/:client", h.DeleteUserClientConsentSession)
}
Expand Down Expand Up @@ -133,6 +136,58 @@ func (h *Handler) DeleteUserClientConsentSession(w http.ResponseWriter, r *http.
w.WriteHeader(http.StatusNoContent)
}

// swagger:route GET /oauth2/auth/sessions/consent/{user} oAuth2 listUserConsentSessions
//
// Lists all consent sessions of a user
//
// This endpoint lists all user's granted consent sessions, including client and granted scope
//
// Consumes:
// - application/json
//
// Produces:
// - application/json
//
// Schemes: http, https
//
// Responses:
// 200: handledConsentRequestList
// 401: genericError
// 403: genericError
// 500: genericError

func (h *Handler) GetConsentSessions(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
user := ps.ByName("user")
if user == "" {
h.H.WriteError(w, r, errors.WithStack(fosite.ErrInvalidRequest.WithDebug("Parameter user is not defined")))
return
}
limit, offset := pagination.Parse(r, 100, 0, 500)

sessions, err := h.M.FindPreviouslyGrantedConsentRequestsByUser(user, limit, offset)

if err == sqlcon.ErrNoRows {
h.H.Write(w, r, []PreviousConsentSession{})
return
} else if err != nil {
h.H.WriteError(w, r, err)
return
}

var a []PreviousConsentSession

for _, session := range sessions {
session.ConsentRequest.Client = sanitizeClient(session.ConsentRequest.Client)
a = append(a, PreviousConsentSession(session))
}

if len(a) == 0 {
a = []PreviousConsentSession{}
}

h.H.Write(w, r, a)
}

// swagger:route DELETE /oauth2/auth/sessions/login/{user} oAuth2 revokeAuthenticationSession
//
// Invalidates a user's authentication session
Expand Down
1 change: 1 addition & 0 deletions consent/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type Manager interface {

VerifyAndInvalidateConsentRequest(verifier string) (*HandledConsentRequest, error)
FindPreviouslyGrantedConsentRequests(client string, user string) ([]HandledConsentRequest, error)
FindPreviouslyGrantedConsentRequestsByUser(user string, limit, offset int) ([]HandledConsentRequest, error)

// Cookie management
GetAuthenticationSession(id string) (*AuthenticationSession, error)
Expand Down
31 changes: 26 additions & 5 deletions consent/manager_memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (

"github.com/ory/fosite"
"github.com/ory/hydra/pkg"
"github.com/ory/pagination"
"github.com/pkg/errors"
)

Expand Down Expand Up @@ -162,6 +163,25 @@ func (m *MemoryManager) VerifyAndInvalidateConsentRequest(verifier string) (*Han
}

func (m *MemoryManager) FindPreviouslyGrantedConsentRequests(client string, subject string) ([]HandledConsentRequest, error) {
var rs []HandledConsentRequest
filteredByUser, err := m.FindPreviouslyGrantedConsentRequestsByUser(subject, -1, -1)
if err != nil {
return nil, err
}

for _, c := range filteredByUser {
if client == c.ConsentRequest.Client.GetID() {
rs = append(rs, c)
}
}
if len(rs) == 0 {
return []HandledConsentRequest{}, nil
}

return rs, nil
}

func (m *MemoryManager) FindPreviouslyGrantedConsentRequestsByUser(subject string, limit, offset int) ([]HandledConsentRequest, error) {
var rs []HandledConsentRequest
for _, c := range m.handledConsentRequests {
cr, err := m.GetConsentRequest(c.Challenge)
Expand All @@ -171,10 +191,6 @@ func (m *MemoryManager) FindPreviouslyGrantedConsentRequests(client string, subj
return nil, err
}

if client != cr.Client.GetID() {
continue
}

if subject != cr.Subject {
continue
}
Expand Down Expand Up @@ -203,7 +219,12 @@ func (m *MemoryManager) FindPreviouslyGrantedConsentRequests(client string, subj
return []HandledConsentRequest{}, nil
}

return rs, nil
if limit < 0 && offset < 0 {
return rs, nil
}

start, end := pagination.Index(limit, offset, len(rs))
return rs[start:end], nil
}

func (m *MemoryManager) GetAuthenticationSession(id string) (*AuthenticationSession, error) {
Expand Down
25 changes: 24 additions & 1 deletion consent/manager_sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -364,8 +364,31 @@ WHERE
return nil, sqlcon.HandleError(err)
}

return m.resolveHandledConsentRequests(a)
}

func (m *SQLManager) FindPreviouslyGrantedConsentRequestsByUser(subject string, limit, offset int) ([]HandledConsentRequest, error) {
var a []sqlHandledConsentRequest

if err := m.db.Select(&a, m.db.Rebind(`SELECT h.* FROM
hydra_oauth2_consent_request_handled as h
JOIN
hydra_oauth2_consent_request as r ON (h.challenge = r.challenge)
WHERE
r.subject=? AND r.skip=FALSE
AND
(h.error='{}' AND h.remember=TRUE)
LIMIT ? OFFSET ?
`), subject, limit, offset); err != nil {
return nil, sqlcon.HandleError(err)
}

return m.resolveHandledConsentRequests(a)
}

func (m *SQLManager) resolveHandledConsentRequests(requests []sqlHandledConsentRequest) ([]HandledConsentRequest, error) {
var aa []HandledConsentRequest
for _, v := range a {
for _, v := range requests {
r, err := m.GetConsentRequest(v.Challenge)
if err != nil {
return nil, err
Expand Down
47 changes: 47 additions & 0 deletions consent/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,53 @@ func TestManagers(t *testing.T) {
})
}
})

t.Run("case=list-handled-consent-requests", func(t *testing.T) {
for k, m := range managers {
cr1, hcr1 := mockConsentRequest("rv1", true, 0, false, false, false)
cr2, hcr2 := mockConsentRequest("rv2", false, 0, false, false, false)
clientManager.CreateClient(cr1.Client)
clientManager.CreateClient(cr2.Client)

require.NoError(t, m.CreateConsentRequest(cr1))
require.NoError(t, m.CreateConsentRequest(cr2))
_, err := m.HandleConsentRequest("challengerv1", hcr1)
require.NoError(t, err)
_, err = m.HandleConsentRequest("challengerv2", hcr2)
require.NoError(t, err)

t.Run("manager="+k, func(t *testing.T) {
for i, tc := range []struct {
subject string
challenges []string
clients []string
}{
{
subject: "subjectrv1",
challenges: []string{"challengerv1"},
clients: []string{"clientrv1"},
},
{
subject: "subjectrv2",
challenges: []string{},
clients: []string{},
},
} {
t.Run(fmt.Sprintf("case=%d/subject=%s", i, tc.subject), func(t *testing.T) {
consents, _ := m.FindPreviouslyGrantedConsentRequestsByUser(tc.subject, 100, 0)

assert.Equal(t, len(tc.challenges), len(consents))

for _, consent := range consents {
assert.Contains(t, tc.challenges, consent.Challenge)
assert.Contains(t, tc.clients, consent.ConsentRequest.Client.ClientID)
}
})
}
})
}

})
}

func compareAuthenticationRequest(t *testing.T, a, b *AuthenticationRequest) {
Expand Down
16 changes: 16 additions & 0 deletions consent/sdk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,16 @@ func TestSDK(t *testing.T) {

cr1, hcr1 := mockConsentRequest("1", false, 0, false, false, false)
cr2, hcr2 := mockConsentRequest("2", false, 0, false, false, false)
cr3, hcr3 := mockConsentRequest("3", true, 3600, false, false, false)
require.NoError(t, m.CreateConsentRequest(cr1))
require.NoError(t, m.CreateConsentRequest(cr2))
require.NoError(t, m.CreateConsentRequest(cr3))
_, err = m.HandleConsentRequest("challenge1", hcr1)
require.NoError(t, err)
_, err = m.HandleConsentRequest("challenge2", hcr2)
require.NoError(t, err)
_, err = m.HandleConsentRequest("challenge3", hcr3)
require.NoError(t, err)

crGot, res, err := sdk.GetConsentRequest("challenge1")
require.NoError(t, err)
Expand Down Expand Up @@ -113,6 +117,18 @@ func TestSDK(t *testing.T) {
_, res, err = sdk.GetConsentRequest("challenge2")
require.NoError(t, err)
require.EqualValues(t, http.StatusNotFound, res.StatusCode)

csGot, res, err := sdk.ListUserConsentSessions("subject3")
require.NoError(t, err)
require.EqualValues(t, http.StatusOK, res.StatusCode)
assert.Equal(t, 1, len(csGot))
cs := csGot[0]
assert.Equal(t, "challenge3", cs.ConsentRequest.Challenge)

csGot, res, err = sdk.ListUserConsentSessions("subject2")
require.NoError(t, err)
require.EqualValues(t, http.StatusOK, res.StatusCode)
assert.Equal(t, 0, len(csGot))
}

func compareSDKLoginRequest(t *testing.T, expected *AuthenticationRequest, got *swagger.LoginRequest) {
Expand Down
25 changes: 25 additions & 0 deletions consent/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,31 @@ type HandledConsentRequest struct {
WasUsed bool `json:"-"`
}

// The response used to return handled consent requests
// same as HandledAuthenticationRequest, just with consent_request exposed as json
type PreviousConsentSession struct {
// GrantScope sets the scope the user authorized the client to use. Should be a subset of `requested_scope`
GrantedScope []string `json:"grant_scope"`

// Session allows you to set (optional) session data for access and ID tokens.
Session *ConsentRequestSessionData `json:"session"`

// Remember, if set to true, tells ORY Hydra to remember this consent authorization and reuse it if the same
// client asks the same user for the same, or a subset of, scope.
Remember bool `json:"remember"`

// RememberFor sets how long the consent authorization should be remembered for in seconds. If set to `0`, the
// authorization will be remembered indefinitely.
RememberFor int `json:"remember_for"`

ConsentRequest *ConsentRequest `json:"consent_request"`
Error *RequestDeniedError `json:"-"`
Challenge string `json:"-"`
RequestedAt time.Time `json:"-"`
AuthenticatedAt time.Time `json:"-"`
WasUsed bool `json:"-"`
}

// The request payload used to accept a login request.
//
// swagger:model acceptLoginRequest
Expand Down

0 comments on commit ce4e4ef

Please sign in to comment.