5c65c8592c
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
250 lines
7.0 KiB
PHP
250 lines
7.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace KTXC\Security\Event;
|
|
|
|
use KTXF\Event\Event;
|
|
|
|
/**
|
|
* Security-specific event for authentication and access control events
|
|
*/
|
|
final class SecurityEvent extends Event implements SecurityEventInterface
|
|
{
|
|
// Event names
|
|
public const AUTH_SUCCESS = 'security.auth.success';
|
|
public const AUTH_LOGOUT = 'security.auth.logout';
|
|
public const TOKEN_REFRESH = 'security.token.refresh';
|
|
public const TOKEN_REVOKED = 'security.token.revoked';
|
|
|
|
public const ACCESS_DENIED = 'security.access.denied';
|
|
public const ACCESS_GRANTED = 'security.access.granted';
|
|
|
|
public const BRUTE_FORCE_DETECTED = 'security.brute_force.detected';
|
|
public const RATE_LIMIT_EXCEEDED = 'security.rate_limit.exceeded';
|
|
public const SUSPICIOUS_ACTIVITY = 'security.suspicious.activity';
|
|
|
|
public const IP_BLOCKED = 'security.ip.blocked';
|
|
public const IP_ALLOWED = 'security.ip.allowed';
|
|
public const DEVICE_BLOCKED = 'security.device.blocked';
|
|
public const FIREWALL_RULE_CREATED = 'security.firewall.rule.created';
|
|
public const FIREWALL_RULE_EXTENDED = 'security.firewall.rule.extended';
|
|
public const FIREWALL_RULE_ENABLED = 'security.firewall.rule.enabled';
|
|
public const FIREWALL_RULE_DISABLED = 'security.firewall.rule.disabled';
|
|
public const FIREWALL_RULE_REMOVED = 'security.firewall.rule.removed';
|
|
public const FIREWALL_SETTINGS_UPDATED = 'security.firewall.settings.updated';
|
|
|
|
// Severity levels
|
|
public const SEVERITY_DEBUG = 0;
|
|
public const SEVERITY_INFO = 1;
|
|
public const SEVERITY_WARNING = 2;
|
|
public const SEVERITY_ERROR = 3;
|
|
public const SEVERITY_CRITICAL = 4;
|
|
|
|
private readonly int $severity;
|
|
|
|
public function __construct(
|
|
string $name,
|
|
array $data = [],
|
|
?string $tenantId = null,
|
|
?string $identityId = null,
|
|
private readonly ?string $ipAddress = null,
|
|
private readonly ?string $deviceFingerprint = null,
|
|
private readonly ?string $userAgent = null,
|
|
private readonly ?string $requestPath = null,
|
|
private readonly ?string $requestMethod = null,
|
|
private readonly ?string $userId = null,
|
|
private readonly ?string $reason = null,
|
|
?int $severity = null,
|
|
) {
|
|
parent::__construct($name, $data, $tenantId, $identityId);
|
|
|
|
$this->severity = $severity ?? self::getSeverityForEvent($name);
|
|
}
|
|
|
|
/**
|
|
* Create a security event with common parameters
|
|
*/
|
|
public static function create(
|
|
string $name,
|
|
?string $ipAddress = null,
|
|
?string $deviceFingerprint = null,
|
|
array $data = [],
|
|
?string $tenantId = null,
|
|
?string $identityId = null,
|
|
?string $userAgent = null,
|
|
?string $requestPath = null,
|
|
?string $requestMethod = null,
|
|
?string $userId = null,
|
|
?string $reason = null,
|
|
?int $severity = null,
|
|
): self {
|
|
return new self(
|
|
$name,
|
|
$data,
|
|
$tenantId,
|
|
$identityId,
|
|
$ipAddress,
|
|
$deviceFingerprint,
|
|
$userAgent,
|
|
$requestPath,
|
|
$requestMethod,
|
|
$userId,
|
|
$reason,
|
|
$severity,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Create an authentication success event
|
|
*/
|
|
public static function authSuccess(
|
|
string $ipAddress,
|
|
?string $deviceFingerprint = null,
|
|
?string $userId = null,
|
|
?string $tenantId = null,
|
|
): self {
|
|
return self::create(
|
|
self::AUTH_SUCCESS,
|
|
$ipAddress,
|
|
$deviceFingerprint,
|
|
['userId' => $userId],
|
|
tenantId: $tenantId,
|
|
userId: $userId,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Create a brute force detection event
|
|
*/
|
|
public static function bruteForceDetected(
|
|
string $ipAddress,
|
|
int $failureCount,
|
|
int $windowSeconds,
|
|
?string $tenantId = null,
|
|
): self {
|
|
return self::create(
|
|
self::BRUTE_FORCE_DETECTED,
|
|
$ipAddress,
|
|
data: ['failureCount' => $failureCount, 'windowSeconds' => $windowSeconds],
|
|
tenantId: $tenantId,
|
|
reason: sprintf('%d failed attempts in %d seconds', $failureCount, $windowSeconds),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Create a rate limit exceeded event
|
|
*/
|
|
public static function rateLimitExceeded(
|
|
string $ipAddress,
|
|
int $requestCount,
|
|
int $windowSeconds,
|
|
?string $endpoint = null,
|
|
?string $tenantId = null,
|
|
): self {
|
|
return self::create(
|
|
self::RATE_LIMIT_EXCEEDED,
|
|
$ipAddress,
|
|
data: [
|
|
'requestCount' => $requestCount,
|
|
'windowSeconds' => $windowSeconds,
|
|
'endpoint' => $endpoint,
|
|
],
|
|
tenantId: $tenantId,
|
|
requestPath: $endpoint,
|
|
reason: sprintf('%d requests in %d seconds', $requestCount, $windowSeconds),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Create an access denied event
|
|
*/
|
|
public static function accessDenied(
|
|
string $ipAddress,
|
|
?string $deviceFingerprint = null,
|
|
?string $ruleId = null,
|
|
?string $ruleScope = null,
|
|
?string $reason = null,
|
|
?string $tenantId = null,
|
|
?string $identityId = null,
|
|
): self {
|
|
return self::create(
|
|
self::ACCESS_DENIED,
|
|
$ipAddress,
|
|
$deviceFingerprint,
|
|
['ruleId' => $ruleId, 'ruleScope' => $ruleScope, 'reason' => $reason],
|
|
$tenantId,
|
|
$identityId,
|
|
reason: $reason,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get default severity for event types
|
|
*/
|
|
private static function getSeverityForEvent(string $eventName): int
|
|
{
|
|
return match ($eventName) {
|
|
self::AUTH_SUCCESS,
|
|
self::ACCESS_GRANTED,
|
|
self::TOKEN_REFRESH => self::SEVERITY_INFO,
|
|
|
|
self::ACCESS_DENIED,
|
|
self::AUTH_LOGOUT,
|
|
self::TOKEN_REVOKED => self::SEVERITY_WARNING,
|
|
|
|
self::RATE_LIMIT_EXCEEDED,
|
|
self::SUSPICIOUS_ACTIVITY => self::SEVERITY_ERROR,
|
|
|
|
self::BRUTE_FORCE_DETECTED,
|
|
self::IP_BLOCKED,
|
|
self::DEVICE_BLOCKED => self::SEVERITY_CRITICAL,
|
|
|
|
default => self::SEVERITY_INFO,
|
|
};
|
|
}
|
|
|
|
// Getters and setters
|
|
|
|
public function getIpAddress(): ?string
|
|
{
|
|
return $this->ipAddress;
|
|
}
|
|
|
|
public function getDeviceFingerprint(): ?string
|
|
{
|
|
return $this->deviceFingerprint;
|
|
}
|
|
|
|
public function getUserAgent(): ?string
|
|
{
|
|
return $this->userAgent;
|
|
}
|
|
|
|
public function getRequestPath(): ?string
|
|
{
|
|
return $this->requestPath;
|
|
}
|
|
|
|
public function getRequestMethod(): ?string
|
|
{
|
|
return $this->requestMethod;
|
|
}
|
|
|
|
public function getUserId(): ?string
|
|
{
|
|
return $this->userId;
|
|
}
|
|
|
|
public function getReason(): ?string
|
|
{
|
|
return $this->reason;
|
|
}
|
|
|
|
public function getSeverity(): int
|
|
{
|
|
return $this->severity;
|
|
}
|
|
|
|
}
|