From cca73bb564adae22d0e9dd0c6dafbf1466a555c1 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Wed, 30 May 2018 10:06:54 -0400 Subject: [PATCH] Avoid migration on stateless firewalls --- .../Factory/GuardAuthenticationFactory.php | 1 + .../Security/Factory/HttpBasicFactory.php | 1 + .../Security/Factory/HttpDigestFactory.php | 1 + .../Security/Factory/RemoteUserFactory.php | 1 + .../SimplePreAuthenticationFactory.php | 1 + .../Security/Factory/X509Factory.php | 1 + .../DependencyInjection/SecurityExtension.php | 4 ++ .../Resources/config/security.xml | 4 ++ .../Bundle/SecurityBundle/composer.json | 2 +- .../Guard/GuardAuthenticatorHandler.php | 24 ++++++++---- .../Tests/GuardAuthenticatorHandlerTest.php | 37 +++++++++++++++++++ .../AbstractPreAuthenticatedListener.php | 24 ++++++++---- .../Firewall/BasicAuthenticationListener.php | 24 ++++++++---- .../Firewall/DigestAuthenticationListener.php | 27 ++++++++++---- .../SimplePreAuthenticationListener.php | 24 ++++++++---- 15 files changed, 138 insertions(+), 38 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/GuardAuthenticationFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/GuardAuthenticationFactory.php index 533560d6d9..bd49cbc932 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/GuardAuthenticationFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/GuardAuthenticationFactory.php @@ -77,6 +77,7 @@ class GuardAuthenticationFactory implements SecurityFactoryInterface $listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.authentication.listener.guard')); $listener->replaceArgument(2, $id); $listener->replaceArgument(3, $authenticatorReferences); + $listener->addMethodCall('setSessionAuthenticationStrategy', array(new Reference('security.authentication.session_strategy.'.$id))); // determine the entryPointId to use $entryPointId = $this->determineEntryPoint($defaultEntryPoint, $config); diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/HttpBasicFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/HttpBasicFactory.php index 162ea05157..f09636ec71 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/HttpBasicFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/HttpBasicFactory.php @@ -41,6 +41,7 @@ class HttpBasicFactory implements SecurityFactoryInterface $listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.authentication.listener.basic')); $listener->replaceArgument(2, $id); $listener->replaceArgument(3, new Reference($entryPointId)); + $listener->addMethodCall('setSessionAuthenticationStrategy', array(new Reference('security.authentication.session_strategy.'.$id))); return array($provider, $listenerId, $entryPointId); } diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/HttpDigestFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/HttpDigestFactory.php index 4cfb79653c..944a9100f3 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/HttpDigestFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/HttpDigestFactory.php @@ -42,6 +42,7 @@ class HttpDigestFactory implements SecurityFactoryInterface $listener->replaceArgument(1, new Reference($userProvider)); $listener->replaceArgument(2, $id); $listener->replaceArgument(3, new Reference($entryPointId)); + $listener->addMethodCall('setSessionAuthenticationStrategy', array(new Reference('security.authentication.session_strategy.'.$id))); return array($provider, $listenerId, $entryPointId); } diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RemoteUserFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RemoteUserFactory.php index cf2e2ed71b..5be068e6c4 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RemoteUserFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RemoteUserFactory.php @@ -38,6 +38,7 @@ class RemoteUserFactory implements SecurityFactoryInterface $listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.authentication.listener.remote_user')); $listener->replaceArgument(2, $id); $listener->replaceArgument(3, $config['user']); + $listener->addMethodCall('setSessionAuthenticationStrategy', array(new Reference('security.authentication.session_strategy.'.$id))); return array($providerId, $listenerId, $defaultEntryPoint); } diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimplePreAuthenticationFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimplePreAuthenticationFactory.php index c1c6e48083..03fca8d6a2 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimplePreAuthenticationFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimplePreAuthenticationFactory.php @@ -57,6 +57,7 @@ class SimplePreAuthenticationFactory implements SecurityFactoryInterface $listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.authentication.listener.simple_preauth')); $listener->replaceArgument(2, $id); $listener->replaceArgument(3, new Reference($config['authenticator'])); + $listener->addMethodCall('setSessionAuthenticationStrategy', array(new Reference('security.authentication.session_strategy.'.$id))); return array($provider, $listenerId, null); } diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/X509Factory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/X509Factory.php index 0467ef2ba2..a745de9b2d 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/X509Factory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/X509Factory.php @@ -39,6 +39,7 @@ class X509Factory implements SecurityFactoryInterface $listener->replaceArgument(2, $id); $listener->replaceArgument(3, $config['user']); $listener->replaceArgument(4, $config['credentials']); + $listener->addMethodCall('setSessionAuthenticationStrategy', array(new Reference('security.authentication.session_strategy.'.$id))); return array($providerId, $listenerId, $defaultEntryPoint); } diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 34276e95e7..5138eff367 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -285,7 +285,11 @@ class SecurityExtension extends Extension } $listeners[] = new Reference($this->createContextListener($container, $contextKey)); + $sessionStrategyId = 'security.authentication.session_strategy'; + } else { + $sessionStrategyId = 'security.authentication.session_strategy_noop'; } + $container->setAlias(new Alias('security.authentication.session_strategy.'.$id, false), $sessionStrategyId); // Logout listener $logoutListenerId = null; diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml index 029395de9d..74b097aa4c 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml @@ -84,6 +84,10 @@ %security.authentication.session_strategy.strategy% + + none + + diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index f588b04888..c0508ea29b 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -18,7 +18,7 @@ "require": { "php": ">=5.3.9", "ext-xml": "*", - "symfony/security": "^2.8.41|^3.4.11", + "symfony/security": "^2.8.42|^3.4.12", "symfony/security-acl": "~2.7|~3.0.0", "symfony/http-kernel": "~2.7|~3.0.0", "symfony/polyfill-php70": "~1.0" diff --git a/src/Symfony/Component/Security/Guard/GuardAuthenticatorHandler.php b/src/Symfony/Component/Security/Guard/GuardAuthenticatorHandler.php index 5e6eba339b..0164ba9235 100644 --- a/src/Symfony/Component/Security/Guard/GuardAuthenticatorHandler.php +++ b/src/Symfony/Component/Security/Guard/GuardAuthenticatorHandler.php @@ -20,6 +20,7 @@ use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; use Symfony\Component\Security\Http\SecurityEvents; +use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; /** * A utility class that does much of the *work* during the guard authentication process. @@ -32,8 +33,8 @@ use Symfony\Component\Security\Http\SecurityEvents; class GuardAuthenticatorHandler { private $tokenStorage; - private $dispatcher; + private $sessionStrategy; public function __construct(TokenStorageInterface $tokenStorage, EventDispatcherInterface $eventDispatcher = null) { @@ -46,7 +47,7 @@ class GuardAuthenticatorHandler */ public function authenticateWithToken(TokenInterface $token, Request $request) { - $this->migrateSession($request); + $this->migrateSession($request, $token); $this->tokenStorage->setToken($token); if (null !== $this->dispatcher) { @@ -129,15 +130,22 @@ class GuardAuthenticatorHandler )); } - private function migrateSession(Request $request) + /** + * Call this method if your authentication token is stored to a session. + * + * @final since version 2.8 + */ + public function setSessionAuthenticationStrategy(SessionAuthenticationStrategyInterface $sessionStrategy) { - if (!$request->hasSession() || !$request->hasPreviousSession()) { + $this->sessionStrategy = $sessionStrategy; + } + + private function migrateSession(Request $request, TokenInterface $token) + { + if (!$this->sessionStrategy || !$request->hasSession() || !$request->hasPreviousSession()) { return; } - // Destroying the old session is broken in php 5.4.0 - 5.4.10 - // See https://bugs.php.net/63379 - $destroy = \PHP_VERSION_ID < 50400 || \PHP_VERSION_ID >= 50411; - $request->getSession()->migrate($destroy); + $this->sessionStrategy->onAuthentication($request, $token); } } diff --git a/src/Symfony/Component/Security/Guard/Tests/GuardAuthenticatorHandlerTest.php b/src/Symfony/Component/Security/Guard/Tests/GuardAuthenticatorHandlerTest.php index 662bace308..49ce6548ac 100644 --- a/src/Symfony/Component/Security/Guard/Tests/GuardAuthenticatorHandlerTest.php +++ b/src/Symfony/Component/Security/Guard/Tests/GuardAuthenticatorHandlerTest.php @@ -25,6 +25,7 @@ class GuardAuthenticatorHandlerTest extends TestCase private $dispatcher; private $token; private $request; + private $sessionStrategy; private $guardAuthenticator; public function testAuthenticateWithToken() @@ -117,12 +118,38 @@ class GuardAuthenticatorHandlerTest extends TestCase return $tests; } + public function testNoFailureIfSessionStrategyNotPassed() + { + $this->configurePreviousSession(); + + $this->tokenStorage->expects($this->once()) + ->method('setToken') + ->with($this->token); + + $handler = new GuardAuthenticatorHandler($this->tokenStorage, $this->dispatcher); + $handler->authenticateWithToken($this->token, $this->request); + } + + public function testSessionStrategyIsCalled() + { + $this->configurePreviousSession(); + + $this->sessionStrategy->expects($this->once()) + ->method('onAuthentication') + ->with($this->request, $this->token); + + $handler = new GuardAuthenticatorHandler($this->tokenStorage, $this->dispatcher); + $handler->setSessionAuthenticationStrategy($this->sessionStrategy); + $handler->authenticateWithToken($this->token, $this->request); + } + protected function setUp() { $this->tokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface')->getMock(); $this->dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); $this->token = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock(); $this->request = new Request(array(), array(), array(), array(), array(), array()); + $this->sessionStrategy = $this->getMockBuilder('Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface')->getMock(); $this->guardAuthenticator = $this->getMockBuilder('Symfony\Component\Security\Guard\GuardAuthenticatorInterface')->getMock(); } @@ -134,4 +161,14 @@ class GuardAuthenticatorHandlerTest extends TestCase $this->request = null; $this->guardAuthenticator = null; } + + private function configurePreviousSession() + { + $session = $this->getMockBuilder('Symfony\Component\HttpFoundation\Session\SessionInterface')->getMock(); + $session->expects($this->any()) + ->method('getName') + ->willReturn('test_session_name'); + $this->request->setSession($session); + $this->request->cookies->set('test_session_name', 'session_cookie_val'); + } } diff --git a/src/Symfony/Component/Security/Http/Firewall/AbstractPreAuthenticatedListener.php b/src/Symfony/Component/Security/Http/Firewall/AbstractPreAuthenticatedListener.php index 2054c4aa07..6451d882e8 100644 --- a/src/Symfony/Component/Security/Http/Firewall/AbstractPreAuthenticatedListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/AbstractPreAuthenticatedListener.php @@ -14,6 +14,7 @@ namespace Symfony\Component\Security\Http\Firewall; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; use Symfony\Component\Security\Http\SecurityEvents; @@ -22,6 +23,7 @@ use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Security\Core\Exception\BadCredentialsException; +use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; /** * AbstractPreAuthenticatedListener is the base class for all listener that @@ -37,6 +39,7 @@ abstract class AbstractPreAuthenticatedListener implements ListenerInterface private $authenticationManager; private $providerKey; private $dispatcher; + private $sessionStrategy; public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, $providerKey, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null) { @@ -83,7 +86,7 @@ abstract class AbstractPreAuthenticatedListener implements ListenerInterface $this->logger->info('Pre-authentication successful.', array('token' => (string) $token)); } - $this->migrateSession($request); + $this->migrateSession($request, $token); $this->tokenStorage->setToken($token); @@ -96,6 +99,16 @@ abstract class AbstractPreAuthenticatedListener implements ListenerInterface } } + /** + * Call this method if your authentication token is stored to a session. + * + * @final since version 2.8 + */ + public function setSessionAuthenticationStrategy(SessionAuthenticationStrategyInterface $sessionStrategy) + { + $this->sessionStrategy = $sessionStrategy; + } + /** * Clears a PreAuthenticatedToken for this provider (if present). */ @@ -118,15 +131,12 @@ abstract class AbstractPreAuthenticatedListener implements ListenerInterface */ abstract protected function getPreAuthenticatedData(Request $request); - private function migrateSession(Request $request) + private function migrateSession(Request $request, TokenInterface $token) { - if (!$request->hasSession() || !$request->hasPreviousSession()) { + if (!$this->sessionStrategy || !$request->hasSession() || !$request->hasPreviousSession()) { return; } - // Destroying the old session is broken in php 5.4.0 - 5.4.10 - // See https://bugs.php.net/63379 - $destroy = \PHP_VERSION_ID < 50400 || \PHP_VERSION_ID >= 50411; - $request->getSession()->migrate($destroy); + $this->sessionStrategy->onAuthentication($request, $token); } } diff --git a/src/Symfony/Component/Security/Http/Firewall/BasicAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/BasicAuthenticationListener.php index 63bd013c64..4b14a842dc 100644 --- a/src/Symfony/Component/Security/Http/Firewall/BasicAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/BasicAuthenticationListener.php @@ -14,11 +14,13 @@ namespace Symfony\Component\Security\Http\Firewall; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Exception\AuthenticationException; +use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; /** * BasicAuthenticationListener implements Basic HTTP authentication. @@ -33,6 +35,7 @@ class BasicAuthenticationListener implements ListenerInterface private $authenticationEntryPoint; private $logger; private $ignoreFailure; + private $sessionStrategy; public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, $providerKey, AuthenticationEntryPointInterface $authenticationEntryPoint, LoggerInterface $logger = null) { @@ -72,7 +75,7 @@ class BasicAuthenticationListener implements ListenerInterface try { $token = $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $request->headers->get('PHP_AUTH_PW'), $this->providerKey)); - $this->migrateSession($request); + $this->migrateSession($request, $token); $this->tokenStorage->setToken($token); } catch (AuthenticationException $e) { @@ -93,15 +96,22 @@ class BasicAuthenticationListener implements ListenerInterface } } - private function migrateSession(Request $request) + /** + * Call this method if your authentication token is stored to a session. + * + * @final since version 2.8 + */ + public function setSessionAuthenticationStrategy(SessionAuthenticationStrategyInterface $sessionStrategy) { - if (!$request->hasSession() || !$request->hasPreviousSession()) { + $this->sessionStrategy = $sessionStrategy; + } + + private function migrateSession(Request $request, TokenInterface $token) + { + if (!$this->sessionStrategy || !$request->hasSession() || !$request->hasPreviousSession()) { return; } - // Destroying the old session is broken in php 5.4.0 - 5.4.10 - // See https://bugs.php.net/63379 - $destroy = \PHP_VERSION_ID < 50400 || \PHP_VERSION_ID >= 50411; - $request->getSession()->migrate($destroy); + $this->sessionStrategy->onAuthentication($request, $token); } } diff --git a/src/Symfony/Component/Security/Http/Firewall/DigestAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/DigestAuthenticationListener.php index 5655315a8b..b4853931ca 100644 --- a/src/Symfony/Component/Security/Http/Firewall/DigestAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/DigestAuthenticationListener.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Security\Http\Firewall; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Http\EntryPoint\DigestAuthenticationEntryPoint; use Psr\Log\LoggerInterface; @@ -23,6 +24,7 @@ use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; use Symfony\Component\Security\Core\Exception\NonceExpiredException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Core\Exception\AuthenticationException; +use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; /** * DigestAuthenticationListener implements Digest HTTP authentication. @@ -36,6 +38,7 @@ class DigestAuthenticationListener implements ListenerInterface private $providerKey; private $authenticationEntryPoint; private $logger; + private $sessionStrategy; public function __construct(TokenStorageInterface $tokenStorage, UserProviderInterface $provider, $providerKey, DigestAuthenticationEntryPoint $authenticationEntryPoint, LoggerInterface $logger = null) { @@ -117,9 +120,20 @@ class DigestAuthenticationListener implements ListenerInterface $this->logger->info('Digest authentication successful.', array('username' => $digestAuth->getUsername(), 'received' => $digestAuth->getResponse())); } - $this->migrateSession($request); + $token = new UsernamePasswordToken($user, $user->getPassword(), $this->providerKey); + $this->migrateSession($request, $token); - $this->tokenStorage->setToken(new UsernamePasswordToken($user, $user->getPassword(), $this->providerKey)); + $this->tokenStorage->setToken($token); + } + + /** + * Call this method if your authentication token is stored to a session. + * + * @final since version 2.8 + */ + public function setSessionAuthenticationStrategy(SessionAuthenticationStrategyInterface $sessionStrategy) + { + $this->sessionStrategy = $sessionStrategy; } private function fail(GetResponseEvent $event, Request $request, AuthenticationException $authException) @@ -136,16 +150,13 @@ class DigestAuthenticationListener implements ListenerInterface $event->setResponse($this->authenticationEntryPoint->start($request, $authException)); } - private function migrateSession(Request $request) + private function migrateSession(Request $request, TokenInterface $token) { - if (!$request->hasSession() || !$request->hasPreviousSession()) { + if (!$this->sessionStrategy || !$request->hasSession() || !$request->hasPreviousSession()) { return; } - // Destroying the old session is broken in php 5.4.0 - 5.4.10 - // See https://bugs.php.net/63379 - $destroy = \PHP_VERSION_ID < 50400 || \PHP_VERSION_ID >= 50411; - $request->getSession()->migrate($destroy); + $this->sessionStrategy->onAuthentication($request, $token); } } diff --git a/src/Symfony/Component/Security/Http/Firewall/SimplePreAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/SimplePreAuthenticationListener.php index 23e517969f..cdfb06d4fa 100644 --- a/src/Symfony/Component/Security/Http/Firewall/SimplePreAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/SimplePreAuthenticationListener.php @@ -19,12 +19,14 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Security\Core\Authentication\SimplePreAuthenticatorInterface; use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; use Symfony\Component\Security\Http\SecurityEvents; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; /** * SimplePreAuthenticationListener implements simple proxying to an authenticator. @@ -39,6 +41,7 @@ class SimplePreAuthenticationListener implements ListenerInterface private $simpleAuthenticator; private $logger; private $dispatcher; + private $sessionStrategy; /** * @param TokenStorageInterface $tokenStorage A TokenStorageInterface instance @@ -62,6 +65,16 @@ class SimplePreAuthenticationListener implements ListenerInterface $this->dispatcher = $dispatcher; } + /** + * Call this method if your authentication token is stored to a session. + * + * @final since version 2.8 + */ + public function setSessionAuthenticationStrategy(SessionAuthenticationStrategyInterface $sessionStrategy) + { + $this->sessionStrategy = $sessionStrategy; + } + /** * Handles basic authentication. */ @@ -87,7 +100,7 @@ class SimplePreAuthenticationListener implements ListenerInterface $token = $this->authenticationManager->authenticate($token); - $this->migrateSession($request); + $this->migrateSession($request, $token); $this->tokenStorage->setToken($token); @@ -124,15 +137,12 @@ class SimplePreAuthenticationListener implements ListenerInterface } } - private function migrateSession(Request $request) + private function migrateSession(Request $request, TokenInterface $token) { - if (!$request->hasSession() || !$request->hasPreviousSession()) { + if (!$this->sessionStrategy || !$request->hasSession() || !$request->hasPreviousSession()) { return; } - // Destroying the old session is broken in php 5.4.0 - 5.4.10 - // See https://bugs.php.net/63379 - $destroy = \PHP_VERSION_ID < 50400 || \PHP_VERSION_ID >= 50411; - $request->getSession()->migrate($destroy); + $this->sessionStrategy->onAuthentication($request, $token); } }