Fix bad method call with guard authentication + session migration
This commit is contained in:
parent
5c2b2bb2ce
commit
2c0ac93e25
@ -77,7 +77,6 @@ class GuardAuthenticationFactory implements SecurityFactoryInterface
|
|||||||
$listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.authentication.listener.guard'));
|
$listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.authentication.listener.guard'));
|
||||||
$listener->replaceArgument(2, $id);
|
$listener->replaceArgument(2, $id);
|
||||||
$listener->replaceArgument(3, $authenticatorReferences);
|
$listener->replaceArgument(3, $authenticatorReferences);
|
||||||
$listener->addMethodCall('setSessionAuthenticationStrategy', array(new Reference('security.authentication.session_strategy.'.$id)));
|
|
||||||
|
|
||||||
// determine the entryPointId to use
|
// determine the entryPointId to use
|
||||||
$entryPointId = $this->determineEntryPoint($defaultEntryPoint, $config);
|
$entryPointId = $this->determineEntryPoint($defaultEntryPoint, $config);
|
||||||
|
@ -39,6 +39,7 @@ class SecurityExtension extends Extension
|
|||||||
private $factories = array();
|
private $factories = array();
|
||||||
private $userProviderFactories = array();
|
private $userProviderFactories = array();
|
||||||
private $expressionLanguage;
|
private $expressionLanguage;
|
||||||
|
private $statelessFirewallKeys = array();
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
@ -89,6 +90,9 @@ class SecurityExtension extends Extension
|
|||||||
$this->createAuthorization($config, $container);
|
$this->createAuthorization($config, $container);
|
||||||
$this->createRoleHierarchy($config, $container);
|
$this->createRoleHierarchy($config, $container);
|
||||||
|
|
||||||
|
$container->getDefinition('security.authentication.guard_handler')
|
||||||
|
->replaceArgument(2, $this->statelessFirewallKeys);
|
||||||
|
|
||||||
if ($config['encoders']) {
|
if ($config['encoders']) {
|
||||||
$this->createEncoders($config['encoders'], $container);
|
$this->createEncoders($config['encoders'], $container);
|
||||||
}
|
}
|
||||||
@ -287,6 +291,7 @@ class SecurityExtension extends Extension
|
|||||||
$listeners[] = new Reference($this->createContextListener($container, $contextKey));
|
$listeners[] = new Reference($this->createContextListener($container, $contextKey));
|
||||||
$sessionStrategyId = 'security.authentication.session_strategy';
|
$sessionStrategyId = 'security.authentication.session_strategy';
|
||||||
} else {
|
} else {
|
||||||
|
$this->statelessFirewallKeys[] = $id;
|
||||||
$sessionStrategyId = 'security.authentication.session_strategy_noop';
|
$sessionStrategyId = 'security.authentication.session_strategy_noop';
|
||||||
}
|
}
|
||||||
$container->setAlias(new Alias('security.authentication.session_strategy.'.$id, false), $sessionStrategyId);
|
$container->setAlias(new Alias('security.authentication.session_strategy.'.$id, false), $sessionStrategyId);
|
||||||
|
@ -10,6 +10,10 @@
|
|||||||
>
|
>
|
||||||
<argument type="service" id="security.token_storage" />
|
<argument type="service" id="security.token_storage" />
|
||||||
<argument type="service" id="event_dispatcher" on-invalid="null" />
|
<argument type="service" id="event_dispatcher" on-invalid="null" />
|
||||||
|
<argument /> <!-- stateless firewall keys -->
|
||||||
|
<call method="setSessionAuthenticationStrategy">
|
||||||
|
<argument type="service" id="security.authentication.session_strategy" />
|
||||||
|
</call>
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<!-- See GuardAuthenticationFactory -->
|
<!-- See GuardAuthenticationFactory -->
|
||||||
|
@ -119,6 +119,33 @@ class SecurityExtensionTest extends TestCase
|
|||||||
$this->assertFalse($container->hasDefinition('security.access.role_hierarchy_voter'));
|
$this->assertFalse($container->hasDefinition('security.access.role_hierarchy_voter'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testGuardHandlerIsPassedStatelessFirewalls()
|
||||||
|
{
|
||||||
|
$container = $this->getRawContainer();
|
||||||
|
|
||||||
|
$container->loadFromExtension('security', array(
|
||||||
|
'providers' => array(
|
||||||
|
'default' => array('id' => 'foo'),
|
||||||
|
),
|
||||||
|
|
||||||
|
'firewalls' => array(
|
||||||
|
'some_firewall' => array(
|
||||||
|
'pattern' => '^/admin',
|
||||||
|
'http_basic' => null,
|
||||||
|
),
|
||||||
|
'stateless_firewall' => array(
|
||||||
|
'pattern' => '/.*',
|
||||||
|
'stateless' => true,
|
||||||
|
'http_basic' => null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
$container->compile();
|
||||||
|
$definition = $container->getDefinition('security.authentication.guard_handler');
|
||||||
|
$this->assertSame(array('stateless_firewall'), $definition->getArgument(2));
|
||||||
|
}
|
||||||
|
|
||||||
protected function getRawContainer()
|
protected function getRawContainer()
|
||||||
{
|
{
|
||||||
$container = new ContainerBuilder();
|
$container = new ContainerBuilder();
|
||||||
|
@ -117,7 +117,7 @@ class GuardAuthenticationListener implements ListenerInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
// sets the token on the token storage, etc
|
// sets the token on the token storage, etc
|
||||||
$this->guardHandler->authenticateWithToken($token, $request);
|
$this->guardHandler->authenticateWithToken($token, $request, $this->providerKey);
|
||||||
} catch (AuthenticationException $e) {
|
} catch (AuthenticationException $e) {
|
||||||
// oh no! Authentication failed!
|
// oh no! Authentication failed!
|
||||||
|
|
||||||
|
@ -35,19 +35,28 @@ class GuardAuthenticatorHandler
|
|||||||
private $tokenStorage;
|
private $tokenStorage;
|
||||||
private $dispatcher;
|
private $dispatcher;
|
||||||
private $sessionStrategy;
|
private $sessionStrategy;
|
||||||
|
private $statelessProviderKeys;
|
||||||
|
|
||||||
public function __construct(TokenStorageInterface $tokenStorage, EventDispatcherInterface $eventDispatcher = null)
|
/**
|
||||||
|
* @param array $statelessProviderKeys An array of provider/firewall keys that are "stateless" and so do not need the session migrated on success
|
||||||
|
*/
|
||||||
|
public function __construct(TokenStorageInterface $tokenStorage, EventDispatcherInterface $eventDispatcher = null, array $statelessProviderKeys = array())
|
||||||
{
|
{
|
||||||
$this->tokenStorage = $tokenStorage;
|
$this->tokenStorage = $tokenStorage;
|
||||||
$this->dispatcher = $eventDispatcher;
|
$this->dispatcher = $eventDispatcher;
|
||||||
|
$this->statelessProviderKeys = $statelessProviderKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authenticates the given token in the system.
|
* Authenticates the given token in the system.
|
||||||
|
*
|
||||||
|
* @param string $providerKey The name of the provider/firewall being used for authentication
|
||||||
*/
|
*/
|
||||||
public function authenticateWithToken(TokenInterface $token, Request $request)
|
public function authenticateWithToken(TokenInterface $token, Request $request/*, string $providerKey */)
|
||||||
{
|
{
|
||||||
$this->migrateSession($request, $token);
|
$providerKey = \func_num_args() > 2 ? func_get_arg(2) : null;
|
||||||
|
|
||||||
|
$this->migrateSession($request, $token, $providerKey);
|
||||||
$this->tokenStorage->setToken($token);
|
$this->tokenStorage->setToken($token);
|
||||||
|
|
||||||
if (null !== $this->dispatcher) {
|
if (null !== $this->dispatcher) {
|
||||||
@ -98,7 +107,7 @@ class GuardAuthenticatorHandler
|
|||||||
// create an authenticated token for the User
|
// create an authenticated token for the User
|
||||||
$token = $authenticator->createAuthenticatedToken($user, $providerKey);
|
$token = $authenticator->createAuthenticatedToken($user, $providerKey);
|
||||||
// authenticate this in the system
|
// authenticate this in the system
|
||||||
$this->authenticateWithToken($token, $request);
|
$this->authenticateWithToken($token, $request, $providerKey);
|
||||||
|
|
||||||
// return the success metric
|
// return the success metric
|
||||||
return $this->handleAuthenticationSuccess($token, $request, $authenticator, $providerKey);
|
return $this->handleAuthenticationSuccess($token, $request, $authenticator, $providerKey);
|
||||||
@ -140,9 +149,9 @@ class GuardAuthenticatorHandler
|
|||||||
$this->sessionStrategy = $sessionStrategy;
|
$this->sessionStrategy = $sessionStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function migrateSession(Request $request, TokenInterface $token)
|
private function migrateSession(Request $request, TokenInterface $token, $providerKey)
|
||||||
{
|
{
|
||||||
if (!$this->sessionStrategy || !$request->hasSession() || !$request->hasPreviousSession()) {
|
if (!$this->sessionStrategy || !$request->hasSession() || !$request->hasPreviousSession() || \in_array($providerKey, $this->statelessProviderKeys, true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,6 +143,18 @@ class GuardAuthenticatorHandlerTest extends TestCase
|
|||||||
$handler->authenticateWithToken($this->token, $this->request);
|
$handler->authenticateWithToken($this->token, $this->request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testSessionStrategyIsNotCalledWhenStateless()
|
||||||
|
{
|
||||||
|
$this->configurePreviousSession();
|
||||||
|
|
||||||
|
$this->sessionStrategy->expects($this->never())
|
||||||
|
->method('onAuthentication');
|
||||||
|
|
||||||
|
$handler = new GuardAuthenticatorHandler($this->tokenStorage, $this->dispatcher, array('some_provider_key'));
|
||||||
|
$handler->setSessionAuthenticationStrategy($this->sessionStrategy);
|
||||||
|
$handler->authenticateWithToken($this->token, $this->request, 'some_provider_key');
|
||||||
|
}
|
||||||
|
|
||||||
protected function setUp()
|
protected function setUp()
|
||||||
{
|
{
|
||||||
$this->tokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface')->getMock();
|
$this->tokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface')->getMock();
|
||||||
|
Reference in New Issue
Block a user