From 4052bd5ee530d3bd4c5524aebce3d9c64150bb55 Mon Sep 17 00:00:00 2001 From: zepatrik Date: Wed, 28 Oct 2020 16:22:24 +0100 Subject: [PATCH 1/6] fix: client update breaks primary key closes #2148 --- client/client.go | 6 +- client/client_test.go | 2 +- client/handler.go | 2 +- client/manager_test_helpers.go | 36 ++++--- client/validator.go | 2 +- client/validator_test.go | 36 +++---- consent/handler_test.go | 6 +- consent/manager_test_helpers.go | 18 ++-- consent/sdk_test.go | 2 +- consent/strategy_default.go | 6 +- consent/strategy_default_test.go | 94 +++++++++---------- .../subject_identifier_algorithm_pairwise.go | 4 +- consent/types.go | 34 +++++-- driver/cors_test.go | 20 ++-- go.mod | 2 + go.sum | 8 +- .../consent/x_manager_sql_migrations_test.go | 2 +- internal/fosite_store.go | 4 +- oauth2/fosite_store_helpers.go | 20 ++-- oauth2/fosite_store_test.go | 2 +- oauth2/handler_test.go | 8 +- oauth2/oauth2_auth_code_test.go | 4 +- oauth2/oauth2_client_credentials_test.go | 2 +- oauth2/oauth2_refresh_token_test.go | 4 +- persistence/sql/migratest/exptected_data.go | 4 +- persistence/sql/migratest/migration_test.go | 4 +- persistence/sql/persister_client.go | 15 ++- persistence/sql/persister_test.go | 2 + 28 files changed, 197 insertions(+), 152 deletions(-) diff --git a/client/client.go b/client/client.go index 6e1d8689837..e9c66599f8a 100644 --- a/client/client.go +++ b/client/client.go @@ -37,10 +37,10 @@ import ( // // swagger:model oAuth2Client type Client struct { - PK int64 `json:"-" db:"pk"` + ID int64 `json:"-" db:"pk"` // ID is the id for this client. - ID string `json:"client_id" db:"id"` + OutfacingID string `json:"client_id" db:"id"` // Name is the human-readable string name of the client to be presented to the // end-user during authorization. @@ -235,7 +235,7 @@ func (c *Client) BeforeSave(_ *pop.Connection) error { } func (c *Client) GetID() string { - return c.ID + return c.OutfacingID } func (c *Client) GetRedirectURIs() []string { diff --git a/client/client_test.go b/client/client_test.go index 599dbe12cf3..90c9f92b1e7 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -33,7 +33,7 @@ var _ fosite.Client = new(Client) func TestClient(t *testing.T) { c := &Client{ - ID: "foo", + OutfacingID: "foo", RedirectURIs: []string{"foo"}, Scope: "foo bar", TokenEndpointAuthMethod: "none", diff --git a/client/handler.go b/client/handler.go index 487b6013706..0c150852e6f 100644 --- a/client/handler.go +++ b/client/handler.go @@ -149,7 +149,7 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request, ps httprouter.P secret = c.Secret } - c.ID = ps.ByName("id") + c.OutfacingID = ps.ByName("id") if err := h.r.ClientValidator().Validate(&c); err != nil { h.r.Writer().WriteError(w, r, err) return diff --git a/client/manager_test_helpers.go b/client/manager_test_helpers.go index d1a0227c231..80342b5b056 100644 --- a/client/manager_test_helpers.go +++ b/client/manager_test_helpers.go @@ -39,7 +39,7 @@ func TestHelperClientAutoGenerateKey(k string, m Storage) func(t *testing.T) { return func(t *testing.T) { ctx := context.TODO() c := &Client{ - ID: "foo", + OutfacingID: "foo", Secret: "secret", RedirectURIs: []string{"http://redirect"}, TermsOfServiceURI: "foo", @@ -54,7 +54,7 @@ func TestHelperClientAuthenticate(k string, m Manager) func(t *testing.T) { return func(t *testing.T) { ctx := context.TODO() require.NoError(t, m.CreateClient(ctx, &Client{ - ID: "1234321", + OutfacingID: "1234321", Secret: "secret", RedirectURIs: []string{"http://redirect"}, })) @@ -68,14 +68,28 @@ func TestHelperClientAuthenticate(k string, m Manager) func(t *testing.T) { } } +func TestHelperUpdateTwoClients(_ string, m Manager) func(t *testing.T) { + return func(t *testing.T) { + c1, c2 := &Client{OutfacingID: "klojdfc", Name: "test client 1"}, &Client{OutfacingID: "jlsdfkj", Name: "test client 2"} + + require.NoError(t, m.CreateClient(context.Background(), c1)) + require.NoError(t, m.CreateClient(context.Background(), c2)) + + c1.Name, c2.Name = "updated klojdfc client 1", "updated klojdfc client 2" + + assert.NoError(t, m.UpdateClient(context.Background(), c1)) + assert.NoError(t, m.UpdateClient(context.Background(), c2)) + } +} + func TestHelperCreateGetUpdateDeleteClient(k string, m Storage) func(t *testing.T) { return func(t *testing.T) { - ctx := context.TODO() - _, err := m.GetClient(ctx, "4321") - assert.NotNil(t, err) + ctx := context.Background() + _, err := m.GetClient(ctx, "1234") + require.Error(t, err) c := &Client{ - ID: "1234", + OutfacingID: "1234", Name: "name", Secret: "secret", RedirectURIs: []string{"http://redirect", "http://redirect1"}, @@ -107,14 +121,14 @@ func TestHelperCreateGetUpdateDeleteClient(k string, m Storage) func(t *testing. BackChannelLogoutSessionRequired: true, } - assert.NoError(t, m.CreateClient(ctx, c)) + require.NoError(t, m.CreateClient(ctx, c)) assert.Equal(t, c.GetID(), "1234") if k != "http" { assert.NotEmpty(t, c.GetHashedSecret()) } assert.NoError(t, m.CreateClient(ctx, &Client{ - ID: "2-1234", + OutfacingID: "2-1234", Name: "name", Secret: "secret", RedirectURIs: []string{"http://redirect"}, @@ -130,8 +144,8 @@ func TestHelperCreateGetUpdateDeleteClient(k string, m Storage) func(t *testing. ds, err := m.GetClients(ctx, 100, 0) assert.NoError(t, err) assert.Len(t, ds, 2) - assert.NotEqual(t, ds[0].ID, ds[1].ID) - assert.NotEqual(t, ds[0].ID, ds[1].ID) + assert.NotEqual(t, ds[0].OutfacingID, ds[1].OutfacingID) + assert.NotEqual(t, ds[0].OutfacingID, ds[1].OutfacingID) // test if SecretExpiresAt was set properly assert.Equal(t, ds[0].SecretExpiresAt, 0) assert.Equal(t, ds[1].SecretExpiresAt, 1) @@ -144,7 +158,7 @@ func TestHelperCreateGetUpdateDeleteClient(k string, m Storage) func(t *testing. assert.NoError(t, err) err = m.UpdateClient(ctx, &Client{ - ID: "2-1234", + OutfacingID: "2-1234", Name: "name-new", Secret: "secret-new", RedirectURIs: []string{"http://redirect/new"}, diff --git a/client/validator.go b/client/validator.go index f8d8f8e7cd2..58cd817bff0 100644 --- a/client/validator.go +++ b/client/validator.go @@ -70,7 +70,7 @@ func NewValidatorWithClient(conf Configuration, client *http.Client) *Validator func (v *Validator) Validate(c *Client) error { id := uuid.New() - c.ID = stringsx.Coalesce(c.ID, id) + c.OutfacingID = stringsx.Coalesce(c.OutfacingID, id) if c.TokenEndpointAuthMethod == "" { c.TokenEndpointAuthMethod = "client_secret_basic" diff --git a/client/validator_test.go b/client/validator_test.go index c0c7040c9f2..5d942ec445c 100644 --- a/client/validator_test.go +++ b/client/validator_test.go @@ -53,59 +53,59 @@ func TestValidate(t *testing.T) { { in: new(Client), check: func(t *testing.T, c *Client) { - assert.NotEmpty(t, c.ID) + assert.NotEmpty(t, c.OutfacingID) assert.NotEmpty(t, c.GetID()) - assert.Equal(t, c.GetID(), c.ID) + assert.Equal(t, c.GetID(), c.OutfacingID) }, }, { - in: &Client{ID: "foo"}, + in: &Client{OutfacingID: "foo"}, check: func(t *testing.T, c *Client) { - assert.Equal(t, c.GetID(), c.ID) + assert.Equal(t, c.GetID(), c.OutfacingID) }, }, { - in: &Client{ID: "foo"}, + in: &Client{OutfacingID: "foo"}, check: func(t *testing.T, c *Client) { - assert.Equal(t, c.GetID(), c.ID) + assert.Equal(t, c.GetID(), c.OutfacingID) }, }, { - in: &Client{ID: "foo", UserinfoSignedResponseAlg: "foo"}, + in: &Client{OutfacingID: "foo", UserinfoSignedResponseAlg: "foo"}, expectErr: true, }, { - in: &Client{ID: "foo", TokenEndpointAuthMethod: "private_key_jwt"}, + in: &Client{OutfacingID: "foo", TokenEndpointAuthMethod: "private_key_jwt"}, expectErr: true, }, { - in: &Client{ID: "foo", JSONWebKeys: &x.JoseJSONWebKeySet{JSONWebKeySet: new(jose.JSONWebKeySet)}, JSONWebKeysURI: "asdf", TokenEndpointAuthMethod: "private_key_jwt"}, + in: &Client{OutfacingID: "foo", JSONWebKeys: &x.JoseJSONWebKeySet{JSONWebKeySet: new(jose.JSONWebKeySet)}, JSONWebKeysURI: "asdf", TokenEndpointAuthMethod: "private_key_jwt"}, expectErr: true, }, { - in: &Client{ID: "foo", JSONWebKeys: &x.JoseJSONWebKeySet{JSONWebKeySet: new(jose.JSONWebKeySet)}, TokenEndpointAuthMethod: "private_key_jwt", TokenEndpointAuthSigningAlgorithm: "HS256"}, + in: &Client{OutfacingID: "foo", JSONWebKeys: &x.JoseJSONWebKeySet{JSONWebKeySet: new(jose.JSONWebKeySet)}, TokenEndpointAuthMethod: "private_key_jwt", TokenEndpointAuthSigningAlgorithm: "HS256"}, expectErr: true, }, { - in: &Client{ID: "foo", PostLogoutRedirectURIs: []string{"https://bar/"}, RedirectURIs: []string{"https://foo/"}}, + in: &Client{OutfacingID: "foo", PostLogoutRedirectURIs: []string{"https://bar/"}, RedirectURIs: []string{"https://foo/"}}, expectErr: true, }, { - in: &Client{ID: "foo", PostLogoutRedirectURIs: []string{"http://foo/"}, RedirectURIs: []string{"https://foo/"}}, + in: &Client{OutfacingID: "foo", PostLogoutRedirectURIs: []string{"http://foo/"}, RedirectURIs: []string{"https://foo/"}}, expectErr: true, }, { - in: &Client{ID: "foo", PostLogoutRedirectURIs: []string{"https://foo:1234/"}, RedirectURIs: []string{"https://foo/"}}, + in: &Client{OutfacingID: "foo", PostLogoutRedirectURIs: []string{"https://foo:1234/"}, RedirectURIs: []string{"https://foo/"}}, expectErr: true, }, { - in: &Client{ID: "foo", PostLogoutRedirectURIs: []string{"https://foo/"}, RedirectURIs: []string{"https://foo/"}}, + in: &Client{OutfacingID: "foo", PostLogoutRedirectURIs: []string{"https://foo/"}, RedirectURIs: []string{"https://foo/"}}, check: func(t *testing.T, c *Client) { assert.Equal(t, []string{"https://foo/"}, []string(c.PostLogoutRedirectURIs)) }, }, { - in: &Client{ID: "foo"}, + in: &Client{OutfacingID: "foo"}, check: func(t *testing.T, c *Client) { assert.Equal(t, "public", c.SubjectType) }, @@ -115,19 +115,19 @@ func TestValidate(t *testing.T) { viper.Set(configuration.ViperKeySubjectTypesSupported, []string{"pairwise"}) return NewValidator(c) }, - in: &Client{ID: "foo"}, + in: &Client{OutfacingID: "foo"}, check: func(t *testing.T, c *Client) { assert.Equal(t, "pairwise", c.SubjectType) }, }, { - in: &Client{ID: "foo", SubjectType: "pairwise"}, + in: &Client{OutfacingID: "foo", SubjectType: "pairwise"}, check: func(t *testing.T, c *Client) { assert.Equal(t, "pairwise", c.SubjectType) }, }, { - in: &Client{ID: "foo", SubjectType: "foo"}, + in: &Client{OutfacingID: "foo", SubjectType: "foo"}, expectErr: true, }, } { diff --git a/consent/handler_test.go b/consent/handler_test.go index e05c86a4f49..665303a9ef0 100644 --- a/consent/handler_test.go +++ b/consent/handler_test.go @@ -106,7 +106,7 @@ func TestGetLogoutRequest(t *testing.T) { reg := internal.NewRegistryMemory(t, conf) if tc.exists { - cl := &client.Client{ID: "client" + key} + cl := &client.Client{OutfacingID: "client" + key} require.NoError(t, reg.ClientManager().CreateClient(context.Background(), cl)) require.NoError(t, reg.ConsentManager().CreateLogoutRequest(context.TODO(), &LogoutRequest{ Client: cl, @@ -147,7 +147,7 @@ func TestGetLoginRequest(t *testing.T) { reg := internal.NewRegistryMemory(t, conf) if tc.exists { - cl := &client.Client{ID: "client" + key} + cl := &client.Client{OutfacingID: "client" + key} require.NoError(t, reg.ClientManager().CreateClient(context.Background(), cl)) require.NoError(t, reg.ConsentManager().CreateLoginRequest(context.Background(), &LoginRequest{ Client: cl, @@ -192,7 +192,7 @@ func TestGetConsentRequest(t *testing.T) { reg := internal.NewRegistryMemory(t, conf) if tc.exists { - cl := &client.Client{ID: "client" + key} + cl := &client.Client{OutfacingID: "client" + key} require.NoError(t, reg.ClientManager().CreateClient(context.Background(), cl)) require.NoError(t, reg.ConsentManager().CreateConsentRequest(context.Background(), &ConsentRequest{ Client: cl, diff --git a/consent/manager_test_helpers.go b/consent/manager_test_helpers.go index eb92f4105ea..c057245b0c2 100644 --- a/consent/manager_test_helpers.go +++ b/consent/manager_test_helpers.go @@ -51,7 +51,7 @@ func MockConsentRequest(key string, remember bool, rememberFor int, hasError boo UILocales: []string{"fr" + key, "de" + key}, Display: "popup" + key, }, - Client: &client.Client{ID: "fk-client-" + key}, + Client: &client.Client{OutfacingID: "fk-client-" + key}, RequestURL: "https://request-url/path" + key, LoginChallenge: sqlxx.NullString("fk-login-challenge-" + key), LoginSessionID: sqlxx.NullString("fk-login-session-" + key), @@ -103,7 +103,7 @@ func MockLogoutRequest(key string, withClient bool) (c *LogoutRequest) { var cl *client.Client if withClient { cl = &client.Client{ - ID: "fk-client-" + key, + OutfacingID: "fk-client-" + key, } } return &LogoutRequest{ @@ -128,7 +128,7 @@ func MockAuthRequest(key string, authAt bool) (c *LoginRequest, h *HandledLoginR Display: "popup" + key, }, RequestedAt: time.Now().UTC().Add(-time.Hour), - Client: &client.Client{ID: "fk-client-" + key}, + Client: &client.Client{OutfacingID: "fk-client-" + key}, Subject: "subject" + key, RequestURL: "https://request-url/path" + key, Skip: true, @@ -262,7 +262,7 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit 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"} { - require.NoError(t, clientManager.CreateClient(context.Background(), &client.Client{ID: fmt.Sprintf("fk-client-%s", k)})) + require.NoError(t, clientManager.CreateClient(context.Background(), &client.Client{OutfacingID: fmt.Sprintf("fk-client-%s", k)})) require.NoError(t, m.CreateLoginSession(context.Background(), &LoginSession{ ID: fmt.Sprintf("fk-login-session-%s", k), @@ -273,7 +273,7 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit require.NoError(t, m.CreateLoginRequest(context.Background(), &LoginRequest{ ID: fmt.Sprintf("fk-login-challenge-%s", k), Verifier: fmt.Sprintf("fk-login-verifier-%s", k), - Client: &client.Client{ID: fmt.Sprintf("fk-client-%s", k)}, + Client: &client.Client{OutfacingID: fmt.Sprintf("fk-client-%s", k)}, AuthenticatedAt: sqlxx.NullTime(time.Now()), RequestedAt: time.Now(), })) @@ -646,7 +646,7 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit require.NoError(t, err) for _, consent := range consents { assert.Contains(t, tc.challenges, consent.ID) - assert.Contains(t, tc.clients, consent.ConsentRequest.Client.ID) + assert.Contains(t, tc.clients, consent.ConsentRequest.Client.OutfacingID) } } @@ -710,7 +710,7 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit } require.NoError(t, m.CreateLoginSession(context.Background(), ls)) - cl := &client.Client{ID: uuid.New().String()} + cl := &client.Client{OutfacingID: uuid.New().String()} switch k % 4 { case 0: cl.FrontChannelLogoutURI = "http://some-url.com/" @@ -746,10 +746,10 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit for _, e := range es { var found bool for _, a := range actual { - if e.ID == a.ID { + if e.OutfacingID == a.OutfacingID { found = true } - assert.Equal(t, e.ID, a.ID) + assert.Equal(t, e.OutfacingID, a.OutfacingID) assert.Equal(t, e.FrontChannelLogoutURI, a.FrontChannelLogoutURI) assert.Equal(t, e.BackChannelLogoutURI, a.BackChannelLogoutURI) } diff --git a/consent/sdk_test.go b/consent/sdk_test.go index 592e5f4edd4..6b3396267d0 100644 --- a/consent/sdk_test.go +++ b/consent/sdk_test.go @@ -135,7 +135,7 @@ func TestSDK(t *testing.T) { _, err = sdk.Admin.RevokeConsentSessions(admin.NewRevokeConsentSessionsParams().WithSubject("subject1")) require.Error(t, err) - _, err = sdk.Admin.RevokeConsentSessions(admin.NewRevokeConsentSessionsParams().WithSubject(cr4.Subject).WithClient(&cr4.Client.ID)) + _, err = sdk.Admin.RevokeConsentSessions(admin.NewRevokeConsentSessionsParams().WithSubject(cr4.Subject).WithClient(&cr4.Client.OutfacingID)) require.NoError(t, err) _, err = sdk.Admin.RevokeConsentSessions(admin.NewRevokeConsentSessionsParams().WithSubject("subject1").WithAll(pointerx.Bool(true))) diff --git a/consent/strategy_default.go b/consent/strategy_default.go index 441b79a3c7e..118e6b8ab8f 100644 --- a/consent/strategy_default.go +++ b/consent/strategy_default.go @@ -332,7 +332,7 @@ func (s *DefaultStrategy) obfuscateSubjectIdentifier(cl fosite.Client, subject, if c, ok := cl.(*client.Client); ok && c.SubjectType == "pairwise" { algorithm, ok := s.r.SubjectIdentifierAlgorithm()[c.SubjectType] if !ok { - return "", errors.WithStack(fosite.ErrInvalidRequest.WithHint(fmt.Sprintf(`Subject Identifier Algorithm "%s" was requested by OAuth 2.0 Client "%s", but is not configured.`, c.SubjectType, c.ID))) + return "", errors.WithStack(fosite.ErrInvalidRequest.WithHint(fmt.Sprintf(`Subject Identifier Algorithm "%s" was requested by OAuth 2.0 Client "%s", but is not configured.`, c.SubjectType, c.OutfacingID))) } if len(forcedIdentifier) > 0 { @@ -683,7 +683,7 @@ func (s *DefaultStrategy) executeBackChannelLogout(ctx context.Context, r *http. t, _, err := s.r.OpenIDJWTStrategy().Generate(ctx, jwtgo.MapClaims{ "iss": s.c.IssuerURL().String(), - "aud": []string{c.ID}, + "aud": []string{c.OutfacingID}, "iat": time.Now().UTC().Unix(), "jti": uuid.New(), "events": map[string]struct{}{"http://schemas.openid.net/event/backchannel-logout": {}}, @@ -695,7 +695,7 @@ func (s *DefaultStrategy) executeBackChannelLogout(ctx context.Context, r *http. return err } - tasks = append(tasks, task{url: c.BackChannelLogoutURI, clientID: c.ID, token: t}) + tasks = append(tasks, task{url: c.BackChannelLogoutURI, clientID: c.OutfacingID, token: t}) } var wg sync.WaitGroup diff --git a/consent/strategy_default_test.go b/consent/strategy_default_test.go index 5f7ea6e00f4..5e6c5927ba5 100644 --- a/consent/strategy_default_test.go +++ b/consent/strategy_default_test.go @@ -234,7 +234,7 @@ func runLogout(t *testing.T, method string) { viper.Set(configuration.ViperKeyLogoutURL, logoutProviderServer.URL) viper.Set(configuration.ViperKeyLogoutRedirectURL, defaultRedirServer.URL) - defaultClient := &client.Client{ID: uuid.New(), PostLogoutRedirectURIs: []string{defaultRedirServer.URL + "/custom"}} + defaultClient := &client.Client{OutfacingID: uuid.New(), PostLogoutRedirectURIs: []string{defaultRedirServer.URL + "/custom"}} require.NoError(t, reg.ClientManager().CreateClient(context.TODO(), defaultClient)) jar1 := newValidAuthCookieJar(t, reg, logoutServer.URL, "logout-session-1", "logout-subject-1") @@ -335,7 +335,7 @@ func runLogout(t *testing.T, method string) { "state": {"1234"}, "post_logout_redirect_uri": {defaultRedirServer.URL + "/custom"}, "id_token_hint": {genIDToken(t, reg, jwtgo.MapClaims{ - "aud": defaultClient.ID, + "aud": defaultClient.OutfacingID, "sub": "logout-subject-temp1", "sid": "logout-session-temp1", "exp": time.Now().Add(-time.Hour).Unix(), @@ -353,7 +353,7 @@ func runLogout(t *testing.T, method string) { "state": {"1234"}, "post_logout_redirect_uri": {defaultRedirServer.URL + "/custom"}, "id_token_hint": {genIDToken(t, reg, jwtgo.MapClaims{ - "aud": defaultClient.ID, + "aud": defaultClient.OutfacingID, "iss": "some-issuer", "sub": "logout-subject-temp2", "sid": "logout-session-temp2", @@ -372,7 +372,7 @@ func runLogout(t *testing.T, method string) { "state": {"1234"}, "post_logout_redirect_uri": {defaultRedirServer.URL + "/custom"}, "id_token_hint": {genIDToken(t, reg, jwtgo.MapClaims{ - "aud": defaultClient.ID, + "aud": defaultClient.OutfacingID, "iss": conf.IssuerURL().String(), "sub": "logout-subject-temp3", "sid": "logout-session-temp3", @@ -391,7 +391,7 @@ func runLogout(t *testing.T, method string) { "state": {"1234"}, "post_logout_redirect_uri": {"https://this-is-not-a-valid-redirect-url/custom"}, "id_token_hint": {genIDToken(t, reg, jwtgo.MapClaims{ - "aud": defaultClient.ID, + "aud": defaultClient.OutfacingID, "iss": conf.IssuerURL().String(), "sub": "logout-subject-temp4", "sid": "logout-session-temp4", @@ -410,7 +410,7 @@ func runLogout(t *testing.T, method string) { "state": {"1234"}, "post_logout_redirect_uri": {defaultRedirServer.URL + "/custom"}, "id_token_hint": {genIDToken(t, reg, jwtgo.MapClaims{ - "aud": defaultClient.ID, + "aud": defaultClient.OutfacingID, "iss": conf.IssuerURL().String(), "sub": "logout-subject-temp5", "sid": "logout-session-temp5", @@ -429,7 +429,7 @@ func runLogout(t *testing.T, method string) { "state": {"1234"}, "post_logout_redirect_uri": {defaultRedirServer.URL + "/custom"}, "id_token_hint": {genIDToken(t, reg, jwtgo.MapClaims{ - "aud": []string{defaultClient.ID}, // make sure this works with string slices too + "aud": []string{defaultClient.OutfacingID}, // make sure this works with string slices too "iss": conf.IssuerURL().String(), "sub": "logout-subject-3", "sid": "logout-session-3", @@ -455,7 +455,7 @@ func runLogout(t *testing.T, method string) { "state": {"1234"}, "post_logout_redirect_uri": {defaultRedirServer.URL + "/custom"}, "id_token_hint": {genIDToken(t, reg, jwtgo.MapClaims{ - "aud": []string{defaultClient.ID}, // make sure this works with string slices too + "aud": []string{defaultClient.OutfacingID}, // make sure this works with string slices too "iss": conf.IssuerURL().String(), "sub": "logout-subject-3", "sid": "i-do-not-exist", @@ -577,7 +577,7 @@ func TestStrategyLoginConsent(t *testing.T) { persistentCJ4 := newCookieJar(t) nonexistentCJ := newAuthCookieJar(t, reg, ap.URL, "i-do-not-exist") - require.NoError(t, reg.ClientManager().CreateClient(context.Background(), &client.Client{ID: "client-id"})) + require.NoError(t, reg.ClientManager().CreateClient(context.Background(), &client.Client{OutfacingID: "client-id"})) for k, tc := range []struct { setup func() @@ -598,7 +598,7 @@ func TestStrategyLoginConsent(t *testing.T) { }{ { d: "This should fail because a login verifier was given that doesn't exist in the store", - req: fosite.AuthorizeRequest{Request: fosite.Request{Client: &client.Client{ID: "client-id"}}}, + req: fosite.AuthorizeRequest{Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}}}, lv: "invalid", expectErrType: []error{fosite.ErrAccessDenied}, expectErr: []bool{true}, @@ -606,7 +606,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, { d: "This should fail because a consent verifier was given but no login verifier", - req: fosite.AuthorizeRequest{Request: fosite.Request{Client: &client.Client{ID: "client-id"}}}, + req: fosite.AuthorizeRequest{Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}}}, lv: "", cv: "invalid", expectErrType: []error{fosite.ErrAccessDenied}, @@ -617,7 +617,7 @@ func TestStrategyLoginConsent(t *testing.T) { d: "This should fail because the request was redirected but the login endpoint doesn't do anything (like redirecting back)", req: fosite.AuthorizeRequest{ Request: fosite.Request{ - Client: &client.Client{ID: "client-id"}, + Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}, }, }, @@ -645,7 +645,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, { d: "This should fail because the request was redirected but the login endpoint rejected the request", - req: fosite.AuthorizeRequest{Request: fosite.Request{Client: &client.Client{ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, lph: func(t *testing.T) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { vr, err := apiClient.Admin.RejectLoginRequest(admin.NewRejectLoginRequestParams(). @@ -670,7 +670,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, { d: "This should fail because no cookie jar / invalid csrf", - req: fosite.AuthorizeRequest{Request: fosite.Request{Client: &client.Client{ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, lph: passAuthentication(apiClient, false), cph: func(t *testing.T) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { @@ -685,7 +685,7 @@ func TestStrategyLoginConsent(t *testing.T) { { d: "This should fail because consent endpoints idles after login was granted - but consent endpoint should be called because cookie jar exists", jar: newCookieJar(t), - req: fosite.AuthorizeRequest{Request: fosite.Request{Client: &client.Client{ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, lph: passAuthentication(apiClient, false), other: "display=page&ui_locales=de+en&acr_values=1+2", cph: func(t *testing.T) func(w http.ResponseWriter, r *http.Request) { @@ -715,14 +715,14 @@ func TestStrategyLoginConsent(t *testing.T) { d: "This should fail because consent verifier was set but does not exist", jar: newCookieJar(t), cv: "invalid", - req: fosite.AuthorizeRequest{Request: fosite.Request{Client: &client.Client{ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, expectFinalStatusCode: http.StatusForbidden, expectErrType: []error{fosite.ErrAccessDenied}, expectErr: []bool{true}, }, { d: "This should fail because consent endpoints denies the request after login was granted", - req: fosite.AuthorizeRequest{Request: fosite.Request{Client: &client.Client{ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, jar: newCookieJar(t), lph: passAuthentication(apiClient, false), cph: func(t *testing.T) func(w http.ResponseWriter, r *http.Request) { @@ -750,7 +750,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, { d: "This should pass because login and consent have been granted", - req: fosite.AuthorizeRequest{Request: fosite.Request{Client: &client.Client{ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, jar: newCookieJar(t), lph: passAuthentication(apiClient, false), cph: passAuthorization(apiClient, false), @@ -770,7 +770,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, { d: "This should pass and set acr values properly", - req: fosite.AuthorizeRequest{Request: fosite.Request{Client: &client.Client{ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, jar: newCookieJar(t), lph: passAuthentication(apiClient, false), cph: passAuthorization(apiClient, false), @@ -790,7 +790,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, { d: "This should pass because login and consent have been granted, this time we remember the decision", - req: fosite.AuthorizeRequest{Request: fosite.Request{Client: &client.Client{ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, jar: persistentCJ, lph: passAuthentication(apiClient, true), cph: passAuthorization(apiClient, true), @@ -810,7 +810,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, { d: "This should pass because login and consent have been granted, this time we remember the decision", - req: fosite.AuthorizeRequest{Request: fosite.Request{Client: &client.Client{ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, jar: persistentCJ, lph: func(t *testing.T) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { @@ -844,7 +844,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, { d: "This should pass because login and consent have been granted, this time we remember the decision", - req: fosite.AuthorizeRequest{Request: fosite.Request{Client: &client.Client{ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, jar: persistentCJ, lph: func(t *testing.T) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { @@ -878,7 +878,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, { d: "This should pass because login was remembered and session id should be set and session context should also work", - req: fosite.AuthorizeRequest{Request: fosite.Request{Client: &client.Client{ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, jar: persistentCJ, lph: func(t *testing.T) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { @@ -935,7 +935,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, { d: "This should fail because prompt=none, client is public, and redirection scheme is not HTTPS but a custom scheme and acustom domain", - req: fosite.AuthorizeRequest{RedirectURI: mustParseURL(t, "custom://redirection-scheme/path"), Request: fosite.Request{Client: &client.Client{TokenEndpointAuthMethod: "none", ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{RedirectURI: mustParseURL(t, "custom://redirection-scheme/path"), Request: fosite.Request{Client: &client.Client{TokenEndpointAuthMethod: "none", OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, prompt: "none", jar: persistentCJ, lph: passAuthentication(apiClient, false), @@ -945,7 +945,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, { d: "This should fail because prompt=none, client is public, and redirection scheme is not HTTPS but a custom scheme", - req: fosite.AuthorizeRequest{RedirectURI: mustParseURL(t, "custom://localhost/path"), Request: fosite.Request{Client: &client.Client{TokenEndpointAuthMethod: "none", ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{RedirectURI: mustParseURL(t, "custom://localhost/path"), Request: fosite.Request{Client: &client.Client{TokenEndpointAuthMethod: "none", OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, prompt: "none", jar: persistentCJ, lph: passAuthentication(apiClient, false), @@ -955,7 +955,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, { d: "This should pass because prompt=none, client is public, redirection scheme is HTTP and host is localhost", - req: fosite.AuthorizeRequest{RedirectURI: mustParseURL(t, "http://localhost/path"), Request: fosite.Request{Client: &client.Client{TokenEndpointAuthMethod: "none", ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{RedirectURI: mustParseURL(t, "http://localhost/path"), Request: fosite.Request{Client: &client.Client{TokenEndpointAuthMethod: "none", OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, prompt: "none", jar: persistentCJ, lph: passAuthentication(apiClient, true), @@ -1039,7 +1039,7 @@ func TestStrategyLoginConsent(t *testing.T) { // }, { d: "This should fail at login screen because subject from accept does not match subject from session", - req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"code"}, Request: fosite.Request{Client: &client.Client{ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"code"}, Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, jar: persistentCJ, lph: func(t *testing.T) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { @@ -1069,7 +1069,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, { d: "This should pass and confirm previous authentication and consent because it is a authorization_code", - req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"code"}, Request: fosite.Request{Client: &client.Client{ID: "client-id", Secret: "should-not-be-included"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"code"}, Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id", Secret: "should-not-be-included"}, RequestedScope: []string{"scope-a"}}}, jar: persistentCJ, lph: func(t *testing.T) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { @@ -1125,7 +1125,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, { d: "This should pass and require re-authentication although session is set (because prompt=login)", - req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"code"}, Request: fosite.Request{Client: &client.Client{ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"code"}, Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, jar: persistentCJ, prompt: "login+consent", lph: func(t *testing.T) func(w http.ResponseWriter, r *http.Request) { @@ -1188,7 +1188,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, { d: "This should pass and require re-authentication although session is set (because max_age=1)", - req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"code"}, Request: fosite.Request{Client: &client.Client{ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"code"}, Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, jar: persistentCJ, maxAge: "1", setup: func() { @@ -1242,7 +1242,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, { d: "This should fail because max_age=1 but prompt=none", - req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"code"}, Request: fosite.Request{Client: &client.Client{ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"code"}, Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, jar: persistentCJ, setup: func() { time.Sleep(time.Second * 2) @@ -1256,7 +1256,7 @@ func TestStrategyLoginConsent(t *testing.T) { { d: "This should fail because prompt is none but no auth session exists", prompt: "none", - req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"code"}, Request: fosite.Request{Client: &client.Client{ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"code"}, Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, jar: newCookieJar(t), expectFinalStatusCode: http.StatusBadRequest, expectErrType: []error{fosite.ErrLoginRequired}, @@ -1265,7 +1265,7 @@ func TestStrategyLoginConsent(t *testing.T) { { d: "This should fail because prompt is none and consent is missing a permission which requires re-authorization of the app", prompt: "none", - req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"code"}, Request: fosite.Request{Client: &client.Client{ID: "client-id"}, RequestedScope: []string{"scope-a", "this-scope-has-not-been-granted-before"}}}, + req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"code"}, Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a", "this-scope-has-not-been-granted-before"}}}, jar: persistentCJ, lph: func(t *testing.T) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { @@ -1296,7 +1296,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, { d: "This pass and properly require authentication as well as authorization because prompt is set to login and consent - although previous session exists", - req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"code"}, Request: fosite.Request{Client: &client.Client{ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"code"}, Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, jar: persistentCJ, prompt: "login+consent", lph: func(t *testing.T) func(w http.ResponseWriter, r *http.Request) { @@ -1337,7 +1337,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, { d: "This should fail because id_token_hint does not match authentication session and prompt is none", - req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"code"}, Request: fosite.Request{Client: &client.Client{ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"code"}, Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, jar: persistentCJ, prompt: "none", idTokenHint: fooUserIDToken, @@ -1347,7 +1347,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, { d: "This should pass and require authentication because id_token_hint does not match subject from session", - req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"code"}, Request: fosite.Request{Client: &client.Client{ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"code"}, Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, jar: persistentCJ, idTokenHint: fooUserIDToken, lph: func(t *testing.T) func(w http.ResponseWriter, r *http.Request) { @@ -1378,7 +1378,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, { d: "This should pass and require authentication because id_token_hint does not match subject from session", - req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"code"}, Request: fosite.Request{Client: &client.Client{ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"code"}, Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, jar: persistentCJ, idTokenHint: fooUserIDToken, lph: func(t *testing.T) func(w http.ResponseWriter, r *http.Request) { @@ -1444,7 +1444,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, { d: "This should pass as regularly even though id_token_hint is expired", - req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"token", "code", "id_token"}, Request: fosite.Request{Client: &client.Client{ID: "client-id", SectorIdentifierURI: "foo"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"token", "code", "id_token"}, Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id", SectorIdentifierURI: "foo"}, RequestedScope: []string{"scope-a"}}}, jar: newCookieJar(t), idTokenHint: genIDToken(t, reg, jwt.IDTokenClaims{ Subject: "user", @@ -1461,7 +1461,7 @@ func TestStrategyLoginConsent(t *testing.T) { // Pairwise auth { d: "This should pass as regularly and create a new session with pairwise subject set by hydra", - req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"token", "code", "id_token"}, Request: fosite.Request{Client: &client.Client{ID: "client-id", SubjectType: "pairwise", SectorIdentifierURI: "foo"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"token", "code", "id_token"}, Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id", SubjectType: "pairwise", SectorIdentifierURI: "foo"}, RequestedScope: []string{"scope-a"}}}, jar: persistentCJ3, lph: func(t *testing.T) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { @@ -1494,7 +1494,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, // these tests depend on one another { d: "This should pass as regularly and create a new session with pairwise subject and also with the ID token set", - req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"token", "code", "id_token"}, Request: fosite.Request{Client: &client.Client{ID: "client-id", SubjectType: "pairwise", SectorIdentifierURI: "foo"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"token", "code", "id_token"}, Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id", SubjectType: "pairwise", SectorIdentifierURI: "foo"}, RequestedScope: []string{"scope-a"}}}, jar: persistentCJ3, idTokenHint: genIDToken(t, reg, jwt.IDTokenClaims{ Subject: "c737d5e1fec8896d096d49f6b1a73eb45ac7becb87de9ac3f0a350bad2a9c9fd", @@ -1533,7 +1533,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, { d: "This should pass as regularly and create a new session with pairwise subject set login request", - req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"token", "code", "id_token"}, Request: fosite.Request{Client: &client.Client{ID: "client-id", SubjectType: "pairwise", SectorIdentifierURI: "foo"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"token", "code", "id_token"}, Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id", SubjectType: "pairwise", SectorIdentifierURI: "foo"}, RequestedScope: []string{"scope-a"}}}, jar: persistentCJ4, lph: func(t *testing.T) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { @@ -1567,7 +1567,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, // these tests depend on one another { d: "This should pass as regularly and create a new session with pairwise subject set on login request and also with the ID token set", - req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"token", "code", "id_token"}, Request: fosite.Request{Client: &client.Client{ID: "client-id", SubjectType: "pairwise", SectorIdentifierURI: "foo"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"token", "code", "id_token"}, Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id", SubjectType: "pairwise", SectorIdentifierURI: "foo"}, RequestedScope: []string{"scope-a"}}}, jar: persistentCJ3, idTokenHint: genIDToken(t, reg, jwt.IDTokenClaims{ Subject: "forced-auth-user", @@ -1608,7 +1608,7 @@ func TestStrategyLoginConsent(t *testing.T) { // checks revoking sessions { d: "This should pass as regularly and create a new session and forward data", - req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"token", "code", "id_token"}, Request: fosite.Request{Client: &client.Client{ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"token", "code", "id_token"}, Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, jar: persistentCJ2, lph: func(t *testing.T) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { @@ -1631,7 +1631,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, { d: "This should pass and also revoke the session cookie", - req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"token", "code", "id_token"}, Request: fosite.Request{Client: &client.Client{ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"token", "code", "id_token"}, Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, jar: persistentCJ2, prompt: "login", lph: func(t *testing.T) func(w http.ResponseWriter, r *http.Request) { @@ -1655,7 +1655,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, // these two tests depend on one another { d: "This should require re-authentication because the session was revoked in the previous test", - req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"token", "code", "id_token"}, Request: fosite.Request{Client: &client.Client{ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"token", "code", "id_token"}, Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, jar: persistentCJ2, lph: func(t *testing.T) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { @@ -1684,7 +1684,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, { d: "This should require re-authentication because the session does not exist in the store", - req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"token", "code", "id_token"}, Request: fosite.Request{Client: &client.Client{ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"token", "code", "id_token"}, Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, jar: nonexistentCJ, lph: func(t *testing.T) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { @@ -1713,7 +1713,7 @@ func TestStrategyLoginConsent(t *testing.T) { }, { d: "This should fail because the user from the ID token does not match the user from the accept login request", - req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"token", "code", "id_token"}, Request: fosite.Request{Client: &client.Client{ID: "client-id"}, RequestedScope: []string{"scope-a"}}}, + req: fosite.AuthorizeRequest{ResponseTypes: fosite.Arguments{"token", "code", "id_token"}, Request: fosite.Request{Client: &client.Client{OutfacingID: "client-id"}, RequestedScope: []string{"scope-a"}}}, jar: newCookieJar(t), idTokenHint: fooUserIDToken, lph: func(t *testing.T) func(w http.ResponseWriter, r *http.Request) { diff --git a/consent/subject_identifier_algorithm_pairwise.go b/consent/subject_identifier_algorithm_pairwise.go index 8bfaadcd40a..3da994fce42 100644 --- a/consent/subject_identifier_algorithm_pairwise.go +++ b/consent/subject_identifier_algorithm_pairwise.go @@ -43,9 +43,9 @@ func (g *SubjectIdentifierAlgorithmPairwise) Obfuscate(subject string, client *c // sub = SHA-256 ( sector_identifier || local_account_id || salt ). var id string if len(client.SectorIdentifierURI) == 0 && len(client.RedirectURIs) > 1 { - return "", errors.WithStack(fosite.ErrInvalidRequest.WithHint(fmt.Sprintf("OAuth 2.0 Client %s has multiple redirect_uris but no sector_identifier_uri was set which is not allowed when performing using subject type pairwise. Please reconfigure the OAuth 2.0 client properly.", client.ID))) + return "", errors.WithStack(fosite.ErrInvalidRequest.WithHint(fmt.Sprintf("OAuth 2.0 Client %s has multiple redirect_uris but no sector_identifier_uri was set which is not allowed when performing using subject type pairwise. Please reconfigure the OAuth 2.0 client properly.", client.OutfacingID))) } else if len(client.SectorIdentifierURI) == 0 && len(client.RedirectURIs) == 0 { - return "", errors.WithStack(fosite.ErrInvalidRequest.WithHint(fmt.Sprintf("OAuth 2.0 Client %s neither specifies a sector_identifier_uri nor a redirect_uri which is not allowed when performing using subject type pairwise. Please reconfigure the OAuth 2.0 client properly.", client.ID))) + return "", errors.WithStack(fosite.ErrInvalidRequest.WithHint(fmt.Sprintf("OAuth 2.0 Client %s neither specifies a sector_identifier_uri nor a redirect_uri which is not allowed when performing using subject type pairwise. Please reconfigure the OAuth 2.0 client properly.", client.OutfacingID))) } else if len(client.SectorIdentifierURI) > 0 { id = client.SectorIdentifierURI } else { diff --git a/consent/types.go b/consent/types.go index 322d349b616..72dadcf50ff 100644 --- a/consent/types.go +++ b/consent/types.go @@ -428,7 +428,7 @@ func (r *LogoutRequest) BeforeSave(_ *pop.Connection) error { if r.Client != nil { r.ClientID = sql.NullString{ Valid: true, - String: r.Client.ID, + String: r.Client.OutfacingID, } } return nil @@ -437,7 +437,7 @@ func (r *LogoutRequest) BeforeSave(_ *pop.Connection) error { func (r *LogoutRequest) AfterFind(c *pop.Connection) error { if r.ClientID.Valid { r.Client = &client.Client{} - return sqlcon.HandleError(c.Find(r.Client, r.ClientID.String)) + return sqlcon.HandleError(c.Where("id = ?", r.ClientID.String).First(r.Client)) } return nil } @@ -492,7 +492,7 @@ type LoginRequest struct { // Client is the OAuth 2.0 Client that initiated the request. // // required: true - Client *client.Client `json:"client" belongs_to:"hydra_client" fk_id:"ClientID"` + Client *client.Client `json:"client" db:"-"` ClientID string `json:"-" db:"client_id"` @@ -525,10 +525,21 @@ func (_ LoginRequest) TableName() string { func (r *LoginRequest) FindInDB(c *pop.Connection, id string) error { return c.Select("hydra_oauth2_authentication_request.*", "COALESCE(hr.was_used, FALSE) as was_handled"). LeftJoin("hydra_oauth2_authentication_request_handled as hr", "hydra_oauth2_authentication_request.challenge = hr.challenge"). - Eager(). Find(r, id) } +func (r *LoginRequest) BeforeSave(_ *pop.Connection) error { + if r.Client != nil { + r.ClientID = r.Client.OutfacingID + } + return nil +} + +func (r *LoginRequest) AfterFind(c *pop.Connection) error { + r.Client = &client.Client{} + return sqlcon.HandleError(c.Where("id = ?", r.ClientID).First(r.Client)) +} + // Contains information on an ongoing consent request. // // swagger:model consentRequest @@ -559,7 +570,7 @@ type ConsentRequest struct { OpenIDConnectContext *OpenIDConnectContext `json:"oidc_context" db:"oidc_context"` // Client is the OAuth 2.0 Client that initiated the request. - Client *client.Client `json:"client" belongs_to:"hydra_client" fk_id:"ClientID"` + Client *client.Client `json:"client" db:"-"` ClientID string `json:"-" db:"client_id"` // RequestURL is the original OAuth 2.0 Authorization URL requested by the OAuth 2.0 client. It is the URL which @@ -602,10 +613,21 @@ func (r *ConsentRequest) FindInDB(c *pop.Connection, id string) error { return c.Select("COALESCE(hr.was_used, false) as was_handled", "hydra_oauth2_consent_request.*"). Where("hydra_oauth2_consent_request.challenge = ?", id). LeftJoin("hydra_oauth2_consent_request_handled AS hr", "hr.challenge = hydra_oauth2_consent_request.challenge"). - Eager(). First(r) } +func (r *ConsentRequest) BeforeSave(_ *pop.Connection) error { + if r.Client != nil { + r.ClientID = r.Client.OutfacingID + } + return nil +} + +func (r *ConsentRequest) AfterFind(c *pop.Connection) error { + r.Client = &client.Client{} + return sqlcon.HandleError(c.Where("id = ?", r.ClientID).First(r.Client)) +} + // Used to pass session data to a consent request. // // swagger:model consentRequestSession diff --git a/driver/cors_test.go b/driver/cors_test.go index 65123a192df..309fb5fa787 100644 --- a/driver/cors_test.go +++ b/driver/cors_test.go @@ -77,7 +77,7 @@ func TestOAuth2AwareCORSMiddleware(t *testing.T) { prep: func() { viper.Set("serve.public.cors.enabled", true) viper.Set("serve.public.cors.allowed_origins", []string{"http://not-test-domain.com"}) - r.ClientManager().CreateClient(context.Background(), &client.Client{ID: "foo-2", Secret: "bar", AllowedCORSOrigins: []string{"http://not-foobar.com"}}) + r.ClientManager().CreateClient(context.Background(), &client.Client{OutfacingID: "foo-2", Secret: "bar", AllowedCORSOrigins: []string{"http://not-foobar.com"}}) }, code: http.StatusNotImplemented, header: http.Header{"Origin": {"http://foobar.com"}, "Authorization": {fmt.Sprintf("Basic %s", x.BasicAuth("foo-2", "bar"))}}, @@ -87,7 +87,7 @@ func TestOAuth2AwareCORSMiddleware(t *testing.T) { d: "should accept when basic auth client exists and origin allowed", prep: func() { viper.Set("serve.public.cors.enabled", true) - r.ClientManager().CreateClient(context.Background(), &client.Client{ID: "foo-3", Secret: "bar", AllowedCORSOrigins: []string{"http://foobar.com"}}) + r.ClientManager().CreateClient(context.Background(), &client.Client{OutfacingID: "foo-3", Secret: "bar", AllowedCORSOrigins: []string{"http://foobar.com"}}) }, code: http.StatusNotImplemented, header: http.Header{"Origin": {"http://foobar.com"}, "Authorization": {fmt.Sprintf("Basic %s", x.BasicAuth("foo-3", "bar"))}}, @@ -97,7 +97,7 @@ func TestOAuth2AwareCORSMiddleware(t *testing.T) { d: "should accept when basic auth client exists and origin (with partial wildcard) is allowed per client", prep: func() { viper.Set("serve.public.cors.enabled", true) - r.ClientManager().CreateClient(context.Background(), &client.Client{ID: "foo-4", Secret: "bar", AllowedCORSOrigins: []string{"http://*.foobar.com"}}) + r.ClientManager().CreateClient(context.Background(), &client.Client{OutfacingID: "foo-4", Secret: "bar", AllowedCORSOrigins: []string{"http://*.foobar.com"}}) }, code: http.StatusNotImplemented, header: http.Header{"Origin": {"http://foo.foobar.com"}, "Authorization": {fmt.Sprintf("Basic %s", x.BasicAuth("foo-4", "bar"))}}, @@ -108,7 +108,7 @@ func TestOAuth2AwareCORSMiddleware(t *testing.T) { prep: func() { viper.Set("serve.public.cors.enabled", true) viper.Set("serve.public.cors.allowed_origins", []string{"*"}) - r.ClientManager().CreateClient(context.Background(), &client.Client{ID: "foo-5", Secret: "bar", AllowedCORSOrigins: []string{"http://barbar.com"}}) + r.ClientManager().CreateClient(context.Background(), &client.Client{OutfacingID: "foo-5", Secret: "bar", AllowedCORSOrigins: []string{"http://barbar.com"}}) }, code: http.StatusNotImplemented, header: http.Header{"Origin": {"*"}, "Authorization": {fmt.Sprintf("Basic %s", x.BasicAuth("foo-5", "bar"))}}, @@ -119,7 +119,7 @@ func TestOAuth2AwareCORSMiddleware(t *testing.T) { prep: func() { viper.Set("serve.public.cors.enabled", true) viper.Set("serve.public.cors.allowed_origins", []string{"http://*.foobar.com"}) - r.ClientManager().CreateClient(context.Background(), &client.Client{ID: "foo-6", Secret: "bar", AllowedCORSOrigins: []string{"http://barbar.com"}}) + r.ClientManager().CreateClient(context.Background(), &client.Client{OutfacingID: "foo-6", Secret: "bar", AllowedCORSOrigins: []string{"http://barbar.com"}}) }, code: http.StatusNotImplemented, header: http.Header{"Origin": {"http://foo.foobar.com"}, "Authorization": {fmt.Sprintf("Basic %s", x.BasicAuth("foo-6", "bar"))}}, @@ -130,7 +130,7 @@ func TestOAuth2AwareCORSMiddleware(t *testing.T) { prep: func() { viper.Set("serve.public.cors.enabled", true) viper.Set("serve.public.cors.allowed_origins", []string{"http://not-test-domain.com"}) - r.ClientManager().CreateClient(context.Background(), &client.Client{ID: "foo-7", Secret: "bar", AllowedCORSOrigins: []string{"*"}}) + r.ClientManager().CreateClient(context.Background(), &client.Client{OutfacingID: "foo-7", Secret: "bar", AllowedCORSOrigins: []string{"*"}}) }, code: http.StatusNotImplemented, header: http.Header{"Origin": {"http://foobar.com"}, "Authorization": {fmt.Sprintf("Basic %s", x.BasicAuth("foo-7", "bar"))}}, @@ -154,7 +154,7 @@ func TestOAuth2AwareCORSMiddleware(t *testing.T) { sess := oauth2.NewSession("foo-9") sess.SetExpiresAt(fosite.AccessToken, time.Now().Add(time.Hour)) ar := fosite.NewAccessRequest(sess) - cl := &client.Client{ID: "foo-9", Secret: "bar", AllowedCORSOrigins: []string{"http://foobar.com"}} + cl := &client.Client{OutfacingID: "foo-9", Secret: "bar", AllowedCORSOrigins: []string{"http://foobar.com"}} ar.Client = cl if err := r.ClientManager().CreateClient(context.Background(), cl); err != nil { panic(err) @@ -171,7 +171,7 @@ func TestOAuth2AwareCORSMiddleware(t *testing.T) { d: "should accept any allowed specified origin protocol", prep: func() { viper.Set("serve.public.cors.enabled", true) - r.ClientManager().CreateClient(context.Background(), &client.Client{ID: "foo-11", Secret: "bar", AllowedCORSOrigins: []string{"*"}}) + r.ClientManager().CreateClient(context.Background(), &client.Client{OutfacingID: "foo-11", Secret: "bar", AllowedCORSOrigins: []string{"*"}}) viper.Set("serve.public.cors.enabled", true) viper.Set("serve.public.cors.allowed_origins", []string{"http://*", "https://*"}) }, @@ -184,7 +184,7 @@ func TestOAuth2AwareCORSMiddleware(t *testing.T) { prep: func() { viper.Set("serve.public.cors.enabled", true) viper.Set("serve.public.cors.allowed_origins", []string{"http://**.example.com"}) - r.ClientManager().CreateClient(context.Background(), &client.Client{ID: "foo-12", Secret: "bar", AllowedCORSOrigins: []string{"http://myapp.example.biz"}}) + r.ClientManager().CreateClient(context.Background(), &client.Client{OutfacingID: "foo-12", Secret: "bar", AllowedCORSOrigins: []string{"http://myapp.example.biz"}}) }, code: http.StatusNotImplemented, header: http.Header{"Origin": {"http://myapp.example.biz"}, "Authorization": {fmt.Sprintf("Basic %s", x.BasicAuth("foo-12", "bar"))}}, @@ -195,7 +195,7 @@ func TestOAuth2AwareCORSMiddleware(t *testing.T) { prep: func() { viper.Set("serve.public.cors.enabled", true) viper.Set("serve.public.cors.allowed_origins", []string{"http://**.example.com"}) - r.ClientManager().CreateClient(context.Background(), &client.Client{ID: "foo-13", Secret: "bar", AllowedCORSOrigins: []string{"http://myapp.example.biz"}}) + r.ClientManager().CreateClient(context.Background(), &client.Client{OutfacingID: "foo-13", Secret: "bar", AllowedCORSOrigins: []string{"http://myapp.example.biz"}}) }, code: http.StatusNotImplemented, header: http.Header{"Origin": {"http://client-app.example.com"}, "Authorization": {fmt.Sprintf("Basic %s", x.BasicAuth("foo-13", "bar"))}}, diff --git a/go.mod b/go.mod index 4c2f0d8633d..7f08f540f7d 100644 --- a/go.mod +++ b/go.mod @@ -62,3 +62,5 @@ require ( gopkg.in/DataDog/dd-trace-go.v1 v1.27.1 gopkg.in/square/go-jose.v2 v2.5.1 ) + +replace github.com/gobuffalo/pop/v5 => github.com/zepatrik/pop/v5 v5.0.12-0.20201028144522-91a5f8eec0a1 diff --git a/go.sum b/go.sum index 9f62304d458..a8990a793ca 100644 --- a/go.sum +++ b/go.sum @@ -477,11 +477,6 @@ github.com/gobuffalo/pop v4.8.3+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVD github.com/gobuffalo/pop v4.8.4+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg= github.com/gobuffalo/pop v4.13.1+incompatible h1:AhbqPxNOBN/DBb2DBaiBqzOXIBQXxEYzngHHJ+ytP4g= github.com/gobuffalo/pop v4.13.1+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg= -github.com/gobuffalo/pop/v5 v5.0.11/go.mod h1:mZJHJbA3cy2V18abXYuVop2ldEJ8UZ2DK6qOekC5u5g= -github.com/gobuffalo/pop/v5 v5.2.0/go.mod h1:Hj586Cr7FoTFNmvzyNdUcajv3r0A+W+bkil4RIX/zKo= -github.com/gobuffalo/pop/v5 v5.2.4/go.mod h1:4mYDlrcXTnG2n9rG8p+c10X1QnfMc4YIRVmiC8ihMAI= -github.com/gobuffalo/pop/v5 v5.3.1 h1:dJbBPy6e0G0VRjn28md3fk16wpYIBv5iYVQWd0eqmkQ= -github.com/gobuffalo/pop/v5 v5.3.1/go.mod h1:vcEDhh6cJ3WVENqJDFt/6z7zNb7lLnlN8vj3n5G9rYA= github.com/gobuffalo/release v1.0.35/go.mod h1:VtHFAKs61vO3wboCec5xr9JPTjYyWYcvaM3lclkc4x4= github.com/gobuffalo/release v1.0.38/go.mod h1:VtHFAKs61vO3wboCec5xr9JPTjYyWYcvaM3lclkc4x4= github.com/gobuffalo/release v1.0.42/go.mod h1:RPs7EtafH4oylgetOJpGP0yCZZUiO4vqHfTHJjSdpug= @@ -1184,6 +1179,8 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= +github.com/zepatrik/pop/v5 v5.0.12-0.20201028144522-91a5f8eec0a1 h1:DqKKcBVzyUlXGbjoCn9aGtswci9E/WePs5+UL7GBBCQ= +github.com/zepatrik/pop/v5 v5.0.12-0.20201028144522-91a5f8eec0a1/go.mod h1:vcEDhh6cJ3WVENqJDFt/6z7zNb7lLnlN8vj3n5G9rYA= github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= @@ -1320,7 +1317,6 @@ golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200219183655-46282727080f/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= diff --git a/internal/fizzmigrate/consent/x_manager_sql_migrations_test.go b/internal/fizzmigrate/consent/x_manager_sql_migrations_test.go index fa64ae49dce..44e010e8860 100644 --- a/internal/fizzmigrate/consent/x_manager_sql_migrations_test.go +++ b/internal/fizzmigrate/consent/x_manager_sql_migrations_test.go @@ -32,7 +32,7 @@ func TestXXMigrations(t *testing.T) { var clients []client.Client for k := range migrateClient.Migrations[dbal.DriverMySQL].Box.List() { - clients = append(clients, client.Client{ID: fmt.Sprintf("%d-client", k+1)}) + clients = append(clients, client.Client{OutfacingID: fmt.Sprintf("%d-client", k+1)}) } migratest.RunPackrMigrationTests( diff --git a/internal/fosite_store.go b/internal/fosite_store.go index 2d98ab4a463..aa21bc06bc8 100644 --- a/internal/fosite_store.go +++ b/internal/fosite_store.go @@ -10,7 +10,7 @@ import ( func AddFositeExamples(r driver.Registry) { for _, c := range []client.Client{ { - ID: "my-client", + OutfacingID: "my-client", Secret: "foobar", RedirectURIs: []string{"http://localhost:3846/callback"}, ResponseTypes: []string{"id_token", "code", "token"}, @@ -18,7 +18,7 @@ func AddFositeExamples(r driver.Registry) { Scope: "fosite,openid,photos,offline", }, { - ID: "encoded:client", + OutfacingID: "encoded:client", Secret: "encoded&password", RedirectURIs: []string{"http://localhost:3846/callback"}, ResponseTypes: []string{"id_token", "code", "token"}, diff --git a/oauth2/fosite_store_helpers.go b/oauth2/fosite_store_helpers.go index 17acf8ff90f..cdc1ccffee0 100644 --- a/oauth2/fosite_store_helpers.go +++ b/oauth2/fosite_store_helpers.go @@ -87,7 +87,7 @@ type AssertionJWTReader interface { var defaultRequest = fosite.Request{ ID: "blank", RequestedAt: time.Now().UTC().Round(time.Second), - Client: &client.Client{ID: "foobar"}, + Client: &client.Client{OutfacingID: "foobar"}, RequestedScope: fosite.Arguments{"fa", "ba"}, GrantedScope: fosite.Arguments{"fa", "ba"}, RequestedAudience: fosite.Arguments{"ad1", "ad2"}, @@ -101,7 +101,7 @@ var flushRequests = []*fosite.Request{ { ID: "flush-1", RequestedAt: time.Now().Round(time.Second), - Client: &client.Client{ID: "foobar"}, + Client: &client.Client{OutfacingID: "foobar"}, RequestedScope: fosite.Arguments{"fa", "ba"}, GrantedScope: fosite.Arguments{"fa", "ba"}, Form: url.Values{"foo": []string{"bar", "baz"}}, @@ -110,7 +110,7 @@ var flushRequests = []*fosite.Request{ { ID: "flush-2", RequestedAt: time.Now().Round(time.Second).Add(-(lifespan + time.Minute)), - Client: &client.Client{ID: "foobar"}, + Client: &client.Client{OutfacingID: "foobar"}, RequestedScope: fosite.Arguments{"fa", "ba"}, GrantedScope: fosite.Arguments{"fa", "ba"}, Form: url.Values{"foo": []string{"bar", "baz"}}, @@ -119,7 +119,7 @@ var flushRequests = []*fosite.Request{ { ID: "flush-3", RequestedAt: time.Now().Round(time.Second).Add(-(lifespan + time.Hour)), - Client: &client.Client{ID: "foobar"}, + Client: &client.Client{OutfacingID: "foobar"}, RequestedScope: fosite.Arguments{"fa", "ba"}, GrantedScope: fosite.Arguments{"fa", "ba"}, Form: url.Values{"foo": []string{"bar", "baz"}}, @@ -128,7 +128,7 @@ var flushRequests = []*fosite.Request{ } func mockRequestForeignKey(t *testing.T, id string, x InternalRegistry, createClient bool) { - cl := &client.Client{ID: "foobar"} + cl := &client.Client{OutfacingID: "foobar"} cr := &consent.ConsentRequest{ Client: cl, OpenIDConnectContext: new(consent.OpenIDConnectContext), LoginChallenge: sqlxx.NullString(id), ID: id, Verifier: id, AuthenticatedAt: sqlxx.NullTime(time.Now()), RequestedAt: time.Now(), @@ -191,7 +191,7 @@ func testHelperUniqueConstraints(m InternalRegistry, storageType string) func(t requestId := uuid.New() mockRequestForeignKey(t, requestId, m, true) - cl := &client.Client{ID: "foobar"} + cl := &client.Client{OutfacingID: "foobar"} signatureOne := uuid.New() signatureTwo := uuid.New() @@ -277,10 +277,10 @@ func testHelperRevokeRefreshToken(x InternalRegistry) func(t *testing.T) { mockRequestForeignKey(t, reqIdOne, x, false) mockRequestForeignKey(t, reqIdTwo, x, false) - err = m.CreateRefreshTokenSession(ctx, "1111", &fosite.Request{ID: reqIdOne, Client: &client.Client{ID: "foobar"}, RequestedAt: time.Now().UTC().Round(time.Second), Session: &Session{}}) + err = m.CreateRefreshTokenSession(ctx, "1111", &fosite.Request{ID: reqIdOne, Client: &client.Client{OutfacingID: "foobar"}, RequestedAt: time.Now().UTC().Round(time.Second), Session: &Session{}}) require.NoError(t, err) - err = m.CreateRefreshTokenSession(ctx, "1122", &fosite.Request{ID: reqIdTwo, Client: &client.Client{ID: "foobar"}, RequestedAt: time.Now().UTC().Round(time.Second), Session: &Session{}}) + err = m.CreateRefreshTokenSession(ctx, "1122", &fosite.Request{ID: reqIdTwo, Client: &client.Client{OutfacingID: "foobar"}, RequestedAt: time.Now().UTC().Round(time.Second), Session: &Session{}}) require.NoError(t, err) _, err = m.GetRefreshTokenSession(ctx, "1111", &Session{}) @@ -332,7 +332,7 @@ func testHelperCreateGetDeleteAuthorizeCodes(x InternalRegistry) func(t *testing func testHelperNilAccessToken(x InternalRegistry) func(t *testing.T) { return func(t *testing.T) { m := x.OAuth2Storage() - c := &client.Client{ID: "nil-request-client-id-123"} + c := &client.Client{OutfacingID: "nil-request-client-id-123"} require.NoError(t, x.ClientManager().CreateClient(context.Background(), c)) err := m.CreateAccessTokenSession(context.TODO(), "nil-request-id", &fosite.Request{ ID: "", @@ -757,7 +757,7 @@ func createTestRequest(id string) *fosite.Request { return &fosite.Request{ ID: id, RequestedAt: time.Now().UTC().Round(time.Second), - Client: &client.Client{ID: "foobar"}, + Client: &client.Client{OutfacingID: "foobar"}, RequestedScope: fosite.Arguments{"fa", "ba"}, GrantedScope: fosite.Arguments{"fa", "ba"}, RequestedAudience: fosite.Arguments{"ad1", "ad2"}, diff --git a/oauth2/fosite_store_test.go b/oauth2/fosite_store_test.go index 712d379ad18..126ec703113 100644 --- a/oauth2/fosite_store_test.go +++ b/oauth2/fosite_store_test.go @@ -85,7 +85,7 @@ func TestManagers(t *testing.T) { for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { setupRegistries(t) - require.NoError(t, registries["memory"].ClientManager().CreateClient(context.Background(), &client.Client{ID: "foobar"})) // this is a workaround because the client is not being created for memory store by test helpers. + require.NoError(t, registries["memory"].ClientManager().CreateClient(context.Background(), &client.Client{OutfacingID: "foobar"})) // this is a workaround because the client is not being created for memory store by test helpers. viper.Set(configuration.ViperKeyEncryptSessionData, tc.enableSessionEncrypted) diff --git a/oauth2/handler_test.go b/oauth2/handler_test.go index 0fc5cc58c90..7b1e9b2f49e 100644 --- a/oauth2/handler_test.go +++ b/oauth2/handler_test.go @@ -65,7 +65,7 @@ var flushRequests = []*fosite.Request{ { ID: "flush-1", RequestedAt: time.Now().Round(time.Second), - Client: &client.Client{ID: "foobar"}, + Client: &client.Client{OutfacingID: "foobar"}, RequestedScope: fosite.Arguments{"fa", "ba"}, GrantedScope: fosite.Arguments{"fa", "ba"}, Form: url.Values{"foo": []string{"bar", "baz"}}, @@ -74,7 +74,7 @@ var flushRequests = []*fosite.Request{ { ID: "flush-2", RequestedAt: time.Now().Round(time.Second).Add(-(lifespan + time.Minute)), - Client: &client.Client{ID: "foobar"}, + Client: &client.Client{OutfacingID: "foobar"}, RequestedScope: fosite.Arguments{"fa", "ba"}, GrantedScope: fosite.Arguments{"fa", "ba"}, Form: url.Values{"foo": []string{"bar", "baz"}}, @@ -83,7 +83,7 @@ var flushRequests = []*fosite.Request{ { ID: "flush-3", RequestedAt: time.Now().Round(time.Second).Add(-(lifespan + time.Hour)), - Client: &client.Client{ID: "foobar"}, + Client: &client.Client{OutfacingID: "foobar"}, RequestedScope: fosite.Arguments{"fa", "ba"}, GrantedScope: fosite.Arguments{"fa", "ba"}, Form: url.Values{"foo": []string{"bar", "baz"}}, @@ -104,7 +104,7 @@ func TestHandlerDeleteHandler(t *testing.T) { deleteRequest := &fosite.Request{ ID: "del-1", RequestedAt: time.Now().Round(time.Second), - Client: &client.Client{ID: "foobar"}, + Client: &client.Client{OutfacingID: "foobar"}, RequestedScope: fosite.Arguments{"fa", "ba"}, GrantedScope: fosite.Arguments{"fa", "ba"}, Form: url.Values{"foo": []string{"bar", "baz"}}, diff --git a/oauth2/oauth2_auth_code_test.go b/oauth2/oauth2_auth_code_test.go index 97c237cfd9b..ffa3ad3f7ed 100644 --- a/oauth2/oauth2_auth_code_test.go +++ b/oauth2/oauth2_auth_code_test.go @@ -201,7 +201,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { viper.Set(configuration.ViperKeyConsentRequestMaxAge, time.Hour) client := hc.Client{ - ID: "e2e-app-client" + km + strat.d, Secret: "secret", RedirectURIs: []string{ts.URL + "/callback"}, + OutfacingID: "e2e-app-client" + km + strat.d, Secret: "secret", RedirectURIs: []string{ts.URL + "/callback"}, ResponseTypes: []string{"id_token", "code", "token"}, GrantTypes: []string{"implicit", "refresh_token", "authorization_code", "password", "client_credentials"}, Scope: "hydra offline openid", @@ -1156,7 +1156,7 @@ func TestAuthCodeWithMockStrategy(t *testing.T) { var mutex sync.Mutex require.NoError(t, reg.ClientManager().CreateClient(context.TODO(), &hc.Client{ - ID: "app-client", + OutfacingID: "app-client", Secret: "secret", RedirectURIs: []string{ts.URL + "/callback"}, ResponseTypes: []string{"id_token", "code", "token"}, diff --git a/oauth2/oauth2_client_credentials_test.go b/oauth2/oauth2_client_credentials_test.go index ca5176e01f9..71fc0a5e7c7 100644 --- a/oauth2/oauth2_client_credentials_test.go +++ b/oauth2/oauth2_client_credentials_test.go @@ -65,7 +65,7 @@ func TestClientCredentials(t *testing.T) { }) require.NoError(t, reg.ClientManager().CreateClient(context.TODO(), &hc.Client{ - ID: "app-client", + OutfacingID: "app-client", Secret: "secret", RedirectURIs: []string{ts.URL + "/callback"}, ResponseTypes: []string{"token"}, diff --git a/oauth2/oauth2_refresh_token_test.go b/oauth2/oauth2_refresh_token_test.go index 02e16fb0c3b..136b4e7da97 100644 --- a/oauth2/oauth2_refresh_token_test.go +++ b/oauth2/oauth2_refresh_token_test.go @@ -45,7 +45,7 @@ func TestCreateRefreshTokenSessionStress(t *testing.T) { token := "234c678fed33c1d2025537ae464a1ebf7d23fc4a" tokenSignature := "4c7c7e8b3a77ad0c3ec846a21653c48b45dbfa31" testClient := hc.Client{ - ID: uuid.New(), + OutfacingID: uuid.New(), Secret: "secret", ResponseTypes: []string{"id_token", "code", "token"}, GrantTypes: []string{"implicit", "refresh_token", "authorization_code", "password", "client_credentials"}, @@ -61,7 +61,7 @@ func TestCreateRefreshTokenSessionStress(t *testing.T) { RequestedAt: time.Now(), ID: uuid.New(), Client: &hc.Client{ - ID: testClient.ID, + OutfacingID: testClient.OutfacingID, }, RequestedScope: []string{"offline"}, GrantedScope: []string{"offline"}, diff --git a/persistence/sql/migratest/exptected_data.go b/persistence/sql/migratest/exptected_data.go index 6613355d29d..1c554a4c70c 100644 --- a/persistence/sql/migratest/exptected_data.go +++ b/persistence/sql/migratest/exptected_data.go @@ -17,8 +17,8 @@ import ( func expectedClient(i int) *client.Client { c := &client.Client{ - PK: int64(i), - ID: fmt.Sprintf("client-%04d", i), + ID: int64(i), + OutfacingID: fmt.Sprintf("client-%04d", i), Name: fmt.Sprintf("Client %04d", i), Secret: fmt.Sprintf("secret-%04d", i), RedirectURIs: []string{fmt.Sprintf("http://redirect/%04d_1", i)}, diff --git a/persistence/sql/migratest/migration_test.go b/persistence/sql/migratest/migration_test.go index 617cde414dc..691f9ba8500 100644 --- a/persistence/sql/migratest/migration_test.go +++ b/persistence/sql/migratest/migration_test.go @@ -81,7 +81,7 @@ func TestMigrations(t *testing.T) { t.Run(fmt.Sprintf("case=client migration %d", i), func(t *testing.T) { expected := expectedClient(i) actual := &client.Client{} - require.NoError(t, c.Find(actual, expected.ID)) + require.NoError(t, c.Find(actual, expected.OutfacingID)) assertEqualClients(t, expected, actual) lastClient = actual }) @@ -129,7 +129,7 @@ func TestMigrations(t *testing.T) { assertEqualHandledLoginRequests(t, ehlr, ahlr) if efols != nil { - afols, err := d.Registry().ConsentManager().GetForcedObfuscatedLoginSession(context.Background(), lastClient.ID, efols.SubjectObfuscated) + afols, err := d.Registry().ConsentManager().GetForcedObfuscatedLoginSession(context.Background(), lastClient.OutfacingID, efols.SubjectObfuscated) require.NoError(t, err) assertEqualForcedObfucscatedLoginSessions(t, efols, afols) } diff --git a/persistence/sql/persister_client.go b/persistence/sql/persister_client.go index d133ee68cc7..ba74b16a15d 100644 --- a/persistence/sql/persister_client.go +++ b/persistence/sql/persister_client.go @@ -13,7 +13,7 @@ import ( func (p *Persister) GetConcreteClient(ctx context.Context, id string) (*client.Client, error) { var cl client.Client - return &cl, sqlcon.HandleError(p.Connection(ctx).Find(&cl, id)) + return &cl, sqlcon.HandleError(p.Connection(ctx).Where("id = ?", id).First(&cl)) } func (p *Persister) GetClient(ctx context.Context, id string) (fosite.Client, error) { @@ -22,7 +22,7 @@ func (p *Persister) GetClient(ctx context.Context, id string) (fosite.Client, er func (p *Persister) UpdateClient(ctx context.Context, cl *client.Client) error { return p.transaction(ctx, func(ctx context.Context, c *pop.Connection) error { - o, err := p.GetClient(ctx, cl.GetID()) + o, err := p.GetConcreteClient(ctx, cl.GetID()) if err != nil { return err } @@ -36,6 +36,8 @@ func (p *Persister) UpdateClient(ctx context.Context, cl *client.Client) error { } cl.Secret = string(h) } + // set the internal primary key + cl.ID = o.ID return sqlcon.HandleError(c.Update(cl)) }) @@ -65,7 +67,14 @@ func (p *Persister) CreateClient(ctx context.Context, c *client.Client) error { } func (p *Persister) DeleteClient(ctx context.Context, id string) error { - return sqlcon.HandleError(p.Connection(ctx).Destroy(&client.Client{ID: id})) + return p.transaction(ctx, func(ctx context.Context, c *pop.Connection) error { + cl, err := p.GetConcreteClient(ctx, id) + if err != nil { + return err + } + + return sqlcon.HandleError(p.Connection(ctx).Destroy(&client.Client{ID: cl.ID})) + }) } func (p *Persister) GetClients(ctx context.Context, limit, offset int) ([]client.Client, error) { diff --git a/persistence/sql/persister_test.go b/persistence/sql/persister_test.go index 7cadedd8948..b72835dbb18 100644 --- a/persistence/sql/persister_test.go +++ b/persistence/sql/persister_test.go @@ -36,6 +36,8 @@ func TestManagers(t *testing.T) { t.Run("case=autogenerate-key", client.TestHelperClientAutoGenerateKey(k, m.ClientManager())) t.Run("case=auth-client", client.TestHelperClientAuthenticate(k, m.ClientManager())) + + 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())) From 271060ca7a3160f3ca39a3cf79728e1fff4d3b7b Mon Sep 17 00:00:00 2001 From: zepatrik Date: Wed, 28 Oct 2020 16:27:31 +0100 Subject: [PATCH 2/6] chore: format docs --- docs/config.js | 10 +++++++--- docs/docs/configure-deploy.mdx | 1 - 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/config.js b/docs/config.js index 9cd7eed2db2..6062d30366d 100644 --- a/docs/config.js +++ b/docs/config.js @@ -23,12 +23,16 @@ module.exports = { files: ['quickstart.yml'] }, { - image: "oryd/hydra-login-consent-node", + image: 'oryd/hydra-login-consent-node', files: ['quickstart.yml'] }, { - image: "oryd/hydra", - files: ['quickstart-cockroach.yml', 'quickstart-mysql.yml', 'quickstart-postgres.yml'] + image: 'oryd/hydra', + files: [ + 'quickstart-cockroach.yml', + 'quickstart-mysql.yml', + 'quickstart-postgres.yml' + ] } ], updateConfig: { diff --git a/docs/docs/configure-deploy.mdx b/docs/docs/configure-deploy.mdx index f852a492d9c..1b7aa914862 100644 --- a/docs/docs/configure-deploy.mdx +++ b/docs/docs/configure-deploy.mdx @@ -314,4 +314,3 @@ proceed. When completed, you should land at a screen that looks like this one: ![OAuth 2.0 access and refresh token in the result page](images/install-result.png) - From bf7ce965e300e629136a9223756795561055c6cc Mon Sep 17 00:00:00 2001 From: zepatrik Date: Thu, 29 Oct 2020 10:03:16 +0100 Subject: [PATCH 3/6] fix: migration test --- persistence/sql/migratest/migration_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/persistence/sql/migratest/migration_test.go b/persistence/sql/migratest/migration_test.go index 691f9ba8500..e9eb187c4a6 100644 --- a/persistence/sql/migratest/migration_test.go +++ b/persistence/sql/migratest/migration_test.go @@ -81,7 +81,7 @@ func TestMigrations(t *testing.T) { t.Run(fmt.Sprintf("case=client migration %d", i), func(t *testing.T) { expected := expectedClient(i) actual := &client.Client{} - require.NoError(t, c.Find(actual, expected.OutfacingID)) + require.NoError(t, c.Where("id = ?", expected.OutfacingID).First(actual)) assertEqualClients(t, expected, actual) lastClient = actual }) From b791c9d8517f0d90dea7d0eee33b05aedfac5ef6 Mon Sep 17 00:00:00 2001 From: zepatrik Date: Thu, 29 Oct 2020 10:44:16 +0100 Subject: [PATCH 4/6] fix: e2e test --- persistence/sql/persister_client.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/persistence/sql/persister_client.go b/persistence/sql/persister_client.go index ba74b16a15d..85b322bab1e 100644 --- a/persistence/sql/persister_client.go +++ b/persistence/sql/persister_client.go @@ -13,6 +13,10 @@ import ( func (p *Persister) GetConcreteClient(ctx context.Context, id string) (*client.Client, error) { var cl client.Client + pop.Debug = true + defer func() { + pop.Debug = false + }() return &cl, sqlcon.HandleError(p.Connection(ctx).Where("id = ?", id).First(&cl)) } @@ -67,14 +71,12 @@ func (p *Persister) CreateClient(ctx context.Context, c *client.Client) error { } func (p *Persister) DeleteClient(ctx context.Context, id string) error { - return p.transaction(ctx, func(ctx context.Context, c *pop.Connection) error { - cl, err := p.GetConcreteClient(ctx, id) - if err != nil { - return err - } + cl, err := p.GetConcreteClient(ctx, id) + if err != nil { + return err + } - return sqlcon.HandleError(p.Connection(ctx).Destroy(&client.Client{ID: cl.ID})) - }) + return sqlcon.HandleError(p.Connection(ctx).Destroy(&client.Client{ID: cl.ID})) } func (p *Persister) GetClients(ctx context.Context, limit, offset int) ([]client.Client, error) { From 3efb4a7e6050760691dfd77ae342233f0ca8444b Mon Sep 17 00:00:00 2001 From: zepatrik Date: Thu, 29 Oct 2020 10:47:01 +0100 Subject: [PATCH 5/6] chore: remove debug statement --- persistence/sql/persister_client.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/persistence/sql/persister_client.go b/persistence/sql/persister_client.go index 85b322bab1e..696b5331d6c 100644 --- a/persistence/sql/persister_client.go +++ b/persistence/sql/persister_client.go @@ -13,10 +13,6 @@ import ( func (p *Persister) GetConcreteClient(ctx context.Context, id string) (*client.Client, error) { var cl client.Client - pop.Debug = true - defer func() { - pop.Debug = false - }() return &cl, sqlcon.HandleError(p.Connection(ctx).Where("id = ?", id).First(&cl)) } From b661ace407c97522c8a116488a7ddb781f2b96c4 Mon Sep 17 00:00:00 2001 From: zepatrik Date: Thu, 29 Oct 2020 14:25:27 +0100 Subject: [PATCH 6/6] deps: use gobuffalo replace --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 7f08f540f7d..34c531a928e 100644 --- a/go.mod +++ b/go.mod @@ -63,4 +63,4 @@ require ( gopkg.in/square/go-jose.v2 v2.5.1 ) -replace github.com/gobuffalo/pop/v5 => github.com/zepatrik/pop/v5 v5.0.12-0.20201028144522-91a5f8eec0a1 +replace github.com/gobuffalo/pop/v5 => github.com/gobuffalo/pop/v5 v5.3.2-0.20201029132236-f36afb546df1 diff --git a/go.sum b/go.sum index a8990a793ca..869a46b999f 100644 --- a/go.sum +++ b/go.sum @@ -477,6 +477,8 @@ github.com/gobuffalo/pop v4.8.3+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVD github.com/gobuffalo/pop v4.8.4+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg= github.com/gobuffalo/pop v4.13.1+incompatible h1:AhbqPxNOBN/DBb2DBaiBqzOXIBQXxEYzngHHJ+ytP4g= github.com/gobuffalo/pop v4.13.1+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg= +github.com/gobuffalo/pop/v5 v5.3.2-0.20201029132236-f36afb546df1 h1:0ae/j500iOmCqMZK9260020ZUdele6sBpQ/pdxck7ek= +github.com/gobuffalo/pop/v5 v5.3.2-0.20201029132236-f36afb546df1/go.mod h1:vcEDhh6cJ3WVENqJDFt/6z7zNb7lLnlN8vj3n5G9rYA= github.com/gobuffalo/release v1.0.35/go.mod h1:VtHFAKs61vO3wboCec5xr9JPTjYyWYcvaM3lclkc4x4= github.com/gobuffalo/release v1.0.38/go.mod h1:VtHFAKs61vO3wboCec5xr9JPTjYyWYcvaM3lclkc4x4= github.com/gobuffalo/release v1.0.42/go.mod h1:RPs7EtafH4oylgetOJpGP0yCZZUiO4vqHfTHJjSdpug= @@ -1179,8 +1181,6 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -github.com/zepatrik/pop/v5 v5.0.12-0.20201028144522-91a5f8eec0a1 h1:DqKKcBVzyUlXGbjoCn9aGtswci9E/WePs5+UL7GBBCQ= -github.com/zepatrik/pop/v5 v5.0.12-0.20201028144522-91a5f8eec0a1/go.mod h1:vcEDhh6cJ3WVENqJDFt/6z7zNb7lLnlN8vj3n5G9rYA= github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=