[Security] Add XML support for authenticator manager

This commit is contained in:
Wouter de Jong 2021-03-16 14:36:31 +01:00 committed by Fabien Potencier
parent ca06651235
commit 77fb0eb0a1
7 changed files with 119 additions and 2 deletions

View File

@ -31,7 +31,7 @@ class LoginLinkFactory extends AbstractFactory implements AuthenticatorFactoryIn
public function addConfiguration(NodeDefinition $node)
{
/** @var NodeBuilder $builder */
$builder = $node->children();
$builder = $node->fixXmlConfig('signature_property', 'signature_properties')->children();
$builder
->scalarNode('check_route')
@ -98,6 +98,10 @@ class LoginLinkFactory extends AbstractFactory implements AuthenticatorFactoryIn
if (null !== $config['max_uses'] && !isset($config['used_link_cache'])) {
$config['used_link_cache'] = 'security.authenticator.cache.expired_links';
$defaultCacheDefinition = $container->getDefinition($config['used_link_cache']);
if (!$defaultCacheDefinition->hasTag('cache.pool')) {
$defaultCacheDefinition->addTag('cache.pool');
}
}
$expiredStorageId = null;

View File

@ -23,6 +23,7 @@
<xsd:attribute name="hide-user-not-found" type="xsd:boolean" />
<xsd:attribute name="always-authenticate-before-granting" type="xsd:boolean" />
<xsd:attribute name="erase-credentials" type="xsd:boolean" />
<xsd:attribute name="enable-authenticator-manager" type="xsd:boolean" />
</xsd:complexType>
<xsd:complexType name="encoders">
@ -141,6 +142,7 @@
<xsd:element name="http-basic-ldap" type="http_basic_ldap" minOccurs="0" maxOccurs="1" />
<xsd:element name="json-login" type="json_login" minOccurs="0" maxOccurs="1" />
<xsd:element name="json-login-ldap" type="json_login_ldap" minOccurs="0" maxOccurs="1" />
<xsd:element name="login-throttling" type="login_throttling" minOccurs="0" maxOccurs="1" />
<xsd:element name="remember-me" type="remember_me" minOccurs="0" maxOccurs="1" />
<xsd:element name="remote-user" type="remote_user" minOccurs="0" maxOccurs="1" />
<xsd:element name="x509" type="x509" minOccurs="0" maxOccurs="1" />
@ -160,6 +162,7 @@
<xsd:attribute name="provider" type="xsd:string" />
<xsd:attribute name="stateless" type="xsd:boolean" />
<xsd:attribute name="context" type="xsd:string" />
<xsd:attribute name="lazy" type="xsd:boolean" />
<!-- allow factories to use dynamic elements -->
<xsd:anyAttribute processContents="lax" />
</xsd:complexType>
@ -231,6 +234,7 @@
<xsd:attribute name="csrf-token-id" type="xsd:string" />
<xsd:attribute name="post-only" type="xsd:boolean" />
<xsd:attribute name="csrf-token-generator" type="xsd:string" />
<xsd:attribute name="enable-csrf" type="xsd:boolean" />
<xsd:attributeGroup ref="success-handler-options" />
<xsd:attributeGroup ref="failure-handler-options" />
</xsd:extension>
@ -283,6 +287,25 @@
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="login_link">
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="signature-property" type="xsd:string" />
</xsd:choice>
<xsd:attribute name="check-route" type="xsd:string" />
<xsd:attribute name="check-post-only" type="xsd:boolean" />
<xsd:attribute name="lifetime" type="xsd:integer" />
<xsd:attribute name="max-uses" type="xsd:integer" />
<xsd:attribute name="used-link-cache" type="xsd:string" />
<xsd:attribute name="success-handler" type="xsd:string" />
<xsd:attribute name="failure-handler" type="xsd:string" />
<xsd:attribute name="provider" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="login_throttling">
<xsd:attribute name="limiter" type="xsd:string" />
<xsd:attribute name="max-attempts" type="xsd:integer" />
</xsd:complexType>
<xsd:complexType name="remember_me">
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="user-provider" type="xsd:string" />

View File

@ -51,7 +51,6 @@ return static function (ContainerConfigurator $container) {
->set('security.authenticator.cache.expired_links')
->parent('cache.app')
->private()
->tag('cache.pool')
->set('security.authenticator.firewall_aware_login_link_handler', FirewallAwareLoginLinkHandler::class)
->args([

View File

@ -21,6 +21,7 @@ use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\Security\Core\Authorization\AccessDecisionManager;
use Symfony\Component\Security\Core\Encoder\NativePasswordEncoder;
use Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder;
use Symfony\Component\Security\Http\Authentication\AuthenticatorManager;
abstract class CompleteConfigurationTest extends TestCase
{
@ -28,6 +29,38 @@ abstract class CompleteConfigurationTest extends TestCase
abstract protected function getFileExtension();
public function testAuthenticatorManager()
{
$container = $this->getContainer('authenticator_manager');
$this->assertEquals(AuthenticatorManager::class, $container->getDefinition('security.authenticator.manager.main')->getClass());
// login link
$expiredStorage = $container->getDefinition($expiredStorageId = 'security.authenticator.expired_login_link_storage.main');
$this->assertEquals('cache.redis', (string) $expiredStorage->getArgument(0));
$this->assertEquals(3600, (string) $expiredStorage->getArgument(1));
$linker = $container->getDefinition($linkerId = 'security.authenticator.login_link_handler.main');
$this->assertEquals(['id', 'email'], $linker->getArgument(3));
$this->assertEquals([
'route_name' => 'login_check',
'lifetime' => 3600,
'max_uses' => 1,
], $linker->getArgument(5));
$this->assertEquals($expiredStorageId, (string) $linker->getArgument(6));
$authenticator = $container->getDefinition('security.authenticator.login_link.main');
$this->assertEquals($linkerId, (string) $authenticator->getArgument(0));
$this->assertEquals([
'check_route' => 'login_check',
'check_post_only' => true,
], $authenticator->getArgument(4));
// login throttling
$listener = $container->getDefinition('security.listener.login_throttling.main');
$this->assertEquals('app.rate_limiter', (string) $listener->getArgument(1));
}
public function testRolesHierarchy()
{
$container = $this->getContainer('container1');
@ -648,6 +681,7 @@ abstract class CompleteConfigurationTest extends TestCase
$container->setParameter('kernel.debug', false);
$container->setParameter('request_listener.http_port', 80);
$container->setParameter('request_listener.https_port', 443);
$container->register('cache.app', \stdClass::class);
$security = new SecurityExtension();
$container->registerExtension($security);

View File

@ -0,0 +1,20 @@
<?php
$container->loadFromExtension('security', [
'enable_authenticator_manager' => true,
'firewalls' => [
'main' => [
'login_link' => [
'check_route' => 'login_check',
'check_post_only' => true,
'signature_properties' => ['id', 'email'],
'max_uses' => 1,
'lifetime' => 3600,
'used_link_cache' => 'cache.redis',
],
'login_throttling' => [
'limiter' => 'app.rate_limiter',
],
],
],
]);

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<srv:container xmlns="http://symfony.com/schema/dic/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:srv="http://symfony.com/schema/dic/services"
xsi:schemaLocation="http://symfony.com/schema/dic/services
https://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/security
https://symfony.com/schema/dic/security/security-1.0.xsd">
<config enable-authenticator-manager="true">
<firewall name="main">
<login-link check-route="login_check"
check-post-only="true"
max-uses="1"
lifetime="3600"
used-link-cache="cache.redis"
>
<signature-property>id</signature-property>
<signature-property>email</signature-property>
</login-link>
<login-throttling limiter="app.rate_limiter"/>
</firewall>
</config>
</srv:container>

View File

@ -0,0 +1,13 @@
security:
enable_authenticator_manager: true
firewalls:
main:
login_link:
check_route: login_check
check_post_only: true
signature_properties: [id, email]
max_uses: 1
lifetime: 3600
used_link_cache: 'cache.redis'
login_throttling:
limiter: 'app.rate_limiter'