From 65335eaa62866e3441fefd7318a5b9dbd98e25e1 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 12 Apr 2013 20:08:12 +0200 Subject: [PATCH] [Security] Renamed simple_token to simple_http, added support for failure and success handler to both simple firewalls --- .../Security/Factory/AbstractFactory.php | 14 ++- .../Security/Factory/SimpleFormFactory.php | 22 ++-- ...TokenFactory.php => SimpleHttpFactory.php} | 14 +-- .../Resources/config/security_listeners.xml | 13 ++- .../Bundle/SecurityBundle/SecurityBundle.php | 4 +- .../SimpleAuthenticatorInterface.php | 6 - ...p => SimpleHttpAuthenticatorInterface.php} | 2 +- .../SimpleAuthenticationHandler.php | 105 ++++++++++++++++++ ...p => SimpleHttpAuthenticationListener.php} | 40 +++++-- 9 files changed, 177 insertions(+), 43 deletions(-) rename src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/{SimpleTokenFactory.php => SimpleHttpFactory.php} (78%) rename src/Symfony/Component/Security/Core/Authentication/{SimpleTokenAuthenticatorInterface.php => SimpleHttpAuthenticatorInterface.php} (85%) create mode 100644 src/Symfony/Component/Security/Http/Authentication/SimpleAuthenticationHandler.php rename src/Symfony/Component/Security/Http/Firewall/{SimpleTokenAuthenticationListener.php => SimpleHttpAuthenticationListener.php} (57%) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php index 27f08b0a1f..10032c6aa1 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php @@ -174,7 +174,7 @@ abstract class AbstractFactory implements SecurityFactoryInterface return $config['success_handler']; } - $successHandlerId = 'security.authentication.success_handler.'.$id.'.'.str_replace('-', '_', $this->getKey()); + $successHandlerId = $this->getSuccessHandlerId($id); $successHandler = $container->setDefinition($successHandlerId, new DefinitionDecorator('security.authentication.success_handler')); $successHandler->replaceArgument(1, array_intersect_key($config, $this->defaultSuccessHandlerOptions)); @@ -189,11 +189,21 @@ abstract class AbstractFactory implements SecurityFactoryInterface return $config['failure_handler']; } - $id = 'security.authentication.failure_handler.'.$id.'.'.str_replace('-', '_', $this->getKey()); + $id = $this->getFailureHandlerId($id); $failureHandler = $container->setDefinition($id, new DefinitionDecorator('security.authentication.failure_handler')); $failureHandler->replaceArgument(2, array_intersect_key($config, $this->defaultFailureHandlerOptions)); return $id; } + + protected function getSuccessHandlerId($id) + { + return 'security.authentication.success_handler.'.$id.'.'.str_replace('-', '_', $this->getKey()); + } + + protected function getFailureHandlerId($id) + { + return 'security.authentication.failure_handler.'.$id.'.'.str_replace('-', '_', $this->getKey()); + } } diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleFormFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleFormFactory.php index fc1344db25..8fdef89a74 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleFormFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleFormFactory.php @@ -28,8 +28,6 @@ class SimpleFormFactory extends FormLoginFactory $this->addOption('authenticator', null); } -// TODO create proxies for success_handler/failure_handler that call the impl ones then the default ones by default if no response is returned - public function getKey() { return 'simple-form'; @@ -65,17 +63,21 @@ class SimpleFormFactory extends FormLoginFactory protected function createListener($container, $id, $config, $userProvider) { $listenerId = parent::createListener($container, $id, $config, $userProvider); + $listener = $container->getDefinition($listenerId); if (!isset($config['csrf_provider'])) { - $container - ->getDefinition($listenerId) - ->addArgument(null) - ; + $listener->addArgument(null); } - $container - ->getDefinition($listenerId) - ->addArgument(new Reference($config['authenticator'])) - ; + + $simpleAuthHandlerId = 'security.authentication.simple_success_failure_handler.'.$id; + $simpleAuthHandler = $container->setDefinition($simpleAuthHandlerId, new DefinitionDecorator('security.authentication.simple_success_failure_handler')); + $simpleAuthHandler->replaceArgument(0, new Reference($config['authenticator'])); + $simpleAuthHandler->replaceArgument(1, new Reference($this->getSuccessHandlerId($id))); + $simpleAuthHandler->replaceArgument(2, new Reference($this->getFailureHandlerId($id))); + + $listener->replaceArgument(5, new Reference($simpleAuthHandlerId)); + $listener->replaceArgument(6, new Reference($simpleAuthHandlerId)); + $listener->addArgument(new Reference($config['authenticator'])); return $listenerId; } diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleTokenFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleHttpFactory.php similarity index 78% rename from src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleTokenFactory.php rename to src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleHttpFactory.php index beca6a81b9..d9613c1ccd 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleTokenFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleHttpFactory.php @@ -19,7 +19,7 @@ use Symfony\Component\DependencyInjection\Reference; /** * @author Jordi Boggiano */ -class SimpleTokenFactory implements SecurityFactoryInterface +class SimpleHttpFactory implements SecurityFactoryInterface { public function getPosition() { @@ -28,11 +28,9 @@ class SimpleTokenFactory implements SecurityFactoryInterface public function getKey() { - return 'simple-token'; + return 'simple-http'; } -// TODO add support for success_handler/failure_handler that call the impl ones - public function addConfiguration(NodeDefinition $node) { $node @@ -45,7 +43,7 @@ class SimpleTokenFactory implements SecurityFactoryInterface public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint) { - $provider = 'security.authentication.provider.simple_form.'.$id; + $provider = 'security.authentication.provider.simple_http.'.$id; $container ->setDefinition($provider, new DefinitionDecorator('security.authentication.provider.simple')) ->replaceArgument(0, new Reference($config['authenticator'])) @@ -54,11 +52,11 @@ class SimpleTokenFactory implements SecurityFactoryInterface ; // listener - $listenerId = 'security.authentication.listener.simple_token.'.$id; - $listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.authentication.listener.simple_token')); + $listenerId = 'security.authentication.listener.simple_http.'.$id; + $listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.authentication.listener.simple_http')); $listener->replaceArgument(2, $id); $listener->replaceArgument(3, new Reference($config['authenticator'])); - return array($provider, $listenerId); + return array($provider, $listenerId, null); } } diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml index d9dea17af6..8281fc657d 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml @@ -14,7 +14,7 @@ Symfony\Component\Security\Http\Firewall\SimpleFormAuthenticationListener - Symfony\Component\Security\Http\Firewall\SimpleTokenAuthenticationListener + Symfony\Component\Security\Http\Firewall\SimpleHttpAuthenticationListener Symfony\Component\Security\Http\Firewall\BasicAuthenticationListener Symfony\Component\Security\Http\EntryPoint\BasicAuthenticationEntryPoint @@ -46,6 +46,7 @@ Symfony\Component\Security\Http\Authentication\DefaultAuthenticationSuccessHandler Symfony\Component\Security\Http\Authentication\DefaultAuthenticationFailureHandler + Symfony\Component\Security\Http\Authentication\SimpleAuthenticationHandler @@ -144,7 +145,15 @@ abstract="true"> - + + + + + + + + + diff --git a/src/Symfony/Bundle/SecurityBundle/SecurityBundle.php b/src/Symfony/Bundle/SecurityBundle/SecurityBundle.php index cbdc69f521..85c4a22b2e 100644 --- a/src/Symfony/Bundle/SecurityBundle/SecurityBundle.php +++ b/src/Symfony/Bundle/SecurityBundle/SecurityBundle.php @@ -19,7 +19,7 @@ use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\HttpBasic use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\HttpDigestFactory; use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\RememberMeFactory; use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\X509Factory; -use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SimpleTokenFactory; +use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SimpleHttpFactory; use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SimpleFormFactory; use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider\InMemoryFactory; @@ -40,7 +40,7 @@ class SecurityBundle extends Bundle $extension->addSecurityListenerFactory(new HttpDigestFactory()); $extension->addSecurityListenerFactory(new RememberMeFactory()); $extension->addSecurityListenerFactory(new X509Factory()); - $extension->addSecurityListenerFactory(new SimpleTokenFactory()); + $extension->addSecurityListenerFactory(new SimpleHttpFactory()); $extension->addSecurityListenerFactory(new SimpleFormFactory()); $extension->addUserProviderFactory(new InMemoryFactory()); diff --git a/src/Symfony/Component/Security/Core/Authentication/SimpleAuthenticatorInterface.php b/src/Symfony/Component/Security/Core/Authentication/SimpleAuthenticatorInterface.php index fbbaa37bbb..868d072714 100644 --- a/src/Symfony/Component/Security/Core/Authentication/SimpleAuthenticatorInterface.php +++ b/src/Symfony/Component/Security/Core/Authentication/SimpleAuthenticatorInterface.php @@ -12,9 +12,7 @@ namespace Symfony\Component\Security\Core\Authentication; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\User\UserProviderInterface; -use Symfony\Component\HttpFoundation\Request; /** * @author Jordi Boggiano @@ -24,8 +22,4 @@ interface SimpleAuthenticatorInterface public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey); public function supportsToken(TokenInterface $token, $providerKey); - - public function onAuthenticationFailure(Request $request, AuthenticationException $exception); - - public function onAuthenticationSuccess(Request $request, TokenInterface $token); } diff --git a/src/Symfony/Component/Security/Core/Authentication/SimpleTokenAuthenticatorInterface.php b/src/Symfony/Component/Security/Core/Authentication/SimpleHttpAuthenticatorInterface.php similarity index 85% rename from src/Symfony/Component/Security/Core/Authentication/SimpleTokenAuthenticatorInterface.php rename to src/Symfony/Component/Security/Core/Authentication/SimpleHttpAuthenticatorInterface.php index a6117544d4..b64aad9193 100644 --- a/src/Symfony/Component/Security/Core/Authentication/SimpleTokenAuthenticatorInterface.php +++ b/src/Symfony/Component/Security/Core/Authentication/SimpleHttpAuthenticatorInterface.php @@ -16,7 +16,7 @@ use Symfony\Component\HttpFoundation\Request; /** * @author Jordi Boggiano */ -interface SimpleTokenAuthenticatorInterface extends SimpleAuthenticatorInterface +interface SimpleHttpAuthenticatorInterface extends SimpleAuthenticatorInterface { public function createToken(Request $request, $providerKey); } diff --git a/src/Symfony/Component/Security/Http/Authentication/SimpleAuthenticationHandler.php b/src/Symfony/Component/Security/Http/Authentication/SimpleAuthenticationHandler.php new file mode 100644 index 0000000000..ce56ee3f88 --- /dev/null +++ b/src/Symfony/Component/Security/Http/Authentication/SimpleAuthenticationHandler.php @@ -0,0 +1,105 @@ + + * + * 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; +use Symfony\Component\HttpFoundation\Response; +use Psr\Log\LoggerInterface; +use Symfony\Component\Security\Core\Exception\AuthenticationException; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authentication\SimpleAuthenticatorInterface; + +/** + * Class to proxy authentication success/failure handlers + * + * Events are sent to the SimpleAuthenticatorInterface if it implements + * the right interface, otherwise (or if it fails to return a Response) + * the default handlers are triggered. + * + * @author Jordi Boggiano + */ +class SimpleAuthenticationHandler implements AuthenticationFailureHandlerInterface, AuthenticationSuccessHandlerInterface +{ + protected $successHandler; + protected $failureHandler; + protected $simpleAuthenticator; + + /** + * Constructor. + * + * @param SimpleAuthenticatorInterface $authenticator SimpleAuthenticatorInterface instance + * @param AuthenticationSuccessHandlerInterface $successHandler Default success handler + * @param AuthenticationFailureHandlerInterface $failureHandler Default failure handler + * @param LoggerInterface $logger Optional logger + */ + public function __construct(SimpleAuthenticatorInterface $authenticator, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, LoggerInterface $logger = null) + { + $this->simpleAuthenticator = $authenticator; + $this->successHandler = $successHandler; + $this->failureHandler = $failureHandler; + $this->logger = $logger; + } + + /** + * {@inheritDoc} + */ + public function onAuthenticationSuccess(Request $request, TokenInterface $token) + { + if ($this->simpleAuthenticator instanceof AuthenticationSuccessHandlerInterface) { + if ($this->logger) { + $this->logger->debug(sprintf('Using the %s object as authentication success handler', get_class($this->simpleAuthenticator))); + } + + $response = $this->simpleAuthenticator->onAuthenticationSuccess($request, $token); + if ($response instanceof Response) { + return $response; + } + + if (null !== $response) { + throw new \UnexpectedValueException(sprintf('The %s::onAuthenticationSuccess method must return null to use the default success handler, or a Response object', get_class($this->simpleAuthenticator))); + } + } + + if ($this->logger) { + $this->logger->debug('Fallback to the default authentication success handler'); + } + + return $this->successHandler->onAuthenticationSuccess($request, $token); + } + + /** + * {@inheritDoc} + */ + public function onAuthenticationFailure(Request $request, AuthenticationException $exception) + { + if ($this->simpleAuthenticator instanceof AuthenticationFailureHandlerInterface) { + if ($this->logger) { + $this->logger->debug(sprintf('Using the %s object as authentication failure handler', get_class($this->simpleAuthenticator))); + } + + $response = $this->simpleAuthenticator->onAuthenticationFailure($request, $exception); + if ($response instanceof Response) { + return $response; + } + + if (null !== $response) { + throw new \UnexpectedValueException(sprintf('The %s::onAuthenticationFailure method must return null to use the default failure handler, or a Response object', get_class($this->simpleAuthenticator))); + } + } + + if ($this->logger) { + $this->logger->debug('Fallback to the default authentication failure handler'); + } + + return $this->failureHandler->onAuthenticationFailure($request, $exception); + } +} diff --git a/src/Symfony/Component/Security/Http/Firewall/SimpleTokenAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/SimpleHttpAuthenticationListener.php similarity index 57% rename from src/Symfony/Component/Security/Http/Firewall/SimpleTokenAuthenticationListener.php rename to src/Symfony/Component/Security/Http/Firewall/SimpleHttpAuthenticationListener.php index cda535b009..ab49b14165 100644 --- a/src/Symfony/Component/Security/Http/Firewall/SimpleTokenAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/SimpleHttpAuthenticationListener.php @@ -16,16 +16,19 @@ use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterfac use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; -use Symfony\Component\Security\Core\Authentication\SimpleTokenAuthenticatorInterface; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Security\Core\Authentication\SimpleHttpAuthenticatorInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; +use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; +use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; /** - * SimpleTokenListener implements simple proxying to an authenticator. + * SimpleHttpListener implements simple proxying to an authenticator. * * @author Jordi Boggiano */ -class SimpleTokenAuthenticationListener implements ListenerInterface +class SimpleHttpAuthenticationListener implements ListenerInterface { private $securityContext; private $authenticationManager; @@ -39,10 +42,10 @@ class SimpleTokenAuthenticationListener implements ListenerInterface * @param SecurityContextInterface $securityContext A SecurityContext instance * @param AuthenticationManagerInterface $authenticationManager An AuthenticationManagerInterface instance * @param string $providerKey - * @param SimpleTokenAuthenticatorInterface $simpleAuthenticator A SimpleTokenAuthenticatorInterface instance + * @param SimpleHttpAuthenticatorInterface $simpleAuthenticator A SimpleHttpAuthenticatorInterface instance * @param LoggerInterface $logger A LoggerInterface instance */ - public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, $providerKey, SimpleTokenAuthenticatorInterface $simpleAuthenticator, LoggerInterface $logger = null) + public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, $providerKey, SimpleHttpAuthenticatorInterface $simpleAuthenticator, LoggerInterface $logger = null) { if (empty($providerKey)) { throw new \InvalidArgumentException('$providerKey must not be empty.'); @@ -65,26 +68,39 @@ class SimpleTokenAuthenticationListener implements ListenerInterface $request = $event->getRequest(); if (null !== $this->logger) { - $this->logger->info(sprintf('Attempting simple token authorization %s', $this->providerKey)); + $this->logger->info(sprintf('Attempting simple http authorization %s', $this->providerKey)); } - try { $token = $this->simpleAuthenticator->createToken($request, $this->providerKey); $token = $this->authenticationManager->authenticate($token); $this->securityContext->setToken($token); - - } catch (AuthenticationException $failed) { + } catch (AuthenticationException $e) { $this->securityContext->setToken(null); if (null !== $this->logger) { - $this->logger->info(sprintf('Authentication request failed: %s', $failed->getMessage())); + $this->logger->info(sprintf('Authentication request failed: %s', $e->getMessage())); + } + + if ($this->simpleAuthenticator instanceof AuthenticationFailureHandlerInterface) { + $response = $this->simpleAuthenticator->onAuthenticationFailure($request, $e); + if ($response instanceof Response) { + $event->setResponse($response); + } elseif (null !== $response) { + throw new \UnexpectedValueException(sprintf('The %s::onAuthenticationFailure method must return null or a Response object', get_class($this->simpleAuthenticator))); + } } - // TODO call failure handler return; } - // TODO call success handler + if ($this->simpleAuthenticator instanceof AuthenticationSuccessHandlerInterface) { + $response = $this->simpleAuthenticator->onAuthenticationSuccess($request, $token); + if ($response instanceof Response) { + $event->setResponse($response); + } elseif (null !== $response) { + throw new \UnexpectedValueException(sprintf('The %s::onAuthenticationSuccess method must return null or a Response object', get_class($this->simpleAuthenticator))); + } + } } }