diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/JsonLoginFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/JsonLoginFactory.php index 5a391ffacaeab..6c7adb032395b 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/JsonLoginFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/JsonLoginFactory.php @@ -89,6 +89,7 @@ protected function createListener($container, $id, $config, $userProvider) $listener->replaceArgument(4, isset($config['success_handler']) ? new Reference($this->createAuthenticationSuccessHandler($container, $id, $config)) : null); $listener->replaceArgument(5, isset($config['failure_handler']) ? new Reference($this->createAuthenticationFailureHandler($container, $id, $config)) : null); $listener->replaceArgument(6, array_intersect_key($config, $this->options)); + $listener->addMethodCall('setSessionAuthenticationStrategy', array(new Reference('security.authentication.session_strategy.'.$id))); $listenerId .= '.'.$id; $container->setDefinition($listenerId, $listener); diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index d8f1db8dd96f4..b17c93f3e90c2 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -377,7 +377,11 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a $this->logoutOnUserChangeByContextKey[$contextKey] = array($id, $logoutOnUserChange); $listeners[] = new Reference($this->createContextListener($container, $contextKey, $logoutOnUserChange)); + $sessionStrategyId = 'security.authentication.session_strategy'; + } else { + $sessionStrategyId = 'security.authentication.session_strategy_noop'; } + $container->setAlias(new Alias('security.authentication.session_strategy.'.$id, false), $sessionStrategyId); $config->replaceArgument(6, $contextKey); diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml index 515f56db6e8ca..dea2481df457a 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml @@ -62,6 +62,9 @@ %security.authentication.session_strategy.strategy% + + none + diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index cc46a01f0f678..ebf39d1beea59 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -18,7 +18,7 @@ "require": { "php": "^5.5.9|>=7.0.8", "ext-xml": "*", - "symfony/security": "~3.4.11|^4.0.11", + "symfony/security": "~3.4.12|^4.0.12|^4.1.1", "symfony/dependency-injection": "^3.4.3|^4.0.3", "symfony/http-kernel": "~3.4|~4.0", "symfony/polyfill-php70": "~1.0" diff --git a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordJsonAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordJsonAuthenticationListener.php index 8bde1e00151e8..d83e94d4b2efb 100644 --- a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordJsonAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordJsonAuthenticationListener.php @@ -33,6 +33,7 @@ use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; use Symfony\Component\Security\Http\HttpUtils; use Symfony\Component\Security\Http\SecurityEvents; +use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; /** * UsernamePasswordJsonAuthenticationListener is a stateless implementation of @@ -52,6 +53,7 @@ class UsernamePasswordJsonAuthenticationListener implements ListenerInterface private $logger; private $eventDispatcher; private $propertyAccessor; + private $sessionStrategy; public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler = null, AuthenticationFailureHandlerInterface $failureHandler = null, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $eventDispatcher = null, PropertyAccessorInterface $propertyAccessor = null) { @@ -139,7 +141,7 @@ private function onSuccess(Request $request, TokenInterface $token) $this->logger->info('User has been authenticated successfully.', array('username' => $token->getUsername())); } - $this->migrateSession($request); + $this->migrateSession($request, $token); $this->tokenStorage->setToken($token); @@ -185,11 +187,21 @@ private function onFailure(Request $request, AuthenticationException $failed) return $response; } - private function migrateSession(Request $request) + /** + * Call this method if your authentication token is stored to a session. + * + * @final since version 3.4 + */ + public function setSessionAuthenticationStrategy(SessionAuthenticationStrategyInterface $sessionStrategy) + { + $this->sessionStrategy = $sessionStrategy; + } + + private function migrateSession(Request $request, TokenInterface $token) { - if (!$request->hasSession() || !$request->hasPreviousSession()) { + if (!$this->sessionStrategy || !$request->hasSession() || !$request->hasPreviousSession()) { return; } - $request->getSession()->migrate(true); + $this->sessionStrategy->onAuthentication($request, $token); } } diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/UsernamePasswordJsonAuthenticationListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/UsernamePasswordJsonAuthenticationListenerTest.php index 74526fcd543e0..d8bb77bb9e818 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/UsernamePasswordJsonAuthenticationListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/UsernamePasswordJsonAuthenticationListenerTest.php @@ -212,4 +212,42 @@ public function testAttemptAuthenticationIfRequestPathMatchesCheckPath() $this->listener->handle($event); $this->assertSame('ok', $event->getResponse()->getContent()); } + + public function testNoErrorOnMissingSessionStrategy() + { + $this->createListener(); + $request = new Request(array(), array(), array(), array(), array(), array('HTTP_CONTENT_TYPE' => 'application/json'), '{"username": "dunglas", "password": "foo"}'); + $this->configurePreviousSession($request); + $event = new GetResponseEvent($this->getMockBuilder(KernelInterface::class)->getMock(), $request, KernelInterface::MASTER_REQUEST); + + $this->listener->handle($event); + $this->assertEquals('ok', $event->getResponse()->getContent()); + } + + public function testMigratesViaSessionStrategy() + { + $this->createListener(); + $request = new Request(array(), array(), array(), array(), array(), array('HTTP_CONTENT_TYPE' => 'application/json'), '{"username": "dunglas", "password": "foo"}'); + $this->configurePreviousSession($request); + $event = new GetResponseEvent($this->getMockBuilder(KernelInterface::class)->getMock(), $request, KernelInterface::MASTER_REQUEST); + + $sessionStrategy = $this->getMockBuilder('Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface')->getMock(); + $sessionStrategy->expects($this->once()) + ->method('onAuthentication') + ->with($request, $this->isInstanceOf(TokenInterface::class)); + $this->listener->setSessionAuthenticationStrategy($sessionStrategy); + + $this->listener->handle($event); + $this->assertEquals('ok', $event->getResponse()->getContent()); + } + + private function configurePreviousSession(Request $request) + { + $session = $this->getMockBuilder('Symfony\Component\HttpFoundation\Session\SessionInterface')->getMock(); + $session->expects($this->any()) + ->method('getName') + ->willReturn('test_session_name'); + $request->setSession($session); + $request->cookies->set('test_session_name', 'session_cookie_val'); + } }