From 95dce676290340231464108cbeee32e51779fd8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Geoffrey=20P=C3=A9cro?= Date: Sun, 29 Jul 2018 20:56:37 +0200 Subject: [PATCH] [Security] Do not deauthenticate user when the first refreshed user has changed --- .../Http/Firewall/ContextListener.php | 22 +++++++++++++++---- .../Tests/Firewall/ContextListenerTest.php | 9 ++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php index 4c250a777367..cdaebbca7589 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php @@ -161,6 +161,7 @@ protected function refreshUser(TokenInterface $token) } $userNotFoundByProvider = false; + $userDeauthenticated = false; foreach ($this->userProviders as $provider) { if (!$provider instanceof UserProviderInterface) { @@ -169,21 +170,26 @@ protected function refreshUser(TokenInterface $token) try { $refreshedUser = $provider->refreshUser($user); - $token->setUser($refreshedUser); + $newToken = unserialize(serialize($token)); + $newToken->setUser($refreshedUser); // tokens can be deauthenticated if the user has been changed. - if (!$token->isAuthenticated()) { + if (!$newToken->isAuthenticated()) { if ($this->logoutOnUserChange) { + $userDeauthenticated = true; + if (null !== $this->logger) { - $this->logger->debug('Token was deauthenticated after trying to refresh it.', array('username' => $refreshedUser->getUsername(), 'provider' => \get_class($provider))); + $this->logger->debug('Cannot refresh token because user has changed.', array('username' => $refreshedUser->getUsername(), 'provider' => \get_class($provider))); } - return null; + continue; } @trigger_error('Refreshing a deauthenticated user is deprecated as of 3.4 and will trigger a logout in 4.0.', E_USER_DEPRECATED); } + $token->setUser($refreshedUser); + if (null !== $this->logger) { $context = array('provider' => \get_class($provider), 'username' => $refreshedUser->getUsername()); @@ -209,6 +215,14 @@ protected function refreshUser(TokenInterface $token) } } + if ($userDeauthenticated) { + if (null !== $this->logger) { + $this->logger->debug('Token was deauthenticated after trying to refresh it.'); + } + + return null; + } + if ($userNotFoundByProvider) { return null; } diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php index f4e2ae7f724c..bb49d039611c 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php @@ -273,6 +273,15 @@ public function testIfTokenIsDeauthenticated() $this->assertNull($tokenStorage->getToken()); } + public function testIfTokenIsNotDeauthenticated() + { + $tokenStorage = new TokenStorage(); + $badRefreshedUser = new User('foobar', 'baz'); + $goodRefreshedUser = new User('foobar', 'bar'); + $this->handleEventWithPreviousSession($tokenStorage, array(new SupportingUserProvider($badRefreshedUser), new SupportingUserProvider($goodRefreshedUser)), $goodRefreshedUser, true); + $this->assertSame($goodRefreshedUser, $tokenStorage->getToken()->getUser()); + } + public function testTryAllUserProvidersUntilASupportingUserProviderIsFound() { $tokenStorage = new TokenStorage();