Files
michaelschiemer/tests/Framework/Security/AuthenticationSecurityTest.php
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

234 lines
8.0 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
namespace Tests\Framework\Security;
use App\Framework\Auth\Auth;
use App\Framework\Http\MiddlewareContext;
use App\Framework\Http\Middlewares\AuthMiddleware;
use App\Framework\Http\Next;
use App\Framework\Http\Request;
use App\Framework\Http\RequestStateManager;
use App\Framework\Http\Session\SessionInterface;
use PHPUnit\Framework\TestCase;
/**
* Critical Security Tests for Authentication
* Tests gegen OWASP A07:2021 Identification and Authentication Failures
*/
final class AuthenticationSecurityTest extends TestCase
{
private SessionInterface $session;
private Auth $auth;
private AuthMiddleware $middleware;
private RequestStateManager $stateManager;
protected function setUp(): void
{
$this->session = $this->createMock(SessionInterface::class);
$this->auth = $this->createMock(Auth::class);
$this->middleware = new AuthMiddleware($this->auth);
$this->stateManager = $this->createMock(RequestStateManager::class);
}
/**
* Test: Nicht-authentifizierte Benutzer werden blockiert
* OWASP A07:2021 Identification and Authentication Failures
*/
public function test_blocks_unauthenticated_access(): void
{
// Arrange: Benutzer nicht authentifiziert
$this->auth->method('isAuthenticated')->willReturn(false);
$request = $this->createMock(Request::class);
$context = new MiddlewareContext($request);
$next = $this->createMock(Next::class);
$next->expects($this->never())->method('__invoke');
// Act & Assert: Exception erwartet
$this->expectException(\App\Framework\Http\Exception\HttpException::class);
$this->middleware->__invoke($context, $next, $this->stateManager);
}
/**
* Test: Authentifizierte Benutzer werden durchgelassen
*/
public function test_allows_authenticated_access(): void
{
// Arrange: Benutzer authentifiziert
$this->auth->method('isAuthenticated')->willReturn(true);
$request = $this->createMock(Request::class);
$context = new MiddlewareContext($request);
$next = $this->createMock(Next::class);
$next->expects($this->once())->method('__invoke')->willReturn($context);
// Act
$result = $this->middleware->__invoke($context, $next, $this->stateManager);
// Assert
$this->assertSame($context, $result);
}
/**
* Test: Session Hijacking Schutz
* Validiert Session-Fingerprinting
*/
public function test_session_fingerprint_validation(): void
{
// Arrange: Authentifiziert aber Session-Fingerprint geändert
$this->auth->method('isAuthenticated')->willReturn(true);
$this->auth->method('validateSessionFingerprint')->willReturn(false);
$request = $this->createMock(Request::class);
$context = new MiddlewareContext($request);
$next = $this->createMock(Next::class);
// Act & Assert: Session Hijacking erkannt
$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('Session fingerprint validation failed');
$this->middleware->__invoke($context, $next, $this->stateManager);
}
/**
* Test: Concurrent Login Detection
* Erkennt verdächtige gleichzeitige Logins
*/
public function test_concurrent_login_detection(): void
{
// Arrange: Benutzer von verschiedenen IPs eingeloggt
$this->auth->method('isAuthenticated')->willReturn(true);
$this->auth->method('validateSessionFingerprint')->willReturn(true);
$this->auth->method('detectConcurrentSessions')->willReturn(true);
$request = $this->createMock(Request::class);
$context = new MiddlewareContext($request);
$next = $this->createMock(Next::class);
// Act & Assert: Concurrent Session erkannt
$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('Concurrent session detected');
$this->middleware->__invoke($context, $next, $this->stateManager);
}
/**
* Test: Session Timeout Validierung
*/
public function test_session_timeout_validation(): void
{
// Arrange: Session abgelaufen
$this->auth->method('isAuthenticated')->willReturn(true);
$this->auth->method('isSessionExpired')->willReturn(true);
$request = $this->createMock(Request::class);
$context = new MiddlewareContext($request);
$next = $this->createMock(Next::class);
// Act & Assert: Session Timeout
$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('Session expired');
$this->middleware->__invoke($context, $next, $this->stateManager);
}
/**
* Test: Rate Limiting für Authentication Failures
* Verhindert Brute Force Attacks
*/
public function test_authentication_rate_limiting(): void
{
// Arrange: Zu viele fehlgeschlagene Login-Versuche
$this->auth->method('isAuthenticated')->willReturn(false);
$this->auth->method('isRateLimited')->willReturn(true);
$request = $this->createMock(Request::class);
$context = new MiddlewareContext($request);
$next = $this->createMock(Next::class);
// Act & Assert: Rate Limit erreicht
$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('Authentication rate limit exceeded');
$this->middleware->__invoke($context, $next, $this->stateManager);
}
/**
* Test: IP Whitelist Validation
* Admin-Bereiche nur von bestimmten IPs
*/
public function test_ip_whitelist_validation(): void
{
// Arrange: IP nicht in Whitelist
$this->auth->method('isAuthenticated')->willReturn(true);
$this->auth->method('isIpWhitelisted')->willReturn(false);
$request = $this->createRequestWithIp('192.168.1.100');
$context = new MiddlewareContext($request);
$next = $this->createMock(Next::class);
// Act & Assert: IP nicht erlaubt
$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('Access from this IP address is not allowed');
$this->middleware->__invoke($context, $next, $this->stateManager);
}
/**
* Test: Account Lockout nach fehlgeschlagenen Versuchen
*/
public function test_account_lockout_after_failed_attempts(): void
{
// Arrange: Account gesperrt nach zu vielen Versuchen
$this->auth->method('isAuthenticated')->willReturn(false);
$this->auth->method('isAccountLocked')->willReturn(true);
$request = $this->createMock(Request::class);
$context = new MiddlewareContext($request);
$next = $this->createMock(Next::class);
// Act & Assert: Account gesperrt
$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('Account is locked due to too many failed attempts');
$this->middleware->__invoke($context, $next, $this->stateManager);
}
/**
* Test: Two-Factor Authentication Validation
*/
public function test_two_factor_authentication_required(): void
{
// Arrange: 2FA erforderlich aber nicht bereitgestellt
$this->auth->method('isAuthenticated')->willReturn(true);
$this->auth->method('requires2FA')->willReturn(true);
$this->auth->method('is2FAValid')->willReturn(false);
$request = $this->createMock(Request::class);
$context = new MiddlewareContext($request);
$next = $this->createMock(Next::class);
// Act & Assert: 2FA erforderlich
$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('Two-factor authentication required');
$this->middleware->__invoke($context, $next, $this->stateManager);
}
// Helper Methods
private function createRequestWithIp(string $ip): Request
{
$request = $this->createMock(Request::class);
$request->method('getClientIp')->willReturn($ip);
return $request;
}
}