From d9308fa0dba26019a59e4d97e85b036133ad8362 Mon Sep 17 00:00:00 2001 From: DennisPattmann5012 <44261569+DennisPattmann5012@users.noreply.github.com> Date: Mon, 3 Feb 2020 10:21:06 +0100 Subject: [PATCH] feat(consent)!: Track handled_at for consent requests (#1689) This patch adds a feature where handling (accepting or rejecting) a consent request causes a time stamp (`handled_at`) to be updated. This patch includes schema changes that required `hydra migrate sql` to be applied. Closes #1684 Co-authored-by: Marco Hutzsch <39520486+marcohutzsch1234@users.noreply.github.com> --- consent/handler.go | 2 + consent/manager_test_helpers.go | 5 +- consent/migrations/sql/cockroach/14.sql | 5 ++ consent/migrations/sql/shared/14.sql | 5 ++ consent/migrations/sql/tests/14_test.sql | 46 ++++++++++++++++ consent/sql_helper.go | 4 ++ consent/sql_migration_files.go | 69 ++++++++++++++++++++++++ consent/types.go | 4 ++ cypress/integration/oauth2/consent.js | 7 +++ oauth2/fosite_store_helpers.go | 1 + 10 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 consent/migrations/sql/cockroach/14.sql create mode 100644 consent/migrations/sql/shared/14.sql create mode 100644 consent/migrations/sql/tests/14_test.sql diff --git a/consent/handler.go b/consent/handler.go index c09cbedf644..4b6c0024601 100644 --- a/consent/handler.go +++ b/consent/handler.go @@ -553,6 +553,7 @@ func (h *Handler) AcceptConsentRequest(w http.ResponseWriter, r *http.Request, p p.Challenge = challenge p.RequestedAt = cr.RequestedAt + p.HandledAt = time.Now().UTC() hr, err := h.r.ConsentManager().HandleConsentRequest(r.Context(), challenge, &p) if err != nil { @@ -633,6 +634,7 @@ func (h *Handler) RejectConsentRequest(w http.ResponseWriter, r *http.Request, p Error: &p, Challenge: challenge, RequestedAt: hr.RequestedAt, + HandledAt: time.Now().UTC(), }) if err != nil { h.r.Writer().WriteError(w, r, errors.WithStack(err)) diff --git a/consent/manager_test_helpers.go b/consent/manager_test_helpers.go index 4d39f78dfa0..aed675a5faa 100644 --- a/consent/manager_test_helpers.go +++ b/consent/manager_test_helpers.go @@ -88,7 +88,8 @@ func MockConsentRequest(key string, remember bool, rememberFor int, hasError boo GrantedScope: []string{"scopea" + key, "scopeb" + key}, GrantedAudience: []string{"auda" + key, "audb" + key}, Error: err, - // WasUsed: true, + HandledAt: time.Now().UTC(), + //WasUsed: true, } return c, h @@ -187,6 +188,7 @@ func SaneMockHandleConsentRequest(t *testing.T, m Manager, c *ConsentRequest, au GrantedAudience: []string{"auda", "audb"}, Error: rde, WasUsed: false, + HandledAt: time.Now().UTC().Add(-time.Minute), } _, err := m.HandleConsentRequest(context.Background(), c.Challenge, h) @@ -418,6 +420,7 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit got1, err = m.HandleConsentRequest(context.TODO(), "challenge"+tc.key, h) require.NoError(t, err) + require.Equal(t, time.Now().UTC().Round(time.Minute), h.HandledAt.Round(time.Minute)) compareConsentRequest(t, c, got1) _, err = m.HandleConsentRequest(context.TODO(), "challenge"+tc.key, h) diff --git a/consent/migrations/sql/cockroach/14.sql b/consent/migrations/sql/cockroach/14.sql new file mode 100644 index 00000000000..6a61c673bce --- /dev/null +++ b/consent/migrations/sql/cockroach/14.sql @@ -0,0 +1,5 @@ +-- +migrate Up +ALTER TABLE hydra_oauth2_consent_request_handled ADD handled_at timestamp NULL; + +-- +migrate Down +ALTER TABLE hydra_oauth2_consent_request_handled DROP COLUMN handled_at; diff --git a/consent/migrations/sql/shared/14.sql b/consent/migrations/sql/shared/14.sql new file mode 100644 index 00000000000..6a61c673bce --- /dev/null +++ b/consent/migrations/sql/shared/14.sql @@ -0,0 +1,5 @@ +-- +migrate Up +ALTER TABLE hydra_oauth2_consent_request_handled ADD handled_at timestamp NULL; + +-- +migrate Down +ALTER TABLE hydra_oauth2_consent_request_handled DROP COLUMN handled_at; diff --git a/consent/migrations/sql/tests/14_test.sql b/consent/migrations/sql/tests/14_test.sql new file mode 100644 index 00000000000..628975f0818 --- /dev/null +++ b/consent/migrations/sql/tests/14_test.sql @@ -0,0 +1,46 @@ +-- +migrate Up +INSERT INTO hydra_client (id, allowed_cors_origins, client_name, client_secret, redirect_uris, grant_types, response_types, scope, owner, policy_uri, tos_uri, client_uri, logo_uri, contacts, client_secret_expires_at, sector_identifier_uri, jwks, jwks_uri, token_endpoint_auth_method, request_uris, request_object_signing_alg, userinfo_signed_response_alg, subject_type, audience, frontchannel_logout_uri, frontchannel_logout_session_required, post_logout_redirect_uris, backchannel_logout_uri, backchannel_logout_session_required, metadata) +VALUES + ('14-client', 'http://localhost|http://google', 'some-client', 'abcdef', 'http://localhost|http://google', 'authorize_code|implicit', 'token|id_token', 'foo|bar', 'aeneas', 'http://policy', 'http://tos', 'http://client', 'http://logo', 'aeneas|foo', 0, 'http://sector', '{"keys": []}', 'http://jwks', 'none', 'http://uri1|http://uri2', 'rs256', 'rs526', 'public', 'https://www.ory.sh/api', 'http://fc-logout/', true, 'http://redir1/|http://redir2/', 'http://bc-logout/', true, '{"foo":"bar"}'); + +INSERT INTO + hydra_oauth2_authentication_session (id, authenticated_at, subject, remember) +VALUES + ('14-login-session-id', NOW(), '14-sub', true); + +INSERT INTO + hydra_oauth2_authentication_request (challenge, verifier, client_id, subject, request_url, skip, requested_scope, csrf, authenticated_at, requested_at, oidc_context, login_session_id, requested_at_audience) +VALUES + ('14-challenge', '14-verifier', '14-client', '14-subject', '14-redirect', false, '14-scope', '14-csrf', NOW(), NOW(), '{}', '14-login-session-id', '14-aud'); + +INSERT INTO + hydra_oauth2_consent_request (challenge, verifier, client_id, subject, request_url, skip, requested_scope, csrf, authenticated_at, requested_at, oidc_context, forced_subject_identifier, login_session_id, login_challenge, requested_at_audience, acr, context) +VALUES + ('14-challenge', '14-verifier', '14-client', '14-subject', '14-redirect', false, '14-scope', '14-csrf', NOW(), NOW(), '{}', '14-forced-sub', '14-login-session-id', '14-challenge', '14-aud', '14-acr', '{"foo":"bar"}'); + +INSERT INTO + hydra_oauth2_consent_request_handled (challenge, granted_scope, remember, remember_for, error, requested_at, session_access_token, session_id_token, authenticated_at, was_used, granted_at_audience, handled_at) +VALUES + ('14-challenge', '14-scope', true, 3600, '{}', NOW(), '{}', '{}', NOW(), false, '14-aud', NOW()); + +INSERT INTO + hydra_oauth2_authentication_request_handled (challenge, subject, remember, remember_for, error, acr, requested_at, authenticated_at, was_used, forced_subject_identifier, context) +VALUES + ('14-challenge', '14-sub', true, 3600, '{}', '1', NOW(), NOW(), false, '14-forced-sub', '{"foo":"bar"}'); + +INSERT INTO + hydra_oauth2_obfuscated_authentication_session (subject, client_id, subject_obfuscated) +VALUES + ('14-sub', '14-client', '14-obfuscated'); + +INSERT INTO + hydra_oauth2_logout_request (challenge, verifier, subject, sid, client_id, request_url, redir_url, was_used, accepted, rejected, rp_initiated) +VALUES + ('14-challenge', '14-verifier', '14-subject', '14-session-id', '14-client', 'https://request-url/', 'https://redirect-url', false, false, false, false); + +INSERT INTO + hydra_oauth2_logout_request (challenge, verifier, subject, sid, client_id, request_url, redir_url, was_used, accepted, rejected, rp_initiated) +VALUES + ('14-1-challenge', '14-1-verifier', '14-1-subject', '14-1-session-id', NULL, 'https://request-url/', 'https://redirect-url', false, false, false, false); + +-- +migrate Down diff --git a/consent/sql_helper.go b/consent/sql_helper.go index e3a84e885c3..b5321cf4b85 100644 --- a/consent/sql_helper.go +++ b/consent/sql_helper.go @@ -98,6 +98,7 @@ var sqlParamsConsentRequestHandled = []string{ "session_access_token", "session_id_token", "was_used", + "handled_at", } var sqlParamsConsentRequestHandledUpdate = func() []string { p := make([]string, len(sqlParamsConsentRequestHandled)) @@ -369,6 +370,7 @@ type sqlHandledConsentRequest struct { RequestedAt time.Time `db:"requested_at"` WasUsed bool `db:"was_used"` AuthenticatedAt *time.Time `db:"authenticated_at"` + HandledAt time.Time `db:"handled_at"` } func newSQLHandledConsentRequest(c *HandledConsentRequest) (*sqlHandledConsentRequest, error) { @@ -414,6 +416,7 @@ func newSQLHandledConsentRequest(c *HandledConsentRequest) (*sqlHandledConsentRe RequestedAt: c.RequestedAt, WasUsed: c.WasUsed, AuthenticatedAt: toMySQLDateHack(c.AuthenticatedAt), + HandledAt: c.HandledAt, }, nil } @@ -451,6 +454,7 @@ func (s *sqlHandledConsentRequest) toHandledConsentRequest(r *ConsentRequest) (* Error: e, ConsentRequest: r, AuthenticatedAt: fromMySQLDateHack(s.AuthenticatedAt), + HandledAt: s.HandledAt, }, nil } diff --git a/consent/sql_migration_files.go b/consent/sql_migration_files.go index de57b54b3b6..fc27a3d8c67 100644 --- a/consent/sql_migration_files.go +++ b/consent/sql_migration_files.go @@ -2,6 +2,7 @@ // sources: // migrations/sql/cockroach/12.sql // migrations/sql/cockroach/13.sql +// migrations/sql/cockroach/14.sql // migrations/sql/mysql/.gitkeep // migrations/sql/mysql/10.sql // migrations/sql/mysql/12.sql @@ -23,6 +24,7 @@ // migrations/sql/shared/.gitkeep // migrations/sql/shared/1.sql // migrations/sql/shared/11.sql +// migrations/sql/shared/14.sql // migrations/sql/shared/2.sql // migrations/sql/shared/3.sql // migrations/sql/shared/9.sql @@ -31,6 +33,7 @@ // migrations/sql/tests/11_test.sql // migrations/sql/tests/12_test.sql // migrations/sql/tests/13_test.sql +// migrations/sql/tests/14_test.sql // migrations/sql/tests/1_test.sql // migrations/sql/tests/2_test.sql // migrations/sql/tests/3_test.sql @@ -156,6 +159,26 @@ func migrationsSqlCockroach13Sql() (*asset, error) { return a, nil } +var _migrationsSqlCockroach14Sql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xd2\xd5\x55\xd0\xce\xcd\x4c\x2f\x4a\x2c\x49\x55\x08\x2d\xe0\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\xc8\xa8\x4c\x29\x4a\x8c\xcf\x4f\x2c\x2d\xc9\x30\x8a\x4f\xce\xcf\x2b\x4e\xcd\x2b\x89\x2f\x4a\x2d\x2c\x4d\x2d\x2e\x89\xcf\x48\xcc\x4b\xc9\x49\x4d\x51\x70\x74\x71\x51\x80\xb2\xe3\x13\x4b\x14\x4a\x32\x73\x53\x8b\x4b\x12\x73\x0b\x14\xfc\x42\x7d\x7c\xac\xb9\xb8\x90\xcd\x77\xc9\x2f\xcf\x23\xdd\x06\x97\x20\xff\x00\x05\x67\x7f\x9f\x50\x5f\x3f\x24\x9b\xac\xb9\x00\x01\x00\x00\xff\xff\x68\x09\xe5\xf3\xba\x00\x00\x00") + +func migrationsSqlCockroach14SqlBytes() ([]byte, error) { + return bindataRead( + _migrationsSqlCockroach14Sql, + "migrations/sql/cockroach/14.sql", + ) +} + +func migrationsSqlCockroach14Sql() (*asset, error) { + bytes, err := migrationsSqlCockroach14SqlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "migrations/sql/cockroach/14.sql", size: 186, mode: os.FileMode(420), modTime: time.Unix(1578061360, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + var _migrationsSqlMysqlGitkeep = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x01\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00") func migrationsSqlMysqlGitkeepBytes() ([]byte, error) { @@ -576,6 +599,26 @@ func migrationsSqlShared11Sql() (*asset, error) { return a, nil } +var _migrationsSqlShared14Sql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xd2\xd5\x55\xd0\xce\xcd\x4c\x2f\x4a\x2c\x49\x55\x08\x2d\xe0\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\xc8\xa8\x4c\x29\x4a\x8c\xcf\x4f\x2c\x2d\xc9\x30\x8a\x4f\xce\xcf\x2b\x4e\xcd\x2b\x89\x2f\x4a\x2d\x2c\x4d\x2d\x2e\x89\xcf\x48\xcc\x4b\xc9\x49\x4d\x51\x70\x74\x71\x51\x80\xb2\xe3\x13\x4b\x14\x4a\x32\x73\x53\x8b\x4b\x12\x73\x0b\x14\xfc\x42\x7d\x7c\xac\xb9\xb8\x90\xcd\x77\xc9\x2f\xcf\x23\xdd\x06\x97\x20\xff\x00\x05\x67\x7f\x9f\x50\x5f\x3f\x24\x9b\xac\xb9\x00\x01\x00\x00\xff\xff\x68\x09\xe5\xf3\xba\x00\x00\x00") + +func migrationsSqlShared14SqlBytes() ([]byte, error) { + return bindataRead( + _migrationsSqlShared14Sql, + "migrations/sql/shared/14.sql", + ) +} + +func migrationsSqlShared14Sql() (*asset, error) { + bytes, err := migrationsSqlShared14SqlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "migrations/sql/shared/14.sql", size: 186, mode: os.FileMode(420), modTime: time.Unix(1578061360, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + var _migrationsSqlShared2Sql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\xd1\x41\x4f\xf3\x20\x18\x07\xf0\x33\x7c\x8a\xe7\xb6\x2d\xef\x76\x59\xb2\x53\x4f\xbc\x2d\x46\x23\x5b\x17\xd2\x9a\xec\x44\x18\x50\x8b\x99\xa0\x40\x35\x7e\x7b\xd3\xa5\x73\xc6\xd8\x64\x99\x3d\xf4\xf4\xe7\xf9\xc1\xf3\x5f\x2c\xe0\xdf\xb3\x7d\x0c\x32\x19\xa8\x5f\x30\x61\x15\xe5\x50\x91\xff\x8c\x42\xfb\xa1\x83\x14\x5e\x76\xa9\x5d\x0a\xe5\x5d\x34\x2e\x89\x60\x5e\x3b\x13\x13\x90\xa2\x80\xc6\x07\x65\xb4\x88\xdd\xfe\xc9\xa8\x24\xac\x36\x2e\xd9\xc6\x9a\x00\x0f\x84\xe7\xb7\x84\x4f\x97\xab\xd5\x0c\x36\x35\x63\x50\xd0\x1b\x52\xb3\x0a\x26\x93\x6c\x1c\xe9\xff\xfd\x0c\x25\x93\xf5\xee\x64\x89\x56\x3a\x7d\x30\xfa\x4f\x66\xce\x29\xa9\xe8\x6f\xa8\xdf\x37\x5d\x54\x32\x19\xfd\xd3\x8f\x26\x46\xeb\x1d\x4c\x31\x1a\x3c\x00\x84\x10\x0c\xdf\x9b\x0c\xaa\x95\x61\x00\xcb\xea\x88\xce\x31\x52\x07\xdb\x6f\xca\xea\x73\x78\x2c\x7a\x7a\xc6\xf9\x0e\x68\x3c\xbc\xe5\x77\x6b\xc2\x77\x70\x4f\x77\xd3\xe1\xe0\x1c\xbe\xb0\x19\x9e\x65\x18\x7f\xaf\xb3\xf0\xef\xee\xf2\x42\x0b\x5e\x6e\x21\x2f\x59\xbd\xde\x8c\x2f\xf9\xfa\xee\x2e\x1c\x7f\x8c\x5d\x53\x52\x86\x3f\x03\x00\x00\xff\xff\x48\xef\x86\x01\xca\x02\x00\x00") func migrationsSqlShared2SqlBytes() ([]byte, error) { @@ -736,6 +779,26 @@ func migrationsSqlTests13_testSql() (*asset, error) { return a, nil } +var _migrationsSqlTests14_testSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xd4\x57\x4d\x6f\x1b\x37\x10\x3d\x47\xbf\x82\xd0\x45\x36\x4a\x45\x96\xdb\xe4\xe0\x9e\x0a\x34\x87\x00\x86\x03\x34\x71\x7b\x28\x0a\x82\x22\x67\x57\x8c\x57\x9c\x2d\x87\x5b\x59\xb5\xfc\xdf\x0b\x7e\xac\x76\x57\xda\xd8\x4e\xd1\x43\x7a\xb1\xc9\x19\x0e\x77\xe6\xbd\x99\xb7\xab\xf9\x9c\x7d\xb7\x31\xa5\x93\x1e\xd8\x6d\x3d\x79\x7f\xf3\xf1\xdd\x2f\x9f\xd8\xfb\x9b\x4f\x1f\xd8\x7a\xa7\x9d\x14\xaa\x32\x60\x3d\x3b\x33\x9a\x33\x59\x55\xb8\x05\x2d\x14\x3a\x12\xe8\x4c\x69\x2c\x71\x96\x4e\x08\x2b\x37\x70\xd8\x10\x28\x07\x9e\x33\x07\xda\x38\x50\x5e\x34\xce\x10\x67\xa5\x93\xd6\x0b\xbf\xab\x81\x82\x8f\x6a\xb4\x04\xed\x9e\x14\xd6\xc0\x19\x6e\x2d\x38\xce\x6a\xac\x8c\xda\x85\x38\xce\x3c\x52\x5a\xe4\xdb\xe3\xba\xc2\x12\xb3\x15\xad\x97\xca\xd3\xd1\xd3\x05\xdc\xd7\xc6\x01\x09\xe9\x39\x23\x50\x1e\x9d\x30\x1a\xac\x37\x85\x01\x97\x42\x3f\x6f\xef\x28\xfd\x6d\x9f\x74\x07\x56\x80\xd5\x35\x1a\xeb\x85\x6c\xfc\x5a\x6c\xc0\xaf\x51\x87\x7c\xff\x6c\x80\xda\x52\xda\x1d\xae\x3e\x87\xfa\xc8\x94\xd6\xd8\x52\xc8\xaa\xe4\xac\x21\x70\xc6\x16\x18\xad\xa0\xc5\xa1\xd2\xe8\xa5\x26\x85\x84\xb2\x39\x93\x8d\x36\x60\x15\x70\x56\x38\xb4\x5e\xad\xa5\xb5\x50\x89\x50\x5d\x93\x2b\x1d\x73\x10\x10\x19\xb4\x22\xa4\x61\x1c\xe8\x00\x18\xf9\xd6\x7b\x04\xfb\x4a\xaa\xbb\xb1\x8b\x47\xec\xa7\xf7\x6e\xc0\x4b\x2d\xbd\x3c\x9f\xfc\xfa\xd3\xf5\xed\xbb\x8f\x13\xc6\xce\x66\xcb\x1f\xe6\x09\xeb\x19\x67\xb3\xb5\xf7\xf5\xd5\x62\x51\xa1\x92\xd5\x1a\xc9\xef\xb3\xa1\x44\x2c\x2b\x08\x27\x08\x37\xd0\x0b\x90\x2b\xa5\xa1\x78\x59\x68\xa0\x00\x9d\xf9\x1b\x84\x42\x0d\x7b\xb3\xa9\x2b\xa3\x4c\xbc\x26\x92\xb5\x37\x5a\xc4\x45\xb0\x14\x88\xfb\x95\x74\x31\x0e\x2c\x48\xea\x3d\x23\x35\x54\xcf\xe0\xb1\xef\x1e\x29\xa7\xc4\xee\xa2\x7d\x81\x61\x77\xd1\xf9\x53\x47\x85\x13\x0f\xd3\x3b\xd8\xd1\xf4\x8a\xfd\xfe\xc7\x63\xef\x82\xd0\x55\x61\x6b\xd1\x42\xcf\xdc\x38\xb3\xdc\x77\xeb\xcb\xe0\x72\x74\xf9\xe6\x6d\x5a\xbc\xb9\x8c\x8b\xba\x59\x55\x46\xb5\x61\x74\xb5\x58\x6c\xb7\xdb\xd7\xe8\x76\xaf\x69\xbd\x90\xb5\xe9\x5d\x58\xa8\x79\x22\x6f\x31\xe3\xcc\xbb\x06\x3a\x57\xec\x83\xe5\x62\xdf\xdf\x5e\x2e\x7a\xb1\xab\x91\xd8\x87\x69\x81\x38\xbd\x9a\xae\xa4\x9b\x3e\xce\xce\x7f\x9c\xf4\x55\x61\xf2\x2a\xc9\x02\x06\x5e\x2e\xe3\x80\x84\x89\x52\xd2\x87\xae\xc9\xdd\x93\xd5\xa2\xf3\x81\x4e\x43\x98\x3a\x3f\x0c\xcf\x06\x36\x2b\x70\x87\x9e\x7a\x15\x5b\xaa\xc2\xd2\xd8\x79\xbe\x64\x6e\xf4\x8c\xb3\x9b\x0f\xbf\x9d\x9d\x73\x16\xbc\xd4\xac\x72\x92\x5f\x95\x53\x1e\x54\x76\xa6\xd6\xb2\xaa\xc0\x96\xc0\xd9\x5f\xe0\xa2\x08\x1c\x14\x23\xe4\xdb\xcb\xae\x1d\xf4\x8a\x33\xba\x33\xf5\xc1\x04\x5a\x64\x95\x52\xe4\x8a\xb1\x12\xbb\x83\x61\x87\x46\x2b\x11\xe4\x09\xee\x7d\x54\x2c\x73\xc0\x28\x3e\xb2\x7f\x5a\xb4\x4a\x70\x04\xca\x21\xed\x59\x82\xa1\xcd\x3d\x6f\xbb\xbe\x4d\x10\x85\x12\xf2\xae\x55\x81\x19\x67\x85\xac\x08\xf2\x99\x50\x40\x1b\x4c\xae\xe8\x40\x6e\xb1\x7e\x78\xcc\xee\x11\x3e\x82\x59\x36\xfa\x99\xb6\x50\x41\xed\xac\xff\x86\xb0\x2f\xd0\xa9\x70\x43\xd6\xde\xee\x3d\x30\x46\x4b\xb2\xf4\x72\x1e\xe5\x89\x33\xa9\x5c\x7a\xfb\xc0\xbd\xff\x76\x58\x4b\xa5\xe6\x71\x79\x82\xc6\xe3\x14\x03\xad\x79\xa5\xb2\xae\xbd\x5c\x08\x8e\x18\x17\x6b\x69\x75\x05\x7a\xc0\x7c\x7c\xfb\x77\x34\xb6\x22\xd0\xad\x44\x81\x8e\x33\x70\x0e\xdd\x31\x9b\x2d\x3d\x52\x29\x20\x4a\x8a\xdf\x59\xdb\x77\xc0\x58\x57\x6c\x25\x89\x86\xc2\x9b\xac\x7d\xfe\x80\xc3\x9c\xa8\x90\xcf\x31\xd8\x32\x90\x54\xf2\xfb\xb7\x17\x17\x2d\xe8\x43\x06\xfa\xa6\x1e\x81\x09\xdd\x68\xff\x37\xf2\x35\x0a\xe8\x89\x9e\x7e\x01\xca\xd8\xa7\x43\x3c\x9f\xc2\xe9\x89\x59\x79\x59\xb3\x77\x4a\x3d\x04\x6a\xb6\x3c\x69\xdb\x1e\x42\xc3\xbe\xfd\x9a\xe6\xc3\x55\xd1\x50\xae\xe4\x0b\x2f\xa4\x03\x54\xa7\xa2\xd3\x0b\x3f\xaa\xab\x1b\xa1\xc1\xbc\x76\xe7\x9f\xc9\xeb\xf0\x35\xf6\x94\x0a\x1e\x32\xa3\x90\x53\x2f\xbd\x81\x14\x46\x55\x48\xcb\x8e\xa8\x30\x0c\xb5\x87\x78\x36\xdc\x11\x57\xb5\x30\xd6\x78\x33\x52\xce\x33\x9a\x34\x94\xa1\x53\xb9\x18\x7c\x20\x51\xfc\x9c\x88\x09\xce\x1b\x57\x2d\x86\xf6\xa4\x60\xc1\xd1\xa9\xd8\xc8\xbf\xff\x15\x7a\xcb\x13\xfc\x96\xc7\x08\x2e\x8f\x30\x5c\x1e\x7d\xcb\xdc\x5e\x5f\xff\xd7\xf0\xf5\x7f\xbf\xfd\x8c\x5b\x3b\xf9\x27\x00\x00\xff\xff\xcf\x01\x21\xd2\xd1\x0d\x00\x00") + +func migrationsSqlTests14_testSqlBytes() ([]byte, error) { + return bindataRead( + _migrationsSqlTests14_testSql, + "migrations/sql/tests/14_test.sql", + ) +} + +func migrationsSqlTests14_testSql() (*asset, error) { + bytes, err := migrationsSqlTests14_testSqlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "migrations/sql/tests/14_test.sql", size: 3537, mode: os.FileMode(420), modTime: time.Unix(1578061360, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + var _migrationsSqlTests1_testSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x56\xcd\x8e\xdb\x36\x10\x3e\xc7\x4f\x41\xf8\xa2\x5d\x94\x8e\xd7\x2e\x92\x83\x7b\x2a\xd0\x1c\x02\x14\x1b\xa0\x49\xda\x43\x51\x10\x14\x39\x92\x18\x53\x1c\x95\x43\x55\x71\xd7\x79\xf7\x82\xa2\x64\x69\xbd\x42\x9a\xed\xb9\x97\xc5\xfc\x70\x46\xf3\x7d\xf3\xb3\xde\x6c\xd8\x77\xb5\x29\xbd\x0c\xc0\x3e\x36\xab\xd5\xdb\xfb\xf7\x6f\x7e\xf9\xc0\xde\xde\x7f\x78\xc7\xaa\x93\xf6\x52\x28\x6b\xc0\x05\x76\x63\x34\x67\xd2\x5a\xec\x40\x0b\x85\x9e\x04\x7a\x53\x1a\x47\x9c\xa5\x17\xc2\xc9\x1a\x2e\x0a\x81\xf2\x10\x38\xf3\xa0\x8d\x07\x15\x44\xeb\x0d\x71\x56\x7a\xe9\x82\x08\xa7\x06\x28\xfa\xa8\x41\x47\x30\xea\xa4\xb0\x01\xce\xb0\x73\xe0\x39\x6b\xd0\x1a\x75\x8a\x71\x9c\x05\xa4\x24\x0c\xd9\x7b\xd9\x62\x89\x83\x15\x5d\x90\x2a\xd0\xd5\xd7\x05\x7c\x6e\x8c\x07\x12\x32\x70\x46\xa0\x02\x7a\x61\x34\xb8\x60\x0a\x03\x3e\x85\x7e\xea\x8e\x94\xfe\x8e\x5f\x3a\x82\x13\xe0\x74\x83\xc6\x05\x21\xdb\x50\x89\x1a\x42\x85\x3a\xd6\xfb\x67\x0b\x34\x42\x19\x35\xcc\x3f\x45\x7c\x64\x4a\x67\x5c\x29\xa4\x2d\x39\x6b\x09\xbc\x71\x05\xf6\x56\xd0\xe2\x82\xb4\xf7\x52\x9b\x42\x22\x6c\xce\x64\xab\x0d\x38\x05\x9c\x15\x1e\x5d\x50\x95\x74\x0e\xac\x88\xe8\xda\x01\xe9\x92\x83\x80\xc8\xa0\x13\xb1\x0c\xe3\x41\x47\xc2\x28\x8c\xde\x2b\xda\x73\xa9\x8e\x4b\x89\x17\xec\x4f\xf3\xd6\x10\xa4\x96\x41\xde\xae\x7e\xfd\xf1\xe7\x8f\x6f\xde\xaf\x18\xbb\xc9\x76\x9b\x44\x75\xc6\x59\x56\x85\xd0\x1c\xb6\x5b\x8b\x4a\xda\x0a\x29\x9c\x07\x43\x89\x58\x5a\x88\x2f\x08\x6b\x98\x05\xc8\x5c\x69\x28\xbe\x2d\x34\x76\x00\xbd\xf9\x1b\x84\x42\x0d\x67\x53\x37\xd6\x28\xd3\xa7\xe9\x7b\x75\x36\x5a\xf4\x42\xb4\x14\x88\xe7\x5c\xfa\x3e\x0e\x1c\x48\x9a\x7d\x23\xcd\xd3\xcc\x10\x70\xee\x5e\x80\x53\xe2\x94\xe8\x5c\x60\xd4\xee\x26\x7f\x1a\xa8\xf8\xe2\x61\x7d\x84\x13\xad\x0f\xec\xf7\x3f\xbe\xcc\x12\xc4\xa1\x8a\xaa\x43\x07\x33\x73\xeb\xcd\xee\x3c\xc9\xfb\xe8\xf2\xb4\x7f\xf5\x3a\x09\xaf\xf6\xbd\xd0\xb4\xb9\x35\x6a\x0c\xa3\xc3\x76\xdb\x75\xdd\x4b\xf4\xa7\x97\x54\x6d\x65\x63\x66\x09\x0b\xb5\x49\xbd\xdb\x66\x9c\x05\xdf\xc2\xe4\xea\xc7\x60\xb7\x3d\xcf\xd5\xfd\x76\x16\x9b\x2f\xc4\x3e\xac\x0b\xc4\xf5\x61\x9d\x4b\xbf\xfe\x92\xdd\xfe\xf0\xe8\x28\xac\x5e\xa4\xab\x80\xb1\x2f\xfb\x7e\x3f\xe2\x42\x29\x19\xe2\xd0\x0c\xc3\x33\x1c\x8b\xc9\x07\x3a\xed\x60\x1a\xfc\xcb\x20\xbd\x88\x73\x64\xb1\x34\x6e\x33\x44\x6e\x8c\xce\x38\xbb\x7f\xf7\xdb\xcd\x2d\x67\xd9\x6e\x43\x6d\xfe\xbc\x0a\x86\xad\x64\x37\xaa\x92\xd6\x82\x2b\x81\xb3\xbf\xc0\xf7\x1b\x7f\x39\x0f\xb1\xba\xa1\x96\xf9\x56\x5b\xce\xe8\x68\x9a\x8b\x09\xb4\x18\x4e\x92\x22\x5f\x2c\x01\x9a\x1e\x46\x0d\x8d\x56\x22\xde\x22\xf8\x7c\x85\xf1\x52\x4c\xd6\xa3\x1a\x0b\x4a\xda\x34\x79\x3d\xde\x58\x55\x52\xc6\x25\xce\x38\x2b\xa4\x25\x48\x2f\x62\x45\x43\x20\xf9\x62\x62\x6b\x24\xed\xe1\xdf\x7a\xa6\xe2\x25\x72\xe1\x7f\xaa\x9e\x4d\x95\xa8\xa4\xd3\x16\xf4\x23\xca\xfa\x7f\x69\x13\x7e\x0f\x35\xd4\x79\x64\x70\x94\x44\x81\x9e\x33\xf0\x1e\xfd\x35\x0d\xe3\xb1\x95\x4a\x01\x51\xba\x63\x93\x75\xbc\x6c\x4b\x74\x76\x92\x44\x4b\xa0\xbf\x4a\xde\x48\x40\x5a\xec\xef\x5f\xdf\xdd\x25\xd0\x8f\x18\xb8\x32\xf5\xf4\x5d\xb3\xc2\xbe\x61\xe5\x16\xc9\x99\x8d\xce\x57\x69\x91\xea\x09\x37\xff\x15\x73\x9b\x2f\x22\xce\x76\x4f\xfa\x7f\x81\x3a\xff\x11\xf4\x13\x76\x6e\xf5\x4f\x00\x00\x00\xff\xff\x8b\x6b\x7d\x2e\x16\x09\x00\x00") func migrationsSqlTests1_testSqlBytes() ([]byte, error) { @@ -970,6 +1033,7 @@ func AssetNames() []string { var _bindata = map[string]func() (*asset, error){ "migrations/sql/cockroach/12.sql": migrationsSqlCockroach12Sql, "migrations/sql/cockroach/13.sql": migrationsSqlCockroach13Sql, + "migrations/sql/cockroach/14.sql": migrationsSqlCockroach14Sql, "migrations/sql/mysql/.gitkeep": migrationsSqlMysqlGitkeep, "migrations/sql/mysql/10.sql": migrationsSqlMysql10Sql, "migrations/sql/mysql/12.sql": migrationsSqlMysql12Sql, @@ -991,6 +1055,7 @@ var _bindata = map[string]func() (*asset, error){ "migrations/sql/shared/.gitkeep": migrationsSqlSharedGitkeep, "migrations/sql/shared/1.sql": migrationsSqlShared1Sql, "migrations/sql/shared/11.sql": migrationsSqlShared11Sql, + "migrations/sql/shared/14.sql": migrationsSqlShared14Sql, "migrations/sql/shared/2.sql": migrationsSqlShared2Sql, "migrations/sql/shared/3.sql": migrationsSqlShared3Sql, "migrations/sql/shared/9.sql": migrationsSqlShared9Sql, @@ -999,6 +1064,7 @@ var _bindata = map[string]func() (*asset, error){ "migrations/sql/tests/11_test.sql": migrationsSqlTests11_testSql, "migrations/sql/tests/12_test.sql": migrationsSqlTests12_testSql, "migrations/sql/tests/13_test.sql": migrationsSqlTests13_testSql, + "migrations/sql/tests/14_test.sql": migrationsSqlTests14_testSql, "migrations/sql/tests/1_test.sql": migrationsSqlTests1_testSql, "migrations/sql/tests/2_test.sql": migrationsSqlTests2_testSql, "migrations/sql/tests/3_test.sql": migrationsSqlTests3_testSql, @@ -1056,6 +1122,7 @@ var _bintree = &bintree{nil, map[string]*bintree{ "cockroach": &bintree{nil, map[string]*bintree{ "12.sql": &bintree{migrationsSqlCockroach12Sql, map[string]*bintree{}}, "13.sql": &bintree{migrationsSqlCockroach13Sql, map[string]*bintree{}}, + "14.sql": &bintree{migrationsSqlCockroach14Sql, map[string]*bintree{}}, }}, "mysql": &bintree{nil, map[string]*bintree{ ".gitkeep": &bintree{migrationsSqlMysqlGitkeep, map[string]*bintree{}}, @@ -1083,6 +1150,7 @@ var _bintree = &bintree{nil, map[string]*bintree{ ".gitkeep": &bintree{migrationsSqlSharedGitkeep, map[string]*bintree{}}, "1.sql": &bintree{migrationsSqlShared1Sql, map[string]*bintree{}}, "11.sql": &bintree{migrationsSqlShared11Sql, map[string]*bintree{}}, + "14.sql": &bintree{migrationsSqlShared14Sql, map[string]*bintree{}}, "2.sql": &bintree{migrationsSqlShared2Sql, map[string]*bintree{}}, "3.sql": &bintree{migrationsSqlShared3Sql, map[string]*bintree{}}, "9.sql": &bintree{migrationsSqlShared9Sql, map[string]*bintree{}}, @@ -1093,6 +1161,7 @@ var _bintree = &bintree{nil, map[string]*bintree{ "11_test.sql": &bintree{migrationsSqlTests11_testSql, map[string]*bintree{}}, "12_test.sql": &bintree{migrationsSqlTests12_testSql, map[string]*bintree{}}, "13_test.sql": &bintree{migrationsSqlTests13_testSql, map[string]*bintree{}}, + "14_test.sql": &bintree{migrationsSqlTests14_testSql, map[string]*bintree{}}, "1_test.sql": &bintree{migrationsSqlTests1_testSql, map[string]*bintree{}}, "2_test.sql": &bintree{migrationsSqlTests2_testSql, map[string]*bintree{}}, "3_test.sql": &bintree{migrationsSqlTests3_testSql, map[string]*bintree{}}, diff --git a/consent/types.go b/consent/types.go index 1b9c4460037..ab3f331382f 100644 --- a/consent/types.go +++ b/consent/types.go @@ -97,6 +97,9 @@ type HandledConsentRequest struct { // authorization will be remembered indefinitely. RememberFor int `json:"remember_for"` + // HandledAt contains the timestamp the consent request was handled. + HandledAt time.Time `json:"handled_at"` + ConsentRequest *ConsentRequest `json:"-"` Error *RequestDeniedError `json:"-"` Challenge string `json:"-"` @@ -125,6 +128,7 @@ type PreviousConsentSession struct { // authorization will be remembered indefinitely. RememberFor int `json:"remember_for"` + HandledAt time.Time `json:"handled_at"` ConsentRequest *ConsentRequest `json:"consent_request"` Error *RequestDeniedError `json:"-"` Challenge string `json:"-"` diff --git a/cypress/integration/oauth2/consent.js b/cypress/integration/oauth2/consent.js index 59d5b544a59..12ab79e8185 100644 --- a/cypress/integration/oauth2/consent.js +++ b/cypress/integration/oauth2/consent.js @@ -36,6 +36,13 @@ describe('OAuth 2.0 End-User Authorization', () => { .then(body => { expect(body.length).to.be.greaterThan(0); expect(hasConsent(client, body)).to.be.true; + body.forEach(consent => { + expect( + consent.handled_at.match( + /^[2-9]\d{3}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/ + ) + ).not.to.be.empty; + }); }); cy.request( diff --git a/oauth2/fosite_store_helpers.go b/oauth2/fosite_store_helpers.go index 2b4036c69d6..2d11171d4d1 100644 --- a/oauth2/fosite_store_helpers.go +++ b/oauth2/fosite_store_helpers.go @@ -102,6 +102,7 @@ func mockRequestForeignKey(t *testing.T, id string, x InternalRegistry, createCl ConsentRequest: cr, Session: new(consent.ConsentRequestSessionData), AuthenticatedAt: time.Now(), Challenge: id, RequestedAt: time.Now(), + HandledAt: time.Now(), }) require.NoError(t, err) }