From 23c0fae36fb8159bcf8b95bae98555201146457e Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Mon, 3 Sep 2018 15:33:13 +0100 Subject: Added csrf middleware --- tests/Unit/Http/SessionServiceProviderTest.php | 21 +++- tests/Unit/Middleware/VerifyCsrfTokenTest.php | 128 +++++++++++++++++++++++ tests/Unit/Renderer/Twig/Extensions/CsrfTest.php | 63 +++++++++++ 3 files changed, 209 insertions(+), 3 deletions(-) create mode 100644 tests/Unit/Middleware/VerifyCsrfTokenTest.php create mode 100644 tests/Unit/Renderer/Twig/Extensions/CsrfTest.php (limited to 'tests/Unit') diff --git a/tests/Unit/Http/SessionServiceProviderTest.php b/tests/Unit/Http/SessionServiceProviderTest.php index dd0e538f..70e751f3 100644 --- a/tests/Unit/Http/SessionServiceProviderTest.php +++ b/tests/Unit/Http/SessionServiceProviderTest.php @@ -9,6 +9,7 @@ use Engelsystem\Http\SessionServiceProvider; use Engelsystem\Test\Unit\ServiceProviderTest; use PHPUnit_Framework_MockObject_MockObject as MockObject; use Symfony\Component\HttpFoundation\Session\Session; +use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; use Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface as StorageInterface; @@ -104,8 +105,16 @@ class SessionServiceProviderTest extends ServiceProviderTest ['driver' => 'pdo', 'name' => 'foobar'] ); - $this->setExpects($app, 'bind', [StorageInterface::class, 'session.storage'], null, $this->atLeastOnce()); + $app->expects($this->atLeastOnce()) + ->method('bind') + ->withConsecutive( + [StorageInterface::class, 'session.storage'], + [SessionInterface::class, Session::class] + ); + $this->setExpects($request, 'setSession', [$session], null, $this->atLeastOnce()); + $this->setExpects($session, 'has', ['_token'], false, $this->atLeastOnce()); + $this->setExpects($session, 'set', ['_token'], null, $this->atLeastOnce()); $this->setExpects($session, 'start', null, null, $this->atLeastOnce()); $serviceProvider->register(); @@ -142,10 +151,16 @@ class SessionServiceProviderTest extends ServiceProviderTest [Session::class, $session], ['session', $session] ); + $app->expects($this->atLeastOnce()) + ->method('bind') + ->withConsecutive( + [StorageInterface::class, 'session.storage'], + [SessionInterface::class, Session::class] + ); - $this->setExpects($app, 'bind', [StorageInterface::class, 'session.storage']); $this->setExpects($app, 'get', ['request'], $request); $this->setExpects($request, 'setSession', [$session]); + $this->setExpects($session, 'has', ['_token'], true); $this->setExpects($session, 'start'); $serviceProvider = new SessionServiceProvider($app); @@ -160,7 +175,7 @@ class SessionServiceProviderTest extends ServiceProviderTest $sessionStorage = $this->getMockForAbstractClass(StorageInterface::class); return $this->getMockBuilder(Session::class) ->setConstructorArgs([$sessionStorage]) - ->setMethods(['start']) + ->setMethods(['start', 'has', 'set']) ->getMock(); } diff --git a/tests/Unit/Middleware/VerifyCsrfTokenTest.php b/tests/Unit/Middleware/VerifyCsrfTokenTest.php new file mode 100644 index 00000000..60280c5b --- /dev/null +++ b/tests/Unit/Middleware/VerifyCsrfTokenTest.php @@ -0,0 +1,128 @@ +getMockForAbstractClass(ServerRequestInterface::class); + /** @var RequestHandlerInterface|MockObject $handler */ + $handler = $this->getMockForAbstractClass(RequestHandlerInterface::class); + /** @var ResponseInterface|MockObject $response */ + $response = $this->getMockForAbstractClass(ResponseInterface::class); + + $handler->expects($this->exactly(2)) + ->method('handle') + ->with($request) + ->willReturn($response); + + /** @var VerifyCsrfToken|MockObject $middleware */ + $middleware = $this->getMockBuilder(VerifyCsrfToken::class) + ->disableOriginalConstructor() + ->setMethods(['notAuthorizedResponse', 'tokensMatch']) + ->getMock(); + + $middleware->expects($this->exactly(1)) + ->method('notAuthorizedResponse') + ->willReturn($response); + + $middleware->expects($this->exactly(2)) + ->method('tokensMatch') + ->willReturnOnConsecutiveCalls(true, false); + + // Results in true, false, false + $request->expects($this->exactly(3)) + ->method('getMethod') + ->willReturnOnConsecutiveCalls('GET', 'POST', 'DELETE'); + + $middleware->process($request, $handler); + $middleware->process($request, $handler); + $middleware->process($request, $handler); + } + + /** + * @covers \Engelsystem\Middleware\VerifyCsrfToken::__construct + * @covers \Engelsystem\Middleware\VerifyCsrfToken::tokensMatch + */ + public function testTokensMatch() + { + /** @var ServerRequestInterface|MockObject $request */ + $request = $this->getMockForAbstractClass(ServerRequestInterface::class); + /** @var RequestHandlerInterface|MockObject $handler */ + $handler = $this->getMockForAbstractClass(RequestHandlerInterface::class); + /** @var ResponseInterface|MockObject $response */ + $response = $this->getMockForAbstractClass(ResponseInterface::class); + /** @var ResponseInterface|MockObject $noAuthResponse */ + $noAuthResponse = $this->getMockForAbstractClass(ResponseInterface::class); + /** @var SessionInterface|MockObject $session */ + $session = $this->getMockForAbstractClass(SessionInterface::class); + + /** @var VerifyCsrfToken|MockObject $middleware */ + $middleware = $this->getMockBuilder(VerifyCsrfToken::class) + ->setConstructorArgs([$session]) + ->setMethods(['isReading', 'notAuthorizedResponse']) + ->getMock(); + + $middleware->expects($this->atLeastOnce()) + ->method('isReading') + ->willReturn(false); + $middleware->expects($this->exactly(1)) + ->method('notAuthorizedResponse') + ->willReturn($noAuthResponse); + + $handler->expects($this->exactly(3)) + ->method('handle') + ->willReturn($response); + + $request->expects($this->exactly(4)) + ->method('getParsedBody') + ->willReturnOnConsecutiveCalls( + null, + null, + ['_token' => 'PostFooToken'], + ['_token' => 'PostBarToken'] + ); + $request->expects($this->exactly(4)) + ->method('getHeader') + ->with('X-CSRF-TOKEN') + ->willReturnOnConsecutiveCalls( + [], + ['HeaderFooToken'], + [], + ['HeaderBarToken'] + ); + + $session->expects($this->exactly(4)) + ->method('get') + ->with('_token') + ->willReturnOnConsecutiveCalls( + 'NotAvailableToken', + 'HeaderFooToken', + 'PostFooToken', + 'PostBarToken' + ); + + // Not tokens + $this->assertEquals($noAuthResponse, $middleware->process($request, $handler)); + // Header token + $this->assertEquals($response, $middleware->process($request, $handler)); + // POST token + $this->assertEquals($response, $middleware->process($request, $handler)); + // Header and POST tokens + $this->assertEquals($response, $middleware->process($request, $handler)); + } +} diff --git a/tests/Unit/Renderer/Twig/Extensions/CsrfTest.php b/tests/Unit/Renderer/Twig/Extensions/CsrfTest.php new file mode 100644 index 00000000..644e6d50 --- /dev/null +++ b/tests/Unit/Renderer/Twig/Extensions/CsrfTest.php @@ -0,0 +1,63 @@ +createMock(SessionInterface::class); + + $extension = new Csrf($session); + $functions = $extension->getFunctions(); + + $this->assertExtensionExists('csrf', [$extension, 'getCsrfField'], $functions, ['is_safe' => ['html']]); + $this->assertExtensionExists('csrf_token', [$extension, 'getCsrfToken'], $functions); + } + + /** + * @covers \Engelsystem\Renderer\Twig\Extensions\Csrf::getCsrfField + */ + public function testGetCsrfField() + { + /** @var Csrf|MockObject $extension */ + $extension = $this->getMockBuilder(Csrf::class) + ->disableOriginalConstructor() + ->setMethods(['getCsrfToken']) + ->getMock(); + + $extension->expects($this->once()) + ->method('getCsrfToken') + ->willReturn('SomeRandomCsrfToken'); + + $this->assertEquals( + '', + $extension->getCsrfField() + ); + } + + /** + * @covers \Engelsystem\Renderer\Twig\Extensions\Csrf::__construct + * @covers \Engelsystem\Renderer\Twig\Extensions\Csrf::getCsrfToken + */ + public function testGetCsrfToken() + { + /** @var SessionInterface|MockObject $session */ + $session = $this->createMock(SessionInterface::class); + $session->expects($this->once()) + ->method('get') + ->with('_token') + ->willReturn('SomeOtherCsrfToken'); + + $extension = new Csrf($session); + $this->assertEquals('SomeOtherCsrfToken', $extension->getCsrfToken()); + } +} -- cgit v1.2.3-54-g00ecf