| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- <?php
- declare(strict_types=1);
- namespace App\Tests\Unit\Auth;
- use App\Domain\Auth\AuthenticatedPrincipal;
- use App\Domain\Auth\Role;
- use App\Domain\Auth\TokenKind;
- use App\Infrastructure\Http\Middleware\RbacMiddleware;
- use App\Infrastructure\Http\Middleware\TokenAuthenticationMiddleware;
- use PHPUnit\Framework\TestCase;
- use Psr\Http\Message\ResponseInterface;
- use Psr\Http\Message\ServerRequestInterface;
- use Psr\Http\Server\RequestHandlerInterface;
- use Slim\Psr7\Factory\ResponseFactory;
- use Slim\Psr7\Factory\ServerRequestFactory;
- use Slim\Psr7\Response;
- /**
- * Direct unit coverage for the RBAC tier table from M03 §7. Integration
- * tests in AuthMatrixTest exercise the routes that exist; these target
- * the operator/admin rungs which have no live route in M03.
- */
- final class RbacMiddlewareTest extends TestCase
- {
- public function testAdminPrincipalSatisfiesAdminRoute(): void
- {
- self::assertSame(200, $this->dispatch(Role::Admin, $this->principal(Role::Admin)));
- }
- public function testOperatorPrincipalSatisfiesOperatorRoute(): void
- {
- self::assertSame(200, $this->dispatch(Role::Operator, $this->principal(Role::Operator)));
- }
- public function testViewerPrincipalForbiddenFromOperatorRoute(): void
- {
- self::assertSame(403, $this->dispatch(Role::Operator, $this->principal(Role::Viewer)));
- }
- public function testOperatorPrincipalForbiddenFromAdminRoute(): void
- {
- self::assertSame(403, $this->dispatch(Role::Admin, $this->principal(Role::Operator)));
- }
- public function testReporterPrincipalUnauthorizedOnAnyAdminRoute(): void
- {
- $principal = new AuthenticatedPrincipal(
- tokenKind: TokenKind::Reporter,
- userId: null,
- role: null,
- reporterId: 1,
- consumerId: null,
- tokenId: 1,
- );
- self::assertSame(401, $this->dispatch(Role::Viewer, $principal));
- }
- public function testServicePrincipalWithoutRoleForbidden(): void
- {
- // ImpersonationMiddleware would normally have populated role; if it
- // didn't (e.g. someone mounted an admin route without it), we expect
- // a defensive 403 rather than a misleading 200.
- $principal = new AuthenticatedPrincipal(
- tokenKind: TokenKind::Service,
- userId: null,
- role: null,
- reporterId: null,
- consumerId: null,
- tokenId: 1,
- );
- self::assertSame(403, $this->dispatch(Role::Viewer, $principal));
- }
- public function testMissingPrincipalReturns401(): void
- {
- $factory = new ResponseFactory();
- $middleware = RbacMiddleware::require($factory, Role::Viewer);
- $request = (new ServerRequestFactory())->createServerRequest('GET', '/x');
- $handler = new class () implements RequestHandlerInterface {
- public function handle(ServerRequestInterface $request): ResponseInterface
- {
- return new Response();
- }
- };
- $response = $middleware->process($request, $handler);
- self::assertSame(401, $response->getStatusCode());
- }
- private function principal(Role $role): AuthenticatedPrincipal
- {
- return new AuthenticatedPrincipal(
- tokenKind: TokenKind::Admin,
- userId: 42,
- role: $role,
- reporterId: null,
- consumerId: null,
- tokenId: 7,
- );
- }
- private function dispatch(Role $required, AuthenticatedPrincipal $principal): int
- {
- $factory = new ResponseFactory();
- $middleware = RbacMiddleware::require($factory, $required);
- $request = (new ServerRequestFactory())
- ->createServerRequest('GET', '/x')
- ->withAttribute(TokenAuthenticationMiddleware::ATTR_PRINCIPAL, $principal);
- $handler = new class () implements RequestHandlerInterface {
- public function handle(ServerRequestInterface $request): ResponseInterface
- {
- return new Response();
- }
- };
- return $middleware->process($request, $handler)->getStatusCode();
- }
- }
|