From 41326c0806019c709a6b0525e3618b1b51a6baad Mon Sep 17 00:00:00 2001 From: Mart Aarma Date: Thu, 31 Mar 2022 18:10:48 +0300 Subject: [PATCH] fix: add extend consent tests --- consent/handler_test.go | 71 ++++++++++++ consent/manager_test_helpers.go | 161 ++++++++++++++++++++++++++- persistence/sql/persister_consent.go | 14 +-- persistence/sql/persister_test.go | 2 +- 4 files changed, 234 insertions(+), 14 deletions(-) diff --git a/consent/handler_test.go b/consent/handler_test.go index 60fa873b1df..34d4415ca89 100644 --- a/consent/handler_test.go +++ b/consent/handler_test.go @@ -21,12 +21,14 @@ package consent_test import ( + "bytes" "context" "encoding/json" "fmt" "net/http" "net/http/httptest" "testing" + "time" "github.com/ory/hydra/x" @@ -213,3 +215,72 @@ func TestGetConsentRequest(t *testing.T) { }) } } + +func TestAcceptConsentRequest(t *testing.T) { + t.Run("case=extend consent expiry time", func(t *testing.T) { + conf := internal.NewConfigurationWithDefaults() + reg := internal.NewRegistryMemory(t, conf) + h := NewHandler(reg, conf) + r := x.NewRouterAdmin() + h.SetRoutes(r) + ts := httptest.NewServer(r) + defer ts.Close() + c := &http.Client{} + cl := &client.Client{OutfacingID: "client-1"} + require.NoError(t, reg.ClientManager().CreateClient(context.Background(), cl)) + + var initialRememberFor time.Duration = 300 + var remainingValidTime time.Duration = 100 + + require.NoError(t, reg.ConsentManager().CreateLoginSession(context.Background(), &LoginSession{ + ID: "session-1", + Subject: "subject-1", + })) + require.NoError(t, reg.ConsentManager().CreateConsentRequest(context.Background(), &ConsentRequest{ + Subject: "subject-1", + Client: cl, + ID: "challenge-1", + LoginSessionID: "session-1", + Skip: false, + })) + requestedTimeInPast := time.Now().UTC().Add(-(initialRememberFor - remainingValidTime) * time.Second) + _, err := reg.ConsentManager().HandleConsentRequest(context.Background(), "challenge-1", &HandledConsentRequest{ + ID: "challenge-1", + Remember: true, + RememberFor: int(initialRememberFor), + RequestedAt: requestedTimeInPast, + WasHandled: true, + }) + require.NoError(t, err) + require.NoError(t, reg.ConsentManager().CreateConsentRequest(context.Background(), &ConsentRequest{ + Subject: "subject-1", + Client: cl, + ID: "challenge-2", + LoginSessionID: "session-1", + RequestedAt: time.Now().UTC(), + Skip: true, + })) + + var b bytes.Buffer + var extendRememberFor time.Duration = 300 + require.NoError(t, json.NewEncoder(&b).Encode(&HandledConsentRequest{ + Remember: true, + RememberFor: int(extendRememberFor), + })) + + req, err := http.NewRequest("PUT", ts.URL+ConsentPath+"/accept?challenge=challenge-2", &b) + + require.NoError(t, err) + resp, err := c.Do(req) + require.NoError(t, err) + require.EqualValues(t, 200, resp.StatusCode) + crs, err := reg.ConsentManager().FindSubjectsGrantedConsentRequests(context.Background(), "subject-1", 100, 0) + require.NoError(t, err) + require.NotNil(t, crs) + require.EqualValues(t, 1, len(crs)) + expectedRememberFor := int(initialRememberFor + extendRememberFor - remainingValidTime) + cr := crs[0] + require.EqualValues(t, "challenge-1", cr.ID) + require.InDelta(t, expectedRememberFor, cr.RememberFor, 1) + }) +} diff --git a/consent/manager_test_helpers.go b/consent/manager_test_helpers.go index 960fd50d865..7f329c25a9c 100644 --- a/consent/manager_test_helpers.go +++ b/consent/manager_test_helpers.go @@ -258,7 +258,7 @@ func SaneMockAuthRequest(t *testing.T, m Manager, ls *LoginSession, cl *client.C return c } -func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.FositeStorer) func(t *testing.T) { +func ManagerTests(m Manager, clientManager client.Manager, scopeStrategy fosite.ScopeStrategy, fositeManager x.FositeStorer) func(t *testing.T) { return func(t *testing.T) { t.Run("case=init-fks", func(t *testing.T) { for _, k := range []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "rv1", "rv2"} { @@ -486,6 +486,165 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit } }) + t.Run("case=extend consent request", func(t *testing.T) { + cl := &client.Client{OutfacingID: "client-1"} + _ = clientManager.CreateClient(context.Background(), cl) + consentHandler := func(subject, sessionId, challenge string, initialRememberFor, remainingValidTime time.Duration) { + require.NoError(t, m.CreateLoginSession(context.Background(), &LoginSession{ + ID: sessionId, + Subject: subject, + })) + require.NoError(t, m.CreateConsentRequest(context.Background(), &ConsentRequest{ + Client: cl, + Subject: subject, + ID: challenge, + LoginSessionID: sqlxx.NullString(sessionId), + Skip: false, + RequestedAt: time.Now().UTC().Add(-initialRememberFor * time.Second), + Verifier: uuid.New().String(), + RequestedScope: []string{"scopea"}, + })) + requestedTimeInPast := time.Now().UTC().Round(time.Second).Add(-(initialRememberFor - remainingValidTime) * time.Second) + _, err := m.HandleConsentRequest(context.Background(), challenge, &HandledConsentRequest{ + ID: challenge, + Remember: true, + RememberFor: int(initialRememberFor), + RequestedAt: requestedTimeInPast, + WasHandled: true, + GrantedScope: []string{"scopea"}, + }) + require.NoError(t, err) + } + + t.Run("case=extend session related and latest consent expiry times", func(t *testing.T) { + var initialRememberForSession1 time.Duration = 300 + var remainingValidTimeSession1 time.Duration = 100 + var initialRememberForSession2 time.Duration = 300 + var remainingValidTimeSession2 time.Duration = 150 + subject := uuid.New().String() + session1 := uuid.New().String() + challenge1 := uuid.New().String() + challenge2 := uuid.New().String() + challenge3 := uuid.New().String() + consentHandler(subject, session1, challenge1, initialRememberForSession1, remainingValidTimeSession1) + consentHandler(subject, uuid.New().String(), challenge2, initialRememberForSession2, remainingValidTimeSession2) + cr := &ConsentRequest{ + Client: cl, + Subject: subject, + ID: challenge3, + LoginSessionID: sqlxx.NullString(session1), + RequestedAt: time.Now().UTC(), + Skip: true, + } + require.NoError(t, m.CreateConsentRequest(context.Background(), cr)) + var extendRememberFor time.Duration = 300 + _, err := m.HandleConsentRequest(context.Background(), challenge3, &HandledConsentRequest{ + ID: challenge3, + Remember: true, + RememberFor: int(extendRememberFor), + WasHandled: true, + RequestedAt: time.Now().UTC(), + }) + require.NoError(t, err) + require.NoError(t, m.ExtendConsentRequest(context.Background(), scopeStrategy, cr, int(extendRememberFor))) + crs, err := m.FindSubjectsGrantedConsentRequests(context.Background(), subject, 100, 0) + require.NoError(t, err) + require.EqualValues(t, 2, len(crs)) + + cr1 := crs[1] + require.EqualValues(t, challenge1, cr1.ID) + expectedRememberFor1 := int(initialRememberForSession1 + extendRememberFor - remainingValidTimeSession1) + require.InDelta(t, expectedRememberFor1, cr1.RememberFor, 1) + + cr2 := crs[0] + require.EqualValues(t, challenge2, cr2.ID) + expectedRememberFor2 := int(initialRememberForSession2 + extendRememberFor - remainingValidTimeSession2) + require.InDelta(t, expectedRememberFor2, cr2.RememberFor, 1) + }) + + t.Run("case=session related consent not found", func(t *testing.T) { + cr := &ConsentRequest{ + Client: cl, + Subject: "subject-1", + LoginSessionID: "session-1", + } + require.ErrorIs(t, m.ExtendConsentRequest(context.Background(), scopeStrategy, cr, 300), ErrNoPreviousConsentFound) + }) + + t.Run("case=invalid requested scope", func(t *testing.T) { + subject := uuid.New().String() + session1 := uuid.New().String() + challenge1 := uuid.New().String() + challenge2 := uuid.New().String() + + consentHandler(subject, session1, challenge1, 300, 100) + cr := &ConsentRequest{ + Client: cl, + Subject: subject, + ID: challenge2, + LoginSessionID: sqlxx.NullString(session1), + RequestedAt: time.Now().UTC(), + Skip: true, + RequestedScope: []string{"scopeb"}, + Verifier: uuid.New().String(), + } + require.NoError(t, m.CreateConsentRequest(context.Background(), cr)) + var extendRememberFor time.Duration = 300 + _, err := m.HandleConsentRequest(context.Background(), challenge2, &HandledConsentRequest{ + ID: challenge2, + Remember: true, + RememberFor: int(extendRememberFor), + WasHandled: true, + RequestedAt: time.Now().UTC(), + }) + require.NoError(t, err) + + require.NoError(t, m.ExtendConsentRequest(context.Background(), scopeStrategy, cr, int(extendRememberFor))) + + crs, err := m.FindSubjectsGrantedConsentRequests(context.Background(), subject, 100, 0) + require.NoError(t, err) + require.EqualValues(t, 1, len(crs)) + cr1 := crs[0] + require.EqualValues(t, challenge1, cr1.ID) + require.EqualValues(t, 300, cr1.RememberFor) + }) + + t.Run("case=initial consent request expired", func(t *testing.T) { + subject := uuid.New().String() + session1 := uuid.New().String() + challenge1 := uuid.New().String() + challenge2 := uuid.New().String() + + consentHandler(subject, session1, challenge1, 300, 0) + time.Sleep(time.Second) + + cr := &ConsentRequest{ + Client: cl, + Subject: subject, + ID: challenge2, + LoginSessionID: sqlxx.NullString(session1), + RequestedAt: time.Now().UTC(), + Skip: true, + Verifier: uuid.New().String(), + } + require.NoError(t, m.CreateConsentRequest(context.Background(), cr)) + var extendRememberFor time.Duration = 300 + _, err := m.HandleConsentRequest(context.Background(), challenge2, &HandledConsentRequest{ + ID: challenge2, + Remember: true, + RememberFor: int(extendRememberFor), + WasHandled: true, + RequestedAt: time.Now().UTC(), + }) + require.NoError(t, err) + + require.NoError(t, m.ExtendConsentRequest(context.Background(), scopeStrategy, cr, int(extendRememberFor))) + + _, err = m.FindSubjectsGrantedConsentRequests(context.Background(), subject, 100, 0) + require.Error(t, err, ErrNoPreviousConsentFound) + }) + }) + t.Run("case=revoke-auth-request", func(t *testing.T) { require.NoError(t, m.CreateLoginSession(context.Background(), &LoginSession{ ID: "rev-session-1", diff --git a/persistence/sql/persister_consent.go b/persistence/sql/persister_consent.go index f1288a8961e..a539a4cd8c4 100644 --- a/persistence/sql/persister_consent.go +++ b/persistence/sql/persister_consent.go @@ -218,9 +218,6 @@ func (p *Persister) ExtendConsentRequest(ctx context.Context, scopeStrategy fosi Order(fmt.Sprintf("%s.requested_at DESC", tn)). Limit(1). First(&latestHcr); err != nil { - if errors.Is(err, sql.ErrNoRows) { - return errorsx.WithStack(consent.ErrNoPreviousConsentFound) - } return sqlcon.HandleError(err) } @@ -250,16 +247,9 @@ func (p *Persister) extendHandledConsentRequest(ctx context.Context, cr *consent } remainingTime := hcr.RequestedAt.Unix() + int64(hcr.RememberFor) - time.Now().Unix() - if remainingTime > 0 { - hcr.RememberFor = hcr.RememberFor + extendBy - int(remainingTime) - } else { - hcr.RememberFor = hcr.RememberFor + extendBy - } + hcr.RememberFor = hcr.RememberFor + extendBy - int(remainingTime) - if err := sqlcon.HandleError(p.Connection(ctx).Update(&hcr)); err != nil { - return err - } - return nil + return sqlcon.HandleError(p.Connection(ctx).Update(&hcr)) } func (p *Persister) VerifyAndInvalidateConsentRequest(ctx context.Context, verifier string) (*consent.HandledConsentRequest, error) { diff --git a/persistence/sql/persister_test.go b/persistence/sql/persister_test.go index 9cf4f3865cf..533db847b38 100644 --- a/persistence/sql/persister_test.go +++ b/persistence/sql/persister_test.go @@ -44,7 +44,7 @@ func TestManagers(t *testing.T) { t.Run("case=update-two-clients", client.TestHelperUpdateTwoClients(k, m.ClientManager())) }) - t.Run("package=consent/manager="+k, consent.ManagerTests(m.ConsentManager(), m.ClientManager(), m.OAuth2Storage())) + t.Run("package=consent/manager="+k, consent.ManagerTests(m.ConsentManager(), m.ClientManager(), m.ScopeStrategy(), m.OAuth2Storage())) t.Run("package=consent/janitor="+k, testhelpers.JanitorTests(m.Config(), m.ConsentManager(), m.ClientManager(), m.OAuth2Storage()))