Files
e-ticket/tests/EventSubscriber/CsrfProtectionSubscriberTest.php

160 lines
5.8 KiB
PHP
Raw Normal View History

<?php
namespace App\Tests\EventSubscriber;
use App\EventSubscriber\CsrfProtectionSubscriber;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
class CsrfProtectionSubscriberTest extends TestCase
{
private function createSubscriber(?CsrfTokenManagerInterface $csrfManager = null): CsrfProtectionSubscriber
{
$csrfManager ??= $this->createMock(CsrfTokenManagerInterface::class);
return new CsrfProtectionSubscriber($csrfManager);
}
public function testSubscribedEvents(): void
{
$events = CsrfProtectionSubscriber::getSubscribedEvents();
self::assertArrayHasKey(KernelEvents::REQUEST, $events);
self::assertArrayHasKey(KernelEvents::RESPONSE, $events);
}
public function testIgnoresGetRequests(): void
{
$subscriber = $this->createSubscriber();
$request = Request::create('/test', 'GET');
$request->attributes->set('_route', 'app_test');
$kernel = $this->createMock(HttpKernelInterface::class);
$event = new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST);
$subscriber->onKernelRequest($event);
self::assertNull($event->getResponse());
}
public function testIgnoresExcludedRoutes(): void
{
$subscriber = $this->createSubscriber();
$request = Request::create('/webhooks/stripe/insta', 'POST');
$request->attributes->set('_route', 'app_stripe_webhook_insta');
$kernel = $this->createMock(HttpKernelInterface::class);
$event = new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST);
$subscriber->onKernelRequest($event);
self::assertNull($event->getResponse());
}
public function testIgnoresJsonRequests(): void
{
$subscriber = $this->createSubscriber();
$request = Request::create('/test', 'POST', [], [], [], ['CONTENT_TYPE' => 'application/json']);
$request->attributes->set('_route', 'app_test');
$kernel = $this->createMock(HttpKernelInterface::class);
$event = new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST);
$subscriber->onKernelRequest($event);
self::assertNull($event->getResponse());
}
public function testIgnoresPostWithoutToken(): void
{
$subscriber = $this->createSubscriber();
$request = Request::create('/test', 'POST');
$request->attributes->set('_route', 'app_test');
$kernel = $this->createMock(HttpKernelInterface::class);
$event = new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST);
$subscriber->onKernelRequest($event);
self::assertNull($event->getResponse());
}
public function testRejectsInvalidToken(): void
{
$csrfManager = $this->createMock(CsrfTokenManagerInterface::class);
$csrfManager->method('isTokenValid')->willReturn(false);
$subscriber = $this->createSubscriber($csrfManager);
$request = Request::create('/test', 'POST', ['_csrf_token' => 'bad']);
$request->attributes->set('_route', 'app_test');
$kernel = $this->createMock(HttpKernelInterface::class);
$event = new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST);
$subscriber->onKernelRequest($event);
self::assertNotNull($event->getResponse());
self::assertSame(403, $event->getResponse()->getStatusCode());
}
public function testAcceptsValidToken(): void
{
$csrfManager = $this->createMock(CsrfTokenManagerInterface::class);
$csrfManager->method('isTokenValid')->willReturn(true);
$subscriber = $this->createSubscriber($csrfManager);
$request = Request::create('/test', 'POST', ['_csrf_token' => 'valid']);
$request->attributes->set('_route', 'app_test');
$kernel = $this->createMock(HttpKernelInterface::class);
$event = new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST);
$subscriber->onKernelRequest($event);
self::assertNull($event->getResponse());
}
public function testInjectsTokenInHtmlResponse(): void
{
$csrfManager = $this->createMock(CsrfTokenManagerInterface::class);
$csrfManager->method('getToken')->willReturn(new CsrfToken('form_protection', 'abc123'));
$subscriber = $this->createSubscriber($csrfManager);
$response = new Response('<form method="post"><button>Submit</button></form>');
$response->headers->set('Content-Type', 'text/html');
$request = Request::create('/test');
$kernel = $this->createMock(HttpKernelInterface::class);
$event = new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response);
$subscriber->onKernelResponse($event);
self::assertStringContainsString('name="_csrf_token"', $response->getContent());
self::assertStringContainsString('value="abc123"', $response->getContent());
}
public function testDoesNotInjectInNonHtml(): void
{
$subscriber = $this->createSubscriber();
$response = new Response('{"ok":true}');
$response->headers->set('Content-Type', 'application/json');
$request = Request::create('/test');
$kernel = $this->createMock(HttpKernelInterface::class);
$event = new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response);
$subscriber->onKernelResponse($event);
self::assertStringNotContainsString('_csrf_token', $response->getContent());
}
}