package oidc_test import ( "context" "database/sql" "encoding/json" "fmt" "testing" "time" "github.com/golang/mock/gomock" "github.com/google/uuid" "github.com/ory/fosite" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" "github.com/authelia/authelia/v4/internal/authorization" "github.com/authelia/authelia/v4/internal/configuration/schema" "github.com/authelia/authelia/v4/internal/mocks" "github.com/authelia/authelia/v4/internal/model" "github.com/authelia/authelia/v4/internal/oidc" "github.com/authelia/authelia/v4/internal/storage" ) func TestOpenIDConnectStore_GetInternalClient(t *testing.T) { s := oidc.NewStore(&schema.OpenIDConnect{ IssuerCertificateChain: schema.X509CertificateChain{}, IssuerPrivateKey: keyRSA2048, Clients: []schema.OpenIDConnectClient{ { ID: myclient, Description: myclientdesc, Policy: onefactor, Scopes: []string{oidc.ScopeOpenID, oidc.ScopeProfile}, Secret: tOpenIDConnectPlainTextClientSecret, }, }, }, nil) client, err := s.GetClient(context.Background(), "myinvalidclient") assert.EqualError(t, err, "invalid_client") assert.Nil(t, client) client, err = s.GetClient(context.Background(), myclient) require.NoError(t, err) require.NotNil(t, client) assert.Equal(t, myclient, client.GetID()) } func TestOpenIDConnectStore_GetInternalClient_ValidClient(t *testing.T) { id := myclient c1 := schema.OpenIDConnectClient{ ID: id, Description: myclientdesc, Policy: onefactor, Scopes: []string{oidc.ScopeOpenID, oidc.ScopeProfile}, Secret: tOpenIDConnectPlainTextClientSecret, } s := oidc.NewStore(&schema.OpenIDConnect{ IssuerCertificateChain: schema.X509CertificateChain{}, IssuerPrivateKey: keyRSA2048, Clients: []schema.OpenIDConnectClient{c1}, }, nil) client, err := s.GetFullClient(id) require.NoError(t, err) require.NotNil(t, client) assert.Equal(t, id, client.GetID()) assert.Equal(t, myclientdesc, client.GetDescription()) assert.Equal(t, fosite.Arguments(c1.Scopes), client.GetScopes()) assert.Equal(t, fosite.Arguments([]string{oidc.GrantTypeAuthorizationCode}), client.GetGrantTypes()) assert.Equal(t, fosite.Arguments([]string{oidc.ResponseTypeAuthorizationCodeFlow}), client.GetResponseTypes()) assert.Equal(t, []string(nil), client.GetRedirectURIs()) assert.Equal(t, authorization.OneFactor, client.GetAuthorizationPolicy(authorization.Subject{})) assert.Equal(t, "$plaintext$client-secret", client.GetSecret().Encode()) } func TestOpenIDConnectStore_GetInternalClient_InvalidClient(t *testing.T) { c1 := schema.OpenIDConnectClient{ ID: myclient, Description: myclientdesc, Policy: onefactor, Scopes: []string{oidc.ScopeOpenID, oidc.ScopeProfile}, Secret: tOpenIDConnectPlainTextClientSecret, } s := oidc.NewStore(&schema.OpenIDConnect{ IssuerCertificateChain: schema.X509CertificateChain{}, IssuerPrivateKey: keyRSA2048, Clients: []schema.OpenIDConnectClient{c1}, }, nil) client, err := s.GetFullClient("another-client") assert.Nil(t, client) assert.EqualError(t, err, "invalid_client") } func TestOpenIDConnectStore_IsValidClientID(t *testing.T) { s := oidc.NewStore(&schema.OpenIDConnect{ IssuerCertificateChain: schema.X509CertificateChain{}, IssuerPrivateKey: keyRSA2048, Clients: []schema.OpenIDConnectClient{ { ID: myclient, Description: myclientdesc, Policy: onefactor, Scopes: []string{oidc.ScopeOpenID, oidc.ScopeProfile}, Secret: tOpenIDConnectPlainTextClientSecret, }, }, }, nil) validClient := s.IsValidClientID(myclient) invalidClient := s.IsValidClientID("myinvalidclient") assert.True(t, validClient) assert.False(t, invalidClient) } func TestStoreSuite(t *testing.T) { suite.Run(t, &StoreSuite{}) } type StoreSuite struct { suite.Suite ctx context.Context ctrl *gomock.Controller mock *mocks.MockStorage store *oidc.Store } func (s *StoreSuite) SetupTest() { s.ctx = context.Background() s.ctrl = gomock.NewController(s.T()) s.mock = mocks.NewMockStorage(s.ctrl) s.store = oidc.NewStore(&schema.OpenIDConnect{ Clients: []schema.OpenIDConnectClient{ { ID: "hs256", Secret: tOpenIDConnectPBKDF2ClientSecret, Policy: authorization.OneFactor.String(), RedirectURIs: []string{ "https://client.example.com", }, TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretJWT, TokenEndpointAuthSigningAlg: oidc.SigningAlgHMACUsingSHA256, }, }}, s.mock) } func (s *StoreSuite) TestGetSubject() { s.T().Run("GenerateNew", func(t *testing.T) { s.mock. EXPECT(). LoadUserOpaqueIdentifierBySignature(s.ctx, "openid", "", "john"). Return(nil, nil) s.mock. EXPECT(). SaveUserOpaqueIdentifier(s.ctx, gomock.Any()). Return(nil) opaqueID, err := s.store.GetSubject(s.ctx, "", "john") assert.NoError(t, err) assert.NotEqual(t, uint32(0), opaqueID) }) s.T().Run("ReturnDatabaseErrorOnLoad", func(t *testing.T) { s.mock. EXPECT(). LoadUserOpaqueIdentifierBySignature(s.ctx, "openid", "", "john"). Return(nil, fmt.Errorf("failed to load")) opaqueID, err := s.store.GetSubject(s.ctx, "", "john") assert.EqualError(t, err, "failed to load") assert.Equal(t, uint32(0), opaqueID.ID()) }) s.T().Run("ReturnDatabaseErrorOnSave", func(t *testing.T) { s.mock. EXPECT(). LoadUserOpaqueIdentifierBySignature(s.ctx, "openid", "", "john"). Return(nil, nil) s.mock. EXPECT(). SaveUserOpaqueIdentifier(s.ctx, gomock.Any()). Return(fmt.Errorf("failed to save")) opaqueID, err := s.store.GetSubject(s.ctx, "", "john") assert.EqualError(t, err, "failed to save") assert.Equal(t, uint32(0), opaqueID.ID()) }) } func (s *StoreSuite) TestTx() { gomock.InOrder( s.mock.EXPECT().BeginTX(s.ctx).Return(s.ctx, nil), s.mock.EXPECT().Commit(s.ctx).Return(nil), s.mock.EXPECT().Rollback(s.ctx).Return(nil), s.mock.EXPECT().BeginTX(s.ctx).Return(nil, fmt.Errorf("failed to begin")), s.mock.EXPECT().Commit(s.ctx).Return(fmt.Errorf("failed to commit")), s.mock.EXPECT().Rollback(s.ctx).Return(fmt.Errorf("failed to rollback")), ) x, err := s.store.BeginTX(s.ctx) s.Equal(s.ctx, x) s.NoError(err) s.NoError(s.store.Commit(s.ctx)) s.NoError(s.store.Rollback(s.ctx)) x, err = s.store.BeginTX(s.ctx) s.Equal(nil, x) s.EqualError(err, "failed to begin") s.EqualError(s.store.Commit(s.ctx), "failed to commit") s.EqualError(s.store.Rollback(s.ctx), "failed to rollback") } func (s *StoreSuite) TestClientAssertionJWTValid() { gomock.InOrder( s.mock. EXPECT(). LoadOAuth2BlacklistedJTI(s.ctx, "3a240379e8286a7a8ff5e99d68567e0e5e34e80168b8feffa89d3d33dea95b63"). Return(&model.OAuth2BlacklistedJTI{ ID: 1, Signature: "3a240379e8286a7a8ff5e99d68567e0e5e34e80168b8feffa89d3d33dea95b63", ExpiresAt: time.Now().Add(time.Hour), }, nil), s.mock. EXPECT(). LoadOAuth2BlacklistedJTI(s.ctx, "e7f67ad76c80d57d34b19598462817932aec21d2806a08a786a8d4b9dd476068"). Return(&model.OAuth2BlacklistedJTI{ ID: 1, Signature: "e7f67ad76c80d57d34b19598462817932aec21d2806a08a786a8d4b9dd476068", ExpiresAt: time.Now().Add(-time.Hour), }, nil), s.mock. EXPECT(). LoadOAuth2BlacklistedJTI(s.ctx, "f29ef0d85303a09411b76001c579980f1b1b7fc9deb1fa647875a724f4f231c6"). Return(nil, fmt.Errorf("failed to load")), ) s.EqualError(s.store.ClientAssertionJWTValid(s.ctx, "066ee771-e156-4886-b99f-ee09b0d3edf4"), "jti_known") s.NoError(s.store.ClientAssertionJWTValid(s.ctx, "5dad3ff7-e4f2-41b6-98a3-b73d872076ce")) s.EqualError(s.store.ClientAssertionJWTValid(s.ctx, "65471ccb-d650-4006-a95f-cb4f4e3d7202"), "failed to load") } func (s *StoreSuite) TestCreateSessions() { challenge := uuid.Must(uuid.NewRandom()) session := &model.OpenIDSession{ ChallengeID: challenge, } sessionData, _ := json.Marshal(session) gomock.InOrder( s.mock. EXPECT(). SaveOAuth2Session(s.ctx, storage.OAuth2SessionTypeAuthorizeCode, model.OAuth2Session{ChallengeID: challenge, RequestID: "abc", ClientID: "example", Signature: "abc", Active: true, Session: sessionData}). Return(nil), s.mock. EXPECT(). SaveOAuth2Session(s.ctx, storage.OAuth2SessionTypeAuthorizeCode, model.OAuth2Session{ChallengeID: challenge, RequestID: "abc", ClientID: "example", Signature: "abc", Active: true, Session: sessionData}). Return(fmt.Errorf("duplicate key")), s.mock. EXPECT(). SaveOAuth2Session(s.ctx, storage.OAuth2SessionTypeAccessToken, model.OAuth2Session{ChallengeID: challenge, RequestID: "abc", ClientID: "example", Signature: "abc", Active: true, Session: sessionData}). Return(nil), s.mock. EXPECT(). SaveOAuth2Session(s.ctx, storage.OAuth2SessionTypeRefreshToken, model.OAuth2Session{ChallengeID: challenge, RequestID: "abc", ClientID: "example", Signature: "abc", Active: true, Session: sessionData}). Return(nil), s.mock. EXPECT(). SaveOAuth2Session(s.ctx, storage.OAuth2SessionTypeOpenIDConnect, model.OAuth2Session{ChallengeID: challenge, RequestID: "abc", ClientID: "example", Signature: "abc", Active: true, Session: sessionData}). Return(nil), s.mock. EXPECT(). SaveOAuth2Session(s.ctx, storage.OAuth2SessionTypePKCEChallenge, model.OAuth2Session{ChallengeID: challenge, RequestID: "abc", ClientID: "example", Signature: "abc", Active: true, Session: sessionData}). Return(nil), s.mock. EXPECT(). SaveOAuth2PARContext(s.ctx, model.OAuth2PARContext{Signature: "abc", RequestID: "abc", ClientID: "example", Session: sessionData}). Return(nil), ) s.NoError(s.store.CreateAuthorizeCodeSession(s.ctx, "abc", &fosite.Request{ ID: "abc", Client: &oidc.BaseClient{ ID: "example", }, Session: session, })) s.EqualError(s.store.CreateAuthorizeCodeSession(s.ctx, "abc", &fosite.Request{ ID: "abc", Client: &oidc.BaseClient{ ID: "example", }, Session: session, }), "duplicate key") s.EqualError(s.store.CreateAuthorizeCodeSession(s.ctx, "abc", &fosite.Request{ ID: "abc", Client: &oidc.BaseClient{ ID: "example", }, Session: nil, }), "can't convert type '' to an *OAuth2Session") s.NoError(s.store.CreateAccessTokenSession(s.ctx, "abc", &fosite.Request{ ID: "abc", Client: &oidc.BaseClient{ ID: "example", }, Session: session, })) s.NoError(s.store.CreateRefreshTokenSession(s.ctx, "abc", &fosite.Request{ ID: "abc", Client: &oidc.BaseClient{ ID: "example", }, Session: session, })) s.NoError(s.store.CreateOpenIDConnectSession(s.ctx, "abc", &fosite.Request{ ID: "abc", Client: &oidc.BaseClient{ ID: "example", }, Session: session, })) s.NoError(s.store.CreatePKCERequestSession(s.ctx, "abc", &fosite.Request{ ID: "abc", Client: &oidc.BaseClient{ ID: "example", }, Session: session, })) s.NoError(s.store.CreatePARSession(s.ctx, "abc", &fosite.AuthorizeRequest{ Request: fosite.Request{ ID: "abc", Client: &oidc.BaseClient{ ID: "example", }, Session: session, }})) s.EqualError(s.store.CreatePARSession(s.ctx, "abc", &fosite.AuthorizeRequest{ Request: fosite.Request{ ID: "abc", Client: &oidc.BaseClient{ ID: "example", }, Session: nil, }}), "can't convert type '' to an *OAuth2Session") } func (s *StoreSuite) TestRevokeSessions() { gomock.InOrder( s.mock. EXPECT(). DeactivateOAuth2Session(s.ctx, storage.OAuth2SessionTypeAuthorizeCode, "abc1"). Return(nil), s.mock. EXPECT(). DeactivateOAuth2Session(s.ctx, storage.OAuth2SessionTypeAuthorizeCode, "abc2"). Return(fmt.Errorf("not found")), s.mock. EXPECT(). RevokeOAuth2Session(s.ctx, storage.OAuth2SessionTypeAccessToken, "at_example1"). Return(nil), s.mock. EXPECT(). RevokeOAuth2Session(s.ctx, storage.OAuth2SessionTypeAccessToken, "at_example2"). Return(fmt.Errorf("not found")), s.mock. EXPECT(). RevokeOAuth2SessionByRequestID(s.ctx, storage.OAuth2SessionTypeAccessToken, "65471ccb-d650-4006-a95f-cb4f4e3d7200"). Return(nil), s.mock. EXPECT(). RevokeOAuth2SessionByRequestID(s.ctx, storage.OAuth2SessionTypeAccessToken, "65471ccb-d650-4006-a95f-cb4f4e3d7201"). Return(fmt.Errorf("not found")), s.mock. EXPECT(). RevokeOAuth2SessionByRequestID(s.ctx, storage.OAuth2SessionTypeAccessToken, "65471ccb-d650-4006-a95f-cb4f4e3d7202"). Return(sql.ErrNoRows), s.mock. EXPECT(). RevokeOAuth2Session(s.ctx, storage.OAuth2SessionTypeRefreshToken, "rt_example1"). Return(nil), s.mock. EXPECT(). RevokeOAuth2Session(s.ctx, storage.OAuth2SessionTypeRefreshToken, "rt_example2"). Return(fmt.Errorf("not found")), s.mock. EXPECT(). DeactivateOAuth2SessionByRequestID(s.ctx, storage.OAuth2SessionTypeRefreshToken, "65471ccb-d650-4006-a95f-cb4f4e3d7200"). Return(nil), s.mock. EXPECT(). DeactivateOAuth2SessionByRequestID(s.ctx, storage.OAuth2SessionTypeRefreshToken, "65471ccb-d650-4006-a95f-cb4f4e3d7201"). Return(fmt.Errorf("not found")), s.mock. EXPECT(). DeactivateOAuth2SessionByRequestID(s.ctx, storage.OAuth2SessionTypeRefreshToken, "65471ccb-d650-4006-a95f-cb4f4e3d7202"). Return(sql.ErrNoRows), s.mock. EXPECT(). DeactivateOAuth2SessionByRequestID(s.ctx, storage.OAuth2SessionTypeRefreshToken, "65471ccb-d650-4006-a95f-cb4f4e3d7200"). Return(nil), s.mock. EXPECT(). DeactivateOAuth2SessionByRequestID(s.ctx, storage.OAuth2SessionTypeRefreshToken, "65471ccb-d650-4006-a95f-cb4f4e3d7201"). Return(fmt.Errorf("not found")), s.mock. EXPECT(). DeactivateOAuth2SessionByRequestID(s.ctx, storage.OAuth2SessionTypeRefreshToken, "65471ccb-d650-4006-a95f-cb4f4e3d7202"). Return(sql.ErrNoRows), s.mock. EXPECT(). RevokeOAuth2Session(s.ctx, storage.OAuth2SessionTypePKCEChallenge, "pkce1"). Return(nil), s.mock. EXPECT(). RevokeOAuth2Session(s.ctx, storage.OAuth2SessionTypePKCEChallenge, "pkce2"). Return(fmt.Errorf("not found")), s.mock. EXPECT(). RevokeOAuth2Session(s.ctx, storage.OAuth2SessionTypeOpenIDConnect, "ac_1"). Return(nil), s.mock. EXPECT(). RevokeOAuth2Session(s.ctx, storage.OAuth2SessionTypeOpenIDConnect, "ac_2"). Return(fmt.Errorf("not found")), s.mock. EXPECT(). RevokeOAuth2PARContext(s.ctx, "urn:par1"). Return(nil), s.mock. EXPECT(). RevokeOAuth2PARContext(s.ctx, "urn:par2"). Return(fmt.Errorf("not found")), ) s.NoError(s.store.InvalidateAuthorizeCodeSession(s.ctx, "abc1")) s.EqualError(s.store.InvalidateAuthorizeCodeSession(s.ctx, "abc2"), "not found") s.NoError(s.store.DeleteAccessTokenSession(s.ctx, "at_example1")) s.EqualError(s.store.DeleteAccessTokenSession(s.ctx, "at_example2"), "not found") s.NoError(s.store.RevokeAccessToken(s.ctx, "65471ccb-d650-4006-a95f-cb4f4e3d7200")) s.EqualError(s.store.RevokeAccessToken(s.ctx, "65471ccb-d650-4006-a95f-cb4f4e3d7201"), "not found") s.EqualError(s.store.RevokeAccessToken(s.ctx, "65471ccb-d650-4006-a95f-cb4f4e3d7202"), "not_found") s.NoError(s.store.DeleteRefreshTokenSession(s.ctx, "rt_example1")) s.EqualError(s.store.DeleteRefreshTokenSession(s.ctx, "rt_example2"), "not found") s.NoError(s.store.RevokeRefreshToken(s.ctx, "65471ccb-d650-4006-a95f-cb4f4e3d7200")) s.EqualError(s.store.RevokeRefreshToken(s.ctx, "65471ccb-d650-4006-a95f-cb4f4e3d7201"), "not found") s.EqualError(s.store.RevokeRefreshToken(s.ctx, "65471ccb-d650-4006-a95f-cb4f4e3d7202"), "sql: no rows in result set") s.NoError(s.store.RevokeRefreshTokenMaybeGracePeriod(s.ctx, "65471ccb-d650-4006-a95f-cb4f4e3d7200", "1")) s.EqualError(s.store.RevokeRefreshTokenMaybeGracePeriod(s.ctx, "65471ccb-d650-4006-a95f-cb4f4e3d7201", "2"), "not found") s.EqualError(s.store.RevokeRefreshTokenMaybeGracePeriod(s.ctx, "65471ccb-d650-4006-a95f-cb4f4e3d7202", "3"), "sql: no rows in result set") s.NoError(s.store.DeletePKCERequestSession(s.ctx, "pkce1")) s.EqualError(s.store.DeletePKCERequestSession(s.ctx, "pkce2"), "not found") s.NoError(s.store.DeleteOpenIDConnectSession(s.ctx, "ac_1")) s.EqualError(s.store.DeleteOpenIDConnectSession(s.ctx, "ac_2"), "not found") s.NoError(s.store.DeletePARSession(s.ctx, "urn:par1")) s.EqualError(s.store.DeletePARSession(s.ctx, "urn:par2"), "not found") } func (s *StoreSuite) TestGetSessions() { challenge := uuid.Must(uuid.NewRandom()) session := &model.OpenIDSession{ ChallengeID: challenge, ClientID: "hs256", } sessionData, _ := json.Marshal(session) sessionb := &model.OpenIDSession{ ChallengeID: challenge, ClientID: "hs256", } sessionDatab, _ := json.Marshal(sessionb) gomock.InOrder( s.mock.EXPECT().LoadOAuth2Session(s.ctx, storage.OAuth2SessionTypeAuthorizeCode, "ac_123"). Return(&model.OAuth2Session{ClientID: "hs256", Session: sessionData, Active: true}, nil), s.mock.EXPECT().LoadOAuth2Session(s.ctx, storage.OAuth2SessionTypeAuthorizeCode, "ac_456"). Return(&model.OAuth2Session{ClientID: "hs256", Session: sessionData, Active: false}, nil), s.mock.EXPECT().LoadOAuth2Session(s.ctx, storage.OAuth2SessionTypeAuthorizeCode, "ac_aaa"). Return(nil, sql.ErrNoRows), s.mock.EXPECT().LoadOAuth2Session(s.ctx, storage.OAuth2SessionTypeAuthorizeCode, "ac_130"). Return(nil, fmt.Errorf("timeout")), s.mock.EXPECT().LoadOAuth2Session(s.ctx, storage.OAuth2SessionTypeAuthorizeCode, "ac_badclient"). Return(&model.OAuth2Session{ClientID: "no-client", Session: sessionDatab, Active: true}, nil), s.mock.EXPECT().LoadOAuth2Session(s.ctx, storage.OAuth2SessionTypeAccessToken, "at"). Return(&model.OAuth2Session{ClientID: "hs256", Session: sessionData, Active: true}, nil), s.mock.EXPECT().LoadOAuth2Session(s.ctx, storage.OAuth2SessionTypeRefreshToken, "rt"). Return(&model.OAuth2Session{ClientID: "hs256", Session: sessionData, Active: true}, nil), s.mock.EXPECT().LoadOAuth2Session(s.ctx, storage.OAuth2SessionTypePKCEChallenge, "pkce"). Return(&model.OAuth2Session{ClientID: "hs256", Session: sessionData, Active: true}, nil), s.mock.EXPECT().LoadOAuth2Session(s.ctx, storage.OAuth2SessionTypeOpenIDConnect, "ot"). Return(&model.OAuth2Session{ClientID: "hs256", Session: sessionData, Active: true}, nil), s.mock. EXPECT(). LoadOAuth2PARContext(s.ctx, "urn:par"). Return(&model.OAuth2PARContext{Signature: "abc", RequestID: "abc", ClientID: "hs256", Session: sessionData}, nil), s.mock. EXPECT(). LoadOAuth2PARContext(s.ctx, "urn:par"). Return(nil, sql.ErrNoRows), ) var ( r fosite.Requester err error ) r, err = s.store.GetAuthorizeCodeSession(s.ctx, "ac_123", &model.OpenIDSession{}) s.NotNil(r) s.NoError(err) r, err = s.store.GetAuthorizeCodeSession(s.ctx, "ac_456", &model.OpenIDSession{}) s.NotNil(r) s.EqualError(err, "Authorization code has ben invalidated") r, err = s.store.GetAuthorizeCodeSession(s.ctx, "ac_aaa", &model.OpenIDSession{}) s.Nil(r) s.EqualError(err, "not_found") r, err = s.store.GetAuthorizeCodeSession(s.ctx, "ac_130", &model.OpenIDSession{}) s.Nil(r) s.EqualError(err, "timeout") r, err = s.store.GetAuthorizeCodeSession(s.ctx, "ac_badclient", &model.OpenIDSession{}) s.Nil(r) s.EqualError(err, "invalid_client") r, err = s.store.GetAccessTokenSession(s.ctx, "at", &model.OpenIDSession{}) s.NotNil(r) s.NoError(err) r, err = s.store.GetRefreshTokenSession(s.ctx, "rt", &model.OpenIDSession{}) s.NotNil(r) s.NoError(err) r, err = s.store.GetPKCERequestSession(s.ctx, "pkce", &model.OpenIDSession{}) s.NotNil(r) s.NoError(err) r, err = s.store.GetOpenIDConnectSession(s.ctx, "ot", &fosite.Request{ ID: "abc", Client: &oidc.BaseClient{ ID: "example", }, Session: session, }) s.NotNil(r) s.NoError(err) r, err = s.store.GetPARSession(s.ctx, "urn:par") s.NotNil(r) s.NoError(err) r, err = s.store.GetPARSession(s.ctx, "urn:par") s.Nil(r) s.EqualError(err, "sql: no rows in result set") } func (s *StoreSuite) TestIsJWTUsed() { gomock.InOrder( s.mock. EXPECT(). LoadOAuth2BlacklistedJTI(s.ctx, "3a240379e8286a7a8ff5e99d68567e0e5e34e80168b8feffa89d3d33dea95b63"). Return(&model.OAuth2BlacklistedJTI{ ID: 1, Signature: "3a240379e8286a7a8ff5e99d68567e0e5e34e80168b8feffa89d3d33dea95b63", ExpiresAt: time.Now().Add(time.Hour), }, nil), s.mock. EXPECT(). LoadOAuth2BlacklistedJTI(s.ctx, "e7f67ad76c80d57d34b19598462817932aec21d2806a08a786a8d4b9dd476068"). Return(&model.OAuth2BlacklistedJTI{ ID: 1, Signature: "e7f67ad76c80d57d34b19598462817932aec21d2806a08a786a8d4b9dd476068", ExpiresAt: time.Now().Add(-time.Hour), }, nil), s.mock. EXPECT(). LoadOAuth2BlacklistedJTI(s.ctx, "f29ef0d85303a09411b76001c579980f1b1b7fc9deb1fa647875a724f4f231c6"). Return(nil, fmt.Errorf("failed to load")), ) used, err := s.store.IsJWTUsed(s.ctx, "066ee771-e156-4886-b99f-ee09b0d3edf4") s.True(used) s.EqualError(err, "jti_known") used, err = s.store.IsJWTUsed(s.ctx, "5dad3ff7-e4f2-41b6-98a3-b73d872076ce") s.False(used) s.NoError(err) used, err = s.store.IsJWTUsed(s.ctx, "65471ccb-d650-4006-a95f-cb4f4e3d7202") s.True(used) s.EqualError(err, "failed to load") } func (s *StoreSuite) TestMarkJWTUsedForTime() { gomock.InOrder( s.mock.EXPECT(). SaveOAuth2BlacklistedJTI(s.ctx, model.OAuth2BlacklistedJTI{Signature: "f29ef0d85303a09411b76001c579980f1b1b7fc9deb1fa647875a724f4f231c6", ExpiresAt: time.Unix(160000000, 0)}). Return(nil), s.mock.EXPECT().SaveOAuth2BlacklistedJTI(s.ctx, model.OAuth2BlacklistedJTI{Signature: "0dab0de97ed4e05da82763497448daf4f6b555c99218100e3ef5a81f36232940", ExpiresAt: time.Unix(160000000, 0)}). Return(fmt.Errorf("already marked")), ) s.NoError(s.store.MarkJWTUsedForTime(s.ctx, "65471ccb-d650-4006-a95f-cb4f4e3d7202", time.Unix(160000000, 0))) s.EqualError(s.store.MarkJWTUsedForTime(s.ctx, "65471ccb-d650-4006-a95f-cb4f4e3d7201", time.Unix(160000000, 0)), "already marked") }