8000 [Security] made it possible to override the default success/failure h… · symfony/symfony@13d37e7 · GitHub
[go: up one dir, main page]

Skip to content

Commit 13d37e7

Browse files
committed
[Security] made it possible to override the default success/failure handler
1 parent 9752a76 commit 13d37e7

File tree

6 files changed

+173
-60
lines changed

6 files changed

+173
-60
lines changed

src/Symfony/Bundle/SecurityBundle/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
CHANGELOG
22
=========
33

4+
2.6.0
5+
-----
6+
7+
* Added the possibility to override the default success/failure handler
8+
to get the provider key and the options injected
9+
410
2.4.0
511
-----
612

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
namespace Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
1313

1414
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
15-
1615
use Symfony\Component\DependencyInjection\DefinitionDecorator;
1716
use Symfony\Component\DependencyInjection\ContainerBuilder;
1817
use Symfony\Component\DependencyInjection\Reference;
@@ -21,15 +20,16 @@
2120
* AbstractFactory is the base class for all classes inheriting from
2221
* AbstractAuthenticationListener
2322
*
23+
* @author Fabien Potencier <fabien@symfony.com>
2424
* @author Lukas Kahwe Smith <smith@pooteeweet.org>
2525
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
2626
*/
2727
abstract class AbstractFactory implements SecurityFactoryInterface
2828
{
2929
protected $options = array(
30-
'check_path' => '/login_check',
31-
'use_forward' => false,
32-
'require_previous_session' => true,
30+
'check_path' => '/login_check',
31+
'use_forward' => false,
32+
'require_previous_session' => true,
3333
);
3434

3535
protected $defaultSuccessHandlerOptions = array(
@@ -171,28 +171,34 @@ protected function createListener($container, $id, $config, $userProvider)
171171
protected function createAuthenticationSuccessHandler($container, $id, $config)
172172
{
173173
if (isset($config['success_handler'])) {
174-
return $config['success_handler'];
174+
$successHandlerId = $config['success_handler'];
175+
$successHandler = $container->findDefinition($successHandlerId);
176+
} else {
177+
$successHandlerId = $this->getSuccessHandlerId($id);
178+
$successHandler = $container->setDefinition($successHandlerId, new DefinitionDecorator('security.authentication.success_handler'));
175179
}
176180

177-
$successHandlerId = $this->getSuccessHandlerId($id);
178-
179-
$successHandler = $container->setDefinition($successHandlerId, new DefinitionDecorator('security.authentication.success_handler'));
180-
$successHandler->replaceArgument(1, array_intersect_key($config, $this->defaultSuccessHandlerOptions));
181-
$successHandler->addMethodCall('setProviderKey', array($id));
181+
if ($successHandler instanceof DefinitionDecorator && 'security.authentication.success_handler' === $successHandler->getParent()) {
182+
$successHandler->addMethodCall('setOptions', array(array_intersect_key($config, $this->defaultSuccessHandlerOptions)));
183+
$successHandler->addMethodCall('setProviderKey', array($id));
184+
}
182185

183186
return $successHandlerId;
184187
}
185188

186189
protected function createAuthenticationFailureHandler($container, $id, $config)
187190
{
188191
if (isset($config['failure_handler'])) {
189-
return $config['failure_handler'];
192+
$id = $config['failure_handler'];
193+
$failureHandler = $container->findDefinition($id);
194+
} else {
195+
$id = $this->getFailureHandlerId($id);
196+
$failureHandler = $container->setDefinition($id, new DefinitionDecorator('security.authentication.failure_handler'));
190197
}
191198

192-
$id = $this->getFailureHandlerId($id);
193-
194-
$failureHandler = $container->setDefinition($id, new DefinitionDecorator('security.authentication.failure_handler'));
195-
$failureHandler->replaceArgument(2, array_intersect_key($config, $this->defaultFailureHandlerOptions));
199+
if ($failureHandler instanceof DefinitionDecorator && 'security.authentication.failure_handler' === $failureHandler->getParent()) {
200+
$failureHandler->addMethodCall('setOptions', array(array_intersect_key($config, $this->defaultFailureHandlerOptions)));
201+
}
196202

197203
return $id;
198204
}

src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Security/Factory/AbstractFactoryTest.php

Lines changed: 84 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,19 @@
1313

1414
use Symfony\Component\DependencyInjection\Reference;
1515
use Symfony\Component\DependencyInjection\ContainerBuilder;
16+
use Symfony\Component\DependencyInjection\DefinitionDecorator;
1617

1718
class AbstractFactoryTest extends \PHPUnit_Framework_TestCase
1819
{
1920
public function testCreate()
2021
{
21-
list($container,
22-
$authProviderId,
23-
$listenerId,
24-
$entryPointId
25-
) = $this->callFactory('foo', array('use_forward' => true, 'failure_path' => '/foo', 'success_handler' => 'qux', 'failure_handler' => 'bar', 'remember_me' => true), 'user_provider', 'entry_point');
22+
list($container, $authProviderId, $listenerId, $entryPointId) = $this->callFactory('foo', array(
23+
'use_forward' => true,
24+
'failure_path' => '/foo',
25+
'success_handler' => 'custom_success_handler',
26+
'failure_handler' => 'custom_failure_handler',
27+
'remember_me' => true,
28+
), 'user_provider', 'entry_point');
2629

2730
// auth provider
2831
$this->assertEquals('auth_provider', $authProviderId);
@@ -33,41 +36,95 @@ public function testCreate()
3336
$definition = $container->getDefinition('abstract_listener.foo');
3437
$this->assertEquals(array(
3538
'index_4' => 'foo',
36-
'index_5' => new Reference('qux'),
37-
'index_6' => new Reference('bar'),
39+
'index_5' => new Reference('custom_success_handler'),
40+
'index_6' => new Reference('custom_failure_handler'),
3841
'index_7' => array(
39-
'use_forward' => true,
42+
'use_forward' => true,
4043
),
4144
), $definition->getArguments());
4245

4346
// entry point
4447
$this->assertEquals('entry_point', $entryPointId, '->create() does not change the default entry point.');
4548
}
4649

47-
public function testDefaultFailureHandler()
50+
/**
51+
* @dataProvider getFailureHandlers
52+
*/
53+
public function testDefaultFailureHandler($handlerId, $serviceId, $defaultHandlerInjection)
4854
{
49-
list($container,
50-
$authProviderId,
51-
$listenerId,
52-
$entryPointId
53-
) = $this->callFactory('foo', array('remember_me' => true), 'user_provider', 'entry_point');
55+
$options = array(
56+
'remember_me' => true,
57+
'login_path' => '/bar',
58+
);
59+
60+
if ($serviceId) {
61+
$options['failure_handler'] = $serviceId;
62+
}
63+
64+
list($container, $authProviderId, $listenerId, $entryPointId) = $this->callFactory('foo', $options, 'user_provider', 'entry_point');
5465

5566
$definition = $container->getDefinition('abstract_listener.foo');
5667
$arguments = $definition->getArguments();
57-
$this->assertEquals(new Reference('security.authentication.failure_handler.foo.abstract_factory'), $arguments['index_6']);
68+
$this->assertEquals(new Reference($handlerId), $arguments['index_6']);
69+
$failureHandler = $container->findDefinition((string) $arguments['index_6']);
70+
71+
$methodCalls = $failureHandler->getMethodCalls();
72+
if ($defaultHandlerInjection) {
73+
$this->assertEquals('setOptions', $methodCalls[0][0]);
74+
$this->assertEquals(array('login_path' => '/bar'), $methodCalls[0][1][0]);
75+
} else {
76+
$this->assertCount(0, $methodCalls);
77+
}
78+
}
79+
80+
public function getFailureHandlers()
81+
{
82+
return array(
83+
array('security.authentication.failure_handler.foo.abstract_factory', null, true),
84+
array('custom_failure_handler_default', 'custom_failure_handler_default', true),
85+
array('custom_failure_handler', 'custom_failure_handler', false),
86+
);
5887
}
5988

60-
public function testDefaultSuccessHandler()
89+
/**
90+
* @dataProvider getSuccessHandlers
91+
*/
92+
public function testDefaultSuccessHandler($handlerId, $serviceId, $defaultHandlerInjection)
6193
{
62-
list($container,
63-
$authProviderId,
64-
$listenerId,
65-
$entryPointId
66-
) = $this->callFactory('foo', array('remember_me' => true), 'user_provider', 'entry_point');
94+
$options = array(
95+
'remember_me' => true,
96+
'default_target_path' => '/bar',
97+
);
98+
99+
if ($serviceId) {
100+
$options['success_handler'] = $serviceId;
101+
}
102+
103+
list($container, $authProviderId, $listenerId, $entryPointId) = $this->callFactory('foo', $options, 'user_provider', 'entry_point');
67104

68105
$definition = $container->getDefinition('abstract_listener.foo');
69106
$arguments = $definition->getArguments();
70-
$this->assertEquals(new Reference('security.authentication.success_handler.foo.abstract_factory'), $arguments['index_5']);
107+
$this->assertEquals(new Reference($handlerId), $arguments['index_5']);
108+
$successHandler = $container->findDefinition((string) $arguments['index_5']);
109+
$methodCalls = $successHandler->getMethodCalls();
110+
111+
if ($defaultHandlerInjection) {
112+
$this->assertEquals('setOptions', $methodCalls[0][0]);
113+
$this->assertEquals(array('default_target_path' => '/bar'), $methodCalls[0][1][0]);
114+
$this->assertEquals('setProviderKey', $methodCalls[1][0]);
115+
$this->assertEquals(array('foo'), $methodCalls[1][1]);
116+
} else {
117+
$this->assertCount(0, $methodCalls);
118+
}
119+
}
120+
121+
public function getSuccessHandlers()
122+
{
123+
return array(
124+
array('security.authentication.success_handler.foo.abstract_factory', null, true),
125+
array('custom_success_handler_default', 'custom_success_handler_default', true),
126+
array('custom_success_handler', 'custom_success_handler', false),
127+
);
71128
}
72129

73130
protected function callFactory($id, $config, $userProviderId, $defaultEntryPointId)
@@ -92,11 +149,12 @@ protected function callFactory($id, $config, $userProviderId, $defaultEntryPoint
92149

93150
$container = new ContainerBuilder();
94151
$container->register('auth_provider');
152+
$container->register('custom_success_handler');
153+
$container->register('custom_failure_handler');
154+
$container->setDefinition('custom_success_handler_default', new DefinitionDecorator('security.authentication.success_handler'));
155+
$container->setDefinition('custom_failure_handler_default', new DefinitionDecorator('security.authentication.failure_handler'));
95156

96-
list($authProviderId,
97-
$listenerId,
98-
$entryPointId
99-
) = $factory->create($container, $id, $config, $userProviderId, $defaultEntryPointId);
157+
list($authProviderId, $listenerId, $entryPointId) = $factory->create($container, $id, $config, $userProviderId, $defaultEntryPointId);
100158

101159
return array($container, $authProviderId, $listenerId, $entryPointId);
102160
}

src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/localized_form_failure_handler.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
imports:
22
- { resource: ./../config/default.yml }
33

4+
services:
5+
localized_form_failure_handler: { class: stdClass }
6+
47
security:
58
encoders:
69
Symfony\Component\Security\Core\User\User: plaintext

src/Symfony/Component/Security/Http/Authentication/DefaultAuthenticationFailureHandler.php

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ class DefaultAuthenticationFailureHandler implements AuthenticationFailureHandle
3434
protected $httpUtils;
3535
protected $logger;
3636
protected $options;
37+
protected $defaultOptions = array(
38+
'failure_path' => null,
39+
'failure_forward' => false,
40+
'login_path' => '/login',
41+
'failure_path_parameter' => '_failure_path',
42+
);
3743

3844
/**
3945
* Constructor.
@@ -43,18 +49,32 @@ class DefaultAuthenticationFailureHandler implements AuthenticationFailureHandle
4349
* @param array $options Options for processing a failed authentication attempt.
4450
* @param LoggerInterface $logger Optional logger
4551
*/
46-
public function __construct(HttpKernelInterface $httpKernel, HttpUtils $httpUtils, array $options, LoggerInterface $logger = null)
52+
public function __construct(HttpKernelInterface $httpKernel, HttpUtils $httpUtils, array $options = array(), LoggerInterface $logger = null)
4753
{
4854
$this->httpKernel = $httpKernel;
49-
$this->httpUtils = $httpUtils;
50-
$this->logger = $logger;
55+
$this->httpUtils = $httpUtils;
56+
$this->logger = $logger;
57+
$this->setOptions($options);
58+
}
5159

52-
$this->options = array_merge(array(
53-
'failure_path' => null,
54-
'failure_forward' => false,
55-
'login_path' => '/login',
56-
'failure_path_parameter' => '_failure_path',
57-
), $options);
60+
/**
61+
* Gets the options.
62+
*
63+
* @return array An array of options
64+
*/
65+
public function getOptions()
66+
{
67+
return $this->options;
68+
}
69+
70+
/**
71+
* Sets the options.
72+
*
73+
* @param array $options An array of options
74+
*/
75+
public function setOptions(array $options)
76+
{
77+
$this->options = array_merge($this->defaultOptions, $options);
5878
}
5979

6080
/**

src/Symfony/Component/Security/Http/Authentication/DefaultAuthenticationSuccessHandler.php

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,24 @@ class DefaultAuthenticationSuccessHandler implements AuthenticationSuccessHandle
2727
protected $httpUtils;
2828
protected $options;
2929
protected $providerKey;
30+
protected $defaultOptions = array(
31+
'always_use_default_target_path' => false,
32+
'default_target_path' => '/',
33+
'login_path' => '/login',
34+
'target_path_parameter' => '_target_path',
35+
'use_referer' => false,
36+
);
3037

3138
/**
3239
* Constructor.
3340
*
3441
* @param HttpUtils $httpUtils
3542
* @param array $options Options for processing a successful authentication attempt.
3643
*/
37-
public function __construct(HttpUtils $httpUtils, array $options)
44+
public function __construct(HttpUtils $httpUtils, array $options = array())
3845
{
39-
$this->httpUtils = $httpUtils;
40-
41-
$this->options = array_merge(array(
42-
'always_use_default_target_path' => false,
43-
'default_target_path' => '/',
44-
'login_path' => '/login',
45-
'target_path_parameter' => '_target_path',
46-
'use_referer' => false,
47-
), $options);
46+
$this->httpUtils = $httpUtils;
47+
$this->setOptions($options);
4848
}
4949

5050
/**
@@ -55,6 +55,26 @@ public function onAuthenticationSuccess(Request $request, TokenInterface $token)
5555
return $this->httpUtils->createRedirectResponse($request, $this->determineTargetUrl($request));
5656
}
5757

58+
/**
59+
* Gets the options.
60+
*
61+
* @return array An array of options
62+
*/
63+
public function getOptions()
64+
{
65+
return $this->options;
66+
}
67+
68+
/**
69+
* Sets the options.
70+
*
71+
* @param array $options An array of options
72+
*/
73+
public function setOptions(array $options)
74+
{
75+
$this->options = array_merge($this->defaultOptions, $options);
76+
}
77+
5878
/**
5979
* Get the provider key.
6080
*

0 commit comments

Comments
 (0)
0