diff --git a/backend/handler/email_test.go b/backend/handler/email_test.go index db6dd83fa..3be28e962 100644 --- a/backend/handler/email_test.go +++ b/backend/handler/email_test.go @@ -7,9 +7,7 @@ import ( "github.com/gofrs/uuid" "github.com/stretchr/testify/suite" "github.com/teamhanko/hanko/backend/config" - "github.com/teamhanko/hanko/backend/crypto/jwk" "github.com/teamhanko/hanko/backend/dto" - "github.com/teamhanko/hanko/backend/session" "github.com/teamhanko/hanko/backend/test" "net/http" "net/http/httptest" @@ -26,7 +24,7 @@ type emailSuite struct { } func (s *emailSuite) TestEmailHandler_New() { - emailHandler := NewEmailHandler(&config.Config{}, s.Storage, sessionManager{}, test.NewAuditLogger()) + emailHandler := NewEmailHandler(&config.Config{}, s.Storage, s.GetDefaultSessionManager(), test.NewAuditLogger()) s.NotEmpty(emailHandler) } @@ -40,11 +38,6 @@ func (s *emailSuite) TestEmailHandler_List() { e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil, nil) - jwkManager, err := jwk.NewDefaultManager(test.DefaultConfig.Secrets.Keys, s.Storage.GetJwkPersister()) - s.Require().NoError(err) - sessionManager, err := session.NewManager(jwkManager, test.DefaultConfig) - s.Require().NoError(err) - tests := []struct { name string userId uuid.UUID @@ -64,10 +57,7 @@ func (s *emailSuite) TestEmailHandler_List() { for _, currentTest := range tests { s.Run(currentTest.name, func() { - token, _, err := sessionManager.GenerateJWT(currentTest.userId, nil) - s.Require().NoError(err) - cookie, err := sessionManager.GenerateCookie(token) - s.Require().NoError(err) + cookie := s.GenerateSessionCookie(currentTest.userId) req := httptest.NewRequest(http.MethodGet, "/emails", nil) req.AddCookie(cookie) @@ -172,15 +162,7 @@ func (s *emailSuite) TestEmailHandler_Create() { cfg.Email.RequireVerification = currentTest.requiresVerification cfg.Email.Limit = currentTest.maxNumberOfAddresses e := NewPublicRouter(&cfg, s.Storage, nil, nil) - jwkManager, err := jwk.NewDefaultManager(cfg.Secrets.Keys, s.Storage.GetJwkPersister()) - s.Require().NoError(err) - sessionManager, err := session.NewManager(jwkManager, cfg) - s.Require().NoError(err) - - token, _, err := sessionManager.GenerateJWT(currentTest.userId, nil) - s.Require().NoError(err) - cookie, err := sessionManager.GenerateCookie(token) - s.Require().NoError(err) + cookie := s.GenerateSessionCookie(currentTest.userId) body := dto.EmailCreateRequest{ Address: currentTest.email, @@ -235,19 +217,11 @@ func (s *emailSuite) TestEmailHandler_SetPrimaryEmail() { e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil, nil) - jwkManager, err := jwk.NewDefaultManager(test.DefaultConfig.Secrets.Keys, s.Storage.GetJwkPersister()) - s.Require().NoError(err) - sessionManager, err := session.NewManager(jwkManager, test.DefaultConfig) - s.Require().NoError(err) - oldPrimaryEmailId := uuid.FromStringOrNil("51b7c175-ceb6-45ba-aae6-0092221c1b84") newPrimaryEmailId := uuid.FromStringOrNil("8bb4c8a7-a3e6-48bb-b54f-20e3b485ab33") userId := uuid.FromStringOrNil("b5dd5267-b462-48be-b70d-bcd6f1bbe7a5") - token, _, err := sessionManager.GenerateJWT(userId, nil) - s.NoError(err) - cookie, err := sessionManager.GenerateCookie(token) - s.NoError(err) + cookie := s.GenerateSessionCookie(userId) req := httptest.NewRequest(http.MethodPost, fmt.Sprintf("/emails/%s/set_primary", newPrimaryEmailId), nil) req.AddCookie(cookie) @@ -280,15 +254,7 @@ func (s *emailSuite) TestEmailHandler_Delete() { e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil, nil) userId := uuid.FromStringOrNil("b5dd5267-b462-48be-b70d-bcd6f1bbe7a5") - jwkManager, err := jwk.NewDefaultManager(test.DefaultConfig.Secrets.Keys, s.Storage.GetJwkPersister()) - s.Require().NoError(err) - sessionManager, err := session.NewManager(jwkManager, test.DefaultConfig) - s.Require().NoError(err) - - token, _, err := sessionManager.GenerateJWT(userId, nil) - s.NoError(err) - cookie, err := sessionManager.GenerateCookie(token) - s.NoError(err) + cookie := s.GenerateSessionCookie(userId) tests := []struct { name string diff --git a/backend/handler/password_test.go b/backend/handler/password_test.go index 0deeb6d9b..a55755464 100644 --- a/backend/handler/password_test.go +++ b/backend/handler/password_test.go @@ -6,8 +6,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" "github.com/teamhanko/hanko/backend/config" - "github.com/teamhanko/hanko/backend/crypto/jwk" - "github.com/teamhanko/hanko/backend/session" "github.com/teamhanko/hanko/backend/test" "golang.org/x/crypto/bcrypt" "net/http" @@ -90,11 +88,7 @@ func (s *passwordSuite) TestPasswordHandler_Set_Create() { err := s.LoadFixtures("../test/fixtures/password") s.Require().NoError(err) - sessionManager := s.GetDefaultSessionManager() - token, _, err := sessionManager.GenerateJWT(currentTest.userId, nil) - s.Require().NoError(err) - cookie, err := sessionManager.GenerateCookie(token) - s.Require().NoError(err) + cookie := s.GenerateSessionCookie(currentTest.userId) req := httptest.NewRequest(http.MethodPut, "/password", strings.NewReader(currentTest.body)) req.Header.Set("Content-Type", "application/json") @@ -196,15 +190,6 @@ func (s *passwordSuite) TestPasswordHandler_Login() { } } -func (s *passwordSuite) GetDefaultSessionManager() session.Manager { - jwkManager, err := jwk.NewDefaultManager(test.DefaultConfig.Secrets.Keys, s.Storage.GetJwkPersister()) - s.Require().NoError(err) - sessionManager, err := session.NewManager(jwkManager, test.DefaultConfig) - s.Require().NoError(err) - - return sessionManager -} - // TestMaxPasswordLength bcrypt since version 0.5.0 only accepts passwords at least 72 bytes long. This test documents this behaviour. func TestMaxPasswordLength(t *testing.T) { tests := []struct { diff --git a/backend/handler/user_test.go b/backend/handler/user_test.go index 10ab070ab..c8aa256a4 100644 --- a/backend/handler/user_test.go +++ b/backend/handler/user_test.go @@ -7,10 +7,8 @@ import ( "github.com/gofrs/uuid" _ "github.com/lib/pq" "github.com/stretchr/testify/suite" - "github.com/teamhanko/hanko/backend/crypto/jwk" "github.com/teamhanko/hanko/backend/dto" "github.com/teamhanko/hanko/backend/persistence/models" - "github.com/teamhanko/hanko/backend/session" "github.com/teamhanko/hanko/backend/test" "golang.org/x/exp/slices" "net/http" @@ -249,24 +247,13 @@ func (s *userSuite) TestUserHandler_Get() { err := s.LoadFixtures("../test/fixtures/user") s.Require().NoError(err) - userId := "b5dd5267-b462-48be-b70d-bcd6f1bbe7a5" + userId := uuid.FromStringOrNil("b5dd5267-b462-48be-b70d-bcd6f1bbe7a5") e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil, nil) - jwkManager, err := jwk.NewDefaultManager(test.DefaultConfig.Secrets.Keys, s.Storage.GetJwkPersister()) - if err != nil { - panic(fmt.Errorf("failed to create jwk manager: %w", err)) - } - sessionManager, err := session.NewManager(jwkManager, test.DefaultConfig) - if err != nil { - panic(fmt.Errorf("failed to create session generator: %w", err)) - } - token, _, err := sessionManager.GenerateJWT(uuid.FromStringOrNil(userId), nil) - s.Require().NoError(err) - cookie, err := sessionManager.GenerateCookie(token) - s.Require().NoError(err) + cookie := s.GenerateSessionCookie(userId) - req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/users/%s", userId), nil) + req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/users/%s", userId.String()), nil) req.AddCookie(cookie) rec := httptest.NewRecorder() @@ -277,7 +264,7 @@ func (s *userSuite) TestUserHandler_Get() { user := models.User{} err := json.Unmarshal(rec.Body.Bytes(), &user) s.NoError(err) - s.Equal(userId, user.ID.String()) + s.Equal(userId.String(), user.ID.String()) s.Equal(len(user.WebauthnCredentials), 0) } } @@ -289,24 +276,13 @@ func (s *userSuite) TestUserHandler_GetUserWithWebAuthnCredential() { err := s.LoadFixtures("../test/fixtures/user_with_webauthn_credential") s.Require().NoError(err) - userId := "b5dd5267-b462-48be-b70d-bcd6f1bbe7a5" + userId := uuid.FromStringOrNil("b5dd5267-b462-48be-b70d-bcd6f1bbe7a5") e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil, nil) - jwkManager, err := jwk.NewDefaultManager(test.DefaultConfig.Secrets.Keys, s.Storage.GetJwkPersister()) - if err != nil { - panic(fmt.Errorf("failed to create jwk manager: %w", err)) - } - sessionManager, err := session.NewManager(jwkManager, test.DefaultConfig) - if err != nil { - panic(fmt.Errorf("failed to create session generator: %w", err)) - } - token, _, err := sessionManager.GenerateJWT(uuid.FromStringOrNil(userId), nil) - s.Require().NoError(err) - cookie, err := sessionManager.GenerateCookie(token) - s.Require().NoError(err) + cookie := s.GenerateSessionCookie(userId) - req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/users/%s", userId), nil) + req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/users/%s", userId.String()), nil) rec := httptest.NewRecorder() req.AddCookie(cookie) @@ -317,7 +293,7 @@ func (s *userSuite) TestUserHandler_GetUserWithWebAuthnCredential() { user := models.User{} err := json.Unmarshal(rec.Body.Bytes(), &user) s.Require().NoError(err) - s.Equal(userId, user.ID.String()) + s.Equal(userId.String(), user.ID.String()) s.Equal(len(user.WebauthnCredentials), 1) } } @@ -328,21 +304,13 @@ func (s *userSuite) TestUserHandler_Get_InvalidUserId() { } e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil, nil) - userId := "b5dd5267-b462-48be-b70d-bcd6f1bbe7a5" - - jwkManager, err := jwk.NewDefaultManager(test.DefaultConfig.Secrets.Keys, s.Storage.GetJwkPersister()) - if err != nil { - panic(fmt.Errorf("failed to create jwk manager: %w", err)) - } - sessionManager, err := session.NewManager(jwkManager, test.DefaultConfig) - if err != nil { - panic(fmt.Errorf("failed to create session generator: %w", err)) - } - token, _, err := sessionManager.GenerateJWT(uuid.FromStringOrNil(userId), nil) - s.Require().NoError(err) - cookie, err := sessionManager.GenerateCookie(token) + err := s.LoadFixtures("../test/fixtures/user") s.Require().NoError(err) + userId := uuid.FromStringOrNil("b5dd5267-b462-48be-b70d-bcd6f1bbe7a5") + + cookie := s.GenerateSessionCookie(userId) + req := httptest.NewRequest(http.MethodGet, "/users/invalidUserId", nil) req.Header.Set("Content-Type", "application/json") req.AddCookie(cookie) @@ -463,22 +431,11 @@ func (s *userSuite) TestUserHandler_Me() { err := s.LoadFixtures("../test/fixtures/user_with_webauthn_credential") s.Require().NoError(err) - userId := "b5dd5267-b462-48be-b70d-bcd6f1bbe7a5" + userId := uuid.FromStringOrNil("b5dd5267-b462-48be-b70d-bcd6f1bbe7a5") e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil, nil) - jwkManager, err := jwk.NewDefaultManager(test.DefaultConfig.Secrets.Keys, s.Storage.GetJwkPersister()) - if err != nil { - panic(fmt.Errorf("failed to create jwk manager: %w", err)) - } - sessionManager, err := session.NewManager(jwkManager, test.DefaultConfig) - if err != nil { - panic(fmt.Errorf("failed to create session generator: %w", err)) - } - token, _, err := sessionManager.GenerateJWT(uuid.FromStringOrNil(userId), nil) - s.Require().NoError(err) - cookie, err := sessionManager.GenerateCookie(token) - s.Require().NoError(err) + cookie := s.GenerateSessionCookie(userId) req := httptest.NewRequest(http.MethodGet, "/me", nil) req.AddCookie(cookie) @@ -493,7 +450,7 @@ func (s *userSuite) TestUserHandler_Me() { }{} err = json.Unmarshal(rec.Body.Bytes(), &response) s.NoError(err) - s.Equal(userId, response.UserId) + s.Equal(userId.String(), response.UserId) } } @@ -501,22 +458,15 @@ func (s *userSuite) TestUserHandler_Logout() { if testing.Short() { s.T().Skip("skipping test in short mode.") } - userId, _ := uuid.NewV4() - e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil, nil) - jwkManager, err := jwk.NewDefaultManager(test.DefaultConfig.Secrets.Keys, s.Storage.GetJwkPersister()) - if err != nil { - panic(fmt.Errorf("failed to create jwk manager: %w", err)) - } - sessionManager, err := session.NewManager(jwkManager, test.DefaultConfig) - if err != nil { - panic(fmt.Errorf("failed to create session generator: %w", err)) - } - token, _, err := sessionManager.GenerateJWT(userId, nil) - s.Require().NoError(err) - cookie, err := sessionManager.GenerateCookie(token) + err := s.LoadFixtures("../test/fixtures/user") s.Require().NoError(err) + userId := uuid.FromStringOrNil("b5dd5267-b462-48be-b70d-bcd6f1bbe7a5") + e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil, nil) + + cookie := s.GenerateSessionCookie(userId) + req := httptest.NewRequest(http.MethodPost, "/logout", nil) req.AddCookie(cookie) rec := httptest.NewRecorder() @@ -545,18 +495,7 @@ func (s *userSuite) TestUserHandler_Delete() { cfg.Account.AllowDeletion = true e := NewPublicRouter(&cfg, s.Storage, nil, nil) - jwkManager, err := jwk.NewDefaultManager(test.DefaultConfig.Secrets.Keys, s.Storage.GetJwkPersister()) - if err != nil { - panic(fmt.Errorf("failed to create jwk manager: %w", err)) - } - sessionManager, err := session.NewManager(jwkManager, test.DefaultConfig) - if err != nil { - panic(fmt.Errorf("failed to create session generator: %w", err)) - } - token, _, err := sessionManager.GenerateJWT(userId, nil) - s.Require().NoError(err) - cookie, err := sessionManager.GenerateCookie(token) - s.Require().NoError(err) + cookie := s.GenerateSessionCookie(userId) req := httptest.NewRequest(http.MethodDelete, "/user", nil) req.AddCookie(cookie) diff --git a/backend/handler/webauthn_test.go b/backend/handler/webauthn_test.go index 8c457dbc0..be920397c 100644 --- a/backend/handler/webauthn_test.go +++ b/backend/handler/webauthn_test.go @@ -6,12 +6,8 @@ import ( "github.com/go-webauthn/webauthn/protocol" "github.com/gofrs/uuid" "github.com/labstack/echo/v4" - "github.com/lestrrat-go/jwx/v2/jwt" "github.com/stretchr/testify/suite" - "github.com/teamhanko/hanko/backend/crypto/jwk" - "github.com/teamhanko/hanko/backend/dto" "github.com/teamhanko/hanko/backend/persistence/models" - "github.com/teamhanko/hanko/backend/session" "github.com/teamhanko/hanko/backend/test" "net/http" "net/http/httptest" @@ -45,15 +41,11 @@ func (s *webauthnSuite) TestWebauthnHandler_BeginRegistration() { err := s.LoadFixtures("../test/fixtures/webauthn") s.Require().NoError(err) - userId := "ec4ef049-5b88-4321-a173-21b0eff06a04" + userId := uuid.FromStringOrNil("ec4ef049-5b88-4321-a173-21b0eff06a04") e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil, nil) - sessionManager := s.GetDefaultSessionManager() - token, _, err := sessionManager.GenerateJWT(uuid.FromStringOrNil(userId), nil) - s.Require().NoError(err) - cookie, err := sessionManager.GenerateCookie(token) - s.Require().NoError(err) + cookie := s.GenerateSessionCookie(userId) req := httptest.NewRequest(http.MethodPost, "/webauthn/registration/initialize", nil) req.AddCookie(cookie) @@ -70,7 +62,7 @@ func (s *webauthnSuite) TestWebauthnHandler_BeginRegistration() { s.Require().NoError(err) s.NotEmpty(creationOptions.Response.Challenge) - s.Equal(uuid.FromStringOrNil(userId).Bytes(), uId) + s.Equal(uuid.FromStringOrNil(userId.String()).Bytes(), uId) s.Equal(test.DefaultConfig.Webauthn.RelyingParty.Id, creationOptions.Response.RelyingParty.ID) s.Equal(protocol.ResidentKeyRequirementRequired, creationOptions.Response.AuthenticatorSelection.ResidentKey) s.Equal(protocol.VerificationPreferred, creationOptions.Response.AuthenticatorSelection.UserVerification) @@ -86,15 +78,11 @@ func (s *webauthnSuite) TestWebauthnHandler_FinalizeRegistration() { err := s.LoadFixtures("../test/fixtures/webauthn_registration") s.Require().NoError(err) - userId := "ec4ef049-5b88-4321-a173-21b0eff06a04" + userId := uuid.FromStringOrNil("ec4ef049-5b88-4321-a173-21b0eff06a04") e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil, nil) - sessionManager := s.GetDefaultSessionManager() - token, _, err := sessionManager.GenerateJWT(uuid.FromStringOrNil(userId), nil) - s.Require().NoError(err) - cookie, err := sessionManager.GenerateCookie(token) - s.Require().NoError(err) + cookie := s.GenerateSessionCookie(userId) body := `{ "id": "AaFdkcD4SuPjF-jwUoRwH8-ZHuY5RW46fsZmEvBX6RNKHaGtVzpATs06KQVheIOjYz-YneG4cmQOedzl0e0jF951ukx17Hl9jeGgWz5_DKZCO12p2-2LlzjH", @@ -132,15 +120,11 @@ func (s *webauthnSuite) TestWebauthnHandler_FinalizeRegistration_SessionDataExpi err := s.LoadFixtures("../test/fixtures/webauthn_registration") s.Require().NoError(err) - userId := "ec4ef049-5b88-4321-a173-21b0eff06a04" + userId := uuid.FromStringOrNil("ec4ef049-5b88-4321-a173-21b0eff06a04") e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil, nil) - sessionManager := s.GetDefaultSessionManager() - token, _, err := sessionManager.GenerateJWT(uuid.FromStringOrNil(userId), nil) - s.Require().NoError(err) - cookie, err := sessionManager.GenerateCookie(token) - s.Require().NoError(err) + cookie := s.GenerateSessionCookie(userId) body := `{ "id": "4iVZGFN_jktXJmwmBmaSq0Qr4T62T0jX7PS7XcgAWlM", @@ -318,49 +302,8 @@ func (s *webauthnSuite) TestWebauthnHandler_FinalizeAuthentication_TokenInHeader } } -func (s *webauthnSuite) GetDefaultSessionManager() session.Manager { - jwkManager, err := jwk.NewDefaultManager(test.DefaultConfig.Secrets.Keys, s.Storage.GetJwkPersister()) - s.Require().NoError(err) - sessionManager, err := session.NewManager(jwkManager, test.DefaultConfig) - s.Require().NoError(err) - - return sessionManager -} - var userId = "ec4ef049-5b88-4321-a173-21b0eff06a04" -type sessionManager struct { -} - -func (s sessionManager) GenerateJWT(_ uuid.UUID, _ *dto.EmailJwt, _ ...session.JWTOptions) (string, jwt.Token, error) { - return userId, nil, nil -} - -func (s sessionManager) GenerateCookie(token string) (*http.Cookie, error) { - return &http.Cookie{ - Name: "hanko", - Value: token, - Secure: true, - HttpOnly: true, - SameSite: http.SameSiteLaxMode, - }, nil -} - -func (s sessionManager) DeleteCookie() (*http.Cookie, error) { - return &http.Cookie{ - Name: "hanko", - Value: "", - Secure: true, - HttpOnly: true, - SameSite: http.SameSiteLaxMode, - MaxAge: -1, - }, nil -} - -func (s sessionManager) Verify(_ string) (jwt.Token, error) { - return nil, nil -} - var uId, _ = uuid.FromString(userId) var emails = []models.Email{ diff --git a/backend/session/session_test.go b/backend/session/session_test.go index 29009958b..cd3d2992e 100644 --- a/backend/session/session_test.go +++ b/backend/session/session_test.go @@ -155,24 +155,14 @@ func Test_GenerateJWT_SessionID(t *testing.T) { { name: "token has no session id claim if server side sessions are disabled", config: config.Config{ - Session: config.Session{ - Lifespan: "5m", - ServerSide: config.ServerSide{ - Enabled: false, - }, - }, + Session: config.Session{Lifespan: "5m"}, }, tokenShouldHaveSessionID: false, }, { name: "token has a session id claim if server side sessions are disabled", config: config.Config{ - Session: config.Session{ - Lifespan: "5m", - ServerSide: config.ServerSide{ - Enabled: true, - }, - }, + Session: config.Session{Lifespan: "5m"}, }, tokenShouldHaveSessionID: true, }, diff --git a/backend/test/suite.go b/backend/test/suite.go index 4f8003560..cd33428a2 100644 --- a/backend/test/suite.go +++ b/backend/test/suite.go @@ -8,8 +8,13 @@ import ( "github.com/gofrs/uuid" "github.com/stretchr/testify/suite" "github.com/teamhanko/hanko/backend/config" + "github.com/teamhanko/hanko/backend/crypto/jwk" "github.com/teamhanko/hanko/backend/persistence" + "github.com/teamhanko/hanko/backend/persistence/models" + "github.com/teamhanko/hanko/backend/session" + "net/http" "testing" + "time" ) type Suite struct { @@ -101,3 +106,32 @@ func (s *Suite) LoadFixtures(path string) error { func testLogger(level logging.Level, s string, args ...interface{}) { } + +func (s *Suite) GetDefaultSessionManager() session.Manager { + jwkManager, err := jwk.NewDefaultManager(DefaultConfig.Secrets.Keys, s.Storage.GetJwkPersister()) + s.Require().NoError(err) + sessionManager, err := session.NewManager(jwkManager, DefaultConfig) + s.Require().NoError(err) + + return sessionManager +} + +func (s *Suite) GenerateSessionCookie(userId uuid.UUID) *http.Cookie { + token, rawToken, err := s.GetDefaultSessionManager().GenerateJWT(userId, nil) + s.Require().NoError(err) + + sessionID, _ := rawToken.Get("session_id") + _ = s.Storage.GetSessionPersister().Create(models.Session{ + ID: uuid.FromStringOrNil(sessionID.(string)), + UserID: userId, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + ExpiresAt: nil, + LastUsed: time.Now(), + }) + + cookie, err := s.GetDefaultSessionManager().GenerateCookie(token) + s.Require().NoError(err) + + return cookie +}