Skip to content

Commit 0b96e76

Browse files
committed
Merge remote-tracking branch 'origin/5.4' into 6.2
* origin/5.4: [Security] Migrate the session on login only when the user changes
2 parents fa788ff + 0570380 commit 0b96e76

File tree

7 files changed

+45
-116
lines changed

7 files changed

+45
-116
lines changed

Authentication/AuthenticatorManager.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public function authenticateUser(UserInterface $user, AuthenticatorInterface $au
8383
$token = $this->eventDispatcher->dispatch(new AuthenticationTokenCreatedEvent($token, $passport))->getAuthenticatedToken();
8484

8585
// authenticate this in the system
86-
return $this->handleAuthenticationSuccess($token, $passport, $request, $authenticator);
86+
return $this->handleAuthenticationSuccess($token, $passport, $request, $authenticator, $this->tokenStorage->getToken());
8787
}
8888

8989
public function supports(Request $request): ?bool
@@ -165,6 +165,7 @@ private function executeAuthenticators(array $authenticators, Request $request):
165165
private function executeAuthenticator(AuthenticatorInterface $authenticator, Request $request): ?Response
166166
{
167167
$passport = null;
168+
$previousToken = $this->tokenStorage->getToken();
168169

169170
try {
170171
// get the passport from the Authenticator
@@ -213,7 +214,7 @@ private function executeAuthenticator(AuthenticatorInterface $authenticator, Req
213214
}
214215

215216
// success! (sets the token on the token storage, etc)
216-
$response = $this->handleAuthenticationSuccess($authenticatedToken, $passport, $request, $authenticator);
217+
$response = $this->handleAuthenticationSuccess($authenticatedToken, $passport, $request, $authenticator, $previousToken);
217218
if ($response instanceof Response) {
218219
return $response;
219220
}
@@ -223,7 +224,7 @@ private function executeAuthenticator(AuthenticatorInterface $authenticator, Req
223224
return null;
224225
}
225226

226-
private function handleAuthenticationSuccess(TokenInterface $authenticatedToken, Passport $passport, Request $request, AuthenticatorInterface $authenticator): ?Response
227+
private function handleAuthenticationSuccess(TokenInterface $authenticatedToken, Passport $passport, Request $request, AuthenticatorInterface $authenticator, ?TokenInterface $previousToken): ?Response
227228
{
228229
$this->tokenStorage->setToken($authenticatedToken);
229230

@@ -233,7 +234,7 @@ private function handleAuthenticationSuccess(TokenInterface $authenticatedToken,
233234
$this->eventDispatcher->dispatch($loginEvent, SecurityEvents::INTERACTIVE_LOGIN);
234235
}
235236

236-
$this->eventDispatcher->dispatch($loginSuccessEvent = new LoginSuccessEvent($authenticator, $passport, $authenticatedToken, $request, $response, $this->firewallName));
237+
$this->eventDispatcher->dispatch($loginSuccessEvent = new LoginSuccessEvent($authenticator, $passport, $authenticatedToken, $request, $response, $this->firewallName, $previousToken));
237238

238239
return $loginSuccessEvent->getResponse();
239240
}

Event/LoginSuccessEvent.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,17 @@ class LoginSuccessEvent extends Event
3434
private AuthenticatorInterface $authenticator;
3535
private Passport $passport;
3636
private TokenInterface $authenticatedToken;
37+
private ?TokenInterface $previousToken;
3738
private Request $request;
3839
private ?Response $response;
3940
private string $firewallName;
4041

41-
public function __construct(AuthenticatorInterface $authenticator, Passport $passport, TokenInterface $authenticatedToken, Request $request, ?Response $response, string $firewallName)
42+
public function __construct(AuthenticatorInterface $authenticator, Passport $passport, TokenInterface $authenticatedToken, Request $request, ?Response $response, string $firewallName, TokenInterface $previousToken = null)
4243
{
4344
$this->authenticator = $authenticator;
4445
$this->passport = $passport;
4546
$this->authenticatedToken = $authenticatedToken;
47+
$this->previousToken = $previousToken;
4648
$this->request = $request;
4749
$this->response = $response;
4850
$this->firewallName = $firewallName;
@@ -68,6 +70,11 @@ public function getAuthenticatedToken(): TokenInterface
6870
return $this->authenticatedToken;
6971
}
7072

73+
public function getPreviousToken(): ?TokenInterface
74+
{
75+
return $this->previousToken;
76+
}
77+
7178
public function getRequest(): Request
7279
{
7380
return $this->request;

EventListener/SessionStrategyListener.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,15 @@ public function onSuccessfulLogin(LoginSuccessEvent $event): void
4343
return;
4444
}
4545

46+
if ($previousToken = $event->getPreviousToken()) {
47+
$user = $token->getUserIdentifier();
48+
$previousUser = $previousToken->getUserIdentifier();
49+
50+
if ('' !== ($user ?? '') && $user === $previousUser) {
51+
return;
52+
}
53+
}
54+
4655
$this->sessionAuthenticationStrategy->onAuthentication($request, $token);
4756
}
4857

Tests/EventListener/PasswordMigratingListenerTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\HttpFoundation\Request;
1616
use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactoryInterface;
1717
use Symfony\Component\PasswordHasher\PasswordHasherInterface;
18+
use Symfony\Component\Security\Core\Authentication\Token\NullToken;
1819
use Symfony\Component\Security\Core\User\InMemoryUser;
1920
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
2021
use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;
@@ -27,7 +28,6 @@
2728
use Symfony\Component\Security\Http\Event\LoginSuccessEvent;
2829
use Symfony\Component\Security\Http\EventListener\PasswordMigratingListener;
2930
use Symfony\Component\Security\Http\Tests\Fixtures\DummyAuthenticator;
30-
use Symfony\Component\Security\Http\Tests\Fixtures\DummyToken;
3131

3232
class PasswordMigratingListenerTest extends TestCase
3333
{
@@ -112,7 +112,7 @@ private static function createPasswordUpgrader()
112112

113113
private static function createEvent(Passport $passport)
114114
{
115-
return new LoginSuccessEvent(new DummyAuthenticator(), $passport, new DummyToken(), new Request(), null, 'main');
115+
return new LoginSuccessEvent(new DummyAuthenticator(), $passport, new NullToken(), new Request(), null, 'main');
116116
}
117117
}
118118

Tests/EventListener/SessionStrategyListenerTest.php

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\HttpFoundation\Request;
1616
use Symfony\Component\HttpFoundation\Session\SessionInterface;
17-
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
17+
use Symfony\Component\Security\Core\Authentication\Token\NullToken;
1818
use Symfony\Component\Security\Core\User\InMemoryUser;
1919
use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface;
2020
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
@@ -35,7 +35,7 @@ protected function setUp(): void
3535
$this->sessionAuthenticationStrategy = $this->createMock(SessionAuthenticationStrategyInterface::class);
3636
$this->listener = new SessionStrategyListener($this->sessionAuthenticationStrategy);
3737
$this->request = new Request();
38-
$this->token = $this->createMock(TokenInterface::class);
38+
$this->token = $this->createMock(NullToken::class);
3939
}
4040

4141
public function testRequestWithSession()
@@ -62,6 +62,25 @@ public function testStatelessFirewalls()
6262
$listener->onSuccessfulLogin($this->createEvent('api_firewall'));
6363
}
6464

65+
public function testRequestWithSamePreviousUser()
66+
{
67+
$this->configurePreviousSession();
68+
$this->sessionAuthenticationStrategy->expects($this->never())->method('onAuthentication');
69+
70+
$token = $this->createMock(NullToken::class);
71+
$token->expects($this->once())
72+
->method('getUserIdentifier')
73+
->willReturn('test');
74+
$previousToken = $this->createMock(NullToken::class);
75+
$previousToken->expects($this->once())
76+
->method('getUserIdentifier')
77+
->willReturn('test');
78+
79+
$event = new LoginSuccessEvent($this->createMock(AuthenticatorInterface::class), new SelfValidatingPassport(new UserBadge('test', function () {})), $token, $this->request, null, 'main_firewall', $previousToken);
80+
81+
$this->listener->onSuccessfulLogin($event);
82+
}
83+
6584
private function createEvent($firewallName)
6685
{
6786
return new LoginSuccessEvent($this->createMock(AuthenticatorInterface::class), new SelfValidatingPassport(new UserBadge('test', function ($username) { return new InMemoryUser($username, null); })), $this->token, $this->request, null, $firewallName);

Tests/Fixtures/DummySupportsAuthenticator.php

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,6 @@
1212
namespace Symfony\Component\Security\Http\Tests\Fixtures;
1313

1414
use Symfony\Component\HttpFoundation\Request;
15-
use Symfony\Component\HttpFoundation\Response;
16-
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
17-
use Symfony\Component\Security\Core\Exception\AuthenticationException;
18-
use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface;
19-
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
20-
use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;
2115

2216
class DummySupportsAuthenticator extends DummyAuthenticator
2317
{

Tests/Fixtures/DummyToken.php

Lines changed: 0 additions & 101 deletions
This file was deleted.

0 commit comments

Comments
 (0)