mirror of
https://github.com/teamhanko/hanko.git
synced 2025-11-02 23:24:29 +08:00
test: start integration improvement
This commit is contained in:
@ -24,7 +24,7 @@ type DefaultManager struct {
|
||||
persister persistence.JwkPersister
|
||||
}
|
||||
|
||||
//Returns a DefaultManager that reads and persists the jwks to database and generates jwks if a new secret gets added to the config.
|
||||
// Returns a DefaultManager that reads and persists the jwks to database and generates jwks if a new secret gets added to the config.
|
||||
func NewDefaultManager(keys []string, persister persistence.JwkPersister) (*DefaultManager, error) {
|
||||
encrypter, err := aes_gcm.NewAESGCM(keys)
|
||||
if err != nil {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package server
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/labstack/echo-contrib/prometheus"
|
||||
@ -6,9 +6,8 @@ import (
|
||||
"github.com/labstack/echo/v4/middleware"
|
||||
"github.com/teamhanko/hanko/backend/config"
|
||||
"github.com/teamhanko/hanko/backend/dto"
|
||||
"github.com/teamhanko/hanko/backend/handler"
|
||||
hankoMiddleware "github.com/teamhanko/hanko/backend/middleware"
|
||||
"github.com/teamhanko/hanko/backend/persistence"
|
||||
hankoMiddleware "github.com/teamhanko/hanko/backend/server/middleware"
|
||||
)
|
||||
|
||||
func NewAdminRouter(cfg *config.Config, persister persistence.Persister, prometheus *prometheus.Prometheus) *echo.Echo {
|
||||
@ -30,20 +29,20 @@ func NewAdminRouter(cfg *config.Config, persister persistence.Persister, prometh
|
||||
prometheus.SetMetricsPath(e)
|
||||
}
|
||||
|
||||
healthHandler := handler.NewHealthHandler()
|
||||
healthHandler := NewHealthHandler()
|
||||
|
||||
health := e.Group("/health")
|
||||
health.GET("/alive", healthHandler.Alive)
|
||||
health.GET("/ready", healthHandler.Ready)
|
||||
|
||||
userHandler := handler.NewUserHandlerAdmin(persister)
|
||||
userHandler := NewUserHandlerAdmin(persister)
|
||||
|
||||
user := g.Group("/users")
|
||||
user.GET("", userHandler.List)
|
||||
user.GET("/:id", userHandler.Get)
|
||||
user.DELETE("/:id", userHandler.Delete)
|
||||
|
||||
auditLogHandler := handler.NewAuditLogHandler(persister)
|
||||
auditLogHandler := NewAuditLogHandler(persister)
|
||||
|
||||
auditLogs := g.Group("/audit_logs")
|
||||
auditLogs.GET("", auditLogHandler.List)
|
||||
@ -1,4 +1,4 @@
|
||||
package server
|
||||
package handler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -9,10 +9,9 @@ import (
|
||||
"github.com/teamhanko/hanko/backend/config"
|
||||
"github.com/teamhanko/hanko/backend/crypto/jwk"
|
||||
"github.com/teamhanko/hanko/backend/dto"
|
||||
"github.com/teamhanko/hanko/backend/handler"
|
||||
"github.com/teamhanko/hanko/backend/mail"
|
||||
middleware2 "github.com/teamhanko/hanko/backend/middleware"
|
||||
"github.com/teamhanko/hanko/backend/persistence"
|
||||
hankoMiddleware "github.com/teamhanko/hanko/backend/server/middleware"
|
||||
"github.com/teamhanko/hanko/backend/session"
|
||||
)
|
||||
|
||||
@ -22,7 +21,7 @@ func NewPublicRouter(cfg *config.Config, persister persistence.Persister, promet
|
||||
|
||||
e.HTTPErrorHandler = dto.NewHTTPErrorHandler(dto.HTTPErrorHandlerConfig{Debug: false, Logger: e.Logger})
|
||||
e.Use(middleware.RequestID())
|
||||
e.Use(hankoMiddleware.GetLoggerMiddleware())
|
||||
e.Use(middleware2.GetLoggerMiddleware())
|
||||
|
||||
if cfg.Server.Public.Cors.Enabled {
|
||||
e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
|
||||
@ -58,34 +57,34 @@ func NewPublicRouter(cfg *config.Config, persister persistence.Persister, promet
|
||||
auditLogger := auditlog.NewLogger(persister, cfg.AuditLog)
|
||||
|
||||
if cfg.Password.Enabled {
|
||||
passwordHandler := handler.NewPasswordHandler(persister, sessionManager, cfg, auditLogger)
|
||||
passwordHandler := NewPasswordHandler(persister, sessionManager, cfg, auditLogger)
|
||||
|
||||
password := e.Group("/password")
|
||||
password.PUT("", passwordHandler.Set, hankoMiddleware.Session(sessionManager))
|
||||
password.PUT("", passwordHandler.Set, middleware2.Session(sessionManager))
|
||||
password.POST("/login", passwordHandler.Login)
|
||||
}
|
||||
|
||||
userHandler := handler.NewUserHandler(cfg, persister, sessionManager, auditLogger)
|
||||
userHandler := NewUserHandler(cfg, persister, sessionManager, auditLogger)
|
||||
|
||||
e.GET("/me", userHandler.Me, hankoMiddleware.Session(sessionManager))
|
||||
e.GET("/me", userHandler.Me, middleware2.Session(sessionManager))
|
||||
|
||||
user := e.Group("/users")
|
||||
user.POST("", userHandler.Create)
|
||||
user.GET("/:id", userHandler.Get, hankoMiddleware.Session(sessionManager))
|
||||
user.GET("/:id", userHandler.Get, middleware2.Session(sessionManager))
|
||||
|
||||
e.POST("/user", userHandler.GetUserIdByEmail)
|
||||
e.POST("/logout", userHandler.Logout, hankoMiddleware.Session(sessionManager))
|
||||
e.POST("/logout", userHandler.Logout, middleware2.Session(sessionManager))
|
||||
|
||||
if cfg.Account.AllowDeletion {
|
||||
e.DELETE("/user", userHandler.Delete, hankoMiddleware.Session(sessionManager))
|
||||
e.DELETE("/user", userHandler.Delete, middleware2.Session(sessionManager))
|
||||
}
|
||||
|
||||
healthHandler := handler.NewHealthHandler()
|
||||
webauthnHandler, err := handler.NewWebauthnHandler(cfg, persister, sessionManager, auditLogger)
|
||||
healthHandler := NewHealthHandler()
|
||||
webauthnHandler, err := NewWebauthnHandler(cfg, persister, sessionManager, auditLogger)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to create public webauthn handler: %w", err))
|
||||
}
|
||||
passcodeHandler, err := handler.NewPasscodeHandler(cfg, persister, sessionManager, mailer, auditLogger)
|
||||
passcodeHandler, err := NewPasscodeHandler(cfg, persister, sessionManager, mailer, auditLogger)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to create public passcode handler: %w", err))
|
||||
}
|
||||
@ -94,7 +93,7 @@ func NewPublicRouter(cfg *config.Config, persister persistence.Persister, promet
|
||||
health.GET("/alive", healthHandler.Alive)
|
||||
health.GET("/ready", healthHandler.Ready)
|
||||
|
||||
wellKnownHandler, err := handler.NewWellKnownHandler(*cfg, jwkManager)
|
||||
wellKnownHandler, err := NewWellKnownHandler(*cfg, jwkManager)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to create well-known handler: %w", err))
|
||||
}
|
||||
@ -102,13 +101,13 @@ func NewPublicRouter(cfg *config.Config, persister persistence.Persister, promet
|
||||
wellKnown.GET("/jwks.json", wellKnownHandler.GetPublicKeys)
|
||||
wellKnown.GET("/config", wellKnownHandler.GetConfig)
|
||||
|
||||
emailHandler, err := handler.NewEmailHandler(cfg, persister, sessionManager, auditLogger)
|
||||
emailHandler, err := NewEmailHandler(cfg, persister, sessionManager, auditLogger)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to create public email handler: %w", err))
|
||||
}
|
||||
|
||||
webauthn := e.Group("/webauthn")
|
||||
webauthnRegistration := webauthn.Group("/registration", hankoMiddleware.Session(sessionManager))
|
||||
webauthnRegistration := webauthn.Group("/registration", middleware2.Session(sessionManager))
|
||||
webauthnRegistration.POST("/initialize", webauthnHandler.BeginRegistration)
|
||||
webauthnRegistration.POST("/finalize", webauthnHandler.FinishRegistration)
|
||||
|
||||
@ -116,7 +115,7 @@ func NewPublicRouter(cfg *config.Config, persister persistence.Persister, promet
|
||||
webauthnLogin.POST("/initialize", webauthnHandler.BeginAuthentication)
|
||||
webauthnLogin.POST("/finalize", webauthnHandler.FinishAuthentication)
|
||||
|
||||
webauthnCredentials := webauthn.Group("/credentials", hankoMiddleware.Session(sessionManager))
|
||||
webauthnCredentials := webauthn.Group("/credentials", middleware2.Session(sessionManager))
|
||||
webauthnCredentials.GET("", webauthnHandler.ListCredentials)
|
||||
webauthnCredentials.PATCH("/:id", webauthnHandler.UpdateCredential)
|
||||
webauthnCredentials.DELETE("/:id", webauthnHandler.DeleteCredential)
|
||||
@ -126,13 +125,13 @@ func NewPublicRouter(cfg *config.Config, persister persistence.Persister, promet
|
||||
passcodeLogin.POST("/initialize", passcodeHandler.Init)
|
||||
passcodeLogin.POST("/finalize", passcodeHandler.Finish)
|
||||
|
||||
email := e.Group("/emails", hankoMiddleware.Session(sessionManager))
|
||||
email := e.Group("/emails", middleware2.Session(sessionManager))
|
||||
email.GET("", emailHandler.List)
|
||||
email.POST("", emailHandler.Create)
|
||||
email.DELETE("/:id", emailHandler.Delete)
|
||||
email.POST("/:id/set_primary", emailHandler.SetPrimaryEmail)
|
||||
|
||||
thirdPartyHandler := handler.NewThirdPartyHandler(cfg, persister, sessionManager, auditLogger, jwkManager)
|
||||
thirdPartyHandler := NewThirdPartyHandler(cfg, persister, sessionManager, auditLogger, jwkManager)
|
||||
thirdparty := e.Group("thirdparty")
|
||||
thirdparty.GET("/auth", thirdPartyHandler.Auth)
|
||||
thirdparty.GET("/callback", thirdPartyHandler.Callback)
|
||||
@ -3,15 +3,16 @@ package handler
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gofrs/uuid"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/lestrrat-go/jwx/v2/jwt"
|
||||
_ "github.com/lib/pq"
|
||||
"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/persistence"
|
||||
"github.com/teamhanko/hanko/backend/persistence/models"
|
||||
"github.com/teamhanko/hanko/backend/session"
|
||||
"github.com/teamhanko/hanko/backend/test"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@ -24,75 +25,36 @@ func TestUserSuite(t *testing.T) {
|
||||
}
|
||||
|
||||
type userSuite struct {
|
||||
suite.Suite
|
||||
storage persistence.Storage
|
||||
db *test.TestDB
|
||||
}
|
||||
|
||||
func (s *userSuite) SetupSuite() {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
dialect := "postgres"
|
||||
db, err := test.StartDB("user_test", dialect)
|
||||
s.NoError(err)
|
||||
storage, err := persistence.New(config.Database{
|
||||
Url: db.DatabaseUrl,
|
||||
})
|
||||
s.NoError(err)
|
||||
|
||||
s.storage = storage
|
||||
s.db = db
|
||||
}
|
||||
|
||||
func (s *userSuite) SetupTest() {
|
||||
if s.db != nil {
|
||||
err := s.storage.MigrateUp()
|
||||
s.NoError(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *userSuite) TearDownTest() {
|
||||
if s.db != nil {
|
||||
err := s.storage.MigrateDown(-1)
|
||||
s.NoError(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *userSuite) TearDownSuite() {
|
||||
if s.db != nil {
|
||||
s.NoError(test.PurgeDB(s.db))
|
||||
}
|
||||
test.Suite
|
||||
}
|
||||
|
||||
func (s *userSuite) TestUserHandler_Create() {
|
||||
if testing.Short() {
|
||||
s.T().Skip("skipping test in short mode.")
|
||||
}
|
||||
e := echo.New()
|
||||
e.Validator = dto.NewCustomValidator()
|
||||
e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil)
|
||||
|
||||
body := UserCreateBody{Email: "jane.doe@example.com"}
|
||||
bodyJson, err := json.Marshal(body)
|
||||
s.NoError(err)
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/users", bytes.NewReader(bodyJson))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
rec := httptest.NewRecorder()
|
||||
c := e.NewContext(req, rec)
|
||||
|
||||
handler := NewUserHandler(&defaultConfig, s.storage, sessionManager{}, test.NewAuditLogger())
|
||||
e.ServeHTTP(rec, req)
|
||||
|
||||
if s.NoError(handler.Create(c)) {
|
||||
if s.Equal(http.StatusOK, rec.Result().StatusCode) {
|
||||
user := models.User{}
|
||||
err := json.Unmarshal(rec.Body.Bytes(), &user)
|
||||
s.NoError(err)
|
||||
s.False(user.ID.IsNil())
|
||||
|
||||
count, err := s.storage.GetUserPersister().Count(uuid.Nil, "")
|
||||
count, err := s.Storage.GetUserPersister().Count(uuid.Nil, "")
|
||||
s.NoError(err)
|
||||
s.Equal(1, count)
|
||||
|
||||
email, err := s.storage.GetEmailPersister().FindByAddress(body.Email)
|
||||
email, err := s.Storage.GetEmailPersister().FindByAddress(body.Email)
|
||||
s.NoError(err)
|
||||
s.NotNil(email)
|
||||
}
|
||||
@ -102,30 +64,29 @@ func (s *userSuite) TestUserHandler_Create_CaseInsensitive() {
|
||||
if testing.Short() {
|
||||
s.T().Skip("skipping test in short mode.")
|
||||
}
|
||||
e := echo.New()
|
||||
e.Validator = dto.NewCustomValidator()
|
||||
e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil)
|
||||
|
||||
body := UserCreateBody{Email: "JANE.DOE@EXAMPLE.COM"}
|
||||
bodyJson, err := json.Marshal(body)
|
||||
s.NoError(err)
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/users", bytes.NewReader(bodyJson))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
rec := httptest.NewRecorder()
|
||||
c := e.NewContext(req, rec)
|
||||
|
||||
handler := NewUserHandler(&defaultConfig, s.storage, sessionManager{}, test.NewAuditLogger())
|
||||
e.ServeHTTP(rec, req)
|
||||
|
||||
if s.NoError(handler.Create(c)) {
|
||||
if s.Equal(http.StatusOK, rec.Result().StatusCode) {
|
||||
user := models.User{}
|
||||
err := json.Unmarshal(rec.Body.Bytes(), &user)
|
||||
s.NoError(err)
|
||||
s.False(user.ID.IsNil())
|
||||
|
||||
count, err := s.storage.GetUserPersister().Count(uuid.Nil, "")
|
||||
count, err := s.Storage.GetUserPersister().Count(uuid.Nil, "")
|
||||
s.NoError(err)
|
||||
s.Equal(1, count)
|
||||
|
||||
email, err := s.storage.GetEmailPersister().FindByAddress(strings.ToLower(body.Email))
|
||||
email, err := s.Storage.GetEmailPersister().FindByAddress(strings.ToLower(body.Email))
|
||||
s.NoError(err)
|
||||
s.NotNil(email)
|
||||
}
|
||||
@ -135,24 +96,25 @@ func (s *userSuite) TestUserHandler_Create_UserExists() {
|
||||
if testing.Short() {
|
||||
s.T().Skip("skipping test in short mode.")
|
||||
}
|
||||
err := test.LoadFixtures(s.db.DbCon, s.db.Dialect, "../test/fixtures/user")
|
||||
err := s.LoadFixtures("../test/fixtures/user")
|
||||
s.Require().NoError(err)
|
||||
|
||||
e := echo.New()
|
||||
e.Validator = dto.NewCustomValidator()
|
||||
e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil)
|
||||
|
||||
body := UserCreateBody{Email: "john.doe@example.com"}
|
||||
bodyJson, err := json.Marshal(body)
|
||||
s.NoError(err)
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/users", bytes.NewReader(bodyJson))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
rec := httptest.NewRecorder()
|
||||
c := e.NewContext(req, rec)
|
||||
|
||||
handler := NewUserHandler(&defaultConfig, s.storage, sessionManager{}, test.NewAuditLogger())
|
||||
e.ServeHTTP(rec, req)
|
||||
|
||||
err = handler.Create(c)
|
||||
if s.Error(err) {
|
||||
httpError := dto.ToHttpError(err)
|
||||
if s.Equal(http.StatusConflict, rec.Result().StatusCode) {
|
||||
httpError := dto.HTTPError{}
|
||||
err := json.Unmarshal(rec.Body.Bytes(), &httpError)
|
||||
s.NoError(err)
|
||||
s.Equal(http.StatusConflict, httpError.Code)
|
||||
}
|
||||
}
|
||||
@ -161,60 +123,65 @@ func (s *userSuite) TestUserHandler_Create_UserExists_CaseInsensitive() {
|
||||
if testing.Short() {
|
||||
s.T().Skip("skipping test in short mode.")
|
||||
}
|
||||
err := test.LoadFixtures(s.db.DbCon, s.db.Dialect, "../test/fixtures/user")
|
||||
err := s.LoadFixtures("../test/fixtures/user")
|
||||
s.Require().NoError(err)
|
||||
|
||||
e := echo.New()
|
||||
e.Validator = dto.NewCustomValidator()
|
||||
e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil)
|
||||
|
||||
body := UserCreateBody{Email: "JOHN.DOE@EXAMPLE.COM"}
|
||||
bodyJson, err := json.Marshal(body)
|
||||
s.NoError(err)
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/users", bytes.NewReader(bodyJson))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
rec := httptest.NewRecorder()
|
||||
c := e.NewContext(req, rec)
|
||||
|
||||
handler := NewUserHandler(&defaultConfig, s.storage, sessionManager{}, test.NewAuditLogger())
|
||||
e.ServeHTTP(rec, req)
|
||||
|
||||
err = handler.Create(c)
|
||||
if s.Error(err) {
|
||||
httpError := dto.ToHttpError(err)
|
||||
if s.Equal(http.StatusConflict, rec.Result().StatusCode) {
|
||||
httpError := dto.HTTPError{}
|
||||
err := json.Unmarshal(rec.Body.Bytes(), &httpError)
|
||||
s.NoError(err)
|
||||
s.Equal(http.StatusConflict, httpError.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *userSuite) TestUserHandler_Create_InvalidEmail() {
|
||||
e := echo.New()
|
||||
e.Validator = dto.NewCustomValidator()
|
||||
if testing.Short() {
|
||||
s.T().Skip("skipping test in short mode.")
|
||||
}
|
||||
e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil)
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/users", strings.NewReader(`{"email": 123"}`))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
rec := httptest.NewRecorder()
|
||||
c := e.NewContext(req, rec)
|
||||
|
||||
handler := NewUserHandler(&defaultConfig, nil, nil, nil)
|
||||
e.ServeHTTP(rec, req)
|
||||
|
||||
err := handler.Create(c)
|
||||
if s.Error(err) {
|
||||
httpError := dto.ToHttpError(err)
|
||||
if s.Equal(http.StatusBadRequest, rec.Result().StatusCode) {
|
||||
httpError := dto.HTTPError{}
|
||||
err := json.Unmarshal(rec.Body.Bytes(), &httpError)
|
||||
s.NoError(err)
|
||||
s.Equal(http.StatusBadRequest, httpError.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *userSuite) TestUserHandler_Create_EmailMissing() {
|
||||
e := echo.New()
|
||||
e.Validator = dto.NewCustomValidator()
|
||||
if testing.Short() {
|
||||
s.T().Skip("skipping test in short mode.")
|
||||
}
|
||||
e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil)
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/users", strings.NewReader(`{"bogus": 123}`))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
rec := httptest.NewRecorder()
|
||||
c := e.NewContext(req, rec)
|
||||
|
||||
handler := NewUserHandler(&defaultConfig, nil, nil, nil)
|
||||
e.ServeHTTP(rec, req)
|
||||
|
||||
err := handler.Create(c)
|
||||
if s.Error(err) {
|
||||
httpError := dto.ToHttpError(err)
|
||||
if s.Equal(http.StatusBadRequest, rec.Result().StatusCode) {
|
||||
httpError := dto.HTTPError{}
|
||||
err := json.Unmarshal(rec.Body.Bytes(), &httpError)
|
||||
s.NoError(err)
|
||||
s.Equal(http.StatusBadRequest, httpError.Code)
|
||||
}
|
||||
}
|
||||
@ -223,27 +190,33 @@ func (s *userSuite) TestUserHandler_Get() {
|
||||
if testing.Short() {
|
||||
s.T().Skip("skipping test in short mode.")
|
||||
}
|
||||
err := test.LoadFixtures(s.db.DbCon, s.db.Dialect, "../test/fixtures/user")
|
||||
err := s.LoadFixtures("../test/fixtures/user")
|
||||
s.Require().NoError(err)
|
||||
|
||||
userId := "b5dd5267-b462-48be-b70d-bcd6f1bbe7a5"
|
||||
|
||||
e := echo.New()
|
||||
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
c := e.NewContext(req, rec)
|
||||
c.SetPath("/users/:id")
|
||||
c.SetParamNames("id")
|
||||
c.SetParamValues(userId)
|
||||
e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil)
|
||||
|
||||
token := jwt.New()
|
||||
err = token.Set(jwt.SubjectKey, userId)
|
||||
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.Session)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to create session generator: %w", err))
|
||||
}
|
||||
token, err := sessionManager.GenerateJWT(uuid.FromStringOrNil(userId))
|
||||
s.Require().NoError(err)
|
||||
cookie, err := sessionManager.GenerateCookie(token)
|
||||
s.Require().NoError(err)
|
||||
c.Set("session", token)
|
||||
|
||||
handler := NewUserHandler(&defaultConfig, s.storage, sessionManager{}, test.NewAuditLogger())
|
||||
req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/users/%s", userId), nil)
|
||||
req.AddCookie(cookie)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
if s.NoError(handler.Get(c)) {
|
||||
e.ServeHTTP(rec, req)
|
||||
|
||||
if s.Equal(http.StatusOK, rec.Result().StatusCode) {
|
||||
s.Equal(rec.Code, http.StatusOK)
|
||||
user := models.User{}
|
||||
err := json.Unmarshal(rec.Body.Bytes(), &user)
|
||||
@ -257,7 +230,7 @@ func (s *userSuite) TestUserHandler_GetUserWithWebAuthnCredential() {
|
||||
if testing.Short() {
|
||||
s.T().Skip("skipping test in short mode.")
|
||||
}
|
||||
err := test.LoadFixtures(s.db.DbCon, s.db.Dialect, "../test/fixtures/user_with_webauthn_credential")
|
||||
err := s.LoadFixtures("../test/fixtures/user_with_webauthn_credential")
|
||||
s.Require().NoError(err)
|
||||
|
||||
userId := "b5dd5267-b462-48be-b70d-bcd6f1bbe7a5"
|
||||
@ -275,7 +248,7 @@ func (s *userSuite) TestUserHandler_GetUserWithWebAuthnCredential() {
|
||||
s.Require().NoError(err)
|
||||
c.Set("session", token)
|
||||
|
||||
handler := NewUserHandler(&defaultConfig, s.storage, sessionManager{}, test.NewAuditLogger())
|
||||
handler := NewUserHandler(&defaultConfig, s.Storage, sessionManager{}, test.NewAuditLogger())
|
||||
|
||||
if s.NoError(handler.Get(c)) {
|
||||
s.Equal(rec.Code, http.StatusOK)
|
||||
@ -348,7 +321,7 @@ func (s *userSuite) TestUserHandler_GetUserIdByEmail_UserNotFound() {
|
||||
rec := httptest.NewRecorder()
|
||||
c := e.NewContext(req, rec)
|
||||
|
||||
handler := NewUserHandler(&defaultConfig, s.storage, sessionManager{}, test.NewAuditLogger())
|
||||
handler := NewUserHandler(&defaultConfig, s.Storage, sessionManager{}, test.NewAuditLogger())
|
||||
|
||||
err := handler.GetUserIdByEmail(c)
|
||||
if s.Error(err) {
|
||||
@ -361,7 +334,7 @@ func (s *userSuite) TestUserHandler_GetUserIdByEmail() {
|
||||
if testing.Short() {
|
||||
s.T().Skip("skipping test in short mode.")
|
||||
}
|
||||
err := test.LoadFixtures(s.db.DbCon, s.db.Dialect, "../test/fixtures/user_with_webauthn_credential")
|
||||
err := s.LoadFixtures("../test/fixtures/user_with_webauthn_credential")
|
||||
s.Require().NoError(err)
|
||||
|
||||
userId := "b5dd5267-b462-48be-b70d-bcd6f1bbe7a5"
|
||||
@ -373,7 +346,7 @@ func (s *userSuite) TestUserHandler_GetUserIdByEmail() {
|
||||
rec := httptest.NewRecorder()
|
||||
c := e.NewContext(req, rec)
|
||||
|
||||
handler := NewUserHandler(&defaultConfig, s.storage, sessionManager{}, test.NewAuditLogger())
|
||||
handler := NewUserHandler(&defaultConfig, s.Storage, sessionManager{}, test.NewAuditLogger())
|
||||
|
||||
if s.NoError(handler.GetUserIdByEmail(c)) {
|
||||
s.Equal(http.StatusOK, rec.Code)
|
||||
@ -392,7 +365,7 @@ func (s *userSuite) TestUserHandler_GetUserIdByEmail_CaseInsensitive() {
|
||||
if testing.Short() {
|
||||
s.T().Skip("skipping test in short mode.")
|
||||
}
|
||||
err := test.LoadFixtures(s.db.DbCon, s.db.Dialect, "../test/fixtures/user_with_webauthn_credential")
|
||||
err := s.LoadFixtures("../test/fixtures/user_with_webauthn_credential")
|
||||
s.Require().NoError(err)
|
||||
|
||||
userId := "b5dd5267-b462-48be-b70d-bcd6f1bbe7a5"
|
||||
@ -404,7 +377,7 @@ func (s *userSuite) TestUserHandler_GetUserIdByEmail_CaseInsensitive() {
|
||||
rec := httptest.NewRecorder()
|
||||
c := e.NewContext(req, rec)
|
||||
|
||||
handler := NewUserHandler(&defaultConfig, s.storage, sessionManager{}, test.NewAuditLogger())
|
||||
handler := NewUserHandler(&defaultConfig, s.Storage, sessionManager{}, test.NewAuditLogger())
|
||||
|
||||
if s.NoError(handler.GetUserIdByEmail(c)) {
|
||||
s.Equal(http.StatusOK, rec.Code)
|
||||
@ -423,7 +396,7 @@ func (s *userSuite) TestUserHandler_Me() {
|
||||
if testing.Short() {
|
||||
s.T().Skip("skipping test in short mode.")
|
||||
}
|
||||
err := test.LoadFixtures(s.db.DbCon, s.db.Dialect, "../test/fixtures/user_with_webauthn_credential")
|
||||
err := s.LoadFixtures("../test/fixtures/user_with_webauthn_credential")
|
||||
s.Require().NoError(err)
|
||||
|
||||
userId := "b5dd5267-b462-48be-b70d-bcd6f1bbe7a5"
|
||||
@ -439,7 +412,7 @@ func (s *userSuite) TestUserHandler_Me() {
|
||||
s.Require().NoError(err)
|
||||
c.Set("session", token)
|
||||
|
||||
handler := NewUserHandler(&defaultConfig, s.storage, sessionManager{}, test.NewAuditLogger())
|
||||
handler := NewUserHandler(&defaultConfig, s.Storage, sessionManager{}, test.NewAuditLogger())
|
||||
|
||||
if s.NoError(handler.Me(c)) {
|
||||
s.Equal(http.StatusOK, rec.Code)
|
||||
@ -466,7 +439,7 @@ func (s *userSuite) TestUserHandler_Logout() {
|
||||
s.NoError(err)
|
||||
c.Set("session", token)
|
||||
|
||||
handler := NewUserHandler(&defaultConfig, s.storage, sessionManager{}, test.NewAuditLogger())
|
||||
handler := NewUserHandler(&defaultConfig, s.Storage, sessionManager{}, test.NewAuditLogger())
|
||||
|
||||
if s.NoError(handler.Logout(c)) {
|
||||
s.Equal(http.StatusNoContent, rec.Code)
|
||||
|
||||
@ -176,6 +176,13 @@ var defaultConfig = config.Config{
|
||||
},
|
||||
Timeout: 60000,
|
||||
},
|
||||
Secrets: config.Secrets{
|
||||
Keys: []string{"abcdefghijklmnop"},
|
||||
},
|
||||
Passcode: config.Passcode{Smtp: config.SMTP{
|
||||
Host: "localhost",
|
||||
Port: "2500",
|
||||
}},
|
||||
}
|
||||
|
||||
type sessionManager struct {
|
||||
|
||||
@ -3,18 +3,19 @@ package server
|
||||
import (
|
||||
"github.com/labstack/echo-contrib/prometheus"
|
||||
"github.com/teamhanko/hanko/backend/config"
|
||||
"github.com/teamhanko/hanko/backend/handler"
|
||||
"github.com/teamhanko/hanko/backend/persistence"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func StartPublic(cfg *config.Config, wg *sync.WaitGroup, persister persistence.Persister, prometheus *prometheus.Prometheus) {
|
||||
defer wg.Done()
|
||||
router := NewPublicRouter(cfg, persister, prometheus)
|
||||
router := handler.NewPublicRouter(cfg, persister, prometheus)
|
||||
router.Logger.Fatal(router.Start(cfg.Server.Public.Address))
|
||||
}
|
||||
|
||||
func StartAdmin(cfg *config.Config, wg *sync.WaitGroup, persister persistence.Persister, prometheus *prometheus.Prometheus) {
|
||||
defer wg.Done()
|
||||
router := NewAdminRouter(cfg, persister, prometheus)
|
||||
router := handler.NewAdminRouter(cfg, persister, prometheus)
|
||||
router.Logger.Fatal(router.Start(cfg.Server.Admin.Address))
|
||||
}
|
||||
|
||||
22
backend/test/config.go
Normal file
22
backend/test/config.go
Normal file
@ -0,0 +1,22 @@
|
||||
package test
|
||||
|
||||
import "github.com/teamhanko/hanko/backend/config"
|
||||
|
||||
var DefaultConfig = config.Config{
|
||||
Webauthn: config.WebauthnSettings{
|
||||
RelyingParty: config.RelyingParty{
|
||||
Id: "localhost",
|
||||
DisplayName: "Test Relying Party",
|
||||
Icon: "",
|
||||
Origin: "http://localhost:8080",
|
||||
},
|
||||
Timeout: 60000,
|
||||
},
|
||||
Secrets: config.Secrets{
|
||||
Keys: []string{"abcdefghijklmnop"},
|
||||
},
|
||||
Passcode: config.Passcode{Smtp: config.SMTP{
|
||||
Host: "localhost",
|
||||
Port: "2500",
|
||||
}},
|
||||
}
|
||||
@ -4,7 +4,6 @@ import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/go-testfixtures/testfixtures/v3"
|
||||
_ "github.com/lib/pq"
|
||||
"github.com/ory/dockertest/v3"
|
||||
"github.com/ory/dockertest/v3/docker"
|
||||
@ -101,7 +100,7 @@ func getContainerOptions(dialect string) (*dockertest.RunOptions, error) {
|
||||
case "postgres":
|
||||
return &dockertest.RunOptions{
|
||||
Repository: "postgres",
|
||||
Tag: "11",
|
||||
Tag: "12-alpine",
|
||||
Env: []string{
|
||||
fmt.Sprintf("POSTGRES_PASSWORD=%s", database_password),
|
||||
fmt.Sprintf("POSTGRES_USER=%s", database_user),
|
||||
@ -137,22 +136,3 @@ func getPortID(dialect string) string {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// LoadFixtures loads predefined data from the path in the database.
|
||||
func LoadFixtures(db *sql.DB, dialect string, path string) error {
|
||||
fixtures, err := testfixtures.New(
|
||||
testfixtures.Database(db),
|
||||
testfixtures.Dialect(dialect),
|
||||
testfixtures.Directory(path),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create testfixtures: %w", err)
|
||||
}
|
||||
|
||||
err = fixtures.Load()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not load fixtures: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
31
backend/test/random.go
Normal file
31
backend/test/random.go
Normal file
@ -0,0 +1,31 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
)
|
||||
|
||||
// GenerateRandomBytes returns securely generated random bytes.
|
||||
// It will return an error if the system's secure random
|
||||
// number generator fails to function correctly, in which
|
||||
// case the caller should not continue.
|
||||
func GenerateRandomBytes(n int) ([]byte, error) {
|
||||
b := make([]byte, n)
|
||||
_, err := rand.Read(b)
|
||||
// Note that err == nil only if we read len(b) bytes.
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// GenerateRandomStringURLSafe returns a URL-safe, base64 encoded
|
||||
// securely generated random string.
|
||||
// It will return an error if the system's secure random
|
||||
// number generator fails to function correctly, in which
|
||||
// case the caller should not continue.
|
||||
func GenerateRandomStringURLSafe(n int) (string, error) {
|
||||
b, err := GenerateRandomBytes(n)
|
||||
return base64.URLEncoding.EncodeToString(b), err
|
||||
}
|
||||
89
backend/test/suite.go
Normal file
89
backend/test/suite.go
Normal file
@ -0,0 +1,89 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/go-testfixtures/testfixtures/v3"
|
||||
"github.com/gobuffalo/pop/v6"
|
||||
"github.com/gobuffalo/pop/v6/logging"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"github.com/teamhanko/hanko/backend/config"
|
||||
"github.com/teamhanko/hanko/backend/persistence"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type Suite struct {
|
||||
suite.Suite
|
||||
Storage persistence.Storage
|
||||
DB *TestDB
|
||||
Name string // used for database docker container name, so that tests can run in parallel
|
||||
}
|
||||
|
||||
func (s *Suite) SetupSuite() {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
//pop.SetLogger(testLogger)
|
||||
pop.Debug = true
|
||||
if s.Name == "" {
|
||||
var err error
|
||||
s.Name, err = GenerateRandomStringURLSafe(5)
|
||||
s.Name = strings.ReplaceAll(s.Name, "=", "")
|
||||
if err != nil {
|
||||
s.Fail("failed to generate database container name")
|
||||
}
|
||||
}
|
||||
dialect := "postgres"
|
||||
db, err := StartDB(s.Name, dialect)
|
||||
s.NoError(err)
|
||||
storage, err := persistence.New(config.Database{
|
||||
Url: db.DatabaseUrl,
|
||||
})
|
||||
s.NoError(err)
|
||||
|
||||
s.Storage = storage
|
||||
s.DB = db
|
||||
}
|
||||
|
||||
func (s *Suite) SetupTest() {
|
||||
if s.DB != nil {
|
||||
err := s.Storage.MigrateUp()
|
||||
s.NoError(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Suite) TearDownTest() {
|
||||
if s.DB != nil {
|
||||
err := s.Storage.MigrateDown(-1)
|
||||
s.NoError(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Suite) TearDownSuite() {
|
||||
if s.DB != nil {
|
||||
s.NoError(PurgeDB(s.DB))
|
||||
}
|
||||
}
|
||||
|
||||
// LoadFixtures loads predefined data from the path in the database.
|
||||
func (s *Suite) LoadFixtures(path string) error {
|
||||
fixtures, err := testfixtures.New(
|
||||
testfixtures.Database(s.DB.DbCon),
|
||||
testfixtures.Dialect(s.DB.Dialect),
|
||||
testfixtures.Directory(path),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create testfixtures: %w", err)
|
||||
}
|
||||
|
||||
err = fixtures.Load()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not load fixtures: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testLogger(level logging.Level, s string, args ...interface{}) {
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user