fetch_ml/internal/auth/validator.go
Jeremie Fraeys 803677be57 feat: implement Go backend with comprehensive API and internal packages
- Add API server with WebSocket support and REST endpoints
- Implement authentication system with API keys and permissions
- Add task queue system with Redis backend and error handling
- Include storage layer with database migrations and schemas
- Add comprehensive logging, metrics, and telemetry
- Implement security middleware and network utilities
- Add experiment management and container orchestration
- Include configuration management with smart defaults
2025-12-04 16:53:53 -05:00

100 lines
2.6 KiB
Go

package auth
import (
"fmt"
"log"
"os"
"strings"
)
// ValidateAuthConfig enforces authentication requirements
func (c *AuthConfig) ValidateAuthConfig() error {
// Check if we're in production environment
isProduction := os.Getenv("FETCH_ML_ENV") == "production"
if isProduction {
if !c.Enabled {
return fmt.Errorf("authentication must be enabled in production environment")
}
if len(c.APIKeys) == 0 {
return fmt.Errorf("at least one API key must be configured in production")
}
// Ensure at least one admin user exists
hasAdmin := false
for _, entry := range c.APIKeys {
if entry.Admin {
hasAdmin = true
break
}
}
if !hasAdmin {
return fmt.Errorf("at least one admin user must be configured in production")
}
// Check for insecure development override
if os.Getenv("FETCH_ML_ALLOW_INSECURE_AUTH") == "1" {
log.Printf("WARNING: FETCH_ML_ALLOW_INSECURE_AUTH is enabled in production - this is insecure")
}
}
// Validate API key format
for username, entry := range c.APIKeys {
if string(username) == "" {
return fmt.Errorf("empty username not allowed")
}
if entry.Hash == "" {
return fmt.Errorf("user %s has empty API key hash", username)
}
// Validate hash format (should be 64 hex chars for SHA256)
if len(entry.Hash) != 64 {
return fmt.Errorf("user %s has invalid API key hash format", username)
}
// Check hash contains only hex characters
for _, char := range entry.Hash {
if !((char >= '0' && char <= '9') || (char >= 'a' && char <= 'f') || (char >= 'A' && char <= 'F')) {
return fmt.Errorf("user %s has invalid API key hash characters", username)
}
}
}
return nil
}
// CheckConfigFilePermissions ensures config files have secure permissions
func CheckConfigFilePermissions(configPath string) error {
info, err := os.Stat(configPath)
if err != nil {
return fmt.Errorf("cannot stat config file: %w", err)
}
// Check file permissions (should be 600 or 640)
perm := info.Mode().Perm()
if perm&0077 != 0 {
return fmt.Errorf("config file %s has insecure permissions: %o (should be 600 or 640)", configPath, perm)
}
return nil
}
// SanitizeConfig removes sensitive information for logging
func (c *AuthConfig) SanitizeConfig() map[string]interface{} {
sanitized := map[string]interface{}{
"enabled": c.Enabled,
"users": make(map[string]interface{}),
}
for username := range c.APIKeys {
sanitized["users"].(map[string]interface{})[string(username)] = map[string]interface{}{
"admin": c.APIKeys[username].Admin,
"hash": strings.Repeat("*", 8) + "...", // Show only prefix
}
}
return sanitized
}