From 124bdc147f0657cce8cb5c71072da41af652fcd0 Mon Sep 17 00:00:00 2001 From: Thushani Jayasekera Date: Sat, 20 Jun 2026 11:03:31 +0530 Subject: [PATCH] Enhance authentication configuration for production mode - Introduced `validateAuthConfig` function to enforce authentication requirements when demo mode is disabled. - Added checks for file-based authentication and JWT settings to ensure compliance with production standards. - Updated `LoadConfig` to provide clearer error messages regarding JWT secret key generation in demo mode. - Implemented self-signed certificate generation restrictions based on demo mode status. --- platform-api/src/config/config.go | 20 ++++++++++++++- platform-api/src/internal/server/server.go | 30 ++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/platform-api/src/config/config.go b/platform-api/src/config/config.go index 22d5955eb..37dc91bb2 100644 --- a/platform-api/src/config/config.go +++ b/platform-api/src/config/config.go @@ -23,6 +23,7 @@ import ( "encoding/json" "fmt" "log/slog" + "os" "reflect" "strings" "sync" @@ -295,12 +296,19 @@ func LoadConfig(configPath string) (*Server, error) { } if cfg.Auth.JWT.Enabled && cfg.Auth.JWT.SecretKey == "" { + if !demoMode() { + return nil, fmt.Errorf( + "AUTH_JWT_SECRET_KEY must be configured when APIP_DEMO_MODE=false and JWT authentication is enabled; " + + "generate a secret with: openssl rand -hex 32", + ) + } key, err := generateRandomSecret() if err != nil { return nil, fmt.Errorf("failed to generate JWT secret key: %w", err) } cfg.Auth.JWT.SecretKey = key - slog.Warn("auth.jwt.secret_key is not set — generated an ephemeral random key; all sessions will be invalidated on restart") + slog.Warn("JWT_SIGNING_SECRET not set — generated an ephemeral demo key (restart will invalidate all sessions)", + slog.String("JWT_SIGNING_SECRET", key)) } return cfg, nil @@ -314,6 +322,16 @@ func generateRandomSecret() (string, error) { return hex.EncodeToString(b), nil } +// demoMode reports whether APIP_DEMO_MODE is enabled. +// Defaults to true when the variable is unset. +func demoMode() bool { + v := strings.ToLower(strings.TrimSpace(os.Getenv("APIP_DEMO_MODE"))) + if v == "" { + return true + } + return v == "true" || v == "1" +} + // envToKoanfKey maps a lowercased environment variable name to its koanf dot-notation key. // Returns "" for unknown variables, which causes koanf to skip them. diff --git a/platform-api/src/internal/server/server.go b/platform-api/src/internal/server/server.go index 700d6e96c..4886f94e6 100644 --- a/platform-api/src/internal/server/server.go +++ b/platform-api/src/internal/server/server.go @@ -67,8 +67,30 @@ type Server struct { logger *slog.Logger } +// validateAuthConfig enforces production auth requirements when demo mode is off. +func validateAuthConfig(cfg *config.Server) error { + if demoMode() { + return nil + } + if cfg.Auth.FileBased.Enabled { + return fmt.Errorf("file-based authentication (AUTH_FILE_BASED_ENABLED=true) is not allowed when APIP_DEMO_MODE=false; configure an IDP (AUTH_IDP_ENABLED=true) or JWT (AUTH_JWT_ENABLED=true) instead") + } + if !cfg.Auth.IDP.Enabled && !cfg.Auth.JWT.Enabled { + return fmt.Errorf("APIP_DEMO_MODE=false requires a real auth mode; set AUTH_IDP_ENABLED=true or AUTH_JWT_ENABLED=true") + } + if cfg.Auth.JWT.Enabled && cfg.Auth.JWT.SkipValidation { + return fmt.Errorf("JWT signature validation cannot be skipped (AUTH_JWT_SKIP_VALIDATION=true) when APIP_DEMO_MODE=false; set AUTH_JWT_SKIP_VALIDATION=false for production") + } + return nil +} + // StartPlatformAPIServer creates a new server instance with all dependencies initialized func StartPlatformAPIServer(cfg *config.Server, slogger *slog.Logger) (*Server, error) { + if err := validateAuthConfig(cfg); err != nil { + slogger.Error("Invalid auth configuration for production mode", "error", err) + return nil, err + } + // Initialize database using configuration db, err := database.NewConnection(&cfg.Database, slogger) if err != nil { @@ -631,6 +653,14 @@ func (s *Server) Start(port string, certDir string) error { // Generate new certificate if not loaded if cert.Certificate == nil { + if !demoMode() { + return fmt.Errorf( + "no TLS certificates found at %q (cert.pem / key.pem) and APIP_DEMO_MODE=false: "+ + "mount real certificates or set TLS_CERT_DIR to a directory containing cert.pem and key.pem; "+ + "self-signed certificate generation is only permitted in demo mode", + certDir, + ) + } s.logger.Info("Generating self-signed certificate for development...") // Ensure cert directory exists if err := os.MkdirAll(certDir, 0755); err != nil {