[Security] Renamed simple_token to simple_http, added support for failure and success handler to both simple firewalls

This commit is contained in:
Jordi Boggiano 2013-04-12 20:08:12 +02:00
parent f7a11a1ab3
commit 65335eaa62
9 changed files with 177 additions and 43 deletions

View File

@ -174,7 +174,7 @@ abstract class AbstractFactory implements SecurityFactoryInterface
return $config['success_handler']; 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 = $container->setDefinition($successHandlerId, new DefinitionDecorator('security.authentication.success_handler'));
$successHandler->replaceArgument(1, array_intersect_key($config, $this->defaultSuccessHandlerOptions)); $successHandler->replaceArgument(1, array_intersect_key($config, $this->defaultSuccessHandlerOptions));
@ -189,11 +189,21 @@ abstract class AbstractFactory implements SecurityFactoryInterface
return $config['failure_handler']; 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 = $container->setDefinition($id, new DefinitionDecorator('security.authentication.failure_handler'));
$failureHandler->replaceArgument(2, array_intersect_key($config, $this->defaultFailureHandlerOptions)); $failureHandler->replaceArgument(2, array_intersect_key($config, $this->defaultFailureHandlerOptions));
return $id; 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());
}
} }

View File

@ -28,8 +28,6 @@ class SimpleFormFactory extends FormLoginFactory
$this->addOption('authenticator', null); $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() public function getKey()
{ {
return 'simple-form'; return 'simple-form';
@ -65,17 +63,21 @@ class SimpleFormFactory extends FormLoginFactory
protected function createListener($container, $id, $config, $userProvider) protected function createListener($container, $id, $config, $userProvider)
{ {
$listenerId = parent::createListener($container, $id, $config, $userProvider); $listenerId = parent::createListener($container, $id, $config, $userProvider);
$listener = $container->getDefinition($listenerId);
if (!isset($config['csrf_provider'])) { if (!isset($config['csrf_provider'])) {
$container $listener->addArgument(null);
->getDefinition($listenerId)
->addArgument(null)
;
} }
$container
->getDefinition($listenerId) $simpleAuthHandlerId = 'security.authentication.simple_success_failure_handler.'.$id;
->addArgument(new Reference($config['authenticator'])) $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; return $listenerId;
} }

View File

@ -19,7 +19,7 @@ use Symfony\Component\DependencyInjection\Reference;
/** /**
* @author Jordi Boggiano <j.boggiano@seld.be> * @author Jordi Boggiano <j.boggiano@seld.be>
*/ */
class SimpleTokenFactory implements SecurityFactoryInterface class SimpleHttpFactory implements SecurityFactoryInterface
{ {
public function getPosition() public function getPosition()
{ {
@ -28,11 +28,9 @@ class SimpleTokenFactory implements SecurityFactoryInterface
public function getKey() 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) public function addConfiguration(NodeDefinition $node)
{ {
$node $node
@ -45,7 +43,7 @@ class SimpleTokenFactory implements SecurityFactoryInterface
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint) public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
{ {
$provider = 'security.authentication.provider.simple_form.'.$id; $provider = 'security.authentication.provider.simple_http.'.$id;
$container $container
->setDefinition($provider, new DefinitionDecorator('security.authentication.provider.simple')) ->setDefinition($provider, new DefinitionDecorator('security.authentication.provider.simple'))
->replaceArgument(0, new Reference($config['authenticator'])) ->replaceArgument(0, new Reference($config['authenticator']))
@ -54,11 +52,11 @@ class SimpleTokenFactory implements SecurityFactoryInterface
; ;
// listener // listener
$listenerId = 'security.authentication.listener.simple_token.'.$id; $listenerId = 'security.authentication.listener.simple_http.'.$id;
$listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.authentication.listener.simple_token')); $listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.authentication.listener.simple_http'));
$listener->replaceArgument(2, $id); $listener->replaceArgument(2, $id);
$listener->replaceArgument(3, new Reference($config['authenticator'])); $listener->replaceArgument(3, new Reference($config['authenticator']));
return array($provider, $listenerId); return array($provider, $listenerId, null);
} }
} }

View File

@ -14,7 +14,7 @@
<parameter key="security.authentication.listener.simple_form.class">Symfony\Component\Security\Http\Firewall\SimpleFormAuthenticationListener</parameter> <parameter key="security.authentication.listener.simple_form.class">Symfony\Component\Security\Http\Firewall\SimpleFormAuthenticationListener</parameter>
<parameter key="security.authentication.listener.simple_token.class">Symfony\Component\Security\Http\Firewall\SimpleTokenAuthenticationListener</parameter> <parameter key="security.authentication.listener.simple_http.class">Symfony\Component\Security\Http\Firewall\SimpleHttpAuthenticationListener</parameter>
<parameter key="security.authentication.listener.basic.class">Symfony\Component\Security\Http\Firewall\BasicAuthenticationListener</parameter> <parameter key="security.authentication.listener.basic.class">Symfony\Component\Security\Http\Firewall\BasicAuthenticationListener</parameter>
<parameter key="security.authentication.basic_entry_point.class">Symfony\Component\Security\Http\EntryPoint\BasicAuthenticationEntryPoint</parameter> <parameter key="security.authentication.basic_entry_point.class">Symfony\Component\Security\Http\EntryPoint\BasicAuthenticationEntryPoint</parameter>
@ -46,6 +46,7 @@
<parameter key="security.authentication.success_handler.class">Symfony\Component\Security\Http\Authentication\DefaultAuthenticationSuccessHandler</parameter> <parameter key="security.authentication.success_handler.class">Symfony\Component\Security\Http\Authentication\DefaultAuthenticationSuccessHandler</parameter>
<parameter key="security.authentication.failure_handler.class">Symfony\Component\Security\Http\Authentication\DefaultAuthenticationFailureHandler</parameter> <parameter key="security.authentication.failure_handler.class">Symfony\Component\Security\Http\Authentication\DefaultAuthenticationFailureHandler</parameter>
<parameter key="security.authentication.simple_success_failure_handler.class">Symfony\Component\Security\Http\Authentication\SimpleAuthenticationHandler</parameter>
</parameters> </parameters>
<services> <services>
@ -144,7 +145,15 @@
abstract="true"> abstract="true">
</service> </service>
<service id="security.authentication.listener.simple_token" class="%security.authentication.listener.simple_token.class%" public="false" abstract="true"> <service id="security.authentication.simple_success_failure_handler" class="%security.authentication.simple_success_failure_handler.class%" public="false" abstract="true">
<tag name="monolog.logger" channel="security" />
<argument /> <!-- Authenticator -->
<argument type="service" id="security.authentication.success_handler" />
<argument type="service" id="security.authentication.failure_handler" />
<argument type="service" id="logger" on-invalid="null" />
</service>
<service id="security.authentication.listener.simple_http" class="%security.authentication.listener.simple_http.class%" public="false" abstract="true">
<tag name="monolog.logger" channel="security" /> <tag name="monolog.logger" channel="security" />
<argument type="service" id="security.context" /> <argument type="service" id="security.context" />
<argument type="service" id="security.authentication.manager" /> <argument type="service" id="security.authentication.manager" />

View File

@ -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\HttpDigestFactory;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\RememberMeFactory; use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\RememberMeFactory;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\X509Factory; 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\Factory\SimpleFormFactory;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider\InMemoryFactory; use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider\InMemoryFactory;
@ -40,7 +40,7 @@ class SecurityBundle extends Bundle
$extension->addSecurityListenerFactory(new HttpDigestFactory()); $extension->addSecurityListenerFactory(new HttpDigestFactory());
$extension->addSecurityListenerFactory(new RememberMeFactory()); $extension->addSecurityListenerFactory(new RememberMeFactory());
$extension->addSecurityListenerFactory(new X509Factory()); $extension->addSecurityListenerFactory(new X509Factory());
$extension->addSecurityListenerFactory(new SimpleTokenFactory()); $extension->addSecurityListenerFactory(new SimpleHttpFactory());
$extension->addSecurityListenerFactory(new SimpleFormFactory()); $extension->addSecurityListenerFactory(new SimpleFormFactory());
$extension->addUserProviderFactory(new InMemoryFactory()); $extension->addUserProviderFactory(new InMemoryFactory());

View File

@ -12,9 +12,7 @@
namespace Symfony\Component\Security\Core\Authentication; namespace Symfony\Component\Security\Core\Authentication;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; 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\Security\Core\User\UserProviderInterface;
use Symfony\Component\HttpFoundation\Request;
/** /**
* @author Jordi Boggiano <j.boggiano@seld.be> * @author Jordi Boggiano <j.boggiano@seld.be>
@ -24,8 +22,4 @@ interface SimpleAuthenticatorInterface
public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey); public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey);
public function supportsToken(TokenInterface $token, $providerKey); public function supportsToken(TokenInterface $token, $providerKey);
public function onAuthenticationFailure(Request $request, AuthenticationException $exception);
public function onAuthenticationSuccess(Request $request, TokenInterface $token);
} }

View File

@ -16,7 +16,7 @@ use Symfony\Component\HttpFoundation\Request;
/** /**
* @author Jordi Boggiano <j.boggiano@seld.be> * @author Jordi Boggiano <j.boggiano@seld.be>
*/ */
interface SimpleTokenAuthenticatorInterface extends SimpleAuthenticatorInterface interface SimpleHttpAuthenticatorInterface extends SimpleAuthenticatorInterface
{ {
public function createToken(Request $request, $providerKey); public function createToken(Request $request, $providerKey);
} }

View File

@ -0,0 +1,105 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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 <j.boggiano@seld.be>
*/
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);
}
}

View File

@ -16,16 +16,19 @@ use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterfac
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent; 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\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException; 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 <j.boggiano@seld.be> * @author Jordi Boggiano <j.boggiano@seld.be>
*/ */
class SimpleTokenAuthenticationListener implements ListenerInterface class SimpleHttpAuthenticationListener implements ListenerInterface
{ {
private $securityContext; private $securityContext;
private $authenticationManager; private $authenticationManager;
@ -39,10 +42,10 @@ class SimpleTokenAuthenticationListener implements ListenerInterface
* @param SecurityContextInterface $securityContext A SecurityContext instance * @param SecurityContextInterface $securityContext A SecurityContext instance
* @param AuthenticationManagerInterface $authenticationManager An AuthenticationManagerInterface instance * @param AuthenticationManagerInterface $authenticationManager An AuthenticationManagerInterface instance
* @param string $providerKey * @param string $providerKey
* @param SimpleTokenAuthenticatorInterface $simpleAuthenticator A SimpleTokenAuthenticatorInterface instance * @param SimpleHttpAuthenticatorInterface $simpleAuthenticator A SimpleHttpAuthenticatorInterface instance
* @param LoggerInterface $logger A LoggerInterface 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)) { if (empty($providerKey)) {
throw new \InvalidArgumentException('$providerKey must not be empty.'); throw new \InvalidArgumentException('$providerKey must not be empty.');
@ -65,26 +68,39 @@ class SimpleTokenAuthenticationListener implements ListenerInterface
$request = $event->getRequest(); $request = $event->getRequest();
if (null !== $this->logger) { 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 { try {
$token = $this->simpleAuthenticator->createToken($request, $this->providerKey); $token = $this->simpleAuthenticator->createToken($request, $this->providerKey);
$token = $this->authenticationManager->authenticate($token); $token = $this->authenticationManager->authenticate($token);
$this->securityContext->setToken($token); $this->securityContext->setToken($token);
} catch (AuthenticationException $e) {
} catch (AuthenticationException $failed) {
$this->securityContext->setToken(null); $this->securityContext->setToken(null);
if (null !== $this->logger) { 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; 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)));
}
}
} }
} }