From 5f16d09578bbe3b030afa9033de1c6619f1d670e Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 2 Jan 2025 18:13:47 +0100 Subject: [PATCH 1/2] [Security] Fix triggering session tracking from ContextListener --- Firewall/ContextListener.php | 3 +++ Tests/Firewall/ContextListenerTest.php | 2 ++ 2 files changed, 5 insertions(+) diff --git a/Firewall/ContextListener.php b/Firewall/ContextListener.php index 7aeec196..e8ad79d8 100644 --- a/Firewall/ContextListener.php +++ b/Firewall/ContextListener.php @@ -164,6 +164,7 @@ public function onKernelResponse(ResponseEvent $event): void $session = $request->getSession(); $sessionId = $session->getId(); $usageIndexValue = $session instanceof Session ? $usageIndexReference = &$session->getUsageIndex() : null; + $usageIndexReference = \PHP_INT_MIN; $token = $this->tokenStorage->getToken(); if (!$this->trustResolver->isAuthenticated($token)) { @@ -178,6 +179,8 @@ public function onKernelResponse(ResponseEvent $event): void if ($this->sessionTrackerEnabler && $session->getId() === $sessionId) { $usageIndexReference = $usageIndexValue; + } else { + $usageIndexReference = $usageIndexReference - \PHP_INT_MIN + $usageIndexValue; } } diff --git a/Tests/Firewall/ContextListenerTest.php b/Tests/Firewall/ContextListenerTest.php index f1d76a17..8d0ab726 100644 --- a/Tests/Firewall/ContextListenerTest.php +++ b/Tests/Firewall/ContextListenerTest.php @@ -323,6 +323,8 @@ public function testSessionIsNotReported() $listener = new ContextListener($tokenStorage, [], 'context_key', null, null, null, $tokenStorage->getToken(...)); $listener(new RequestEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST)); + + $listener->onKernelResponse(new ResponseEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST, new Response())); } public function testOnKernelResponseRemoveListener() From 54f2ccce1f3822eee3fb3a85debd9a67d12762b8 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Thu, 23 Jan 2025 09:38:36 +0100 Subject: [PATCH 2/2] [Security] Throw an explicit error when authenticating a token with a null user --- Firewall/ContextListener.php | 4 ++++ Tests/Firewall/ContextListenerTest.php | 25 +++++++++++++++++++++++++ Tests/Fixtures/NullUserToken.php | 23 +++++++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 Tests/Fixtures/NullUserToken.php diff --git a/Firewall/ContextListener.php b/Firewall/ContextListener.php index e8ad79d8..d06b6d57 100644 --- a/Firewall/ContextListener.php +++ b/Firewall/ContextListener.php @@ -123,6 +123,10 @@ public function authenticate(RequestEvent $event): void ]); if ($token instanceof TokenInterface) { + if (!$token->getUser()) { + throw new \UnexpectedValueException(\sprintf('Cannot authenticate a "%s" token because it doesn\'t store a user.', $token::class)); + } + $originalToken = $token; $token = $this->refreshUser($token); diff --git a/Tests/Firewall/ContextListenerTest.php b/Tests/Firewall/ContextListenerTest.php index 8d0ab726..8dcf96ed 100644 --- a/Tests/Firewall/ContextListenerTest.php +++ b/Tests/Firewall/ContextListenerTest.php @@ -36,6 +36,7 @@ use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Http\Firewall\ContextListener; +use Symfony\Component\Security\Http\Tests\Fixtures\NullUserToken; use Symfony\Contracts\Service\ServiceLocatorTrait; class ContextListenerTest extends TestCase @@ -58,6 +59,30 @@ public function testUserProvidersNeedToImplementAnInterface() $this->handleEventWithPreviousSession([new \stdClass()]); } + public function testTokenReturnsNullUser() + { + $tokenStorage = new TokenStorage(); + $tokenStorage->setToken(new NullUserToken()); + + $session = new Session(new MockArraySessionStorage()); + $session->set('_security_context_key', serialize($tokenStorage->getToken())); + + $request = new Request(); + $request->setSession($session); + $request->cookies->set('MOCKSESSID', true); + + $listener = new ContextListener($tokenStorage, [], 'context_key'); + + $this->expectException(\UnexpectedValueException::class); + $this->expectExceptionMessage('Cannot authenticate a "Symfony\Component\Security\Http\Tests\Fixtures\NullUserToken" token because it doesn\'t store a user.'); + + $listener->authenticate(new RequestEvent( + $this->createMock(HttpKernelInterface::class), + $request, + HttpKernelInterface::MAIN_REQUEST, + )); + } + public function testOnKernelResponseWillAddSession() { $session = $this->runSessionOnKernelResponse( diff --git a/Tests/Fixtures/NullUserToken.php b/Tests/Fixtures/NullUserToken.php new file mode 100644 index 00000000..95048e46 --- /dev/null +++ b/Tests/Fixtures/NullUserToken.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Http\Tests\Fixtures; + +use Symfony\Component\Security\Core\Authentication\Token\AbstractToken; +use Symfony\Component\Security\Core\User\UserInterface; + +class NullUserToken extends AbstractToken +{ + public function getUser(): ?UserInterface + { + return null; + } +}