From 1fe2ed64d1c83d4fac115733dedf7e2b5cb8e2d3 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 19 Nov 2012 18:01:13 +0100 Subject: [PATCH 1/7] [Security] Add SimpleForm authentication --- .../Security/Factory/SimpleFormFactory.php | 93 ++++++++++++++ .../Resources/config/security_listeners.xml | 15 +++ .../Bundle/SecurityBundle/SecurityBundle.php | 2 + .../Provider/SimpleAuthenticationProvider.php | 56 +++++++++ .../SimpleAuthenticatorInterface.php | 30 +++++ .../SimpleFormAuthenticatorInterface.php | 25 ++++ .../SimpleFormAuthenticationListener.php | 116 ++++++++++++++++++ 7 files changed, 337 insertions(+) create mode 100644 src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleFormFactory.php create mode 100644 src/Symfony/Component/Security/Core/Authentication/Provider/SimpleAuthenticationProvider.php create mode 100644 src/Symfony/Component/Security/Core/Authentication/SimpleAuthenticatorInterface.php create mode 100644 src/Symfony/Component/Security/Core/Authentication/SimpleFormAuthenticatorInterface.php create mode 100644 src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleFormFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleFormFactory.php new file mode 100644 index 0000000000000..1acbde25a1518 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleFormFactory.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory; + +use Symfony\Component\Config\Definition\Builder\NodeDefinition; +use Symfony\Component\DependencyInjection\DefinitionDecorator; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + +/** + * @author Jordi Boggiano + */ +class SimpleFormFactory extends FormLoginFactory +{ + public function __construct() + { + parent::__construct(); + + $this->addOption('authenticator', null); + } + + public function getKey() + { + return 'simple-form'; + } + + public function addConfiguration(NodeDefinition $node) + { + parent::addConfiguration($node); + + $node->children() + ->scalarNode('authenticator')->cannotBeEmpty()->end() + ->end(); + } + + protected function getListenerId() + { + return 'security.authentication.listener.simple_form'; + } + + protected function createAuthProvider(ContainerBuilder $container, $id, $config, $userProviderId) + { + $provider = 'security.authentication.provider.simple_form.'.$id; + $container + ->setDefinition($provider, new DefinitionDecorator('security.authentication.provider.simple')) + ->replaceArgument(0, new Reference($config['authenticator'])) + ->replaceArgument(1, new Reference($userProviderId)) + ->replaceArgument(2, $id) + ; + + return $provider; + } + + protected function createListener($container, $id, $config, $userProvider) + { + $listenerId = parent::createListener($container, $id, $config, $userProvider); + + if (!isset($config['csrf_provider'])) { + $container + ->getDefinition($listenerId) + ->addArgument(null) + ; + } + $container + ->getDefinition($listenerId) + ->addArgument(new Reference($config['authenticator'])) + ; + + return $listenerId; + } + + protected function createEntryPoint($container, $id, $config, $defaultEntryPoint) + { + $entryPointId = 'security.authentication.form_entry_point.'.$id; + $container + ->setDefinition($entryPointId, new DefinitionDecorator('security.authentication.form_entry_point')) + ->addArgument(new Reference('security.http_utils')) + ->addArgument($config['login_path']) + ->addArgument($config['use_forward']) + ; + + return $entryPointId; + } +} diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml index 614833752083f..88c70b383df34 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml @@ -12,6 +12,8 @@ Symfony\Component\Security\Http\EntryPoint\FormAuthenticationEntryPoint Symfony\Component\Security\Http\Firewall\UsernamePasswordFormAuthenticationListener + Symfony\Component\Security\Http\Firewall\SimpleFormAuthenticationListener + Symfony\Component\Security\Http\Firewall\BasicAuthenticationListener Symfony\Component\Security\Http\EntryPoint\BasicAuthenticationEntryPoint @@ -35,6 +37,7 @@ Symfony\Component\Security\Http\Firewall\ContextListener Symfony\Component\Security\Core\Authentication\Provider\DaoAuthenticationProvider + Symfony\Component\Security\Core\Authentication\Provider\SimpleAuthenticationProvider Symfony\Component\Security\Core\Authentication\Provider\PreAuthenticatedAuthenticationProvider Symfony\Component\Security\Core\Authentication\Provider\AnonymousAuthenticationProvider @@ -133,6 +136,12 @@ abstract="true"> + + + @@ -170,6 +179,12 @@ %security.authentication.hide_user_not_found% + + + + + + diff --git a/src/Symfony/Bundle/SecurityBundle/SecurityBundle.php b/src/Symfony/Bundle/SecurityBundle/SecurityBundle.php index 7d810fde389f9..2796c232adae9 100644 --- a/src/Symfony/Bundle/SecurityBundle/SecurityBundle.php +++ b/src/Symfony/Bundle/SecurityBundle/SecurityBundle.php @@ -19,6 +19,7 @@ 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\SimpleFormFactory; use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider\InMemoryFactory; /** @@ -38,6 +39,7 @@ public function build(ContainerBuilder $container) $extension->addSecurityListenerFactory(new HttpDigestFactory()); $extension->addSecurityListenerFactory(new RememberMeFactory()); $extension->addSecurityListenerFactory(new X509Factory()); + $extension->addSecurityListenerFactory(new SimpleFormFactory()); $extension->addUserProviderFactory(new InMemoryFactory()); $container->addCompilerPass(new AddSecurityVotersPass()); diff --git a/src/Symfony/Component/Security/Core/Authentication/Provider/SimpleAuthenticationProvider.php b/src/Symfony/Component/Security/Core/Authentication/Provider/SimpleAuthenticationProvider.php new file mode 100644 index 0000000000000..72b82cba35e4a --- /dev/null +++ b/src/Symfony/Component/Security/Core/Authentication/Provider/SimpleAuthenticationProvider.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Core\Authentication\Provider; + +use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; +use Symfony\Component\Security\Core\User\UserProviderInterface; +use Symfony\Component\Security\Core\User\UserCheckerInterface; +use Symfony\Component\Security\Core\User\UserInterface; +use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; +use Symfony\Component\Security\Core\Exception\AuthenticationServiceException; +use Symfony\Component\Security\Core\Exception\BadCredentialsException; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authentication\SimpleAuthenticatorInterface; +use Symfony\Component\Security\Core\Exception\AuthenticationException; + +/** + * @author Jordi Boggiano + */ +class SimpleAuthenticationProvider implements AuthenticationProviderInterface +{ + private $simpleAuthenticator; + private $userProvider; + private $providerKey; + + public function __construct(SimpleAuthenticatorInterface $simpleAuthenticator, UserProviderInterface $userProvider, $providerKey) + { + $this->simpleAuthenticator = $simpleAuthenticator; + $this->userProvider = $userProvider; + $this->providerKey = $providerKey; + } + + public function authenticate(TokenInterface $token) + { + $authToken = $this->simpleAuthenticator->authenticate($token, $this->userProvider, $this->providerKey); + + if ($authToken instanceof TokenInterface) { + return $authToken; + } + + throw new AuthenticationException('Simple authenticator failed to return an authenticated token.'); + } + + public function supports(TokenInterface $token) + { + return $this->simpleAuthenticator->supports($token, $this->providerKey); + } +} diff --git a/src/Symfony/Component/Security/Core/Authentication/SimpleAuthenticatorInterface.php b/src/Symfony/Component/Security/Core/Authentication/SimpleAuthenticatorInterface.php new file mode 100644 index 0000000000000..81f761fd9f67d --- /dev/null +++ b/src/Symfony/Component/Security/Core/Authentication/SimpleAuthenticatorInterface.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Core\Authentication; + +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Exception\AuthenticationException; +use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Security\Core\User\UserProviderInterface; + +/** + * @author Jordi Boggiano + */ +interface SimpleAuthenticatorInterface +{ + public function authenticate(TokenInterface $token, UserProviderInterface $userProvider, $providerKey); + + public function supports(TokenInterface $token, $providerKey); + + public function handleAuthenticationFailure(GetResponseEvent $event, AuthenticationException $exception); +} diff --git a/src/Symfony/Component/Security/Core/Authentication/SimpleFormAuthenticatorInterface.php b/src/Symfony/Component/Security/Core/Authentication/SimpleFormAuthenticatorInterface.php new file mode 100644 index 0000000000000..79fdb1cb3cdfe --- /dev/null +++ b/src/Symfony/Component/Security/Core/Authentication/SimpleFormAuthenticatorInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Core\Authentication; + +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Exception\AuthenticationException; +use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpFoundation\Request; + +/** + * @author Jordi Boggiano + */ +interface SimpleFormAuthenticatorInterface extends SimpleAuthenticatorInterface +{ + public function createToken(Request $request, $username, $password, $providerKey); +} diff --git a/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php new file mode 100644 index 0000000000000..f096c2f2c3296 --- /dev/null +++ b/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php @@ -0,0 +1,116 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Http\Firewall; + +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; +use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; +use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; +use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface; +use Symfony\Component\Security\Core\Authentication\SimpleFormAuthenticatorInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Exception\AuthenticationException; +use Symfony\Component\Security\Core\Exception\SessionUnavailableException; +use Symfony\Component\Security\Core\SecurityContextInterface; +use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; +use Symfony\Component\Security\Http\HttpUtils; +use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface; +use Symfony\Component\Security\Http\SecurityEvents; +use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; + +/** + * @author Jordi Boggiano + */ +class SimpleFormAuthenticationListener extends AbstractAuthenticationListener +{ + private $simpleAuthenticator; + private $csrfProvider; + + /** + * Constructor. + * + * @param SecurityContextInterface $securityContext A SecurityContext instance + * @param AuthenticationManagerInterface $authenticationManager An AuthenticationManagerInterface instance + * @param SessionAuthenticationStrategyInterface $sessionStrategy + * @param HttpUtils $httpUtils An HttpUtilsInterface instance + * @param string $providerKey + * @param AuthenticationSuccessHandlerInterface $successHandler + * @param AuthenticationFailureHandlerInterface $failureHandler + * @param array $options An array of options for the processing of a + * successful, or failed authentication attempt + * @param LoggerInterface $logger A LoggerInterface instance + * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance + * @param SimpleFormAuthenticatorInterface $simpleAuthenticator A SimpleFormAuthenticatorInterface instance + * @param CsrfProviderInterface $csrfProvider A CsrfProviderInterface instance + */ + public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfProviderInterface $csrfProvider = null, SimpleFormAuthenticatorInterface $simpleAuthenticator = null) + { + if (!$simpleAuthenticator) { + throw new \InvalidArgumentException('Missing simple authenticator'); + } + + $this->simpleAuthenticator = $simpleAuthenticator; + $this->csrfProvider = $csrfProvider; + + $options = array_merge(array( + 'username_parameter' => '_username', + 'password_parameter' => '_password', + 'csrf_parameter' => '_csrf_token', + 'intention' => 'authenticate', + 'post_only' => true, + ), $options); + parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, $options, $logger, $dispatcher); + } + + /** + * {@inheritdoc} + */ + protected function requiresAuthentication(Request $request) + { + if ($this->options['post_only'] && !$request->isMethod('POST')) { + return false; + } + + return parent::requiresAuthentication($request); + } + + /** + * {@inheritdoc} + */ + protected function attemptAuthentication(Request $request) + { + if (null !== $this->csrfProvider) { + $csrfToken = $request->get($this->options['csrf_parameter'], null, true); + + if (false === $this->csrfProvider->isCsrfTokenValid($this->options['intention'], $csrfToken)) { + throw new InvalidCsrfTokenException('Invalid CSRF token.'); + } + } + + if ($this->options['post_only']) { + $username = trim($request->request->get($this->options['username_parameter'], null, true)); + $password = $request->request->get($this->options['password_parameter'], null, true); + } else { + $username = trim($request->get($this->options['username_parameter'], null, true)); + $password = $request->get($this->options['password_parameter'], null, true); + } + + $request->getSession()->set(SecurityContextInterface::LAST_USERNAME, $username); + + $token = $this->simpleAuthenticator->createToken($request, $username, $password, $this->providerKey); + + return $this->authenticationManager->authenticate($token); + } +} From f7a11a1ab32b72fdef28c0c1a5df82d788b43f9d Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 12 Apr 2013 13:49:16 +0200 Subject: [PATCH 2/7] [Security] Add simple_token auth method --- .../Security/Factory/SimpleFormFactory.php | 2 + .../Security/Factory/SimpleTokenFactory.php | 64 +++++++++++++ .../Resources/config/security_listeners.xml | 11 +++ .../Bundle/SecurityBundle/SecurityBundle.php | 2 + .../Provider/SimpleAuthenticationProvider.php | 4 +- .../SimpleAuthenticatorInterface.php | 11 +-- .../SimpleFormAuthenticatorInterface.php | 3 - .../SimpleTokenAuthenticatorInterface.php | 22 +++++ .../SimpleTokenAuthenticationListener.php | 90 +++++++++++++++++++ 9 files changed, 199 insertions(+), 10 deletions(-) create mode 100644 src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleTokenFactory.php create mode 100644 src/Symfony/Component/Security/Core/Authentication/SimpleTokenAuthenticatorInterface.php create mode 100644 src/Symfony/Component/Security/Http/Firewall/SimpleTokenAuthenticationListener.php diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleFormFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleFormFactory.php index 1acbde25a1518..fc1344db25d78 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleFormFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleFormFactory.php @@ -28,6 +28,8 @@ public function __construct() $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'; diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleTokenFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleTokenFactory.php new file mode 100644 index 0000000000000..beca6a81b9e97 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleTokenFactory.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory; + +use Symfony\Component\Config\Definition\Builder\NodeDefinition; +use Symfony\Component\DependencyInjection\DefinitionDecorator; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + +/** + * @author Jordi Boggiano + */ +class SimpleTokenFactory implements SecurityFactoryInterface +{ + public function getPosition() + { + return 'http'; + } + + public function getKey() + { + return 'simple-token'; + } + +// TODO add support for success_handler/failure_handler that call the impl ones + + public function addConfiguration(NodeDefinition $node) + { + $node + ->children() + ->scalarNode('provider')->end() + ->scalarNode('authenticator')->cannotBeEmpty()->end() + ->end() + ; + } + + public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint) + { + $provider = 'security.authentication.provider.simple_form.'.$id; + $container + ->setDefinition($provider, new DefinitionDecorator('security.authentication.provider.simple')) + ->replaceArgument(0, new Reference($config['authenticator'])) + ->replaceArgument(1, new Reference($userProvider)) + ->replaceArgument(2, $id) + ; + + // listener + $listenerId = 'security.authentication.listener.simple_token.'.$id; + $listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.authentication.listener.simple_token')); + $listener->replaceArgument(2, $id); + $listener->replaceArgument(3, new Reference($config['authenticator'])); + + return array($provider, $listenerId); + } +} diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml index 88c70b383df34..d9dea17af632e 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml @@ -14,6 +14,8 @@ Symfony\Component\Security\Http\Firewall\SimpleFormAuthenticationListener + Symfony\Component\Security\Http\Firewall\SimpleTokenAuthenticationListener + Symfony\Component\Security\Http\Firewall\BasicAuthenticationListener Symfony\Component\Security\Http\EntryPoint\BasicAuthenticationEntryPoint @@ -142,6 +144,15 @@ abstract="true"> + + + + + + + + + diff --git a/src/Symfony/Bundle/SecurityBundle/SecurityBundle.php b/src/Symfony/Bundle/SecurityBundle/SecurityBundle.php index 2796c232adae9..cbdc69f521a31 100644 --- a/src/Symfony/Bundle/SecurityBundle/SecurityBundle.php +++ b/src/Symfony/Bundle/SecurityBundle/SecurityBundle.php @@ -19,6 +19,7 @@ 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\SimpleFormFactory; use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider\InMemoryFactory; @@ -39,6 +40,7 @@ public function build(ContainerBuilder $container) $extension->addSecurityListenerFactory(new HttpDigestFactory()); $extension->addSecurityListenerFactory(new RememberMeFactory()); $extension->addSecurityListenerFactory(new X509Factory()); + $extension->addSecurityListenerFactory(new SimpleTokenFactory()); $extension->addSecurityListenerFactory(new SimpleFormFactory()); $extension->addUserProviderFactory(new InMemoryFactory()); diff --git a/src/Symfony/Component/Security/Core/Authentication/Provider/SimpleAuthenticationProvider.php b/src/Symfony/Component/Security/Core/Authentication/Provider/SimpleAuthenticationProvider.php index 72b82cba35e4a..8f8ccebb43761 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Provider/SimpleAuthenticationProvider.php +++ b/src/Symfony/Component/Security/Core/Authentication/Provider/SimpleAuthenticationProvider.php @@ -40,7 +40,7 @@ public function __construct(SimpleAuthenticatorInterface $simpleAuthenticator, U public function authenticate(TokenInterface $token) { - $authToken = $this->simpleAuthenticator->authenticate($token, $this->userProvider, $this->providerKey); + $authToken = $this->simpleAuthenticator->authenticateToken($token, $this->userProvider, $this->providerKey); if ($authToken instanceof TokenInterface) { return $authToken; @@ -51,6 +51,6 @@ public function authenticate(TokenInterface $token) public function supports(TokenInterface $token) { - return $this->simpleAuthenticator->supports($token, $this->providerKey); + return $this->simpleAuthenticator->supportsToken($token, $this->providerKey); } } diff --git a/src/Symfony/Component/Security/Core/Authentication/SimpleAuthenticatorInterface.php b/src/Symfony/Component/Security/Core/Authentication/SimpleAuthenticatorInterface.php index 81f761fd9f67d..fbbaa37bbbe91 100644 --- a/src/Symfony/Component/Security/Core/Authentication/SimpleAuthenticatorInterface.php +++ b/src/Symfony/Component/Security/Core/Authentication/SimpleAuthenticatorInterface.php @@ -13,18 +13,19 @@ use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; -use Symfony\Component\HttpKernel\Event\GetResponseEvent; -use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Core\User\UserProviderInterface; +use Symfony\Component\HttpFoundation\Request; /** * @author Jordi Boggiano */ interface SimpleAuthenticatorInterface { - public function authenticate(TokenInterface $token, UserProviderInterface $userProvider, $providerKey); + public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey); + + public function supportsToken(TokenInterface $token, $providerKey); - public function supports(TokenInterface $token, $providerKey); + public function onAuthenticationFailure(Request $request, AuthenticationException $exception); - public function handleAuthenticationFailure(GetResponseEvent $event, AuthenticationException $exception); + public function onAuthenticationSuccess(Request $request, TokenInterface $token); } diff --git a/src/Symfony/Component/Security/Core/Authentication/SimpleFormAuthenticatorInterface.php b/src/Symfony/Component/Security/Core/Authentication/SimpleFormAuthenticatorInterface.php index 79fdb1cb3cdfe..95ee881c18d82 100644 --- a/src/Symfony/Component/Security/Core/Authentication/SimpleFormAuthenticatorInterface.php +++ b/src/Symfony/Component/Security/Core/Authentication/SimpleFormAuthenticatorInterface.php @@ -11,9 +11,6 @@ namespace Symfony\Component\Security\Core\Authentication; -use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -use Symfony\Component\Security\Core\Exception\AuthenticationException; -use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpFoundation\Request; /** diff --git a/src/Symfony/Component/Security/Core/Authentication/SimpleTokenAuthenticatorInterface.php b/src/Symfony/Component/Security/Core/Authentication/SimpleTokenAuthenticatorInterface.php new file mode 100644 index 0000000000000..a6117544d4c6e --- /dev/null +++ b/src/Symfony/Component/Security/Core/Authentication/SimpleTokenAuthenticatorInterface.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Core\Authentication; + +use Symfony\Component\HttpFoundation\Request; + +/** + * @author Jordi Boggiano + */ +interface SimpleTokenAuthenticatorInterface extends SimpleAuthenticatorInterface +{ + public function createToken(Request $request, $providerKey); +} diff --git a/src/Symfony/Component/Security/Http/Firewall/SimpleTokenAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/SimpleTokenAuthenticationListener.php new file mode 100644 index 0000000000000..cda535b009a22 --- /dev/null +++ b/src/Symfony/Component/Security/Http/Firewall/SimpleTokenAuthenticationListener.php @@ -0,0 +1,90 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Http\Firewall; + +use Symfony\Component\Security\Core\SecurityContextInterface; +use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; +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\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Exception\AuthenticationException; + +/** + * SimpleTokenListener implements simple proxying to an authenticator. + * + * @author Jordi Boggiano + */ +class SimpleTokenAuthenticationListener implements ListenerInterface +{ + private $securityContext; + private $authenticationManager; + private $providerKey; + private $simpleAuthenticator; + private $logger; + + /** + * Constructor. + * + * @param SecurityContextInterface $securityContext A SecurityContext instance + * @param AuthenticationManagerInterface $authenticationManager An AuthenticationManagerInterface instance + * @param string $providerKey + * @param SimpleTokenAuthenticatorInterface $simpleAuthenticator A SimpleTokenAuthenticatorInterface instance + * @param LoggerInterface $logger A LoggerInterface instance + */ + public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, $providerKey, SimpleTokenAuthenticatorInterface $simpleAuthenticator, LoggerInterface $logger = null) + { + if (empty($providerKey)) { + throw new \InvalidArgumentException('$providerKey must not be empty.'); + } + + $this->securityContext = $securityContext; + $this->authenticationManager = $authenticationManager; + $this->providerKey = $providerKey; + $this->simpleAuthenticator = $simpleAuthenticator; + $this->logger = $logger; + } + + /** + * Handles basic authentication. + * + * @param GetResponseEvent $event A GetResponseEvent instance + */ + public function handle(GetResponseEvent $event) + { + $request = $event->getRequest(); + + if (null !== $this->logger) { + $this->logger->info(sprintf('Attempting simple token authorization %s', $this->providerKey)); + } + + + try { + $token = $this->simpleAuthenticator->createToken($request, $this->providerKey); + $token = $this->authenticationManager->authenticate($token); + $this->securityContext->setToken($token); + + } catch (AuthenticationException $failed) { + $this->securityContext->setToken(null); + + if (null !== $this->logger) { + $this->logger->info(sprintf('Authentication request failed: %s', $failed->getMessage())); + } + + // TODO call failure handler + return; + } + + // TODO call success handler + } +} From 65335eaa62866e3441fefd7318a5b9dbd98e25e1 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 12 Apr 2013 20:08:12 +0200 Subject: [PATCH 3/7] [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 27f08b0a1f9d9..10032c6aa134e 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 @@ protected function createAuthenticationSuccessHandler($container, $id, $config) 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 @@ protected function createAuthenticationFailureHandler($container, $id, $config) 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 fc1344db25d78..8fdef89a7415e 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 @@ public function __construct() $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 @@ protected function createAuthProvider(ContainerBuilder $container, $id, $config, 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 beca6a81b9e97..d9613c1ccd3e3 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 @@ /** * @author Jordi Boggiano */ -class SimpleTokenFactory implements SecurityFactoryInterface +class SimpleHttpFactory implements SecurityFactoryInterface { public function getPosition() { @@ -28,11 +28,9 @@ public function getPosition() 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 @@ public function addConfiguration(NodeDefinition $node) 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 @@ public function create(ContainerBuilder $container, $id, $config, $userProvider, ; // 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 d9dea17af632e..8281fc657da22 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 cbdc69f521a31..85c4a22b2e872 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\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 @@ public function build(ContainerBuilder $container) $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 fbbaa37bbbe91..868d072714834 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 a6117544d4c6e..b64aad9193107 100644 --- a/src/Symfony/Component/Security/Core/Authentication/SimpleTokenAuthenticatorInterface.php +++ b/src/Symfony/Component/Security/Core/Authentication/SimpleHttpAuthenticatorInterface.php @@ -16,7 +16,7 @@ /** * @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 0000000000000..ce56ee3f88053 --- /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 cda535b009a22..ab49b14165cfe 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\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 @@ public function handle(GetResponseEvent $event) $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))); + } + } } } From 887d9b84738004dcd89004f387c34ffb2637c544 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 5 May 2013 18:52:41 +0200 Subject: [PATCH 4/7] fixed wrong Logger interface --- .../Security/Http/Firewall/SimpleFormAuthenticationListener.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php index f096c2f2c3296..7c4b9716ad5c1 100644 --- a/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php @@ -13,7 +13,6 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; -use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; @@ -29,6 +28,7 @@ use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface; use Symfony\Component\Security\Http\SecurityEvents; use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; +use Psr\Log\LoggerInterface; /** * @author Jordi Boggiano From 01c913be4b13a672a14ed20ec4ce44131cdea9f1 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 5 May 2013 18:58:35 +0200 Subject: [PATCH 5/7] moved the simple HTTP authenticator to a pre-auth one --- ...actory.php => SimplePreAuthenticationFactory.php} | 12 ++++++------ .../Resources/config/security_listeners.xml | 4 ++-- src/Symfony/Bundle/SecurityBundle/SecurityBundle.php | 4 ++-- ...rface.php => SimplePreAuthenticatorInterface.php} | 2 +- ...tener.php => SimplePreAuthenticationListener.php} | 12 ++++++------ 5 files changed, 17 insertions(+), 17 deletions(-) rename src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/{SimpleHttpFactory.php => SimplePreAuthenticationFactory.php} (82%) rename src/Symfony/Component/Security/Core/Authentication/{SimpleHttpAuthenticatorInterface.php => SimplePreAuthenticatorInterface.php} (85%) rename src/Symfony/Component/Security/Http/Firewall/{SimpleHttpAuthenticationListener.php => SimplePreAuthenticationListener.php} (87%) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleHttpFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimplePreAuthenticationFactory.php similarity index 82% rename from src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleHttpFactory.php rename to src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimplePreAuthenticationFactory.php index d9613c1ccd3e3..27d8c5f050ec5 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleHttpFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimplePreAuthenticationFactory.php @@ -19,16 +19,16 @@ /** * @author Jordi Boggiano */ -class SimpleHttpFactory implements SecurityFactoryInterface +class SimplePreAuthenticationFactory implements SecurityFactoryInterface { public function getPosition() { - return 'http'; + return 'pre_auth'; } public function getKey() { - return 'simple-http'; + return 'simple-preauth'; } public function addConfiguration(NodeDefinition $node) @@ -43,7 +43,7 @@ public function addConfiguration(NodeDefinition $node) public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint) { - $provider = 'security.authentication.provider.simple_http.'.$id; + $provider = 'security.authentication.provider.simple_preauth.'.$id; $container ->setDefinition($provider, new DefinitionDecorator('security.authentication.provider.simple')) ->replaceArgument(0, new Reference($config['authenticator'])) @@ -52,8 +52,8 @@ public function create(ContainerBuilder $container, $id, $config, $userProvider, ; // listener - $listenerId = 'security.authentication.listener.simple_http.'.$id; - $listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.authentication.listener.simple_http')); + $listenerId = 'security.authentication.listener.simple_preauth.'.$id; + $listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.authentication.listener.simple_preauth')); $listener->replaceArgument(2, $id); $listener->replaceArgument(3, new Reference($config['authenticator'])); diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml index 8281fc657da22..2bd379931a90b 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\SimpleHttpAuthenticationListener + Symfony\Component\Security\Http\Firewall\SimplePreAuthenticationListener Symfony\Component\Security\Http\Firewall\BasicAuthenticationListener Symfony\Component\Security\Http\EntryPoint\BasicAuthenticationEntryPoint @@ -153,7 +153,7 @@ - + diff --git a/src/Symfony/Bundle/SecurityBundle/SecurityBundle.php b/src/Symfony/Bundle/SecurityBundle/SecurityBundle.php index 85c4a22b2e872..5de413658632e 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\HttpDigestFactory; use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\RememberMeFactory; use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\X509Factory; -use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SimpleHttpFactory; +use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SimplePreAuthenticationFactory; use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SimpleFormFactory; use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider\InMemoryFactory; @@ -40,7 +40,7 @@ public function build(ContainerBuilder $container) $extension->addSecurityListenerFactory(new HttpDigestFactory()); $extension->addSecurityListenerFactory(new RememberMeFactory()); $extension->addSecurityListenerFactory(new X509Factory()); - $extension->addSecurityListenerFactory(new SimpleHttpFactory()); + $extension->addSecurityListenerFactory(new SimplePreAuthenticationFactory()); $extension->addSecurityListenerFactory(new SimpleFormFactory()); $extension->addUserProviderFactory(new InMemoryFactory()); diff --git a/src/Symfony/Component/Security/Core/Authentication/SimpleHttpAuthenticatorInterface.php b/src/Symfony/Component/Security/Core/Authentication/SimplePreAuthenticatorInterface.php similarity index 85% rename from src/Symfony/Component/Security/Core/Authentication/SimpleHttpAuthenticatorInterface.php rename to src/Symfony/Component/Security/Core/Authentication/SimplePreAuthenticatorInterface.php index b64aad9193107..6164e7d9860a7 100644 --- a/src/Symfony/Component/Security/Core/Authentication/SimpleHttpAuthenticatorInterface.php +++ b/src/Symfony/Component/Security/Core/Authentication/SimplePreAuthenticatorInterface.php @@ -16,7 +16,7 @@ /** * @author Jordi Boggiano */ -interface SimpleHttpAuthenticatorInterface extends SimpleAuthenticatorInterface +interface SimplePreAuthenticatorInterface extends SimpleAuthenticatorInterface { public function createToken(Request $request, $providerKey); } diff --git a/src/Symfony/Component/Security/Http/Firewall/SimpleHttpAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/SimplePreAuthenticationListener.php similarity index 87% rename from src/Symfony/Component/Security/Http/Firewall/SimpleHttpAuthenticationListener.php rename to src/Symfony/Component/Security/Http/Firewall/SimplePreAuthenticationListener.php index ab49b14165cfe..80b35a55ac045 100644 --- a/src/Symfony/Component/Security/Http/Firewall/SimpleHttpAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/SimplePreAuthenticationListener.php @@ -17,18 +17,18 @@ use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Security\Core\Authentication\SimpleHttpAuthenticatorInterface; +use Symfony\Component\Security\Core\Authentication\SimplePreAuthenticatorInterface; 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; /** - * SimpleHttpListener implements simple proxying to an authenticator. + * SimplePreAuthenticationListener implements simple proxying to an authenticator. * * @author Jordi Boggiano */ -class SimpleHttpAuthenticationListener implements ListenerInterface +class SimplePreAuthenticationListener implements ListenerInterface { private $securityContext; private $authenticationManager; @@ -42,10 +42,10 @@ class SimpleHttpAuthenticationListener implements ListenerInterface * @param SecurityContextInterface $securityContext A SecurityContext instance * @param AuthenticationManagerInterface $authenticationManager An AuthenticationManagerInterface instance * @param string $providerKey - * @param SimpleHttpAuthenticatorInterface $simpleAuthenticator A SimpleHttpAuthenticatorInterface instance + * @param SimplePreAuthenticatorInterface $simpleAuthenticator A SimplePreAuthenticatorInterface instance * @param LoggerInterface $logger A LoggerInterface instance */ - public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, $providerKey, SimpleHttpAuthenticatorInterface $simpleAuthenticator, LoggerInterface $logger = null) + public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, $providerKey, SimplePreAuthenticatorInterface $simpleAuthenticator, LoggerInterface $logger = null) { if (empty($providerKey)) { throw new \InvalidArgumentException('$providerKey must not be empty.'); @@ -68,7 +68,7 @@ public function handle(GetResponseEvent $event) $request = $event->getRequest(); if (null !== $this->logger) { - $this->logger->info(sprintf('Attempting simple http authorization %s', $this->providerKey)); + $this->logger->info(sprintf('Attempting simple pre-authorization %s', $this->providerKey)); } try { From 471e5bc21a88b75b1bb7769841fda7a65a142c51 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 5 May 2013 19:24:00 +0200 Subject: [PATCH 6/7] [Security] allowed simple pre-auth to be optional if another auth mechanism already authenticated the user --- .../Http/Firewall/SimplePreAuthenticationListener.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Symfony/Component/Security/Http/Firewall/SimplePreAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/SimplePreAuthenticationListener.php index 80b35a55ac045..2a6b4d5c0d291 100644 --- a/src/Symfony/Component/Security/Http/Firewall/SimplePreAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/SimplePreAuthenticationListener.php @@ -19,6 +19,7 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Security\Core\Authentication\SimplePreAuthenticatorInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; @@ -71,6 +72,10 @@ public function handle(GetResponseEvent $event) $this->logger->info(sprintf('Attempting simple pre-authorization %s', $this->providerKey)); } + if (null !== $this->context->getToken() && !$this->context->getToken() instanceof AnonymousToken) { + return; + } + try { $token = $this->simpleAuthenticator->createToken($request, $this->providerKey); $token = $this->authenticationManager->authenticate($token); From 74cfc84c87ac281d1ed5aeb8eca9c86ae46c50cf Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 8 May 2013 14:19:47 +0200 Subject: [PATCH 7/7] marked some classes as being experimental in 2.3 --- .../DependencyInjection/Security/Factory/SimpleFormFactory.php | 2 ++ .../Security/Factory/SimplePreAuthenticationFactory.php | 2 ++ .../Authentication/Provider/SimpleAuthenticationProvider.php | 2 ++ .../Core/Authentication/SimpleAuthenticatorInterface.php | 2 ++ .../Core/Authentication/SimpleFormAuthenticatorInterface.php | 2 ++ .../Core/Authentication/SimplePreAuthenticatorInterface.php | 2 ++ .../Http/Authentication/SimpleAuthenticationHandler.php | 2 ++ .../Security/Http/Firewall/SimpleFormAuthenticationListener.php | 2 ++ .../Security/Http/Firewall/SimplePreAuthenticationListener.php | 2 ++ 9 files changed, 18 insertions(+) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleFormFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleFormFactory.php index 8fdef89a7415e..f13fd5e08d102 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleFormFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleFormFactory.php @@ -18,6 +18,8 @@ /** * @author Jordi Boggiano + * + * @experimental This feature is experimental in 2.3 and might change in future versions */ class SimpleFormFactory extends FormLoginFactory { diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimplePreAuthenticationFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimplePreAuthenticationFactory.php index 27d8c5f050ec5..689316e26f5bd 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimplePreAuthenticationFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimplePreAuthenticationFactory.php @@ -18,6 +18,8 @@ /** * @author Jordi Boggiano + * + * @experimental This feature is experimental in 2.3 and might change in future versions */ class SimplePreAuthenticationFactory implements SecurityFactoryInterface { diff --git a/src/Symfony/Component/Security/Core/Authentication/Provider/SimpleAuthenticationProvider.php b/src/Symfony/Component/Security/Core/Authentication/Provider/SimpleAuthenticationProvider.php index 8f8ccebb43761..50c9a08a7acce 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Provider/SimpleAuthenticationProvider.php +++ b/src/Symfony/Component/Security/Core/Authentication/Provider/SimpleAuthenticationProvider.php @@ -24,6 +24,8 @@ /** * @author Jordi Boggiano + * + * @experimental This feature is experimental in 2.3 and might change in future versions */ class SimpleAuthenticationProvider implements AuthenticationProviderInterface { diff --git a/src/Symfony/Component/Security/Core/Authentication/SimpleAuthenticatorInterface.php b/src/Symfony/Component/Security/Core/Authentication/SimpleAuthenticatorInterface.php index 868d072714834..e8ad7b8fe7c27 100644 --- a/src/Symfony/Component/Security/Core/Authentication/SimpleAuthenticatorInterface.php +++ b/src/Symfony/Component/Security/Core/Authentication/SimpleAuthenticatorInterface.php @@ -16,6 +16,8 @@ /** * @author Jordi Boggiano + * + * @experimental This feature is experimental in 2.3 and might change in future versions */ interface SimpleAuthenticatorInterface { diff --git a/src/Symfony/Component/Security/Core/Authentication/SimpleFormAuthenticatorInterface.php b/src/Symfony/Component/Security/Core/Authentication/SimpleFormAuthenticatorInterface.php index 95ee881c18d82..bfc3ec240eb36 100644 --- a/src/Symfony/Component/Security/Core/Authentication/SimpleFormAuthenticatorInterface.php +++ b/src/Symfony/Component/Security/Core/Authentication/SimpleFormAuthenticatorInterface.php @@ -15,6 +15,8 @@ /** * @author Jordi Boggiano + * + * @experimental This feature is experimental in 2.3 and might change in future versions */ interface SimpleFormAuthenticatorInterface extends SimpleAuthenticatorInterface { diff --git a/src/Symfony/Component/Security/Core/Authentication/SimplePreAuthenticatorInterface.php b/src/Symfony/Component/Security/Core/Authentication/SimplePreAuthenticatorInterface.php index 6164e7d9860a7..8fa7037d396f5 100644 --- a/src/Symfony/Component/Security/Core/Authentication/SimplePreAuthenticatorInterface.php +++ b/src/Symfony/Component/Security/Core/Authentication/SimplePreAuthenticatorInterface.php @@ -15,6 +15,8 @@ /** * @author Jordi Boggiano + * + * @experimental This feature is experimental in 2.3 and might change in future versions */ interface SimplePreAuthenticatorInterface extends SimpleAuthenticatorInterface { diff --git a/src/Symfony/Component/Security/Http/Authentication/SimpleAuthenticationHandler.php b/src/Symfony/Component/Security/Http/Authentication/SimpleAuthenticationHandler.php index ce56ee3f88053..88be8e4b1f7e5 100644 --- a/src/Symfony/Component/Security/Http/Authentication/SimpleAuthenticationHandler.php +++ b/src/Symfony/Component/Security/Http/Authentication/SimpleAuthenticationHandler.php @@ -26,6 +26,8 @@ * the default handlers are triggered. * * @author Jordi Boggiano + * + * @experimental This feature is experimental in 2.3 and might change in future versions */ class SimpleAuthenticationHandler implements AuthenticationFailureHandlerInterface, AuthenticationSuccessHandlerInterface { diff --git a/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php index 7c4b9716ad5c1..8325bb1920574 100644 --- a/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php @@ -32,6 +32,8 @@ /** * @author Jordi Boggiano + * + * @experimental This feature is experimental in 2.3 and might change in future versions */ class SimpleFormAuthenticationListener extends AbstractAuthenticationListener { diff --git a/src/Symfony/Component/Security/Http/Firewall/SimplePreAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/SimplePreAuthenticationListener.php index 2a6b4d5c0d291..637ed396a0b7b 100644 --- a/src/Symfony/Component/Security/Http/Firewall/SimplePreAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/SimplePreAuthenticationListener.php @@ -28,6 +28,8 @@ * SimplePreAuthenticationListener implements simple proxying to an authenticator. * * @author Jordi Boggiano + * + * @experimental This feature is experimental in 2.3 and might change in future versions */ class SimplePreAuthenticationListener implements ListenerInterface {