10000 Fix: exclude remember_me from security login authenticators · symfony/symfony@9d20d21 · GitHub
[go: up one dir, main page]

Skip to content

Commit 9d20d21

Browse files
committed
Fix: exclude remember_me from security login authenticators
1 parent 368bfb7 commit 9d20d21

File tree

2 files changed

+54
-7
lines changed

2 files changed

+54
-7
lines changed

src/Symfony/Bundle/SecurityBundle/Security.php

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ class Security extends InternalSecurity implements AuthorizationCheckerInterface
7070
*/
7171
public const LAST_USERNAME = SecurityRequestAttributes::LAST_USERNAME;
7272

73+
/** @var string[] */
74+
private const SECURITY_LOGIN_EXCLUSIONS = ['remember_me'];
75+
7376
public function __construct(
7477
private readonly ContainerInterface $container,
7578
private readonly array $authenticators = [],
@@ -125,6 +128,10 @@ public function login(UserInterface $user, ?string $authenticatorName = null, ?s
125128
throw new LogicException('Unable to login as the current route is not covered by any firewall.');
126129
}
127130

131+
if (in_array($authenticatorName, self::SECURITY_LOGIN_EXCLUSIONS)) {
132+
throw new LogicException(sprintf('The "%s" authenticator is not allowed to be used with the "%s" method. Use a different authenticator.', $authenticatorName, __METHOD__));
133+
}
134+
128135
$authenticator = $this->getAuthenticator($authenticatorName, $firewallName);
129136

130137
$userCheckerLocator = $this->container->get('security.user_checker_locator');
@@ -188,16 +195,15 @@ private function getAuthenticator(?string $authenticatorName, string $firewallNa
188195
$firewallAuthenticatorLocator = $this->authenticators[$firewallName];
189196

190197
if (!$authenticatorName) {
191-
$authenticatorIds = array_keys($firewallAuthenticatorLocator->getProvidedServices());
192-
193-
if (!$authenticatorIds) {
198+
$availableAuthenticators = $this->getAvailableAuthenticatorsForLogin($firewallAuthenticatorLocator, $firewallName);
199+
if (!$availableAuthenticators) {
194200
throw new LogicException(sprintf('No authenticator was found for the firewall "%s".', $firewallName));
195201
}
196-
if (1 < \count($authenticatorIds)) {
197-
throw new LogicException(sprintf('Too many authenticators were found for the current firewall "%s". You must provide an instance of "%s" to login programmatically. The available authenticators for the firewall "%s" are "%s".', $firewallName, AuthenticatorInterface::class, $firewallName, implode('" ,"', $authenticatorIds)));
202+
if (1 < \count($availableAuthenticators)) {
203+
throw new LogicException(sprintf('Too many authenticators were found for the current firewall "%s". You must provide an instance of "%s" to login programmatically. The available authenticators for the firewall "%s" are "%s".', $firewallName, AuthenticatorInterface::class, $firewallName, implode('" ,"', $availableAuthenticators)));
198204
}
199205

200-
return $firewallAuthenticatorLocator->get($authenticatorIds[0]);
206+
return $firewallAuthenticatorLocator->get($availableAuthenticators[0]);
201207
}
202208

203209
if ($firewallAuthenticatorLocator->has($authenticatorName)) {
@@ -212,4 +218,12 @@ private function getAuthenticator(?string $authenticatorName, string $firewallNa
212218

213219
return $firewallAuthenticatorLocator->get($authenticatorId);
214220
}
221+
222+
private function getAvailableAuthenticatorsForLogin(ServiceProviderInterface $firewallAuthenticatorLocator, string $firewallName): array
223+
{
224+
$authenticatorIds = array_keys($firewallAuthenticatorLocator->getProvidedServices());
225+
$excludedAuthenticatorIds = array_map(fn(string $exclusion) => 'security.authenticator.' . $exclusion . '.' . $firewallName, self::SECURITY_LOGIN_EXCLUSIONS);
226+
227+
return array_values(array_diff($authenticatorIds, $excludedAuthenticatorIds));
228+
}
215229
}

src/Symfony/Bundle/SecurityBundle/Tests/SecurityTest.php

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,10 @@ public function testLogin()
155155
$firewallAuthenticatorLocator
156156
->expects($this->once())
157157
->method('getProvidedServices')
158-
->willReturn(['security.authenticator.custom.dev' => $authenticator])
158+
->willReturn([
159+
'security.authenticator.custom.dev' => $authenticator,
160+
'security.authenticator.remember_me.main' => $authenticator
161+
])
159162
;
160163
$firewallAuthenticatorLocator
161164
->expects($this->once())
@@ -274,6 +277,36 @@ public function testLoginWithoutRequestContext()
274277
$security->login($user);
275278
}
276279

280+
public function testLoginWithExcludeAuthenticator()
281+
{
282+
$request = new Request();
283+
$requestStack = $this->createMock(RequestStack::class);
284+
$firewallMap = $this->createMock(FirewallMap::class);
285+
$firewall = new FirewallConfig('main', 'main');
286+
$user = $this->createMock(UserInterface::class);
287+
$userChecker = $this->createMock(UserCheckerInterface::class);
288+
289+
$container = $this->createMock(ContainerInterface::class);
290+
$container
291+
->expects($this->atLeastOnce())
292+
->method('get')
293+
->willReturnMap([
294+
['request_stack', $requestStack],
295+
['security.firewall.map', $firewallMap],
296+
['security.user_checker', $userChecker],
297+
])
298+
;
299+
300+
$requestStack->expects($this->once())->method('getCurrentRequest')->willReturn($request);
301+
$firewallMap->expects($this->once())->method('getFirewallConfig')->willReturn($firewall);
302+
303+
$security = new Security($container, ['main' => null]);
304+
305+
$this->expectException(\LogicException::class);
306+
$this->expectExceptionMessage('The "remember_me" authenticator is not allowed to be used with the "Symfony\Bundle\SecurityBundle\Security::login" method. Use a different authenticator.');
307+
$security->login($user, 'remember_me');
308+
}
309+
277310
public function testLogout()
278311
{
279312
$request = new Request();

0 commit comments

Comments
 (0)
0