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

Skip to content

Commit 7799078

Browse files
committed
Added remember me functionality
1 parent 2000e06 commit 7799078

File tree

11 files changed

+259
-94
lines changed

11 files changed

+259
-94
lines changed

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

Lines changed: 80 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
use Symfony\Component\DependencyInjection\Reference;
1919
use Symfony\Component\HttpFoundation\Cookie;
2020

21-
class RememberMeFactory implements SecurityFactoryInterface
21+
class RememberMeFactory implements SecurityFactoryInterface, AuthenticatorFactoryInterface
2222
{
2323
protected $options = [
2424
'name' => 'REMEMBERME',
@@ -44,37 +44,15 @@ public function create(ContainerBuilder $container, string $id, array $config, ?
4444
;
4545

4646
// remember me services
47-
if (isset($config['service'])) {
48-
$templateId = $config['service'];
49-
$rememberMeServicesId = $templateId.'.'.$id;
50-
} elseif (isset($config['token_provider'])) {
51-
$templateId = 'security.authentication.rememberme.services.persistent';
52-
$rememberMeServicesId = $templateId.'.'.$id;
53-
} else {
54-
$templateId = 'security.authentication.rememberme.services.simplehash';
55-
$rememberMeServicesId = $templateId.'.'.$id;
56-
}
47+
$templateId = $this->generateRememberMeServicesTemplateId($config, $id);
48+
$rememberMeServicesId = $templateId.'.'.$id;
5749

5850
if ($container->hasDefinition('security.logout_listener.'.$id)) {
5951
$container
6052
->getDefinition('security.logout_listener.'.$id)
61-
->addMethodCall('addHandler', [new Reference($rememberMeServicesId)])
62-
;
63-
}
64-
65-
$rememberMeServices = $container->setDefinition($rememberMeServicesId, new ChildDefinition($templateId));
66-
$rememberMeServices->replaceArgument(1, $config['secret']);
67-
$rememberMeServices->replaceArgument(2, $id);
68-
69-
if (isset($config['token_provider'])) {
70-
$rememberMeServices->addMethodCall('setTokenProvider', [
71-
new Reference($config['token_provider']),
72-
]);
53+
->addMethodCall('addHandler', [new Reference($rememberMeServicesId)]);
7354
}
7455

75-
// remember-me options
76-
$rememberMeServices->replaceArgument(3, array_intersect_key($config, $this->options));
77-
7856
// attach to remember-me aware listeners
7957
$userProviders = [];
8058
foreach ($container->findTaggedServiceIds('security.remember_me_aware') as $serviceId => $attributes) {
@@ -98,17 +76,8 @@ public function create(ContainerBuilder $container, string $id, array $config, ?
9876
;
9977
}
10078
}
101-
if ($config['user_providers']) {
102-
$userProviders = [];
103-
foreach ($config['user_providers'] as $providerName) {
104-
$userProviders[] = new Reference('security.user.provider.concrete.'.$providerName);
105-
}
106-
}
107-
if (0 === \count($userProviders)) {
108-
throw new \RuntimeException('You must configure at least one remember-me aware listener (such as form-login) for each firewall that has remember-me enabled.');
109-
}
11079

111-
$rememberMeServices->replaceArgument(0, new IteratorArgument(array_unique($userProviders)));
80+
$this->createRememberMeServices($container, $id, $templateId, $userProviders, $config);
11281

11382
// remember-me listener
11483
$listenerId = 'security.authentication.listener.rememberme.'.$id;
@@ -119,6 +88,28 @@ public function create(ContainerBuilder $container, string $id, array $config, ?
11988
return [$authProviderId, $listenerId, $defaultEntryPoint];
12089
}
12190

91+
public function createAuthenticator(ContainerBuilder $container, string $id, array $config, ?string $userProviderId): string
92+
{
93+
$templateId = $this->generateRememberMeServicesTemplateId($config, $id);
94+
$rememberMeServicesId = $templateId.'.'.$id;
95+
96+
// create remember me services (which manage the remember me cookies)
97+
$this->createRememberMeServices($container, $id, $templateId, [new Reference('security.user_providers')], $config);
98+
99+
// create remember me listener (which executes the remember me services for other authenticators)
100+
$this->createRememberMeListener($container, $id, $rememberMeServicesId);
101+
102+
// create remember me authenticator (which re-authenticates the user based on the remember me cookie)
103+
$authenticatorId = 'security.authenticator.remember_me.'.$id;
104+
$container
105+
->setDefinition($authenticatorId, new ChildDefinition('security.authenticator.remember_me'))
106+
->replaceArgument(0, new Reference($rememberMeServicesId))
107+
->replaceArgument(3, array_intersect_key($config, $this->options))
108+
;
109+
110+
return $authenticatorId;
111+
}
112+
122113
public function getPosition()
123114
{
124115
return 'remember_me';
@@ -161,4 +152,57 @@ public function addConfiguration(NodeDefinition $node)
161152
}
162153
}
163154
}
155+
156+
private function generateRememberMeServicesTemplateId(array $config, string $id): string
157+
{
158+
if (isset($config['service'])) {
159+
return $config['service'];
160+
}
161+
162+
if (isset($config['token_provider'])) {
163+
return 'security.authentication.rememberme.services.persistent';
164+
}
165+
166+
return 'security.authentication.rememberme.services.simplehash';
167+
}
168+
169+
private function createRememberMeServices(ContainerBuilder $container, string $id, string $templateId, array $userProviders, array $config): void
170+
{
171+
$rememberMeServicesId = $templateId.'.'.$id;
172+
173+
$rememberMeServices = $container->setDefinition($rememberMeServicesId, new ChildDefinition($templateId));
174+
$rememberMeServices->replaceArgument(1, $config['secret']);
175+
$rememberMeServices->replaceArgument(2, $id);
176+
177+
if (isset($config['token_provider'])) {
178+
$rememberMeServices->addMethodCall('setTokenProvider', [
179+
new Reference($config['token_provider']),
180+
]);
181+
}
182+
183+
// remember-me options
184+
$rememberMeServices->replaceArgument(3, array_intersect_key($config, $this->options));
185+
186+
if ($config['user_providers']) {
187+
$userProviders = [];
188+
foreach ($config['user_providers'] as $providerName) {
189+
$userProviders[] = new Reference('security.user.provider.concrete.'.$providerName);
190+
}
191+
}
192+
193+
if (0 === \count($userProviders)) {
194+
throw new \RuntimeException('You must configure at least one remember-me aware listener (such as form-login) for each firewall that has remember-me enabled.');
195+
}
196+
197+
$rememberMeServices->replaceArgument(0, new IteratorArgument(array_unique($userProviders)));
198+
}
199+
200+
private function createRememberMeListener(ContainerBuilder $container, string $id, string $rememberMeServicesId): void
201+
{
202+
$container
203+
->setDefinition('security.listener.remember_me.'.$id, new ChildDefinition('security.listener.remember_me'))
204+
->replaceArgument(0, new Reference($rememberMeServicesId))
205+
->replaceArgument(1, $id)
206+
;
207+
}
164208
}

src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use Symfony\Component\DependencyInjection\ChildDefinition;
2626
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
2727
use Symfony\Component\DependencyInjection\ContainerBuilder;
28+
use Symfony\Component\DependencyInjection\Definition;
2829
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
2930
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
3031
use Symfony\Component\DependencyInjection\Reference;
@@ -33,6 +34,7 @@
3334
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
3435
use Symfony\Component\Security\Core\Encoder\NativePasswordEncoder;
3536
use Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder;
37+
use Symfony\Component\Security\Core\User\ChainUserProvider;
3638
use Symfony\Component\Security\Core\User\UserProviderInterface;
3739
use Symfony\Component\Security\Http\Controller\UserValueResolver;
3840
use Twig\Extension\AbstractExtension;
@@ -229,9 +231,16 @@ private function createFirewalls(array $config, ContainerBuilder $container)
229231
foreach ($providerIds as $userProviderId) {
230232
$userProviders[] = new Reference($userProviderId);
231233
}
232-
$arguments[1] = new IteratorArgument($userProviders);
234+
$arguments[1] = $userProviderIteratorsArgument = new IteratorArgument($userProviders);
233235
$contextListenerDefinition->setArguments($arguments);
234236

237+
if (count($userProviders) > 1) {
238+
$container->setDefinition('security.user_providers', new Definition(ChainUserProvider::class, [$userProviderIteratorsArgument]))
239+
->setPublic(false);
240+
} else {
241+
$container->setAlias('security.user_providers', new Alias(current($providerIds)))->setPublic(false);
242+
}
243+
235244
if (1 === \count($providerIds)) {
236245
$container->setAlias(UserProviderInterface::class, current($providerIds));
237246
}
@@ -410,16 +419,6 @@ private function createFirewall(ContainerBuilder $container, string $id, array $
410419
// Determine default entry point
411420
$configuredEntryPoint = isset($firewall['entry_point']) ? $firewall['entry_point'] : null;
412421

413-
if ($this->authenticatorManagerEnabled) {
414-
// Remember me listener (must be before calling createAuthenticationListeners() to inject remember me services)
415-
$container
416-
->setDefinition('security.listener.remember_me.'.$id, new ChildDefinition('security.listener.remember_me'))
417-
->replaceArgument(0, $id)
418-
->addTag('kernel.event_subscriber')
419-
->addTag('security.remember_me_aware', ['id' => $id, 'provider' => 'none'])
420-
;
421-
}
422-
423422
// Authentication listeners
424423
$firewallAuthenticationProviders = [];
425424
list($authListeners, $defaultEntryPoint) = $this->createAuthenticationListeners($container, $id, $firewall, $firewallAuthenticationProviders, $defaultProvider, $providerIds, $configuredEntryPoint, $contextListenerId);

src/Symfony/Bundle/SecurityBundle/Resources/config/authenticators.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
class="Symfony\Component\Security\Http\EventListener\RememberMeListener"
5353
abstract="true">
5454
<tag name="monolog.logger" channel="security" />
55+
<argument/> <!-- remember me services -->
5556
<argument/> <!-- provider key -->
5657
<argument type="service" id="logger" on-invalid="null" />
5758
</service>
@@ -82,5 +83,15 @@
8283
<argument /> <!-- secret -->
8384
<argument type="service" id="security.untracked_token_storage" />
8485
</service>
86+
87+
<service id="security.authenticator.remember_me"
88+
class="Symfony\Component\Security\Http\Authenticator\Token\RememberMeAuthenticator"
89+
abstract="true">
90+
<argument /> <!-- remember me services -->
91+
<argument>%kernel.secret%</argument>
92+
<argument type="service" id="security.token_storage" />
93+
<argument /> <!-- options -->
94+
<argument type="service" id="security.authentication.session_strategy" />
95+
</service>
8596
</services>
8697
</container>

src/Symfony/Component/Security/Http/Authenticator/AbstractFormLoginAuthenticator.php

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
*
2626
* @experimental in 5.1
2727
*/
28-
abstract class AbstractFormLoginAuthenticator extends AbstractAuthenticator implements AuthenticationEntryPointInterface
28+
abstract class AbstractFormLoginAuthenticator extends AbstractAuthenticator implements AuthenticationEntryPointInterface, RememberMeSupportedInterface
2929
{
3030
/**
3131
* Return the URL to the login page.
@@ -46,11 +46,6 @@ public function onAuthenticationFailure(Request $request, AuthenticationExceptio
4646
return new RedirectResponse($url);
4747
}
4848

49-
public function supportsRememberMe(): bool
50-
{
51-
return true;
52-
}
53-
5449
/**
5550
* Override to control what happens when the user hits a secure page
5651
* but isn't logged in yet.

src/Symfony/Component/Security/Http/Authenticator/AnonymousAuthenticator.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,4 @@ public function onAuthenticationSuccess(Request $request, TokenInterface $token,
6969
{
7070
return null;
7171
}
72-
73-
public function supportsRememberMe(): bool
74-
{
75-
return false;
76-
}
7772
}

src/Symfony/Component/Security/Http/Authenticator/AuthenticatorInterface.php

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -102,18 +102,4 @@ public function onAuthenticationFailure(Request $request, AuthenticationExceptio
102102
* will be authenticated. This makes sense, for example, with an API.
103103
*/
104104
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey): ?Response;
105-
106-
/**
107-
* Does this method support remember me cookies?
108-
*
109-
* Remember me cookie will be set if *all* of the following are met:
110-
* A) This method returns true
111-
* B) The remember_me key under your firewall is configured
112-
* C) The "remember me" functionality is activated. This is usually
113-
* done by having a _remember_me checkbox in your form, but
114-
* can be configured by the "always_remember_me" and "remember_me_parameter"
115-
* parameters under the "remember_me" firewall key
116-
* D) The onAuthenticationSuccess method returns a Response object
117-
*/
118-
public function supportsRememberMe(): bool;
119105
}

src/Symfony/Component/Security/Http/Authenticator/HttpBasicAuthenticator.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,4 @@ public function onAuthenticationFailure(Request $request, AuthenticationExceptio
9494

9595
return $this->start($request, $exception);
9696
}
97-
98-
public function supportsRememberMe(): bool
99-
{
100-
return false;
101-
}
10297
}

0 commit comments

Comments
 (0)