merged branch Seldaek/simplesecurity (PR #6069)
This PR was merged into the master branch. Discussion ---------- [Security] Add simpler customization options The goal of this is to provide a simpler extension point for people that don't have the time to dive into the whole security factory + authentication provider + user provider + authentication listener + token mess. As it stands, it gives you a way to just create one class that is handling all the security stuff in one (by implementing SimpleFormAuthenticatorInterface and UserProviderInterface) + one or more token classes. I would like feedback on whether people think this makes sense or not before continuing and doing a SimpleHttpAuthenticatorInterface for non-form based stuff. Just FYI that's how it would look in security.yml: ```yaml security: providers: simple: id: simple_authenticator firewalls: foo: pattern: ^/ simple_form: provider: simple authenticator: simple_authenticator ``` /cc @atrauzzi (who posted a long rant on the ML about how hard this all is, and I can't agree more - I hope it's the right account on github?) Commits -------74cfc84
marked some classes as being experimental in 2.3471e5bc
[Security] allowed simple pre-auth to be optional if another auth mechanism already authenticated the user01c913b
moved the simple HTTP authenticator to a pre-auth one887d9b8
fixed wrong Logger interface65335ea
[Security] Renamed simple_token to simple_http, added support for failure and success handler to both simple firewallsf7a11a1
[Security] Add simple_token auth method1fe2ed6
[Security] Add SimpleForm authentication
This commit is contained in:
commit
d93883490d
@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,99 @@
|
|||||||
|
<?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\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 <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* @experimental This feature is experimental in 2.3 and might change in future versions
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
$listener = $container->getDefinition($listenerId);
|
||||||
|
|
||||||
|
if (!isset($config['csrf_provider'])) {
|
||||||
|
$listener->addArgument(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
$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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
<?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\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 <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* @experimental This feature is experimental in 2.3 and might change in future versions
|
||||||
|
*/
|
||||||
|
class SimplePreAuthenticationFactory implements SecurityFactoryInterface
|
||||||
|
{
|
||||||
|
public function getPosition()
|
||||||
|
{
|
||||||
|
return 'pre_auth';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getKey()
|
||||||
|
{
|
||||||
|
return 'simple-preauth';
|
||||||
|
}
|
||||||
|
|
||||||
|
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_preauth.'.$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_preauth.'.$id;
|
||||||
|
$listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.authentication.listener.simple_preauth'));
|
||||||
|
$listener->replaceArgument(2, $id);
|
||||||
|
$listener->replaceArgument(3, new Reference($config['authenticator']));
|
||||||
|
|
||||||
|
return array($provider, $listenerId, null);
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,10 @@
|
|||||||
<parameter key="security.authentication.form_entry_point.class">Symfony\Component\Security\Http\EntryPoint\FormAuthenticationEntryPoint</parameter>
|
<parameter key="security.authentication.form_entry_point.class">Symfony\Component\Security\Http\EntryPoint\FormAuthenticationEntryPoint</parameter>
|
||||||
<parameter key="security.authentication.listener.form.class">Symfony\Component\Security\Http\Firewall\UsernamePasswordFormAuthenticationListener</parameter>
|
<parameter key="security.authentication.listener.form.class">Symfony\Component\Security\Http\Firewall\UsernamePasswordFormAuthenticationListener</parameter>
|
||||||
|
|
||||||
|
<parameter key="security.authentication.listener.simple_form.class">Symfony\Component\Security\Http\Firewall\SimpleFormAuthenticationListener</parameter>
|
||||||
|
|
||||||
|
<parameter key="security.authentication.listener.simple_preauth.class">Symfony\Component\Security\Http\Firewall\SimplePreAuthenticationListener</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>
|
||||||
|
|
||||||
@ -35,12 +39,14 @@
|
|||||||
<parameter key="security.context_listener.class">Symfony\Component\Security\Http\Firewall\ContextListener</parameter>
|
<parameter key="security.context_listener.class">Symfony\Component\Security\Http\Firewall\ContextListener</parameter>
|
||||||
|
|
||||||
<parameter key="security.authentication.provider.dao.class">Symfony\Component\Security\Core\Authentication\Provider\DaoAuthenticationProvider</parameter>
|
<parameter key="security.authentication.provider.dao.class">Symfony\Component\Security\Core\Authentication\Provider\DaoAuthenticationProvider</parameter>
|
||||||
|
<parameter key="security.authentication.provider.simple.class">Symfony\Component\Security\Core\Authentication\Provider\SimpleAuthenticationProvider</parameter>
|
||||||
<parameter key="security.authentication.provider.pre_authenticated.class">Symfony\Component\Security\Core\Authentication\Provider\PreAuthenticatedAuthenticationProvider</parameter>
|
<parameter key="security.authentication.provider.pre_authenticated.class">Symfony\Component\Security\Core\Authentication\Provider\PreAuthenticatedAuthenticationProvider</parameter>
|
||||||
|
|
||||||
<parameter key="security.authentication.provider.anonymous.class">Symfony\Component\Security\Core\Authentication\Provider\AnonymousAuthenticationProvider</parameter>
|
<parameter key="security.authentication.provider.anonymous.class">Symfony\Component\Security\Core\Authentication\Provider\AnonymousAuthenticationProvider</parameter>
|
||||||
|
|
||||||
<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>
|
||||||
@ -133,6 +139,29 @@
|
|||||||
abstract="true">
|
abstract="true">
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
<service id="security.authentication.listener.simple_form"
|
||||||
|
class="%security.authentication.listener.simple_form.class%"
|
||||||
|
parent="security.authentication.listener.abstract"
|
||||||
|
abstract="true">
|
||||||
|
</service>
|
||||||
|
|
||||||
|
<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_preauth" class="%security.authentication.listener.simple_preauth.class%" public="false" abstract="true">
|
||||||
|
<tag name="monolog.logger" channel="security" />
|
||||||
|
<argument type="service" id="security.context" />
|
||||||
|
<argument type="service" id="security.authentication.manager" />
|
||||||
|
<argument /> <!-- Provider-shared Key -->
|
||||||
|
<argument /> <!-- Authenticator -->
|
||||||
|
<argument type="service" id="logger" on-invalid="null" />
|
||||||
|
</service>
|
||||||
|
|
||||||
<service id="security.authentication.listener.x509" class="%security.authentication.listener.x509.class%" public="false" abstract="true">
|
<service id="security.authentication.listener.x509" class="%security.authentication.listener.x509.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" />
|
||||||
@ -170,6 +199,12 @@
|
|||||||
<argument>%security.authentication.hide_user_not_found%</argument>
|
<argument>%security.authentication.hide_user_not_found%</argument>
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
<service id="security.authentication.provider.simple" class="%security.authentication.provider.simple.class%" abstract="true" public="false">
|
||||||
|
<argument /> <!-- Simple Authenticator -->
|
||||||
|
<argument /> <!-- User Provider -->
|
||||||
|
<argument /> <!-- Provider-shared Key -->
|
||||||
|
</service>
|
||||||
|
|
||||||
<service id="security.authentication.provider.pre_authenticated" class="%security.authentication.provider.pre_authenticated.class%" abstract="true" public="false">
|
<service id="security.authentication.provider.pre_authenticated" class="%security.authentication.provider.pre_authenticated.class%" abstract="true" public="false">
|
||||||
<argument /> <!-- User Provider -->
|
<argument /> <!-- User Provider -->
|
||||||
<argument type="service" id="security.user_checker" />
|
<argument type="service" id="security.user_checker" />
|
||||||
|
@ -19,6 +19,8 @@ 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\SimplePreAuthenticationFactory;
|
||||||
|
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SimpleFormFactory;
|
||||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider\InMemoryFactory;
|
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider\InMemoryFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,6 +40,8 @@ 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 SimplePreAuthenticationFactory());
|
||||||
|
$extension->addSecurityListenerFactory(new SimpleFormFactory());
|
||||||
|
|
||||||
$extension->addUserProviderFactory(new InMemoryFactory());
|
$extension->addUserProviderFactory(new InMemoryFactory());
|
||||||
$container->addCompilerPass(new AddSecurityVotersPass());
|
$container->addCompilerPass(new AddSecurityVotersPass());
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
<?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\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 <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* @experimental This feature is experimental in 2.3 and might change in future versions
|
||||||
|
*/
|
||||||
|
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->authenticateToken($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->supportsToken($token, $this->providerKey);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
<?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\Core\Authentication;
|
||||||
|
|
||||||
|
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||||
|
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* @experimental This feature is experimental in 2.3 and might change in future versions
|
||||||
|
*/
|
||||||
|
interface SimpleAuthenticatorInterface
|
||||||
|
{
|
||||||
|
public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey);
|
||||||
|
|
||||||
|
public function supportsToken(TokenInterface $token, $providerKey);
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
<?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\Core\Authentication;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* @experimental This feature is experimental in 2.3 and might change in future versions
|
||||||
|
*/
|
||||||
|
interface SimpleFormAuthenticatorInterface extends SimpleAuthenticatorInterface
|
||||||
|
{
|
||||||
|
public function createToken(Request $request, $username, $password, $providerKey);
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
<?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\Core\Authentication;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* @experimental This feature is experimental in 2.3 and might change in future versions
|
||||||
|
*/
|
||||||
|
interface SimplePreAuthenticatorInterface extends SimpleAuthenticatorInterface
|
||||||
|
{
|
||||||
|
public function createToken(Request $request, $providerKey);
|
||||||
|
}
|
@ -0,0 +1,107 @@
|
|||||||
|
<?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>
|
||||||
|
*
|
||||||
|
* @experimental This feature is experimental in 2.3 and might change in future versions
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,118 @@
|
|||||||
|
<?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\Firewall;
|
||||||
|
|
||||||
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||||
|
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
|
||||||
|
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;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* @experimental This feature is experimental in 2.3 and might change in future versions
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,113 @@
|
|||||||
|
<?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\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\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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SimplePreAuthenticationListener implements simple proxying to an authenticator.
|
||||||
|
*
|
||||||
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* @experimental This feature is experimental in 2.3 and might change in future versions
|
||||||
|
*/
|
||||||
|
class SimplePreAuthenticationListener 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 SimplePreAuthenticatorInterface $simpleAuthenticator A SimplePreAuthenticatorInterface instance
|
||||||
|
* @param LoggerInterface $logger A LoggerInterface instance
|
||||||
|
*/
|
||||||
|
public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, $providerKey, SimplePreAuthenticatorInterface $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 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);
|
||||||
|
$this->securityContext->setToken($token);
|
||||||
|
} catch (AuthenticationException $e) {
|
||||||
|
$this->securityContext->setToken(null);
|
||||||
|
|
||||||
|
if (null !== $this->logger) {
|
||||||
|
$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)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user