8000 Fix: exclude remember_me from security login authenticators · symfony/symfony@4f93320 · GitHub
[go: up one dir, main page]

Skip to content
8000

Commit 4f93320

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

File tree

2 files changed

+59
-3
lines changed

2 files changed

+59
-3
lines changed

src/Symfony/Bundle/SecurityBundle/Security.php

Lines changed: 12 additions & 2 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 = [],
@@ -188,8 +191,7 @@ private function getAuthenticator(?string $authenticatorName, string $firewallNa
188191
$firewallAuthenticatorLocator = $this->authenticators[$firewallName];
189192

190193
if (!$authenticatorName) {
191-
$authenticatorIds = array_keys($firewallAuthenticatorLocator->getProvidedServices());
192-
194+
$authenticatorIds = $this->getAvailableAuthenticatorsForLogin($firewallAuthenticatorLocator, $firewallName);
193195
if (!$authenticatorIds) {
194196
throw new LogicException(sprintf('No authenticator was found for the firewall "%s".', $firewallName));
195197
}
@@ -212,4 +214,12 @@ private function getAuthenticator(?string $authenticatorName, string $firewallNa
212214

213215
return $firewallAuthenticatorLocator->get($authenticatorId);
214216
}
217+
218+
private function getAvailableAuthenticatorsForLogin(ServiceProviderInterface $firewallAuthenticatorLocator, string $firewallName): array
219+
{
220+
$authenticatorIds = array_keys($firewallAuthenticatorLocator->getProvidedServices());
221+
$excludedAuthenticatorIds = array_map(fn(string $exclusion) => 'security.authenticator.' . $exclusion . '.' . $firewallName, self::SECURITY_LOGIN_EXCLUSIONS);
222+
223+
return array_values(array_diff($authenticatorIds, $excludedAuthenticatorIds));
224+
}
215225
}

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

Lines changed: 47 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,49 @@ public function testLoginWithoutRequestContext()
274277
$security->login($user);
275278
}
276279

280+
public function testLoginFailsWhenTooManyAuthenticatorsFound()
281+
{
282+
$request = new Request();
283+
$authenticator = $this->createMock(AuthenticatorInterface::class);
284+
$requestStack = $this->createMock(RequestStack::class);
285+
$firewallMap = $this->createMock(FirewallMap::class);
286+
$firewall = new FirewallConfig('main', 'main');
287+
$userAuthenticator = $this->createMock(UserAuthenticatorInterface::class);
288+
$user = $this->createMock(UserInterface::class);
289+
$userChecker = $this->createMock(UserCheckerInterface::class);
290+
291+
$container = $this->createMock(ContainerInterface::class);
292+
$container
293+
->expects($this->atLeastOnce())
294+
->method('get')
295+
->willReturnMap([
296+
['request_stack', $requestStack],
297+
['security.firewall.map', $firewallMap],
298+
['security.authenticator.managers_locator', $this->createContainer('main', $userAuthenticator)],
299+
['security.user_checker_locator', $this->createContainer('main', $userChecker)],
300+
])
301+
;
302+
303+
$requestStack->expects($this->once())->method('getCurrentRequest')->willReturn($request);
304+
$firewallMap->expects($this->once())->method('getFirewallConfig')->willReturn($firewall);
305+
306+
$firewallAuthenticatorLocator = $this->createMock(ServiceProviderInterface::class);
307+
$firewallAuthenticatorLocator
308+
->expects($this->once())
309+
->method('getProvidedServices')
310+
->willReturn([
311+
'security.authenticator.custom.main' => $authenticator,
312+
'security.authenticator.other.main' => $authenticator
313+
])
314+
;
315+
316+
$security = new Security($container, ['main' => $firewallAuthenticatorLocator]);
317+
318+
$this->expectException(\LogicException::class);
319+
$this->expectExceptionMessage('Too many authenticators were found for the current firewall "main". You must provide an instance of "Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface" to login programmatically. The available authenticators for the firewall "main" are "security.authenticator.custom.main" ,"security.authenticator.other.main');
320+
$security->login($user);
321+
}
322+
277323
public function testLogout()
278324
{
279325
$request = new Request();

0 commit comments

Comments
 (0)
0