Skip to content

Commit e208553

Browse files
committed
bug #39389 [Security]  Move the handleAuthenticationSuccess logic outside try/catch block (jderusse)
This PR was merged into the 5.2 branch. Discussion ---------- [Security]  Move the handleAuthenticationSuccess logic outside try/catch block | Q | A | ------------- | --- | Branch? | 5.2 | Bug fix? | yes | New feature? | no | Deprecations? | no | Tickets | - | License | MIT | Doc PR | - The current implementation of `AuthenticationManager` handle the `handleAuthenticationSuccess` logic in a try/catch block which triggers the `handleAuthenticationFailure` in case of failure. Which could leads to inconsistency and unexpected behavior. The authentication is either successfully or failure, but can't be both in the same request. Commits ------- da5c39ec2e Move AuthenticationSuccessEvent outside try/catch block
2 parents 3486a34 + 553df5e commit e208553

File tree

3 files changed

+26
-29
lines changed

3 files changed

+26
-29
lines changed

Authentication/AuthenticatorManager.php

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -185,18 +185,6 @@ private function executeAuthenticator(AuthenticatorInterface $authenticator, Req
185185
if (null !== $this->logger) {
186186
$this->logger->info('Authenticator successful!', ['token' => $authenticatedToken, 'authenticator' => \get_class($authenticator)]);
187187
}
188-
189-
// success! (sets the token on the token storage, etc)
190-
$response = $this->handleAuthenticationSuccess($authenticatedToken, $passport, $request, $authenticator);
191-
if ($response instanceof Response) {
192-
return $response;
193-
}
194-
195-
if (null !== $this->logger) {
196-
$this->logger->debug('Authenticator set no success response: request continues.', ['authenticator' => \get_class($authenticator)]);
197-
}
198-
199-
return null;
200188
} catch (AuthenticationException $e) {
201189
// oh no! Authentication failed!
202190
$response = $this->handleAuthenticationFailure($e, $request, $authenticator, $passport);
@@ -206,6 +194,18 @@ private function executeAuthenticator(AuthenticatorInterface $authenticator, Req
206194

207195
return null;
208196
}
197+
198+
// success! (sets the token on the token storage, etc)
199+
$response = $this->handleAuthenticationSuccess($authenticatedToken, $passport, $request, $authenticator);
200+
if ($response instanceof Response) {
201+
return $response;
202+
}
203+
204+
if (null !== $this->logger) {
205+
$this->logger->debug('Authenticator set no success response: request continues.', ['authenticator' => \get_class($authenticator)]);
206+
}
207+
208+
return null;
209209
}
210210

211211
private function handleAuthenticationSuccess(TokenInterface $authenticatedToken, PassportInterface $passport, Request $request, AuthenticatorInterface $authenticator): ?Response

EventListener/UserCheckerListener.php

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

1414
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
15+
use Symfony\Component\Security\Core\Event\AuthenticationSuccessEvent;
1516
use Symfony\Component\Security\Core\User\UserCheckerInterface;
17+
use Symfony\Component\Security\Core\User\UserInterface;
1618
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\PreAuthenticatedUserBadge;
1719
use Symfony\Component\Security\Http\Authenticator\Passport\UserPassportInterface;
1820
use Symfony\Component\Security\Http\Event\CheckPassportEvent;
19-
use Symfony\Component\Security\Http\Event\LoginSuccessEvent;
2021

2122
/**
2223
* @author Wouter de Jong <[email protected]>
@@ -43,21 +44,21 @@ public function preCheckCredentials(CheckPassportEvent $event): void
4344
$this->userChecker->checkPreAuth($passport->getUser());
4445
}
4546

46-
public function postCheckCredentials(LoginSuccessEvent $event): void
47+
public function postCheckCredentials(AuthenticationSuccessEvent $event): void
4748
{
48-
$passport = $event->getPassport();
49-
if (!$passport instanceof UserPassportInterface || null === $passport->getUser()) {
49+
$user = $event->getAuthenticationToken()->getUser();
50+
if (!$user instanceof UserInterface) {
5051
return;
5152
}
5253

53-
$this->userChecker->checkPostAuth($passport->getUser());
54+
$this->userChecker->checkPostAuth($user);
5455
}
5556

5657
public static function getSubscribedEvents(): array
5758
{
5859
return [
5960
CheckPassportEvent::class => ['preCheckCredentials', 256],
60-
LoginSuccessEvent::class => ['postCheckCredentials', 256],
61+
AuthenticationSuccessEvent::class => ['postCheckCredentials', 256],
6162
];
6263
}
6364
}

Tests/EventListener/UserCheckerListenerTest.php

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,17 @@
1212
namespace Symfony\Component\Security\Http\Tests\EventListener;
1313

1414
use PHPUnit\Framework\TestCase;
15-
use Symfony\Component\HttpFoundation\Request;
16-
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
15+
use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken;
16+
use Symfony\Component\Security\Core\Event\AuthenticationSuccessEvent;
1717
use Symfony\Component\Security\Core\User\User;
1818
use Symfony\Component\Security\Core\User\UserCheckerInterface;
1919
use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface;
2020
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\PreAuthenticatedUserBadge;
2121
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
2222
use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;
2323
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
24+
use Symfony\Component\Security\Http\Authenticator\Token\PostAuthenticationToken;
2425
use Symfony\Component\Security\Http\Event\CheckPassportEvent;
25-
use Symfony\Component\Security\Http\Event\LoginSuccessEvent;
2626
use Symfony\Component\Security\Http\EventListener\UserCheckerListener;
2727

2828
class UserCheckerListenerTest extends TestCase
@@ -63,14 +63,14 @@ public function testPostAuthValidCredentials()
6363
{
6464
$this->userChecker->expects($this->once())->method('checkPostAuth')->with($this->user);
6565

66-
$this->listener->postCheckCredentials($this->createLoginSuccessEvent());
66+
$this->listener->postCheckCredentials(new AuthenticationSuccessEvent(new PostAuthenticationToken($this->user, 'main', [])));
6767
}
6868

6969
public function testPostAuthNoUser()
7070
{
7171
$this->userChecker->expects($this->never())->method('checkPostAuth');
7272

73-
$this->listener->postCheckCredentials($this->createLoginSuccessEvent($this->createMock(PassportInterface::class)));
73+
$this->listener->postCheckCredentials(new AuthenticationSuccessEvent(new PreAuthenticatedToken('nobody', null, 'main')));
7474
}
7575

7676
private function createCheckPassportEvent($passport = null)
@@ -82,12 +82,8 @@ private function createCheckPassportEvent($passport = null)
8282
return new CheckPassportEvent($this->createMock(AuthenticatorInterface::class), $passport);
8383
}
8484

85-
private function createLoginSuccessEvent($passport = null)
85+
private function createAuthenticationSuccessEvent()
8686
{
87-
if (null === $passport) {
88-
$passport = new SelfValidatingPassport(new UserBadge('test', function () { return $this->user; }));
89-
}
90-
91-
return new LoginSuccessEvent($this->createMock(AuthenticatorInterface::class), $passport, $this->createMock(TokenInterface::class), new Request(), null, 'main');
87+
return new AuthenticationSuccessEvent(new PostAuthenticationToken($this->user, 'main', []));
9288
}
9389
}

0 commit comments

Comments
 (0)