fix(firewall): preserve tenant ownership for automatic blocks

Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
2026-07-30 22:11:27 -04:00
parent 3b9a5cd5ab
commit 266b364c93
3 changed files with 254 additions and 8 deletions
+24 -6
View File
@@ -167,7 +167,7 @@ class FirewallService
$failureCount++;
if ($failureCount >= $maxFailures) {
$this->handleBruteForce($ipAddress, $failureCount, $windowSeconds);
$this->handleBruteForce($tenantId, $ipAddress, $failureCount, $windowSeconds);
}
}
@@ -175,13 +175,14 @@ class FirewallService
* Handle detected brute force attack
*/
private function handleBruteForce(
string $tenantId,
string $ipAddress,
int $failureCount,
int $windowSeconds
): void {
// Publish brute force event
$event = SecurityEvent::bruteForceDetected($ipAddress, $failureCount, $windowSeconds);
$event->setTenantId($this->tenantContext->identifier());
$event->setTenantId($tenantId);
$this->events->dispatch($event);
// Auto-block the IP
@@ -191,7 +192,8 @@ class FirewallService
self::MAX_AUTO_BLOCK_DURATION
);
$this->blockIp(
$this->blockIpForTenant(
$tenantId,
$ipAddress,
sprintf('Auto-blocked: %d failed auth attempts in %d seconds', $failureCount, $windowSeconds),
null, // System-created
@@ -284,14 +286,30 @@ class FirewallService
?string $createdBy = null,
?int $durationSeconds = null
): FirewallRuleObject {
$ipAddress = $this->validateIpAddress($ipAddress);
$this->validateDuration($durationSeconds);
$tenantId = $this->tenantContext->identifier();
if (!$tenantId) {
throw new \RuntimeException('Cannot create firewall rule: no tenant configured');
}
return $this->blockIpForTenant(
$tenantId,
$ipAddress,
$reason,
$createdBy,
$durationSeconds
);
}
private function blockIpForTenant(
string $tenantId,
string $ipAddress,
?string $reason,
?string $createdBy,
?int $durationSeconds
): FirewallRuleObject {
$ipAddress = $this->validateIpAddress($ipAddress);
$this->validateDuration($durationSeconds);
// Check if already blocked
$existing = $this->store->findExactIpRule(
$tenantId,