Skip to content

Commit 29ec5ed

Browse files
Seldaekfabpot
authored andcommitted
[Security] [RememberMe] Add support for parallel requests doing remember-me re-authentication
1 parent 1336b3e commit 29ec5ed

File tree

5 files changed

+66
-0
lines changed

5 files changed

+66
-0
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\SecurityBundle\DependencyInjection\Compiler;
13+
14+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
15+
use Symfony\Component\DependencyInjection\ContainerBuilder;
16+
17+
/**
18+
* Cleans up the remember me verifier cache if cache is missing.
19+
*
20+
* @author Jordi Boggiano <[email protected]>
21+
*/
22+
class CleanRememberMeVerifierPass implements CompilerPassInterface
23+
{
24+
/**
25+
* {@inheritdoc}
26+
*/
27+
public function process(ContainerBuilder $container)
28+
{
29+
if (!$container->hasDefinition('cache.system')) {
30+
$container->removeDefinition('cache.security_token_verifier');
31+
}
32+
}
33+
}

DependencyInjection/Security/Factory/RememberMeFactory.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
2020
use Symfony\Component\DependencyInjection\ChildDefinition;
2121
use Symfony\Component\DependencyInjection\ContainerBuilder;
22+
use Symfony\Component\DependencyInjection\ContainerInterface;
2223
use Symfony\Component\DependencyInjection\Definition;
2324
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
2425
use Symfony\Component\DependencyInjection\Reference;
2526
use Symfony\Component\HttpFoundation\Cookie;
27+
use Symfony\Component\Security\Core\Authentication\RememberMe\CacheTokenVerifier;
2628
use Symfony\Component\Security\Http\EventListener\RememberMeLogoutListener;
2729

2830
/**
@@ -116,10 +118,12 @@ public function createAuthenticator(ContainerBuilder $container, string $firewal
116118
->addTag('security.remember_me_handler', ['firewall' => $firewallName]);
117119
} elseif (isset($config['token_provider'])) {
118120
$tokenProviderId = $this->createTokenProvider($container, $firewallName, $config['token_provider']);
121+
$tokenVerifier = $this->createTokenVerifier($container, $firewallName, $config['token_verifier'] ?? null);
119122
$container->setDefinition($rememberMeHandlerId, new ChildDefinition('security.authenticator.persistent_remember_me_handler'))
120123
->replaceArgument(0, new Reference($tokenProviderId))
121124
->replaceArgument(2, new Reference($userProviderId))
122125
->replaceArgument(4, $config)
126+
->replaceArgument(6, $tokenVerifier)
123127
->addTag('security.remember_me_handler', ['firewall' => $firewallName]);
124128
} else {
125129
$signatureHasherId = 'security.authenticator.remember_me_signature_hasher.'.$firewallName;
@@ -214,6 +218,9 @@ public function addConfiguration(NodeDefinition $node)
214218
->end()
215219
->end()
216220
->end()
221+
->end()
222+
->scalarNode('token_verifier')
223+
->info('The service ID of a custom rememberme token verifier.')
217224
->end();
218225

219226
foreach ($this->options as $name => $value) {
@@ -304,4 +311,20 @@ private function createTokenProvider(ContainerBuilder $container, string $firewa
304311

305312
return $tokenProviderId;
306313
}
314+
315+
private function createTokenVerifier(ContainerBuilder $container, string $firewallName, ?string $serviceId): Reference
316+
{
317+
if ($serviceId) {
318+
return new Reference($serviceId);
319+
}
320+
321+
$tokenVerifierId = 'security.remember_me.token_verifier.'.$firewallName;
322+
323+
$container->register($tokenVerifierId, CacheTokenVerifier::class)
324+
->addArgument(new Reference('cache.security_token_verifier', ContainerInterface::NULL_ON_INVALID_REFERENCE))
325+
->addArgument(60)
326+
->addArgument('rememberme-'.$firewallName.'-stale-');
327+
328+
return new Reference($tokenVerifierId, ContainerInterface::NULL_ON_INVALID_REFERENCE);
329+
}
307330
}

Resources/config/schema/security-1.0.xsd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@
350350
<xsd:attribute name="secret" type="xsd:string" use="required" />
351351
<xsd:attribute name="service" type="xsd:string" />
352352
<xsd:attribute name="token-provider" type="xsd:string" />
353+
<xsd:attribute name="token-verifier" type="xsd:string" />
353354
<xsd:attribute name="catch-exceptions" type="xsd:boolean" />
354355
<xsd:attribute name="secure" type="remember_me_secure" />
355356
<xsd:attribute name="samesite" type="remember_me_samesite" />

Resources/config/security_authenticator_remember_me.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
service('request_stack'),
5252
abstract_arg('options'),
5353
service('logger')->nullOnInvalid(),
54+
abstract_arg('token verifier'),
5455
])
5556
->tag('monolog.logger', ['channel' => 'security'])
5657

@@ -87,5 +88,11 @@
8788
service('logger')->nullOnInvalid(),
8889
])
8990
->tag('monolog.logger', ['channel' => 'security'])
91+
92+
// Cache
93+
->set('cache.security_token_verifier')
94+
->parent('cache.system')
95+
->private()
96+
->tag('cache.pool')
9097
;
9198
};

SecurityBundle.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Symfony\Bundle\SecurityBundle\DependencyInjection\Compiler\AddExpressionLanguageProvidersPass;
1515
use Symfony\Bundle\SecurityBundle\DependencyInjection\Compiler\AddSecurityVotersPass;
1616
use Symfony\Bundle\SecurityBundle\DependencyInjection\Compiler\AddSessionDomainConstraintPass;
17+
use Symfony\Bundle\SecurityBundle\DependencyInjection\Compiler\CleanRememberMeVerifierPass;
1718
use Symfony\Bundle\SecurityBundle\DependencyInjection\Compiler\RegisterCsrfFeaturesPass;
1819
use Symfony\Bundle\SecurityBundle\DependencyInjection\Compiler\RegisterEntryPointPass;
1920
use Symfony\Bundle\SecurityBundle\DependencyInjection\Compiler\RegisterGlobalSecurityEventListenersPass;
@@ -76,6 +77,7 @@ public function build(ContainerBuilder $container)
7677
$container->addCompilerPass(new AddExpressionLanguageProvidersPass());
7778
$container->addCompilerPass(new AddSecurityVotersPass());
7879
$container->addCompilerPass(new AddSessionDomainConstraintPass(), PassConfig::TYPE_BEFORE_REMOVING);
80+
$container->addCompilerPass(new CleanRememberMeVerifierPass());
7981
$container->addCompilerPass(new RegisterCsrfFeaturesPass());
8082
$container->addCompilerPass(new RegisterTokenUsageTrackingPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 200);
8183
$container->addCompilerPass(new RegisterLdapLocatorPass());

0 commit comments

Comments
 (0)