From b3b9013aa0ac6de1c819480959b7901b8b975705 Mon Sep 17 00:00:00 2001 From: ornicar Date: Thu, 24 Feb 2011 12:59:23 -0800 Subject: [PATCH] [Security] SoC - Move authentication target url generation out of the authentication listener This adds a new class `TargetUrlGenerator`, responsible for generating the target url after a successful authentication. This logic was previously embedded in the abstract authentication listener. By improving separation of concerns, this change allows to generate the target url from a custom authentication success handler. --- .../Security/Factory/AbstractFactory.php | 42 +++++++++---- .../Security/Factory/FormLoginFactory.php | 4 +- .../Resources/config/security_listeners.xml | 20 +++--- .../AuthenticationSuccessHandlerInterface.php | 11 ++-- .../Authentication/TargetUrlGenerator.php | 61 +++++++++++++++++++ .../AbstractAuthenticationListener.php | 40 ++---------- ...namePasswordFormAuthenticationListener.php | 5 +- 7 files changed, 120 insertions(+), 63 deletions(-) create mode 100644 src/Symfony/Component/Security/Http/Authentication/TargetUrlGenerator.php 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', pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy