354 lines
10 KiB
Go
354 lines
10 KiB
Go
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
|
|
}
|