diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php index 3fdb104cc8a87..879a0cbf2a800 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php @@ -26,16 +26,19 @@ */ abstract class AbstractFactory implements SecurityFactoryInterface { - protected $options = array( + protected $listenerOptions = array( 'check_path' => '/login_check', 'login_path' => '/login', 'use_forward' => false, + 'failure_path' => null, + 'failure_forward' => false, + ); + + protected $targetUrlGeneratorOptions = array( 'always_use_default_target_path' => false, 'default_target_path' => '/', 'target_path_parameter' => '_target_path', - 'use_referer' => false, - 'failure_path' => null, - 'failure_forward' => false, + 'use_referer' => false ); public function create(ContainerBuilder $container, $id, $config, $userProviderId, $defaultEntryPointId) @@ -43,8 +46,11 @@ public function create(ContainerBuilder $container, $id, $config, $userProviderI // authentication provider $authProviderId = $this->createAuthProvider($container, $id, $config, $userProviderId); + // target url generator + $targetUrlGeneratorId = $this->createTargetUrlGenerator($container, $id, $config); + // authentication listener - $listenerId = $this->createListener($container, $id, $config, $userProviderId); + $listenerId = $this->createListener($container, $id, $config, $userProviderId, $targetUrlGeneratorId); // add remember-me aware tag if requested if ($this->isRememberMeAware($config)) { @@ -69,7 +75,7 @@ public function addConfiguration(NodeBuilder $node) ->scalarNode('failure_handler')->end() ; - foreach ($this->options as $name => $default) { + foreach (array_merge($this->listenerOptions, $this->targetUrlGeneratorOptions) as $name => $default) { if (is_bool($default)) { $node->booleanNode($name)->defaultValue($default); } else { @@ -80,7 +86,7 @@ public function addConfiguration(NodeBuilder $node) public final function addOption($name, $default = null) { - $this->options[$name] = $default; + $this->listenerOptions[$name] = $default; } /** @@ -142,21 +148,22 @@ protected function isRememberMeAware($config) return $config['remember_me']; } - protected function createListener($container, $id, $config, $userProvider) + protected function createListener($container, $id, $config, $userProvider, $targetUrlGenerator) { $listenerId = $this->getListenerId(); $listener = new DefinitionDecorator($listenerId); - $listener->setArgument(3, $id); - $listener->setArgument(4, array_intersect_key($config, $this->options)); + $listener->setArgument(3, new Reference($targetUrlGenerator)); + $listener->setArgument(4, $id); + $listener->setArgument(5, array_intersect_key($config, $this->listenerOptions)); // success handler if (isset($config['success_handler'])) { - $listener->setArgument(5, new Reference($config['success_handler'])); + $listener->setArgument(6, new Reference($config['success_handler'])); } // failure handler if (isset($config['failure_handler'])) { - $listener->setArgument(6, new Reference($config['failure_handler'])); + $listener->setArgument(7, new Reference($config['failure_handler'])); } $listenerId .= '.'.$id; @@ -164,4 +171,15 @@ protected function createListener($container, $id, $config, $userProvider) return $listenerId; } + + public function createTargetUrlGenerator(ContainerBuilder $container, $id, $config) + { + $targetUrlGeneratorId = 'security.authentication.target_url_generator.'.$id; + $container + ->setDefinition($targetUrlGeneratorId, new DefinitionDecorator('security.authentication.target_url_generator')) + ->addArgument(array_intersect_key($config, $this->targetUrlGeneratorOptions)) + ; + + return $targetUrlGeneratorId; + } } diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php index 67bb0f67a3915..5fb20e0b37c42 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php @@ -69,9 +69,9 @@ protected function createAuthProvider(ContainerBuilder $container, $id, $config, return $provider; } - protected function createListener($container, $id, $config, $userProvider) + protected function createListener($container, $id, $config, $userProvider, $targetUrlGenerator) { - $listenerId = parent::createListener($container, $id, $config, $userProvider); + $listenerId = parent::createListener($container, $id, $config, $userProvider, $targetUrlGenerator); if (isset($config['csrf_provider'])) { $container diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml index 9c1de812bc97a..e91aaee80cc56 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml @@ -10,6 +10,7 @@ Symfony\Component\Security\Http\Firewall\ChannelListener Symfony\Component\Security\Http\EntryPoint\FormAuthenticationEntryPoint + Symfony\Component\Security\Http\Authentication\TargetUrlGenerator Symfony\Component\Security\Http\Firewall\UsernamePasswordFormAuthenticationListener Symfony\Component\Security\Http\Firewall\BasicAuthenticationListener @@ -26,7 +27,7 @@ SSL_CLIENT_S_DN Symfony\Component\Security\Http\Firewall\AnonymousAuthenticationListener - + Symfony\Component\Security\Http\Firewall\SwitchUserListener Symfony\Component\Security\Http\Firewall\LogoutListener @@ -44,7 +45,7 @@ Symfony\Component\Security\Core\Authentication\Provider\AnonymousAuthenticationProvider SomeRandomValue - + @@ -93,10 +94,13 @@ + + + @@ -104,8 +108,8 @@ - @@ -134,19 +138,19 @@ - + - + - + @@ -173,4 +177,4 @@ - \ No newline at end of file + diff --git a/src/Symfony/Component/Security/Http/Authentication/AuthenticationSuccessHandlerInterface.php b/src/Symfony/Component/Security/Http/Authentication/AuthenticationSuccessHandlerInterface.php index 235eb946a4db1..c9d6811ee460b 100644 --- a/src/Symfony/Component/Security/Http/Authentication/AuthenticationSuccessHandlerInterface.php +++ b/src/Symfony/Component/Security/Http/Authentication/AuthenticationSuccessHandlerInterface.php @@ -22,12 +22,13 @@ interface AuthenticationSuccessHandlerInterface * is called by authentication listeners inheriting from * AbstractAuthenticationListener. * - * @param EventInterface $event the "core.security" event, this event always + * @param EventInterface $event the "core.security" event, this event always * has the kernel as target - * @param Request $request - * @param TokenInterface $token + * @param Request $request + * @param TokenInterface $token + * @param TargetUrlGenerator $targetUrlGenerator - has a determineTargetUrl method * * @return Response the response to return */ - function onAuthenticationSuccess(EventInterface $event, Request $request, TokenInterface $token); -} \ No newline at end of file + function onAuthenticationSuccess(EventInterface $event, Request $request, TokenInterface $token, TargetUrlGenerator $targetUrlGenerator); +} diff --git a/src/Symfony/Component/Security/Http/Authentication/TargetUrlGenerator.php b/src/Symfony/Component/Security/Http/Authentication/TargetUrlGenerator.php new file mode 100644 index 0000000000000..72831c560b1c3 --- /dev/null +++ b/src/Symfony/Component/Security/Http/Authentication/TargetUrlGenerator.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Http\Authentication; + +use Symfony\Component\HttpFoundation\Request; + +/** + * TargetUrlGenerator determines the authentication target url + * + * @author Fabien Potencier + * @author Thibault Duplessis + */ +class TargetUrlGenerator +{ + protected $options; + + public function __construct($options) + { + $this->options = $options; + } + + /** + * Builds the target URL according to the defined options. + * + * @param Request $request + * + * @return string + */ + public function determineTargetUrl(Request $request) + { + if ($this->options['always_use_default_target_path']) { + return $this->options['default_target_path']; + } + + if ($targetUrl = $request->get($this->options['target_path_parameter'])) { + return $targetUrl; + } + + $session = $request->getSession(); + if ($targetUrl = $session->get('_security.target_path')) { + $session->remove('_security.target_path'); + + return $targetUrl; + } + + if ($this->options['use_referer'] && $targetUrl = $request->headers->get('Referer')) { + return $targetUrl; + } + + return $this->options['default_target_path']; + } +} diff --git a/src/Symfony/Component/Security/Http/Firewall/AbstractAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/AbstractAuthenticationListener.php index 353185e218cca..5e1089a96e6a1 100644 --- a/src/Symfony/Component/Security/Http/Firewall/AbstractAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/AbstractAuthenticationListener.php @@ -15,6 +15,7 @@ use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; +use Symfony\Component\Security\Http\Authentication\TargetUrlGenerator; use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface; use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; @@ -50,6 +51,7 @@ abstract class AbstractAuthenticationListener implements ListenerInterface protected $securityContext; protected $authenticationManager; protected $sessionStrategy; + protected $targetUrlGenerator; protected $providerKey; protected $eventDispatcher; protected $options; @@ -66,7 +68,7 @@ abstract class AbstractAuthenticationListener implements ListenerInterface * @param array $options An array of options for the processing of a successful, or failed authentication attempt * @param LoggerInterface $logger A LoggerInterface instance */ - public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, $providerKey, array $options = array(), AuthenticationSuccessHandlerInterface $successHandler = null, AuthenticationFailureHandlerInterface $failureHandler = null, LoggerInterface $logger = null) + public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, TargetUrlGenerator $targetUrlGenerator, $providerKey, array $options = array(), AuthenticationSuccessHandlerInterface $successHandler = null, AuthenticationFailureHandlerInterface $failureHandler = null, LoggerInterface $logger = null) { if (empty($providerKey)) { throw new \InvalidArgumentException('$providerKey must not be empty.'); @@ -75,6 +77,7 @@ public function __construct(SecurityContextInterface $securityContext, Authentic $this->securityContext = $securityContext; $this->authenticationManager = $authenticationManager; $this->sessionStrategy = $sessionStrategy; + $this->targetUrlGenerator = $targetUrlGenerator; $this->providerKey = $providerKey; $this->successHandler = $successHandler; $this->failureHandler = $failureHandler; @@ -226,9 +229,9 @@ protected function onSuccess(EventInterface $event, Request $request, TokenInter } if (null !== $this->successHandler) { - $response = $this->successHandler->onAuthenticationSuccess($event, $request, $token); + $response = $this->successHandler->onAuthenticationSuccess($event, $request, $token, $this->targetUrlGenerator); } else { - $path = $this->determineTargetUrl($request); + $path = $this->targetUrlGenerator->determineTargetUrl($request); $response = new RedirectResponse(0 !== strpos($path, 'http') ? $request->getUriForPath($path) : $path, 302); } @@ -239,37 +242,6 @@ protected function onSuccess(EventInterface $event, Request $request, TokenInter return $response; } - /** - * Builds the target URL according to the defined options. - * - * @param Request $request - * - * @return string - */ - protected function determineTargetUrl(Request $request) - { - if ($this->options['always_use_default_target_path']) { - return $this->options['default_target_path']; - } - - if ($targetUrl = $request->get($this->options['target_path_parameter'])) { - return $targetUrl; - } - - $session = $request->getSession(); - if ($targetUrl = $session->get('_security.target_path')) { - $session->remove('_security.target_path'); - - return $targetUrl; - } - - if ($this->options['use_referer'] && $targetUrl = $request->headers->get('Referer')) { - return $targetUrl; - } - - return $this->options['default_target_path']; - } - /** * Performs authentication. * diff --git a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php index d7518e6f7d7ed..f576bb1836edc 100644 --- a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php @@ -16,6 +16,7 @@ use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; +use Symfony\Component\Security\Http\Authentication\TargetUrlGenerator; use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; @@ -35,9 +36,9 @@ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationL /** * {@inheritdoc} */ - public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, $providerKey, array $options = array(), AuthenticationSuccessHandlerInterface $successHandler = null, AuthenticationFailureHandlerInterface $failureHandler = null, LoggerInterface $logger = null, CsrfProviderInterface $csrfProvider = null) + public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, TargetUrlGenerator $targetUrlGenerator, $providerKey, array $options = array(), AuthenticationSuccessHandlerInterface $successHandler = null, AuthenticationFailureHandlerInterface $failureHandler = null, LoggerInterface $logger = null, CsrfProviderInterface $csrfProvider = null) { - parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $providerKey, array_merge(array( + parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $targetUrlGenerator, $providerKey, array_merge(array( 'username_parameter' => '_username', 'password_parameter' => '_password', 'csrf_parameter' => '_csrf_token',