From 7b14bff03117080680652a5e52811af2847b81d6 Mon Sep 17 00:00:00 2001 From: nealio82 Date: Tue, 11 Sep 2018 18:13:14 +0100 Subject: [PATCH 1/5] add session cookie handling/retrieval for SymfonyAdapter --- src/Bridge/Symfony/SymfonyAdapter.php | 18 ++++++++- tests/Bridge/Symfony/SymfonyAdapterTest.php | 42 ++++++++++++++++++++- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/Bridge/Symfony/SymfonyAdapter.php b/src/Bridge/Symfony/SymfonyAdapter.php index 02bd50759..fc129baca 100644 --- a/src/Bridge/Symfony/SymfonyAdapter.php +++ b/src/Bridge/Symfony/SymfonyAdapter.php @@ -8,6 +8,7 @@ use Psr\Http\Server\RequestHandlerInterface; use Symfony\Bridge\PsrHttpMessage\Factory\DiactorosFactory; use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory; +use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\TerminableInterface; @@ -28,12 +29,27 @@ public function __construct(HttpKernelInterface $httpKernel) $this->httpKernel = $httpKernel; } - public function handle(ServerRequestInterface $request) : ResponseInterface + public function handle(ServerRequestInterface $request): ResponseInterface { $httpFoundationFactory = new HttpFoundationFactory; + $symfonyRequest = $httpFoundationFactory->createRequest($request); + if (!is_null($symfonyRequest->cookies->get(session_name()))) { + $this->httpKernel->getContainer()->get('session')->setId( + $symfonyRequest->cookies->get(session_name()) + ); + } + $symfonyResponse = $this->httpKernel->handle($symfonyRequest); + + $symfonyResponse->headers->setCookie( + new Cookie( + session_name(), + $this->httpKernel->getContainer()->get('session')->getId() + ) + ); + if ($this->httpKernel instanceof TerminableInterface) { $this->httpKernel->terminate($symfonyRequest, $symfonyResponse); } diff --git a/tests/Bridge/Symfony/SymfonyAdapterTest.php b/tests/Bridge/Symfony/SymfonyAdapterTest.php index 842f32fbf..4ec730a89 100644 --- a/tests/Bridge/Symfony/SymfonyAdapterTest.php +++ b/tests/Bridge/Symfony/SymfonyAdapterTest.php @@ -11,6 +11,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\HttpKernelInterface; @@ -45,7 +46,39 @@ public function test 404 are PSR7 responses and not exceptions() self::assertSame(404, $response->getStatusCode()); } - private function createKernel() : HttpKernelInterface + public function test an active session is created() + { + $adapter = new SymfonyAdapter($this->createKernel()); + $response = $adapter->handle(new ServerRequest([], [], '/bar')); + + self::assertArrayHasKey('Set-Cookie', $response->getHeaders()); + } + + public function test an active session is retrieved() + { + $kernel = $this->createKernel(); + $kernel->boot(); + + $adapter = new SymfonyAdapter($kernel); + $symfonyResponse = $adapter->handle( + new ServerRequest( + [], + [], + '/bar', + null, + 'php://input', + [], + [\session_name() => 'SESSIONID'] + ) + ); + + self::assertContains( + sprintf("%s=SESSIONID", \session_name()), + $symfonyResponse->getHeaders()['Set-Cookie'][0] + ); + } + + private function createKernel(): HttpKernelInterface { return new class('dev', false) extends Kernel implements EventSubscriberInterface { use MicroKernelTrait; @@ -57,8 +90,13 @@ public function registerBundles() protected function configureContainer(ContainerBuilder $c) { + $c->register('session_storage', NativeSessionStorage::class); + $c->loadFromExtension('framework', [ - 'secret' => 'foo', + 'secret' => 'foo', + 'session' => [ + 'storage_id' => 'session_storage' + ] ]); } From 975d25a14bf1363617f64582044334f350bfb287 Mon Sep 17 00:00:00 2001 From: nealio82 Date: Tue, 11 Sep 2018 18:56:48 +0100 Subject: [PATCH 2/5] refactor session handling into private methods --- src/Bridge/Symfony/SymfonyAdapter.php | 38 +++++++++++++++++++-------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/src/Bridge/Symfony/SymfonyAdapter.php b/src/Bridge/Symfony/SymfonyAdapter.php index fc129baca..1214018cf 100644 --- a/src/Bridge/Symfony/SymfonyAdapter.php +++ b/src/Bridge/Symfony/SymfonyAdapter.php @@ -35,20 +35,11 @@ public function handle(ServerRequestInterface $request): ResponseInterface $symfonyRequest = $httpFoundationFactory->createRequest($request); - if (!is_null($symfonyRequest->cookies->get(session_name()))) { - $this->httpKernel->getContainer()->get('session')->setId( - $symfonyRequest->cookies->get(session_name()) - ); - } + $this->loadSessionFromCookies($symfonyRequest); $symfonyResponse = $this->httpKernel->handle($symfonyRequest); - $symfonyResponse->headers->setCookie( - new Cookie( - session_name(), - $this->httpKernel->getContainer()->get('session')->getId() - ) - ); + $this->addSessionCookieToResponse($symfonyResponse); if ($this->httpKernel instanceof TerminableInterface) { $this->httpKernel->terminate($symfonyRequest, $symfonyResponse); @@ -59,4 +50,29 @@ public function handle(ServerRequestInterface $request): ResponseInterface return $response; } + + /** + * @param $symfonyRequest + */ + private function loadSessionFromCookies($symfonyRequest): void + { + if (!is_null($symfonyRequest->cookies->get(session_name()))) { + $this->httpKernel->getContainer()->get('session')->setId( + $symfonyRequest->cookies->get(session_name()) + ); + } + } + + /** + * @param $symfonyResponse + */ + private function addSessionCookieToResponse($symfonyResponse): void + { + $symfonyResponse->headers->setCookie( + new Cookie( + session_name(), + $this->httpKernel->getContainer()->get('session')->getId() + ) + ); + } } From 36f3c1c5187ee5ba462a86eac90c4b10ff3dda91 Mon Sep 17 00:00:00 2001 From: nealio82 Date: Tue, 11 Sep 2018 19:27:28 +0100 Subject: [PATCH 3/5] use MockArraySessionStorage in tests --- tests/Bridge/Symfony/SymfonyAdapterTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Bridge/Symfony/SymfonyAdapterTest.php b/tests/Bridge/Symfony/SymfonyAdapterTest.php index 4ec730a89..428055973 100644 --- a/tests/Bridge/Symfony/SymfonyAdapterTest.php +++ b/tests/Bridge/Symfony/SymfonyAdapterTest.php @@ -11,7 +11,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; +use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\HttpKernelInterface; @@ -90,7 +90,7 @@ public function registerBundles() protected function configureContainer(ContainerBuilder $c) { - $c->register('session_storage', NativeSessionStorage::class); + $c->register('session_storage', MockArraySessionStorage::class); $c->loadFromExtension('framework', [ 'secret' => 'foo', From 3aab5043dba81be2e7cfe87cda947e3be24ef64d Mon Sep 17 00:00:00 2001 From: nealio82 Date: Tue, 11 Sep 2018 20:29:34 +0100 Subject: [PATCH 4/5] update cookie test to show httponly --- tests/Bridge/Symfony/SymfonyAdapterTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Bridge/Symfony/SymfonyAdapterTest.php b/tests/Bridge/Symfony/SymfonyAdapterTest.php index 428055973..cd7dde1fd 100644 --- a/tests/Bridge/Symfony/SymfonyAdapterTest.php +++ b/tests/Bridge/Symfony/SymfonyAdapterTest.php @@ -72,8 +72,8 @@ public function test an active session is retrieved() ) ); - self::assertContains( - sprintf("%s=SESSIONID", \session_name()), + self::assertSame( + sprintf("%s=SESSIONID; path=/; httponly", \session_name()), $symfonyResponse->getHeaders()['Set-Cookie'][0] ); } From f92ee66293854bd03f2da98198ce397bee261243 Mon Sep 17 00:00:00 2001 From: nealio82 Date: Tue, 11 Sep 2018 20:54:32 +0100 Subject: [PATCH 5/5] add samesite=lax to session cookie --- src/Bridge/Symfony/SymfonyAdapter.php | 9 ++++++++- tests/Bridge/Symfony/SymfonyAdapterTest.php | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Bridge/Symfony/SymfonyAdapter.php b/src/Bridge/Symfony/SymfonyAdapter.php index 1214018cf..228464335 100644 --- a/src/Bridge/Symfony/SymfonyAdapter.php +++ b/src/Bridge/Symfony/SymfonyAdapter.php @@ -71,7 +71,14 @@ private function addSessionCookieToResponse($symfonyResponse): void $symfonyResponse->headers->setCookie( new Cookie( session_name(), - $this->httpKernel->getContainer()->get('session')->getId() + $this->httpKernel->getContainer()->get('session')->getId(), + 0, + "/", + null, + false, + true, + false, + Cookie::SAMESITE_LAX ) ); } diff --git a/tests/Bridge/Symfony/SymfonyAdapterTest.php b/tests/Bridge/Symfony/SymfonyAdapterTest.php index cd7dde1fd..bec0860cd 100644 --- a/tests/Bridge/Symfony/SymfonyAdapterTest.php +++ b/tests/Bridge/Symfony/SymfonyAdapterTest.php @@ -73,7 +73,7 @@ public function test an active session is retrieved() ); self::assertSame( - sprintf("%s=SESSIONID; path=/; httponly", \session_name()), + sprintf("%s=SESSIONID; path=/; httponly; samesite=lax", \session_name()), $symfonyResponse->getHeaders()['Set-Cookie'][0] ); }