refactor(firewall): separate enforcement from rule management
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace KTXT\Unit\Service;
|
||||
|
||||
use KTXC\Context\IdentityContextInterface;
|
||||
use KTXC\Context\TenantContextInterface;
|
||||
use KTXC\Models\Firewall\FirewallRuleObject;
|
||||
use KTXC\Service\FirewallRuleCache;
|
||||
use KTXC\Service\FirewallRuleManager;
|
||||
use KTXC\Service\SystemFirewallRuleService;
|
||||
use KTXC\Service\TenantFirewallRuleService;
|
||||
use KTXC\Stores\FirewallStore;
|
||||
use KTXF\Event\EventDispatcherInterface;
|
||||
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
|
||||
use PHPUnit\Framework\Attributes\TestDox;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
#[AllowMockObjectsWithoutExpectations]
|
||||
class FirewallRuleServicesTest extends TestCase
|
||||
{
|
||||
private FirewallStore&MockObject $store;
|
||||
private IdentityContextInterface&MockObject $identity;
|
||||
private TenantContextInterface&MockObject $tenant;
|
||||
private FirewallRuleManager $manager;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->store = $this->createMock(FirewallStore::class);
|
||||
$this->identity = $this->createMock(IdentityContextInterface::class);
|
||||
$this->tenant = $this->createMock(TenantContextInterface::class);
|
||||
$events = $this->createMock(EventDispatcherInterface::class);
|
||||
$this->manager = new FirewallRuleManager(
|
||||
$this->store,
|
||||
new FirewallRuleCache($this->store),
|
||||
$events
|
||||
);
|
||||
}
|
||||
|
||||
#[TestDox('Tenant and system boundaries require their dedicated permissions')]
|
||||
public function testPermissions(): void
|
||||
{
|
||||
$this->identity->method('hasPermission')->willReturn(false);
|
||||
$this->store->expects($this->never())->method('depositRule');
|
||||
|
||||
try {
|
||||
$this->tenantService()->blockIp('203.0.113.10');
|
||||
self::fail('Tenant operation should have been rejected.');
|
||||
} catch (\RuntimeException $error) {
|
||||
self::assertStringContainsString(TenantFirewallRuleService::PERMISSION_MANAGE, $error->getMessage());
|
||||
}
|
||||
|
||||
$this->expectException(\RuntimeException::class);
|
||||
$this->expectExceptionMessage(SystemFirewallRuleService::PERMISSION_MANAGE);
|
||||
$this->systemService()->blockIp('203.0.113.10');
|
||||
}
|
||||
|
||||
#[TestDox('Tenant management derives scope from tenant context')]
|
||||
public function testTenantScope(): void
|
||||
{
|
||||
$this->allow(TenantFirewallRuleService::PERMISSION_MANAGE);
|
||||
$this->tenant->method('requireIdentifier')->willReturn('tenant-a');
|
||||
$this->identity->method('identifier')->willReturn('admin-a');
|
||||
$this->store->method('findExactIpRule')->willReturn(null);
|
||||
$this->store->expects($this->once())
|
||||
->method('depositRule')
|
||||
->with(self::callback(static fn(FirewallRuleObject $rule): bool =>
|
||||
$rule->isTenantScoped() && $rule->getTenantId() === 'tenant-a'
|
||||
))
|
||||
->willReturnArgument(0);
|
||||
|
||||
$this->tenantService()->blockIp('203.0.113.10');
|
||||
}
|
||||
|
||||
#[TestDox('System management always delegates with system scope')]
|
||||
public function testSystemScope(): void
|
||||
{
|
||||
$this->allow(SystemFirewallRuleService::PERMISSION_MANAGE);
|
||||
$this->store->method('findExactIpRule')->willReturn(null);
|
||||
$this->store->expects($this->once())
|
||||
->method('depositRule')
|
||||
->with(self::callback(static fn(FirewallRuleObject $rule): bool =>
|
||||
$rule->isSystemScoped() && $rule->getTenantId() === null
|
||||
))
|
||||
->willReturnArgument(0);
|
||||
|
||||
$this->systemService()->blockIp('203.0.113.10');
|
||||
}
|
||||
|
||||
private function allow(string $permission): void
|
||||
{
|
||||
$this->identity->method('hasPermission')->with($permission)->willReturn(true);
|
||||
}
|
||||
|
||||
private function tenantService(): TenantFirewallRuleService
|
||||
{
|
||||
return new TenantFirewallRuleService($this->manager, $this->tenant, $this->identity);
|
||||
}
|
||||
|
||||
private function systemService(): SystemFirewallRuleService
|
||||
{
|
||||
return new SystemFirewallRuleService($this->manager, $this->identity);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user