feat(firewall): complete operational reliability phase
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
@@ -34,7 +34,8 @@ final class FirewallRuleManager
|
||||
?string $reason,
|
||||
?string $createdBy,
|
||||
?int $durationSeconds = null,
|
||||
string $origin = self::ORIGIN_MANUAL
|
||||
string $origin = self::ORIGIN_MANUAL,
|
||||
array $metadata = []
|
||||
): FirewallRuleObject {
|
||||
$ipAddress = FirewallRuleValidator::ipAddress($ipAddress);
|
||||
FirewallRuleValidator::duration($durationSeconds);
|
||||
@@ -46,6 +47,14 @@ final class FirewallRuleManager
|
||||
$scope->scope
|
||||
);
|
||||
if ($existing) {
|
||||
if (
|
||||
$origin === self::ORIGIN_AUTOMATIC
|
||||
&& ($existing->getMetadata()['origin'] ?? null) === self::ORIGIN_AUTOMATIC
|
||||
&& $durationSeconds !== null
|
||||
) {
|
||||
return $this->extendAutomaticBlock($existing, $durationSeconds, $metadata);
|
||||
}
|
||||
|
||||
return $existing;
|
||||
}
|
||||
|
||||
@@ -57,7 +66,8 @@ final class FirewallRuleManager
|
||||
$reason ?? 'Blocked by administrator',
|
||||
$createdBy,
|
||||
$durationSeconds,
|
||||
$origin
|
||||
$origin,
|
||||
$metadata
|
||||
);
|
||||
$this->publishIpEvent(SecurityEvent::IP_BLOCKED, $scope, $ipAddress, $reason);
|
||||
|
||||
@@ -171,7 +181,8 @@ final class FirewallRuleManager
|
||||
string $reason,
|
||||
?string $createdBy,
|
||||
?int $durationSeconds = null,
|
||||
string $origin = self::ORIGIN_MANUAL
|
||||
string $origin = self::ORIGIN_MANUAL,
|
||||
array $metadata = []
|
||||
): FirewallRuleObject {
|
||||
if (!in_array($origin, [self::ORIGIN_MANUAL, self::ORIGIN_AUTOMATIC], true)) {
|
||||
throw new \InvalidArgumentException("Invalid firewall rule origin: {$origin}");
|
||||
@@ -186,12 +197,17 @@ final class FirewallRuleManager
|
||||
->setReason($reason)
|
||||
->setCreatedBy($createdBy)
|
||||
->setCreatedAt(new \DateTimeImmutable())
|
||||
->setMetadata(['origin' => $origin])
|
||||
->setEnabled(true);
|
||||
|
||||
if ($durationSeconds !== null) {
|
||||
$rule->setExpiresAt((new \DateTimeImmutable())->modify("+{$durationSeconds} seconds"));
|
||||
}
|
||||
$metadata = [...$metadata, 'origin' => $origin];
|
||||
if ($origin === self::ORIGIN_AUTOMATIC && $rule->getExpiresAt() !== null) {
|
||||
$metadata['originalExpiresAt'] = $rule->getExpiresAt()->format(\DateTimeInterface::ATOM);
|
||||
$metadata['extensions'] = [];
|
||||
}
|
||||
$rule->setMetadata($metadata);
|
||||
|
||||
$this->store->depositRule($rule);
|
||||
$this->cache->invalidate();
|
||||
@@ -200,6 +216,43 @@ final class FirewallRuleManager
|
||||
return $rule;
|
||||
}
|
||||
|
||||
private function extendAutomaticBlock(
|
||||
FirewallRuleObject $rule,
|
||||
int $durationSeconds,
|
||||
array $policy
|
||||
): FirewallRuleObject {
|
||||
$now = new \DateTimeImmutable();
|
||||
$previousExpiry = $rule->getExpiresAt();
|
||||
$newExpiry = $now->modify("+{$durationSeconds} seconds");
|
||||
if ($previousExpiry !== null && $newExpiry <= $previousExpiry) {
|
||||
return $rule;
|
||||
}
|
||||
|
||||
$metadata = $rule->getMetadata() ?? [];
|
||||
$extensions = is_array($metadata['extensions'] ?? null) ? $metadata['extensions'] : [];
|
||||
$extensions[] = [
|
||||
'extendedAt' => $now->format(\DateTimeInterface::ATOM),
|
||||
'previousExpiresAt' => $previousExpiry?->format(\DateTimeInterface::ATOM),
|
||||
'expiresAt' => $newExpiry->format(\DateTimeInterface::ATOM),
|
||||
'failureCount' => $policy['lastFailureCount'] ?? null,
|
||||
];
|
||||
$rule->setExpiresAt($newExpiry)->setMetadata([
|
||||
...$metadata,
|
||||
...$policy,
|
||||
'origin' => self::ORIGIN_AUTOMATIC,
|
||||
'originalExpiresAt' => $metadata['originalExpiresAt']
|
||||
?? $previousExpiry?->format(\DateTimeInterface::ATOM),
|
||||
'extensions' => $extensions,
|
||||
'lastExtendedAt' => $now->format(\DateTimeInterface::ATOM),
|
||||
]);
|
||||
|
||||
$this->store->depositRule($rule);
|
||||
$this->cache->invalidate();
|
||||
$this->publishLifecycleEvent(SecurityEvent::FIREWALL_RULE_EXTENDED, $rule);
|
||||
|
||||
return $rule;
|
||||
}
|
||||
|
||||
private function ownedRule(FirewallRuleScope $scope, string $ruleId): ?FirewallRuleObject
|
||||
{
|
||||
$rule = $this->store->fetchRule($ruleId);
|
||||
@@ -233,6 +286,7 @@ final class FirewallRuleManager
|
||||
'reason' => $rule->getReason(),
|
||||
'origin' => $rule->getMetadata()['origin'] ?? self::ORIGIN_MANUAL,
|
||||
'expiresAt' => $rule->getExpiresAt()?->format(\DateTimeInterface::ATOM),
|
||||
...($rule->getMetadata() ?? []),
|
||||
]);
|
||||
$event->setTenantId($rule->getTenantId())
|
||||
->setIdentityId($actorId ?? $rule->getCreatedBy());
|
||||
|
||||
Reference in New Issue
Block a user