bug #40490 [Security] Add XML support for authenticator manager (wouterj)

This PR was squashed before being merged into the 5.2 branch.

Discussion
----------

[Security] Add XML support for authenticator manager

| Q             | A
| ------------- | ---
| Branch?       | 5.2
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | -
| License       | MIT
| Doc PR        | -

I discovered we didn't have tests for the experimental configuration and it turns out it didn't support XML at all (this does bring up the question if it's worth maintaining XML support in Symfony).

Commits
-------

77fb0eb0a1 [Security] Add XML support for authenticator manager
This commit is contained in:
Fabien Potencier 2021-03-16 19:11:09 +01:00
commit 827cf0a1a3
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'