Files
michaelschiemer/docs/components/auth/configuration.md
Michael Schiemer 55a330b223 Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug
- Add DISCOVERY_SHOW_PROGRESS=true
- Temporary changes for debugging InitializerProcessor fixes on production
2025-08-11 20:13:26 +02:00

13 KiB

Auth Module Configuration

Konfiguration und Setup für das Auth Module des Custom PHP Frameworks.

Dependency Injection Setup

Container Bindings

use App\Framework\Auth\PasswordHasher;
use App\Framework\Auth\AuthenticationService;
use App\Framework\Cryptography\KeyDerivationFunction;

// services.php oder Container Initialization
$container->singleton(PasswordHasher::class, function(Container $container) {
    return new PasswordHasher(
        kdf: $container->get(KeyDerivationFunction::class),
        defaultAlgorithm: 'argon2id',
        defaultSecurityLevel: PasswordHasher::LEVEL_STANDARD
    );
});

$container->singleton(AuthenticationService::class, function(Container $container) {
    return new AuthenticationService(
        passwordHasher: $container->get(PasswordHasher::class),
        sessionIdGenerator: $container->get(SessionIdGenerator::class),
        repository: $container->get(AuthenticationRepository::class),
        rateLimiter: $container->get(RateLimitService::class)
    );
});

Environment Configuration

// .env Konfiguration
AUTH_SESSION_TIMEOUT=3600                    # Session Timeout in Sekunden (1 Stunde)
AUTH_REMEMBER_TOKEN_EXPIRY=2592000          # Remember Token Expiry (30 Tage)
AUTH_MAX_LOGIN_ATTEMPTS=5                   # Maximale Login-Versuche
AUTH_LOCKOUT_DURATION=900                   # Account Lockout Duration (15 Minuten)
AUTH_RATE_LIMIT_WINDOW=300                  # Rate Limit Window (5 Minuten)

# Password Hashing Configuration
AUTH_DEFAULT_ALGORITHM=argon2id             # Standard Hash-Algorithmus
AUTH_DEFAULT_SECURITY_LEVEL=standard       # low|standard|high
AUTH_PASSWORD_MIN_LENGTH=8                 # Minimale Passwort-Länge
AUTH_PASSWORD_MAX_LENGTH=4096              # Maximale Passwort-Länge

# Session Security
AUTH_SESSION_REGENERATE_ON_LOGIN=true      # Session ID bei Login regenerieren
AUTH_CHECK_IP_CONSISTENCY=false            # IP-Konsistenz-Prüfung (optional)
AUTH_REMEMBER_TOKEN_LENGTH=32              # Remember Token Länge (Bytes)

Typed Configuration Class

final readonly class AuthConfig
{
    public function __construct(
        // Session Configuration
        public int $sessionTimeout = 3600,
        public int $rememberTokenExpiry = 2592000,
        public bool $sessionRegenerateOnLogin = true,
        public bool $checkIpConsistency = false,
        public int $rememberTokenLength = 32,
        
        // Security Configuration  
        public int $maxLoginAttempts = 5,
        public int $lockoutDuration = 900,
        public int $rateLimitWindow = 300,
        
        // Password Configuration
        public string $defaultAlgorithm = 'argon2id',
        public string $defaultSecurityLevel = 'standard',
        public int $passwordMinLength = 8,
        public int $passwordMaxLength = 4096,
        
        // Validation Configuration
        public bool $enforcePasswordComplexity = true,
        public bool $checkCommonPasswords = true,
        public bool $preventSequentialChars = true,
        public int $minPasswordScore = 50
    ) {}
    
    public static function fromEnvironment(Environment $env): self
    {
        return new self(
            sessionTimeout: $env->getInt(EnvKey::AUTH_SESSION_TIMEOUT, 3600),
            rememberTokenExpiry: $env->getInt(EnvKey::AUTH_REMEMBER_TOKEN_EXPIRY, 2592000),
            sessionRegenerateOnLogin: $env->getBool(EnvKey::AUTH_SESSION_REGENERATE_ON_LOGIN, true),
            checkIpConsistency: $env->getBool(EnvKey::AUTH_CHECK_IP_CONSISTENCY, false),
            rememberTokenLength: $env->getInt(EnvKey::AUTH_REMEMBER_TOKEN_LENGTH, 32),
            
            maxLoginAttempts: $env->getInt(EnvKey::AUTH_MAX_LOGIN_ATTEMPTS, 5),
            lockoutDuration: $env->getInt(EnvKey::AUTH_LOCKOUT_DURATION, 900),
            rateLimitWindow: $env->getInt(EnvKey::AUTH_RATE_LIMIT_WINDOW, 300),
            
            defaultAlgorithm: $env->get(EnvKey::AUTH_DEFAULT_ALGORITHM, 'argon2id'),
            defaultSecurityLevel: $env->get(EnvKey::AUTH_DEFAULT_SECURITY_LEVEL, 'standard'),
            passwordMinLength: $env->getInt(EnvKey::AUTH_PASSWORD_MIN_LENGTH, 8),
            passwordMaxLength: $env->getInt(EnvKey::AUTH_PASSWORD_MAX_LENGTH, 4096),
            
            enforcePasswordComplexity: $env->getBool(EnvKey::AUTH_ENFORCE_PASSWORD_COMPLEXITY, true),
            checkCommonPasswords: $env->getBool(EnvKey::AUTH_CHECK_COMMON_PASSWORDS, true),
            preventSequentialChars: $env->getBool(EnvKey::AUTH_PREVENT_SEQUENTIAL_CHARS, true),
            minPasswordScore: $env->getInt(EnvKey::AUTH_MIN_PASSWORD_SCORE, 50)
        );
    }
    
    public function getSecurityLevelParameters(string $algorithm): array
    {
        return match ([$algorithm, $this->defaultSecurityLevel]) {
            ['argon2id', 'low'] => [
                'memory_cost' => 32768,   // 32 MB
                'time_cost' => 2,
                'threads' => 2
            ],
            ['argon2id', 'standard'] => [
                'memory_cost' => 65536,   // 64 MB
                'time_cost' => 4,
                'threads' => 3
            ],
            ['argon2id', 'high'] => [
                'memory_cost' => 131072,  // 128 MB
                'time_cost' => 6,
                'threads' => 4
            ],
            ['pbkdf2-sha256', 'low'] => ['iterations' => 50000],
            ['pbkdf2-sha256', 'standard'] => ['iterations' => 100000],
            ['pbkdf2-sha256', 'high'] => ['iterations' => 200000],
            default => []
        };
    }
}

Database Schema

Required Tables

-- Benutzer-Tabelle (beispielhaft)
CREATE TABLE users (
    id VARCHAR(255) PRIMARY KEY,
    email VARCHAR(255) UNIQUE NOT NULL,
    username VARCHAR(100) UNIQUE,
    password_hash TEXT NOT NULL,
    password_algorithm VARCHAR(50) NOT NULL DEFAULT 'argon2id',
    password_parameters JSON,
    created_at DATETIME NOT NULL,
    updated_at DATETIME NOT NULL,
    last_login_at DATETIME NULL,
    is_active BOOLEAN DEFAULT TRUE,
    
    INDEX idx_email (email),
    INDEX idx_username (username),
    INDEX idx_active (is_active)
);

-- Session-Tabelle
CREATE TABLE auth_sessions (
    id VARCHAR(255) PRIMARY KEY,
    user_id VARCHAR(255) NOT NULL,
    ip_address VARCHAR(45),
    user_agent TEXT,
    created_at DATETIME NOT NULL,
    expires_at DATETIME NOT NULL,
    last_activity DATETIME NOT NULL,
    
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
    INDEX idx_user_id (user_id),
    INDEX idx_expires_at (expires_at),
    INDEX idx_last_activity (last_activity)
);

-- Remember Token Tabelle
CREATE TABLE auth_remember_tokens (
    token_hash VARCHAR(64) PRIMARY KEY,
    user_id VARCHAR(255) NOT NULL,
    created_at DATETIME NOT NULL,
    expires_at DATETIME NOT NULL,
    
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
    INDEX idx_user_id (user_id),
    INDEX idx_expires_at (expires_at)
);

-- Failed Login Attempts Tabelle
CREATE TABLE auth_failed_attempts (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    user_id VARCHAR(255),
    identifier VARCHAR(255),
    ip_address VARCHAR(45),
    attempted_at DATETIME NOT NULL,
    reason VARCHAR(100),
    
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
    INDEX idx_user_id (user_id),
    INDEX idx_identifier (identifier),
    INDEX idx_ip_address (ip_address),
    INDEX idx_attempted_at (attempted_at)
);

-- Security Events Tabelle (optional für Logging)
CREATE TABLE auth_security_events (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    event_type VARCHAR(50) NOT NULL,
    user_id VARCHAR(255),
    session_id VARCHAR(255),
    ip_address VARCHAR(45),
    user_agent TEXT,
    event_data JSON,
    created_at DATETIME NOT NULL,
    
    INDEX idx_event_type (event_type),
    INDEX idx_user_id (user_id),
    INDEX idx_created_at (created_at),
    INDEX idx_ip_address (ip_address)
);

Migration Commands

# Migration erstellen
php console.php make:migration CreateAuthTables Auth

# Migration ausführen
php console.php db:migrate

# Migration Status prüfen
php console.php db:status

Security Level Configuration

Password Hashing Levels

// Niedrige Sicherheit (Development, Testing)
$lowSecurity = new PasswordHasher(
    kdf: $kdf,
    defaultAlgorithm: 'argon2id',
    defaultSecurityLevel: PasswordHasher::LEVEL_LOW
);

// Standard Sicherheit (Production Default)
$standardSecurity = new PasswordHasher(
    kdf: $kdf,
    defaultAlgorithm: 'argon2id',
    defaultSecurityLevel: PasswordHasher::LEVEL_STANDARD
);

// Hohe Sicherheit (Banking, Healthcare)
$highSecurity = new PasswordHasher(
    kdf: $kdf,
    defaultAlgorithm: 'argon2id',
    defaultSecurityLevel: PasswordHasher::LEVEL_HIGH
);

Algorithm Performance Comparison

Algorithm Level Memory Time Iterations Performance Security
Argon2ID Low 32 MB 2 - Fast Good
Argon2ID Standard 64 MB 4 - Medium Excellent
Argon2ID High 128 MB 6 - Slow Maximum
PBKDF2-SHA256 Low - - 50,000 Fast Good
PBKDF2-SHA256 Standard - - 100,000 Fast Good
PBKDF2-SHA256 High - - 200,000 Medium Good
Scrypt Standard 16 MB - - Medium Good

Rate Limiting Configuration

Redis-based Rate Limiting

use App\Framework\Auth\RateLimit\RedisRateLimitService;

$rateLimiter = new RedisRateLimitService(
    redis: $redis,
    config: new RateLimitConfig(
        maxAttempts: 5,
        windowSeconds: 300,
        lockoutDuration: 900
    )
);

File-based Rate Limiting

use App\Framework\Auth\RateLimit\FileRateLimitService;

$rateLimiter = new FileRateLimitService(
    cacheDir: '/tmp/auth_rate_limits',
    config: new RateLimitConfig(
        maxAttempts: 5,
        windowSeconds: 300,
        lockoutDuration: 900,
        cleanupInterval: 3600  // Cleanup alte Einträge jede Stunde
    )
);

Monitoring & Logging

Security Event Configuration

// Security Event Handler
final readonly class SecurityEventHandler
{
    public function __construct(
        private Logger $logger,
        private ?AlertingService $alerting = null
    ) {}
    
    public function handle(SecurityEvent $event): void
    {
        // Log alle Security Events
        $this->logger->warning('Security Event', [
            'event_type' => $event->getType(),
            'user_id' => $event->getUserId(),
            'ip_address' => (string) $event->getIpAddress(),
            'data' => $event->getData()
        ]);
        
        // Kritische Events alarmieren
        if ($event->isCritical()) {
            $this->alerting?->sendAlert($event);
        }
    }
}

Performance Monitoring

// Performance Metrics für Password Hashing
$start = microtime(true);
$hashedPassword = $passwordHasher->hash($password);
$hashTime = microtime(true) - $start;

$this->metrics->histogram('auth.password_hash_duration', $hashTime, [
    'algorithm' => $hashedPassword->getAlgorithm(),
    'security_level' => $securityLevel
]);

Production Deployment

Environment-specific Configuration

// Production
AUTH_DEFAULT_SECURITY_LEVEL=high
AUTH_SESSION_TIMEOUT=1800                   # 30 Minuten
AUTH_CHECK_IP_CONSISTENCY=true             # Striktere IP-Prüfung
AUTH_MAX_LOGIN_ATTEMPTS=3                  # Weniger Versuche
AUTH_LOCKOUT_DURATION=3600                 # 1 Stunde Lockout

// Development
AUTH_DEFAULT_SECURITY_LEVEL=low
AUTH_SESSION_TIMEOUT=86400                 # 24 Stunden
AUTH_CHECK_IP_CONSISTENCY=false
AUTH_MAX_LOGIN_ATTEMPTS=10
AUTH_LOCKOUT_DURATION=300                  # 5 Minuten

// Testing
AUTH_DEFAULT_SECURITY_LEVEL=low
AUTH_SESSION_TIMEOUT=3600
AUTH_MAX_LOGIN_ATTEMPTS=5
AUTH_LOCKOUT_DURATION=60                   # 1 Minute

Security Headers Configuration

// Middleware für Auth-bezogene Security Headers
final readonly class AuthSecurityHeadersMiddleware
{
    public function handle(HttpRequest $request, callable $next): HttpResponse
    {
        $response = $next($request);
        
        if ($request->getUri()->getPath() === '/login') {
            $response = $response->withHeader('X-Frame-Options', 'DENY');
            $response = $response->withHeader('X-Content-Type-Options', 'nosniff');
            $response = $response->withHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
        }
        
        return $response;
    }
}

Backup & Recovery

Session Cleanup

# Cron Job für Session Cleanup (täglich)
0 2 * * * php /path/to/console.php auth:cleanup-expired-sessions

# Manual Cleanup
php console.php auth:cleanup-expired-sessions
php console.php auth:cleanup-expired-tokens

Data Retention

// Cleanup Commands
final readonly class CleanupExpiredSessionsCommand
{
    public function execute(): void
    {
        $expiredCount = $this->repository->deleteExpiredSessions();
        $this->output->writeln("Deleted {$expiredCount} expired sessions");
        
        $tokenCount = $this->repository->deleteExpiredRememberTokens();
        $this->output->writeln("Deleted {$tokenCount} expired remember tokens");
        
        $attemptCount = $this->repository->cleanupOldFailedAttempts(days: 30);
        $this->output->writeln("Cleaned up {$attemptCount} old failed attempts");
    }
}