package security import ( "context" "crypto/tls" "crypto/x509" "fmt" "net/http" "os" "strings" "time" "github.com/golang-jwt/jwt/v5" "github.com/sirupsen/logrus" "golang.org/x/oauth2" "golang.org/x/oauth2/clientcredentials" ) // AuthProvider defines the interface for authentication providers type AuthProvider interface { Authenticate(ctx context.Context, credentials interface{}) (*AuthResult, error) ValidateToken(token string) (*AuthResult, error) GetUserInfo(token string) (*UserInfo, error) } // AuthResult represents the result of an authentication attempt type AuthResult struct { Success bool User *UserInfo Token string ExpiresAt time.Time Permissions []string Metadata map[string]interface{} } // UserInfo represents authenticated user information type UserInfo struct { Username string Email string FullName string Groups []string Permissions []string Metadata map[string]interface{} } // AuthConfig represents authentication configuration type AuthConfig struct { Enabled bool `yaml:"enabled"` Provider string `yaml:"provider"` Kerberos KerberosConfig `yaml:"kerberos"` OIDC OIDCConfig `yaml:"oidc"` APIKey APIKeyConfig `yaml:"api_key"` SSL SSLConfig `yaml:"ssl"` RBAC RBACConfig `yaml:"rbac"` Audit AuditConfig `yaml:"audit"` Custom map[string]interface{} `yaml:"custom"` } // KerberosConfig represents Kerberos authentication configuration type KerberosConfig struct { Enabled bool `yaml:"enabled"` Realm string `yaml:"realm"` KeytabPath string `yaml:"keytab_path"` ServiceName string `yaml:"service_name"` Debug bool `yaml:"debug"` } // OIDCConfig represents OpenID Connect configuration type OIDCConfig struct { Enabled bool `yaml:"enabled"` IssuerURL string `yaml:"issuer_url"` ClientID string `yaml:"client_id"` ClientSecret string `yaml:"client_secret"` RedirectURL string `yaml:"redirect_url"` Scopes string `yaml:"scopes"` TokenEndpoint string `yaml:"token_endpoint"` UserInfoURL string `yaml:"userinfo_url"` JWKSURL string `yaml:"jwks_url"` } // APIKeyConfig represents API key authentication configuration type APIKeyConfig struct { Enabled bool `yaml:"enabled"` HeaderName string `yaml:"header_name"` QueryParam string `yaml:"query_param"` SecretPath string `yaml:"secret_path"` Algorithm string `yaml:"algorithm"` Expiration string `yaml:"expiration"` } // SSLConfig represents SSL/TLS configuration type SSLConfig struct { Enabled bool `yaml:"enabled"` CertFile string `yaml:"cert_file"` KeyFile string `yaml:"key_file"` CAFile string `yaml:"ca_file"` MinVersion string `yaml:"min_version"` MaxVersion string `yaml:"max_version"` CipherSuites []string `yaml:"cipher_suites"` } // RBACConfig represents role-based access control configuration type RBACConfig struct { Enabled bool `yaml:"enabled"` Roles map[string]RoleConfig `yaml:"roles"` Policies map[string]PolicyConfig `yaml:"policies"` DefaultRole string `yaml:"default_role"` } // RoleConfig represents a role configuration type RoleConfig struct { Name string `yaml:"name"` Description string `yaml:"description"` Permissions []string `yaml:"permissions"` Inherits []string `yaml:"inherits"` } // PolicyConfig represents a policy configuration type PolicyConfig struct { Name string `yaml:"name"` Description string `yaml:"description"` Effect string `yaml:"effect"` // allow, deny Resources []string `yaml:"resources"` Actions []string `yaml:"actions"` Conditions map[string]interface{} `yaml:"conditions"` } // AuditConfig represents audit logging configuration type AuditConfig struct { Enabled bool `yaml:"enabled"` LogFile string `yaml:"log_file"` LogLevel string `yaml:"log_level"` MaxSize int `yaml:"max_size"` MaxBackups int `yaml:"max_backups"` MaxAge int `yaml:"max_age"` } // AuthManager manages authentication and authorization type AuthManager struct { config *AuthConfig providers map[string]AuthProvider rbac *RBACManager audit *AuditLogger logger *logrus.Logger } // NewAuthManager creates a new authentication manager func NewAuthManager(config *AuthConfig) (*AuthManager, error) { am := &AuthManager{ config: config, providers: make(map[string]AuthProvider), logger: logrus.New(), } // Initialize RBAC if enabled if config.RBAC.Enabled { rbac, err := NewRBACManager(&config.RBAC) if err != nil { return nil, fmt.Errorf("failed to initialize RBAC: %w", err) } am.rbac = rbac } // Initialize audit logging if enabled if config.Audit.Enabled { audit, err := NewAuditLogger(&config.Audit) if err != nil { return nil, fmt.Errorf("failed to initialize audit logging: %w", err) } am.audit = audit } // Initialize authentication providers if err := am.initializeProviders(); err != nil { return nil, fmt.Errorf("failed to initialize authentication providers: %w", err) } return am, nil } // initializeProviders initializes all configured authentication providers func (am *AuthManager) initializeProviders() error { // Initialize Kerberos provider if enabled if am.config.Kerberos.Enabled { kerberos, err := NewKerberosProvider(&am.config.Kerberos) if err != nil { return fmt.Errorf("failed to initialize Kerberos provider: %w", err) } am.providers["kerberos"] = kerberos } // Initialize OIDC provider if enabled if am.config.OIDC.Enabled { oidc, err := NewOIDCProvider(&am.config.OIDC) if err != nil { return fmt.Errorf("failed to initialize OIDC provider: %w", err) } am.providers["oidc"] = oidc } // Initialize API key provider if enabled if am.config.APIKey.Enabled { apikey, err := NewAPIKeyProvider(&am.config.APIKey) if err != nil { return fmt.Errorf("failed to initialize API key provider: %w", err) } am.providers["apikey"] = apikey } return nil } // Authenticate authenticates a user using the specified provider func (am *AuthManager) Authenticate(ctx context.Context, provider string, credentials interface{}) (*AuthResult, error) { // Get the specified provider authProvider, exists := am.providers[provider] if !exists { return nil, fmt.Errorf("authentication provider %s not found", provider) } // Attempt authentication result, err := authProvider.Authenticate(ctx, credentials) if err != nil { am.logger.Errorf("Authentication failed for provider %s: %v", provider, err) return nil, err } // Log successful authentication if am.audit != nil { am.audit.LogAuthEvent("authentication_success", result.User.Username, provider, nil) } return result, nil } // ValidateToken validates an authentication token func (am *AuthManager) ValidateToken(token string) (*AuthResult, error) { // Try all providers to validate the token for providerName, provider := range am.providers { if result, err := provider.ValidateToken(token); err == nil { // Log token validation if am.audit != nil { am.audit.LogAuthEvent("token_validation", result.User.Username, providerName, nil) } return result, nil } } return nil, fmt.Errorf("invalid or expired token") } // Authorize checks if a user has permission to perform an action func (am *AuthManager) Authorize(user *UserInfo, resource, action string) bool { if am.rbac == nil { // If RBAC is disabled, allow all actions return true } // Check authorization using RBAC authorized := am.rbac.Authorize(user, resource, action) // Log authorization attempt if am.audit != nil { metadata := map[string]interface{}{ "resource": resource, "action": action, "result": authorized, } am.audit.LogAuthEvent("authorization_check", user.Username, "rbac", metadata) } return authorized } // GetTLSConfig returns TLS configuration for secure connections func (am *AuthManager) GetTLSConfig() (*tls.Config, error) { if !am.config.SSL.Enabled { return nil, nil } // Load certificate and key cert, err := tls.LoadX509KeyPair(am.config.SSL.CertFile, am.config.SSL.KeyFile) if err != nil { return nil, fmt.Errorf("failed to load TLS certificate: %w", err) } // Load CA certificate if specified var caPool *x509.CertPool if am.config.SSL.CAFile != "" { caData, err := os.ReadFile(am.config.SSL.CAFile) if err != nil { return nil, fmt.Errorf("failed to read CA file: %w", err) } caPool = x509.NewCertPool() if !caPool.AppendCertsFromPEM(caData) { return nil, fmt.Errorf("failed to parse CA certificate") } } // Create TLS config tlsConfig := &tls.Config{ Certificates: []tls.Certificate{cert}, RootCAs: caPool, MinVersion: tls.VersionTLS12, MaxVersion: tls.VersionTLS13, } // Set minimum version if specified if am.config.SSL.MinVersion != "" { switch strings.ToLower(am.config.SSL.MinVersion) { case "tls1.0": tlsConfig.MinVersion = tls.VersionTLS10 case "tls1.1": tlsConfig.MinVersion = tls.VersionTLS11 case "tls1.2": tlsConfig.MinVersion = tls.VersionTLS12 case "tls1.3": tlsConfig.MinVersion = tls.VersionTLS13 } } // Set maximum version if specified if am.config.SSL.MaxVersion != "" { switch strings.ToLower(am.config.SSL.MaxVersion) { case "tls1.0": tlsConfig.MaxVersion = tls.VersionTLS10 case "tls1.1": tlsConfig.MaxVersion = tls.VersionTLS11 case "tls1.2": tlsConfig.MaxVersion = tls.VersionTLS12 case "tls1.3": tlsConfig.MaxVersion = tls.VersionTLS13 } } return tlsConfig, nil } // GetHTTPClient returns an HTTP client with proper authentication func (am *AuthManager) GetHTTPClient() *http.Client { client := &http.Client{ Timeout: 30 * time.Second, } // Add TLS configuration if enabled if tlsConfig, err := am.GetTLSConfig(); err == nil && tlsConfig != nil { client.Transport = &http.Transport{ TLSClientConfig: tlsConfig, } } return client }