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:
commit
827cf0a1a3
@ -31,7 +31,7 @@ class LoginLinkFactory extends AbstractFactory implements AuthenticatorFactoryIn
|
|||||||
public function addConfiguration(NodeDefinition $node)
|
public function addConfiguration(NodeDefinition $node)
|
||||||
{
|
{
|
||||||
/** @var NodeBuilder $builder */
|
/** @var NodeBuilder $builder */
|
||||||
$builder = $node->children();
|
$builder = $node->fixXmlConfig('signature_property', 'signature_properties')->children();
|
||||||
|
|
||||||
$builder
|
$builder
|
||||||
->scalarNode('check_route')
|
->scalarNode('check_route')
|
||||||
@ -98,6 +98,10 @@ class LoginLinkFactory extends AbstractFactory implements AuthenticatorFactoryIn
|
|||||||
|
|
||||||
if (null !== $config['max_uses'] && !isset($config['used_link_cache'])) {
|
if (null !== $config['max_uses'] && !isset($config['used_link_cache'])) {
|
||||||
$config['used_link_cache'] = 'security.authenticator.cache.expired_links';
|
$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;
|
$expiredStorageId = null;
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<xsd:attribute name="hide-user-not-found" type="xsd:boolean" />
|
<xsd:attribute name="hide-user-not-found" type="xsd:boolean" />
|
||||||
<xsd:attribute name="always-authenticate-before-granting" type="xsd:boolean" />
|
<xsd:attribute name="always-authenticate-before-granting" type="xsd:boolean" />
|
||||||
<xsd:attribute name="erase-credentials" type="xsd:boolean" />
|
<xsd:attribute name="erase-credentials" type="xsd:boolean" />
|
||||||
|
<xsd:attribute name="enable-authenticator-manager" type="xsd:boolean" />
|
||||||
</xsd:complexType>
|
</xsd:complexType>
|
||||||
|
|
||||||
<xsd:complexType name="encoders">
|
<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="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" type="json_login" minOccurs="0" maxOccurs="1" />
|
||||||
<xsd:element name="json-login-ldap" type="json_login_ldap" 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="remember-me" type="remember_me" minOccurs="0" maxOccurs="1" />
|
||||||
<xsd:element name="remote-user" type="remote_user" 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" />
|
<xsd:element name="x509" type="x509" minOccurs="0" maxOccurs="1" />
|
||||||
@ -160,6 +162,7 @@
|
|||||||
<xsd:attribute name="provider" type="xsd:string" />
|
<xsd:attribute name="provider" type="xsd:string" />
|
||||||
<xsd:attribute name="stateless" type="xsd:boolean" />
|
<xsd:attribute name="stateless" type="xsd:boolean" />
|
||||||
<xsd:attribute name="context" type="xsd:string" />
|
<xsd:attribute name="context" type="xsd:string" />
|
||||||
|
<xsd:attribute name="lazy" type="xsd:boolean" />
|
||||||
<!-- allow factories to use dynamic elements -->
|
<!-- allow factories to use dynamic elements -->
|
||||||
<xsd:anyAttribute processContents="lax" />
|
<xsd:anyAttribute processContents="lax" />
|
||||||
</xsd:complexType>
|
</xsd:complexType>
|
||||||
@ -231,6 +234,7 @@
|
|||||||
<xsd:attribute name="csrf-token-id" type="xsd:string" />
|
<xsd:attribute name="csrf-token-id" type="xsd:string" />
|
||||||
<xsd:attribute name="post-only" type="xsd:boolean" />
|
<xsd:attribute name="post-only" type="xsd:boolean" />
|
||||||
<xsd:attribute name="csrf-token-generator" type="xsd:string" />
|
<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="success-handler-options" />
|
||||||
<xsd:attributeGroup ref="failure-handler-options" />
|
<xsd:attributeGroup ref="failure-handler-options" />
|
||||||
</xsd:extension>
|
</xsd:extension>
|
||||||
@ -283,6 +287,25 @@
|
|||||||
</xsd:complexContent>
|
</xsd:complexContent>
|
||||||
</xsd:complexType>
|
</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:complexType name="remember_me">
|
||||||
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||||
<xsd:element name="user-provider" type="xsd:string" />
|
<xsd:element name="user-provider" type="xsd:string" />
|
||||||
|
@ -51,7 +51,6 @@ return static function (ContainerConfigurator $container) {
|
|||||||
->set('security.authenticator.cache.expired_links')
|
->set('security.authenticator.cache.expired_links')
|
||||||
->parent('cache.app')
|
->parent('cache.app')
|
||||||
->private()
|
->private()
|
||||||
->tag('cache.pool')
|
|
||||||
|
|
||||||
->set('security.authenticator.firewall_aware_login_link_handler', FirewallAwareLoginLinkHandler::class)
|
->set('security.authenticator.firewall_aware_login_link_handler', FirewallAwareLoginLinkHandler::class)
|
||||||
->args([
|
->args([
|
||||||
|
@ -21,6 +21,7 @@ use Symfony\Component\DependencyInjection\Reference;
|
|||||||
use Symfony\Component\Security\Core\Authorization\AccessDecisionManager;
|
use Symfony\Component\Security\Core\Authorization\AccessDecisionManager;
|
||||||
use Symfony\Component\Security\Core\Encoder\NativePasswordEncoder;
|
use Symfony\Component\Security\Core\Encoder\NativePasswordEncoder;
|
||||||
use Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder;
|
use Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder;
|
||||||
|
use Symfony\Component\Security\Http\Authentication\AuthenticatorManager;
|
||||||
|
|
||||||
abstract class CompleteConfigurationTest extends TestCase
|
abstract class CompleteConfigurationTest extends TestCase
|
||||||
{
|
{
|
||||||
@ -28,6 +29,38 @@ abstract class CompleteConfigurationTest extends TestCase
|
|||||||
|
|
||||||
abstract protected function getFileExtension();
|
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()
|
public function testRolesHierarchy()
|
||||||
{
|
{
|
||||||
$container = $this->getContainer('container1');
|
$container = $this->getContainer('container1');
|
||||||
@ -648,6 +681,7 @@ abstract class CompleteConfigurationTest extends TestCase
|
|||||||
$container->setParameter('kernel.debug', false);
|
$container->setParameter('kernel.debug', false);
|
||||||
$container->setParameter('request_listener.http_port', 80);
|
$container->setParameter('request_listener.http_port', 80);
|
||||||
$container->setParameter('request_listener.https_port', 443);
|
$container->setParameter('request_listener.https_port', 443);
|
||||||
|
$container->register('cache.app', \stdClass::class);
|
||||||
|
|
||||||
$security = new SecurityExtension();
|
$security = new SecurityExtension();
|
||||||
$container->registerExtension($security);
|
$container->registerExtension($security);
|
||||||
|
@ -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',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
@ -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>
|
@ -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'
|
Reference in New Issue
Block a user