Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5edac9b

Browse files
committed
[Security] Support custom remember me handlers
1 parent 0218f2e commit 5edac9b

File tree

5 files changed

+147
-4
lines changed

5 files changed

+147
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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\Bundle\SecurityBundle\RememberMe\DecoratedRememberMeHandler;
15+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
16+
use Symfony\Component\DependencyInjection\ContainerBuilder;
17+
18+
/**
19+
* Replaces the DecoratedRememberMeHandler services with the real definition.
20+
*
21+
* @author Wouter de Jong <[email protected]>
22+
*
23+
* @internal
24+
*/
25+
final class ReplaceDecoratedRememberMeHandlerPass implements CompilerPassInterface
26+
{
27+
private static $handlerServiceTag = 'security.remember_me_handler';
28+
29+
/**
30+
* {@inheritDoc}
31+
*/
32+
public function process(ContainerBuilder $container): void
33+
{
34+
$handledFirewalls = [];
35+
foreach ($container->findTaggedServiceIds(self::$handlerServiceTag) as $definitionId => $rememberMeHandlerTags) {
36+
$definition = $container->findDefinition($definitionId);
37+
if (DecoratedRememberMeHandler::class !== $definition->getClass()) {
38+
continue;
39+
}
40+
41+
// get the actual custom remember me handler definition (passed to the decorator)
42+
$realRememberMeHandler = $container->findDefinition((string) $definition->getArgument(0));
43+
if (null === $realRememberMeHandler) {
44+
throw new \LogicException(sprintf('Invalid service definition for custom remember me handler; no service found with ID "%s".', (string) $definition->getArgument(0)));
45+
}
46+
47+
foreach ($rememberMeHandlerTags as $rememberMeHandlerTag) {
48+
// some custom handlers may be used on multiple firewalls in the same application
49+
if (\in_array($rememberMeHandlerTag['firewall'], $handledFirewalls, true)) {
50+
continue;
51+
}
52+
53+
$rememberMeHandler = clone $realRememberMeHandler;
54+
$rememberMeHandler->addTag(self::$handlerServiceTag, $rememberMeHandlerTag);
55+
$container->setDefinition('security.authenticator.remember_me_handler.'.$rememberMeHandlerTag['firewall'], $rememberMeHandler);
56+
57+
$handledFirewalls[] = $rememberMeHandlerTag['firewall'];
58+
}
59+
}
60+
}
61+
}

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
1313

1414
use Symfony\Bridge\Doctrine\Security\RememberMe\DoctrineTokenProvider;
15+
use Symfony\Bundle\SecurityBundle\RememberMe\DecoratedRememberMeHandler;
1516
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
1617
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
1718
use Symfony\Component\Config\FileLocator;
@@ -110,7 +111,8 @@ public function createAuthenticator(ContainerBuilder $container, string $firewal
110111
}
111112

112113
if (isset($config['service'])) {
113-
$container->setDefinition($rememberMeHandlerId, $container->getDefinition($config['service']))
114+
$container->register($rememberMeHandlerId, DecoratedRememberMeHandler::class)
115+
->addArgument(new Reference($config['service']))
114116
->addTag('security.remember_me_handler', ['firewall' => $firewallName]);
115117
} elseif (isset($config['token_provider'])) {
116118
$tokenProviderId = $this->createTokenProvider($container, $firewallName, $config['token_provider']);
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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\RememberMe;
13+
14+
use Symfony\Component\Security\Core\User\UserInterface;
15+
use Symfony\Component\Security\Http\RememberMe\RememberMeDetails;
16+
use Symfony\Component\Security\Http\RememberMe\RememberMeHandlerInterface;
17+
18+
/**
19+
* Used as a "workaround" for tagging aliases in the RememberMeFactory.
20+
*
21+
* @author Wouter de Jong <[email protected]>
22+
*
23+
* @internal
24+
*/
25+
final class DecoratedRememberMeHandler implements RememberMeHandlerInterface
26+
{
27+
private $handler;
28+
29+
public function __construct(RememberMeHandlerInterface $handler)
30+
{
31+
$this->handler = $handler;
32+
}
33+
34+
/**
35+
* {@inheritDoc}
36+
*/
37+
public function createRememberMeCookie(UserInterface $user): void
38+
{
39+
$this->handler->createRememberMeCookie($user);
40+
}
41+
42+
/**
43+
* {@inheritDoc}
44+
*/
45+
public function consumeRememberMeCookie(RememberMeDetails $rememberMeDetails): UserInterface
46+
{
47+
return $this->handler->consumeRememberMeCookie($rememberMeDetails);
48+
}
49+
50+
/**
51+
* {@inheritDoc}
52+
*/
53+
public function clearRememberMeCookie(): void
54+
{
55+
$this->handler->clearRememberMeCookie();
56+
}
57+
}

src/Symfony/Bundle/SecurityBundle/SecurityBundle.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\Bundle\SecurityBundle\DependencyInjection\Compiler\RegisterGlobalSecurityEventListenersPass;
2020
use Symfony\Bundle\SecurityBundle\DependencyInjection\Compiler\RegisterLdapLocatorPass;
2121
use Symfony\Bundle\SecurityBundle\DependencyInjection\Compiler\RegisterTokenUsageTrackingPass;
22+
use Symfony\Bundle\SecurityBundle\DependencyInjection\Compiler\ReplaceDecoratedRememberMeHandlerPass;
2223
use Symfony\Bundle\SecurityBundle\DependencyInjection\Compiler\SortFirewallListenersPass;
2324
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AnonymousFactory;
2425
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\CustomAuthenticatorFactory;
@@ -83,6 +84,7 @@ public function build(ContainerBuilder $container)
8384
$container->addCompilerPass(new RegisterGlobalSecurityEventListenersPass(), PassConfig::TYPE_BEFORE_REMOVING, -200);
8485
// execute after ResolveChildDefinitionsPass optimization pass, to ensure class names are set
8586
$container->addCompilerPass(new SortFirewallListenersPass(), PassConfig::TYPE_BEFORE_REMOVING);
87+
$container->addCompilerPass(new ReplaceDecoratedRememberMeHandlerPass(), PassConfig::TYPE_OPTIMIZE);
8688

8789
$container->addCompilerPass(new AddEventAliasesPass(array_merge(
8890
AuthenticationEvents::ALIASES,

src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,27 @@ public function testRememberMeCookieInheritFrameworkSessionCookie($config, $same
388388
$this->assertEquals($secure, $definition->getArgument(3)['secure']);
389389
}
390390

391+
public function testCustomRememberMeHandler()
392+
{
393+
$container = $this->getRawContainer();
394+
395+
$container->register('custom_remember_me', \stdClass::class);
396+
$container->loadFromExtension('security', [
397+
'enable_authenticator_manager' => true,
398+
'firewalls' => [
399+
'default' => [
400+
'remember_me' => ['secret' => 'very', 'service' => 'custom_remember_me'],
401+
],
402+
],
403+
]);
404+
405+
$container->compile();
406+
407+
$handler = $container->getDefinition('security.authenticator.remember_me_handler.default');
408+
$this->assertEquals(\stdClass::class, $handler->getClass());
409+
$this->assertEquals([['firewall' => 'default']], $handler->getTag('security.remember_me_handler'));
410+
}
411+
391412
public function sessionConfigurationProvider()
392413
{
393414
return [
@@ -661,13 +682,13 @@ protected function getRawContainer()
661682
$security = new SecurityExtension();
662683
$container->registerExtension($security);
663684

664-
$bundle = new SecurityBundle();
665-
$bundle->build($container);
666-
667685
$container->getCompilerPassConfig()->setOptimizationPasses([new ResolveChildDefinitionsPass()]);
668686
$container->getCompilerPassConfig()->setRemovingPasses([]);
669687
$container->getCompilerPassConfig()->setAfterRemovingPasses([]);
670688

689+
$bundle = new SecurityBundle();
690+
$bundle->build($container);
691+
671692
return $container;
672693
}
673694

0 commit comments

Comments
 (0)