feature #37917 [Security] Pass Passport to LoginFailureEvent (ihmels)

This PR was merged into the 5.2-dev branch.

Discussion
----------

[Security] Pass Passport to LoginFailureEvent

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Tickets       | Fix #37585
| License       | MIT
| Doc PR        | -

This changes passes a `Passport` to the `LoginFailureEvent`.

Commits
-------

d23434bc23 [Security] Pass Passport to LoginFailureEvent
This commit is contained in:
Fabien Potencier 2020-08-23 09:59:17 +02:00
commit a8abd81840
4 changed files with 16 additions and 5 deletions

View File

@ -7,6 +7,7 @@ CHANGELOG
* Added attributes on `Passport` * Added attributes on `Passport`
* Changed `AuthorizationChecker` to call the access decision manager in unauthenticated sessions with a `NullToken` * Changed `AuthorizationChecker` to call the access decision manager in unauthenticated sessions with a `NullToken`
* [BC break] Removed `AccessListener::PUBLIC_ACCESS` in favor of `AuthenticatedVoter::PUBLIC_ACCESS` * [BC break] Removed `AccessListener::PUBLIC_ACCESS` in favor of `AuthenticatedVoter::PUBLIC_ACCESS`
* Added `Passport` to `LoginFailureEvent`.
5.1.0 5.1.0
----- -----

View File

@ -158,6 +158,8 @@ class AuthenticatorManager implements AuthenticatorManagerInterface, UserAuthent
private function executeAuthenticator(AuthenticatorInterface $authenticator, Request $request): ?Response private function executeAuthenticator(AuthenticatorInterface $authenticator, Request $request): ?Response
{ {
$passport = null;
try { try {
// get the passport from the Authenticator // get the passport from the Authenticator
$passport = $authenticator->authenticate($request); $passport = $authenticator->authenticate($request);
@ -198,7 +200,7 @@ class AuthenticatorManager implements AuthenticatorManagerInterface, UserAuthent
return null; return null;
} catch (AuthenticationException $e) { } catch (AuthenticationException $e) {
// oh no! Authentication failed! // oh no! Authentication failed!
$response = $this->handleAuthenticationFailure($e, $request, $authenticator); $response = $this->handleAuthenticationFailure($e, $request, $authenticator, $passport);
if ($response instanceof Response) { if ($response instanceof Response) {
return $response; return $response;
} }
@ -229,7 +231,7 @@ class AuthenticatorManager implements AuthenticatorManagerInterface, UserAuthent
/** /**
* Handles an authentication failure and returns the Response for the authenticator. * Handles an authentication failure and returns the Response for the authenticator.
*/ */
private function handleAuthenticationFailure(AuthenticationException $authenticationException, Request $request, AuthenticatorInterface $authenticator): ?Response private function handleAuthenticationFailure(AuthenticationException $authenticationException, Request $request, AuthenticatorInterface $authenticator, ?PassportInterface $passport): ?Response
{ {
if (null !== $this->logger) { if (null !== $this->logger) {
$this->logger->info('Authenticator failed.', ['exception' => $authenticationException, 'authenticator' => \get_class($authenticator)]); $this->logger->info('Authenticator failed.', ['exception' => $authenticationException, 'authenticator' => \get_class($authenticator)]);
@ -240,7 +242,7 @@ class AuthenticatorManager implements AuthenticatorManagerInterface, UserAuthent
$this->logger->debug('The "{authenticator}" authenticator set the failure response.', ['authenticator' => \get_class($authenticator)]); $this->logger->debug('The "{authenticator}" authenticator set the failure response.', ['authenticator' => \get_class($authenticator)]);
} }
$this->eventDispatcher->dispatch($loginFailureEvent = new LoginFailureEvent($authenticationException, $authenticator, $request, $response, $this->firewallName)); $this->eventDispatcher->dispatch($loginFailureEvent = new LoginFailureEvent($authenticationException, $authenticator, $request, $response, $this->firewallName, $passport));
// returning null is ok, it means they want the request to continue // returning null is ok, it means they want the request to continue
return $loginFailureEvent->getResponse(); return $loginFailureEvent->getResponse();

View File

@ -15,6 +15,7 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface; use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;
use Symfony\Contracts\EventDispatcher\Event; use Symfony\Contracts\EventDispatcher\Event;
/** /**
@ -32,14 +33,16 @@ class LoginFailureEvent extends Event
private $request; private $request;
private $response; private $response;
private $firewallName; private $firewallName;
private $passport;
public function __construct(AuthenticationException $exception, AuthenticatorInterface $authenticator, Request $request, ?Response $response, string $firewallName) public function __construct(AuthenticationException $exception, AuthenticatorInterface $authenticator, Request $request, ?Response $response, string $firewallName, ?PassportInterface $passport = null)
{ {
$this->exception = $exception; $this->exception = $exception;
$this->authenticator = $authenticator; $this->authenticator = $authenticator;
$this->request = $request; $this->request = $request;
$this->response = $response; $this->response = $response;
$this->firewallName = $firewallName; $this->firewallName = $firewallName;
$this->passport = $passport;
} }
public function getException(): AuthenticationException public function getException(): AuthenticationException
@ -71,4 +74,9 @@ class LoginFailureEvent extends Event
{ {
return $this->response; return $this->response;
} }
public function getPassport(): ?PassportInterface
{
return $this->passport;
}
} }

View File

@ -86,6 +86,6 @@ class RememberMeListenerTest extends TestCase
private function createLoginFailureEvent($providerKey) private function createLoginFailureEvent($providerKey)
{ {
return new LoginFailureEvent(new AuthenticationException(), $this->createMock(AuthenticatorInterface::class), $this->request, null, $providerKey); return new LoginFailureEvent(new AuthenticationException(), $this->createMock(AuthenticatorInterface::class), $this->request, null, $providerKey, null);
} }
} }