harden(rate-limiter): fail secure login scopes with cache fallback

This commit is contained in:
2026-04-25 23:17:46 +02:00
parent f9c09f8746
commit a24dc0c235
4 changed files with 263 additions and 9 deletions

View File

@@ -3,6 +3,7 @@
namespace MintyPHP\Tests\Service\Security;
use MintyPHP\Repository\Security\RateLimitRepositoryInterface;
use MintyPHP\Service\Security\RateLimiterFallbackGateway;
use MintyPHP\Service\Security\RateLimiterService;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
@@ -284,6 +285,53 @@ class RateLimiterServiceTest extends TestCase
$this->assertSame(0, $result['retry_after']);
}
public function testIsBlockedFailsSecureOnExceptionForLoginAuthScope(): void
{
$this->repository->method('findByScopeAndHash')
->willThrowException(new \RuntimeException('DB down'));
$result = $this->service->isBlocked('api.auth.login.ip', '127.0.0.1');
$this->assertFalse($result['allowed']);
$this->assertSame(30, $result['retry_after']);
}
public function testRegisterFailureFailsSecureOnExceptionForLoginAuthScope(): void
{
$this->repository->method('findByScopeAndHash')
->willThrowException(new \RuntimeException('DB down'));
$result = $this->service->registerFailure('login.password.email_ip', 'user@example.com|127.0.0.1', 5, 900, 900);
$this->assertFalse($result['allowed']);
$this->assertSame(30, $result['retry_after']);
}
public function testIsBlockedUsesFallbackGatewayWhenStorageFails(): void
{
$subject = '127.0.0.1';
$subjectHash = hash('sha256', $subject);
$fallback = $this->createMock(RateLimiterFallbackGateway::class);
$fallback->expects($this->once())
->method('load')
->with('api.auth.login.ip', $subjectHash)
->willReturn([
'hits' => 7,
'window_started_at' => time(),
'blocked_until' => time() + 120,
]);
$this->repository->method('findByScopeAndHash')
->willThrowException(new \RuntimeException('DB down'));
$service = new RateLimiterService($this->repository, $fallback);
$result = $service->isBlocked('api.auth.login.ip', $subject);
$this->assertFalse($result['allowed']);
$this->assertGreaterThan(0, $result['retry_after']);
}
// ---------------------------------------------------------------
// reset
// ---------------------------------------------------------------