veza/veza-backend-api/internal/api/routes_auth.go

180 lines
6.5 KiB
Go

package api
import (
"fmt"
"os"
"time"
"github.com/gin-gonic/gin"
authcore "veza-backend-api/internal/core/auth"
"veza-backend-api/internal/handlers"
"veza-backend-api/internal/repositories"
"veza-backend-api/internal/services"
"veza-backend-api/internal/validators"
)
// setupAuthRoutes configure les routes d'authentification avec toutes les dépendances
func (r *APIRouter) setupAuthRoutes(router *gin.RouterGroup) error {
// 1. Instanciation des dépendances
emailValidator := validators.NewEmailValidator(r.db.GormDB)
passwordValidator := validators.NewPasswordValidator()
passwordService := services.NewPasswordService(r.db, r.logger)
passwordResetService := services.NewPasswordResetService(r.db, r.logger)
jwtService, err := services.NewJWTService(r.config.JWTSecret, r.config.JWTIssuer, r.config.JWTAudience)
if err != nil {
return fmt.Errorf("failed to initialize JWT service: %w", err)
}
refreshTokenService := services.NewRefreshTokenService(r.db.GormDB)
emailVerificationService := services.NewEmailVerificationService(r.db, r.logger)
emailService := services.NewEmailService(r.db, r.logger)
sessionService := services.NewSessionService(r.db, r.logger)
refreshLock := services.NewRefreshLock(r.config.RedisClient)
// 2. Service Auth complet
authService := authcore.NewAuthService(
r.db.GormDB,
emailValidator,
passwordValidator,
passwordService,
jwtService,
refreshTokenService,
emailVerificationService,
passwordResetService,
emailService,
r.config.JobWorker,
refreshLock,
r.logger,
)
// BE-SEC-007: Initialize account lockout service and set it on auth service
if r.config.RedisClient != nil {
lockoutConfig := &services.AccountLockoutConfig{
MaxAttempts: 5,
LockoutDuration: 30 * time.Minute,
WindowDuration: 15 * time.Minute,
ExemptEmails: r.config.AccountLockoutExemptEmails,
}
accountLockoutService := services.NewAccountLockoutServiceWithConfig(r.config.RedisClient, r.logger, lockoutConfig)
authService.SetAccountLockoutService(accountLockoutService)
} else {
r.logger.Warn("Redis not available - account lockout disabled")
}
r.authService = authService
// 2.5. User Service for GetMe endpoint
userRepo := repositories.NewGormUserRepository(r.db.GormDB)
userService := services.NewUserServiceWithDB(userRepo, r.db.GormDB)
// 3. Handlers
authGroup := router.Group("/auth")
{
// BE-SEC-005: Apply rate limiting to register endpoint (A04: toujours actif)
registerGroup := authGroup.Group("/register")
if r.config.EndpointLimiter != nil {
registerGroup.Use(r.config.EndpointLimiter.RegisterRateLimit())
}
registerGroup.POST("", handlers.Register(authService, sessionService, r.logger, r.config))
// BE-API-001: Initialize 2FA service for login handler
twoFactorService := services.NewTwoFactorService(r.db, r.logger)
// Apply rate limiting to login endpoint (PR-3)
loginGroup := authGroup.Group("/login")
if r.config.EndpointLimiter != nil {
loginGroup.Use(r.config.EndpointLimiter.LoginRateLimit())
}
loginGroup.POST("", handlers.Login(authService, sessionService, twoFactorService, r.logger, r.config))
loginGroup.POST("/2fa", handlers.LoginWith2FA(authService, sessionService, twoFactorService, r.logger, r.config))
authGroup.POST("/refresh", handlers.Refresh(authService, sessionService, r.logger, r.config))
// BE-SEC-005: Apply rate limiting to email verification endpoints
verifyEmailGroup := authGroup.Group("/verify-email")
if r.config.EndpointLimiter != nil {
verifyEmailGroup.Use(r.config.EndpointLimiter.VerifyEmailRateLimit())
}
verifyEmailGroup.POST("", handlers.VerifyEmail(authService))
resendVerificationGroup := authGroup.Group("/resend-verification")
if r.config.EndpointLimiter != nil {
resendVerificationGroup.Use(r.config.EndpointLimiter.ResendVerificationRateLimit())
}
resendVerificationGroup.POST("", handlers.ResendVerification(authService, r.logger))
authGroup.GET("/check-username", handlers.CheckUsername(authService))
// BE-API-042: OAuth routes
jwtSecretBytes := []byte(r.config.JWTSecret)
oauthService := services.NewOAuthService(r.db, r.logger, jwtSecretBytes)
baseURL := os.Getenv("BASE_URL")
if baseURL == "" {
appDomain := os.Getenv("APP_DOMAIN")
if appDomain == "" {
appDomain = "veza.fr"
}
baseURL = "http://" + appDomain + ":8080"
}
googleClientID := os.Getenv("OAUTH_GOOGLE_CLIENT_ID")
googleClientSecret := os.Getenv("OAUTH_GOOGLE_CLIENT_SECRET")
githubClientID := os.Getenv("OAUTH_GITHUB_CLIENT_ID")
githubClientSecret := os.Getenv("OAUTH_GITHUB_CLIENT_SECRET")
discordClientID := os.Getenv("OAUTH_DISCORD_CLIENT_ID")
discordClientSecret := os.Getenv("OAUTH_DISCORD_CLIENT_SECRET")
if googleClientID != "" && googleClientSecret != "" {
oauthService.InitializeConfigs(googleClientID, googleClientSecret, githubClientID, githubClientSecret, discordClientID, discordClientSecret, baseURL)
}
oauthHandler := handlers.NewOAuthHandler(oauthService, r.logger, r.config.CORSOrigins)
oauthGroup := authGroup.Group("/oauth")
{
oauthGroup.GET("/providers", oauthHandler.GetOAuthProviders)
oauthGroup.GET("/:provider", oauthHandler.InitiateOAuth)
oauthGroup.GET("/:provider/callback", oauthHandler.OAuthCallback)
}
// Password reset routes (public)
passwordGroup := authGroup.Group("/password")
if r.config.EndpointLimiter != nil {
passwordGroup.Use(r.config.EndpointLimiter.PasswordResetRateLimit())
}
{
auditService := services.NewAuditService(r.db, r.logger)
passwordGroup.POST("/reset-request", handlers.RequestPasswordReset(
passwordResetService,
passwordService,
emailService,
auditService,
r.logger,
))
passwordGroup.POST("/reset", handlers.ResetPassword(
passwordResetService,
passwordService,
authService,
sessionService,
auditService,
r.logger,
))
}
// Protected routes (authentification JWT requise)
protected := authGroup.Group("")
protected.Use(r.config.AuthMiddleware.RequireAuth())
r.applyCSRFProtection(protected)
{
protected.POST("/logout", handlers.Logout(authService, sessionService, r.logger, r.config))
protected.GET("/me", handlers.GetMe(userService))
twoFactorHandler := handlers.NewTwoFactorHandler(twoFactorService, userService, r.logger)
{
protected.POST("/2fa/setup", twoFactorHandler.SetupTwoFactor)
protected.POST("/2fa/verify", twoFactorHandler.VerifyTwoFactor)
protected.POST("/2fa/disable", twoFactorHandler.DisableTwoFactor)
protected.GET("/2fa/status", twoFactorHandler.GetTwoFactorStatus)
}
}
}
return nil
}