forked from baron/baron-sso
Resolve merge conflicts with main
This commit is contained in:
@@ -158,6 +158,28 @@ func main() {
|
||||
slog.Warn("Failed to connect to Redis. Auth features may fail.", "error", err)
|
||||
}
|
||||
|
||||
// Oathkeeper 상태를 주기적으로 확인해 다운을 감지합니다.
|
||||
var oathkeeperProbe *HTTPProbe
|
||||
if strings.ToLower(getEnv("OATHKEEPER_HEALTH_ENABLED", "true")) != "false" {
|
||||
intervalSec, err := strconv.Atoi(getEnv("OATHKEEPER_HEALTH_INTERVAL_SECONDS", "10"))
|
||||
if err != nil || intervalSec <= 0 {
|
||||
intervalSec = 10
|
||||
}
|
||||
timeoutSec, err := strconv.Atoi(getEnv("OATHKEEPER_HEALTH_TIMEOUT_SECONDS", "2"))
|
||||
if err != nil || timeoutSec <= 0 {
|
||||
timeoutSec = 2
|
||||
}
|
||||
oathkeeperProbe = NewHTTPProbe(
|
||||
"oathkeeper",
|
||||
getEnv("OATHKEEPER_HEALTH_URL", "http://oathkeeper:4456/health/ready"),
|
||||
time.Duration(intervalSec)*time.Second,
|
||||
time.Duration(timeoutSec)*time.Second,
|
||||
)
|
||||
oathkeeperProbe.Start()
|
||||
} else {
|
||||
slog.Info("Oathkeeper probe disabled")
|
||||
}
|
||||
|
||||
// 2. Initialize Handlers
|
||||
auditHandler := handler.NewAuditHandler(auditRepo)
|
||||
authHandler := handler.NewAuthHandler(redisService, idpProvider)
|
||||
@@ -249,10 +271,14 @@ func main() {
|
||||
app.Use(recover.New(recover.Config{
|
||||
EnableStackTrace: true,
|
||||
}))
|
||||
|
||||
allowedOrigins := getEnv("CORS_ALLOWED_ORIGINS", "http://localhost:5000")
|
||||
allowCredentials := allowedOrigins != "*"
|
||||
app.Use(cors.New(cors.Config{
|
||||
AllowOrigins: "*", // Adjust in production
|
||||
AllowHeaders: "Origin, Content-Type, Accept, Authorization",
|
||||
AllowMethods: "GET, POST, HEAD, PUT, DELETE, PATCH, OPTIONS",
|
||||
AllowOrigins: allowedOrigins,
|
||||
AllowHeaders: "Origin, Content-Type, Accept, Authorization",
|
||||
AllowMethods: "GET, POST, HEAD, PUT, DELETE, PATCH, OPTIONS",
|
||||
AllowCredentials: allowCredentials,
|
||||
}))
|
||||
|
||||
// Ensure COOKIE_SECRET is exactly 32 bytes for AES-256
|
||||
@@ -271,24 +297,30 @@ func main() {
|
||||
Key: cookieSecret,
|
||||
}))
|
||||
|
||||
app.Get("/docs", func(c *fiber.Ctx) error {
|
||||
return c.SendFile("./docs/swagger-ui/index.html")
|
||||
})
|
||||
app.Get("/docs/", func(c *fiber.Ctx) error {
|
||||
return c.SendFile("./docs/swagger-ui/index.html")
|
||||
})
|
||||
app.Static("/docs", "./docs/swagger-ui")
|
||||
app.Get("/redoc", func(c *fiber.Ctx) error {
|
||||
return c.SendFile("./docs/redoc/index.html")
|
||||
})
|
||||
app.Get("/redoc/", func(c *fiber.Ctx) error {
|
||||
return c.SendFile("./docs/redoc/index.html")
|
||||
})
|
||||
app.Static("/redoc", "./docs/redoc")
|
||||
app.Get("/openapi.yaml", func(c *fiber.Ctx) error {
|
||||
c.Type("yaml")
|
||||
return c.SendFile("./docs/openapi.yaml")
|
||||
})
|
||||
// [Security] Disable Swagger/ReDoc in Production
|
||||
if appEnv != "production" {
|
||||
app.Get("/docs", func(c *fiber.Ctx) error {
|
||||
return c.SendFile("./docs/swagger-ui/index.html")
|
||||
})
|
||||
app.Get("/docs/", func(c *fiber.Ctx) error {
|
||||
return c.SendFile("./docs/swagger-ui/index.html")
|
||||
})
|
||||
app.Static("/docs", "./docs/swagger-ui")
|
||||
app.Get("/redoc", func(c *fiber.Ctx) error {
|
||||
return c.SendFile("./docs/redoc/index.html")
|
||||
})
|
||||
app.Get("/redoc/", func(c *fiber.Ctx) error {
|
||||
return c.SendFile("./docs/redoc/index.html")
|
||||
})
|
||||
app.Static("/redoc", "./docs/redoc")
|
||||
app.Get("/openapi.yaml", func(c *fiber.Ctx) error {
|
||||
c.Type("yaml")
|
||||
return c.SendFile("./docs/openapi.yaml")
|
||||
})
|
||||
slog.Info("📚 API Docs enabled", "swagger", "/docs", "redoc", "/redoc")
|
||||
} else {
|
||||
slog.Info("🔒 API Docs disabled in production")
|
||||
}
|
||||
|
||||
// Routes
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
@@ -325,6 +357,32 @@ func main() {
|
||||
status = "degraded"
|
||||
}
|
||||
|
||||
// Check Oathkeeper
|
||||
if oathkeeperProbe != nil {
|
||||
snapshot := oathkeeperProbe.Snapshot()
|
||||
switch snapshot.Status {
|
||||
case "ok":
|
||||
checks["oathkeeper"] = "ok"
|
||||
case "":
|
||||
checks["oathkeeper"] = "unknown"
|
||||
if status != "error" {
|
||||
status = "degraded"
|
||||
}
|
||||
default:
|
||||
if snapshot.Error == "" {
|
||||
checks["oathkeeper"] = "error"
|
||||
} else {
|
||||
checks["oathkeeper"] = "error: " + snapshot.Error
|
||||
}
|
||||
status = "error"
|
||||
}
|
||||
} else {
|
||||
checks["oathkeeper"] = "disabled"
|
||||
if status != "error" {
|
||||
status = "degraded"
|
||||
}
|
||||
}
|
||||
|
||||
if status == "error" {
|
||||
return c.Status(fiber.StatusServiceUnavailable).JSON(fiber.Map{
|
||||
"status": status,
|
||||
@@ -340,12 +398,19 @@ func main() {
|
||||
|
||||
// API Group
|
||||
api := app.Group("/api/v1")
|
||||
api.Use(middleware.RequireAudit(middleware.AuditRequiredConfig{
|
||||
|
||||
workerCount, _ := strconv.Atoi(getEnv("AUDIT_WORKER_COUNT", "5"))
|
||||
queueSize, _ := strconv.Atoi(getEnv("AUDIT_QUEUE_SIZE", "2000"))
|
||||
|
||||
api.Use(middleware.AuditMiddleware(middleware.AuditConfig{
|
||||
Repo: auditRepo,
|
||||
ExcludePaths: map[string]struct{}{
|
||||
"/api/v1/audit": {},
|
||||
"/api/v1/client-log": {},
|
||||
},
|
||||
BodyDump: true,
|
||||
WorkerCount: workerCount,
|
||||
QueueSize: queueSize,
|
||||
}))
|
||||
api.Post("/audit", auditHandler.CreateLog)
|
||||
api.Get("/audit", auditHandler.ListLogs)
|
||||
@@ -355,6 +420,8 @@ func main() {
|
||||
auth.Post("/enchanted-link/init", authHandler.InitEnchantedLink)
|
||||
auth.Post("/enchanted-link/poll", authHandler.PollEnchantedLink)
|
||||
auth.Post("/magic-link/verify", authHandler.VerifyMagicLink)
|
||||
auth.Post("/login/code/verify", authHandler.VerifyLoginCode)
|
||||
auth.Post("/login/code/verify-short", authHandler.VerifyLoginShortCode)
|
||||
auth.Post("/password/login", authHandler.PasswordLogin)
|
||||
auth.Post("/password/reset/initiate", authHandler.InitiatePasswordReset)
|
||||
// [Changed] Use Interstitial Page for GET to prevent Scanner consumption
|
||||
@@ -388,6 +455,7 @@ func main() {
|
||||
admin := api.Group("/admin")
|
||||
admin.Use(middleware.ApiKeyAuth(middleware.ApiKeyAuthConfig{DB: db})) // API Key 인증 추가
|
||||
admin.Get("/check", adminHandler.CheckAuth)
|
||||
admin.Get("/stats", adminHandler.GetSystemStats)
|
||||
admin.Get("/tenants", tenantHandler.ListTenants)
|
||||
admin.Post("/tenants", tenantHandler.CreateTenant)
|
||||
admin.Get("/tenants/:id", tenantHandler.GetTenant)
|
||||
@@ -423,6 +491,9 @@ func main() {
|
||||
// Webhook for Descope Generic Email Gateway (Fake Email Strategy)
|
||||
auth.Post("/webhooks/descope-email", authHandler.HandleDescopeEmailRelay)
|
||||
|
||||
// Webhook for Kratos courier (HTTP delivery)
|
||||
auth.Post("/webhooks/kratos-courier", authHandler.HandleKratosCourierRelay)
|
||||
|
||||
// Client Logging Route (Standardized & Flattened)
|
||||
api.Post("/client-log", func(c *fiber.Ctx) error {
|
||||
type LogReq struct {
|
||||
|
||||
Reference in New Issue
Block a user