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');
+ }
}