diff --git a/src/Symfony/Component/Security/Http/Authentication/AuthenticatorManager.php b/src/Symfony/Component/Security/Http/Authentication/AuthenticatorManager.php index 0e2a653ddfa1b..82c8cd2e7b7a7 100644 --- a/src/Symfony/Component/Security/Http/Authentication/AuthenticatorManager.php +++ b/src/Symfony/Component/Security/Http/Authentication/AuthenticatorManager.php @@ -25,6 +25,7 @@ use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface; +use Symfony\Component\Security\Http\Authenticator\Debug\TraceableAuthenticator; use Symfony\Component\Security\Http\Authenticator\InteractiveAuthenticatorInterface; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\BadgeInterface; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; @@ -151,7 +152,7 @@ private function executeAuthenticators(array $authenticators, Request $request): // lazily (after initialization). if (false === $authenticator->supports($request)) { if (null !== $this->logger) { - $this->logger->debug('Skipping the "{authenticator}" authenticator as it did not support the request.', ['authenticator' => \get_class($authenticator)]); + $this->logger->debug('Skipping the "{authenticator}" authenticator as it did not support the request.', ['authenticator' => \get_class($authenticator instanceof TraceableAuthenticator ? $authenticator->getAuthenticator() : $authenticator)]); } continue; @@ -160,7 +161,7 @@ private function executeAuthenticators(array $authenticators, Request $request): $response = $this->executeAuthenticator($authenticator, $request); if (null !== $response) { if (null !== $this->logger) { - $this->logger->debug('The "{authenticator}" authenticator set the response. Any later authenticator will not be called', ['authenticator' => \get_class($authenticator)]); + $this->logger->debug('The "{authenticator}" authenticator set the response. Any later authenticator will not be called', ['authenticator' => \get_class($authenticator instanceof TraceableAuthenticator ? $authenticator->getAuthenticator() : $authenticator)]); } return $response; @@ -210,7 +211,7 @@ private function executeAuthenticator(AuthenticatorInterface $authenticator, Req $this->eventDispatcher->dispatch(new AuthenticationSuccessEvent($authenticatedToken), AuthenticationEvents::AUTHENTICATION_SUCCESS); if (null !== $this->logger) { - $this->logger->info('Authenticator successful!', ['token' => $authenticatedToken, 'authenticator' => \get_class($authenticator)]); + $this->logger->info('Authenticator successful!', ['token' => $authenticatedToken, 'authenticator' => \get_class($authenticator instanceof TraceableAuthenticator ? $authenticator->getAuthenticator() : $authenticator)]); } } catch (AuthenticationException $e) { // oh no! Authentication failed! @@ -229,7 +230,7 @@ private function executeAuthenticator(AuthenticatorInterface $authenticator, Req } if (null !== $this->logger) { - $this->logger->debug('Authenticator set no success response: request continues.', ['authenticator' => \get_class($authenticator)]); + $this->logger->debug('Authenticator set no success response: request continues.', ['authenticator' => \get_class($authenticator instanceof TraceableAuthenticator ? $authenticator->getAuthenticator() : $authenticator)]); } return null; @@ -262,7 +263,7 @@ private function handleAuthenticationSuccess(TokenInterface $authenticatedToken, private function handleAuthenticationFailure(AuthenticationException $authenticationException, Request $request, AuthenticatorInterface $authenticator, ?PassportInterface $passport): ?Response { 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 instanceof TraceableAuthenticator ? $authenticator->getAuthenticator() : $authenticator)]); } // Avoid leaking error details in case of invalid user (e.g. user not found or invalid account status) @@ -273,7 +274,7 @@ private function handleAuthenticationFailure(AuthenticationException $authentica $response = $authenticator->onAuthenticationFailure($request, $authenticationException); if (null !== $response && null !== $this->logger) { - $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 instanceof TraceableAuthenticator ? $authenticator->getAuthenticator() : $authenticator)]); } $this->eventDispatcher->dispatch($loginFailureEvent = new LoginFailureEvent($authenticationException, $authenticator, $request, $response, $this->firewallName, $passport)); diff --git a/src/Symfony/Component/Security/Http/Authenticator/Debug/TraceableAuthenticator.php b/src/Symfony/Component/Security/Http/Authenticator/Debug/TraceableAuthenticator.php index d7063e5aa4ed4..4b77d9c49f138 100644 --- a/src/Symfony/Component/Security/Http/Authenticator/Debug/TraceableAuthenticator.php +++ b/src/Symfony/Component/Security/Http/Authenticator/Debug/TraceableAuthenticator.php @@ -100,6 +100,14 @@ public function isInteractive(): bool return $this->authenticator instanceof InteractiveAuthenticatorInterface && $this->authenticator->isInteractive(); } + /** + * @internal + */ + public function getAuthenticator(): AuthenticatorInterface + { + return $this->authenticator; + } + public function __call($method, $args) { return $this->authenticator->{$method}(...$args); diff --git a/src/Symfony/Component/Security/Http/Tests/Authentication/AuthenticatorManagerTest.php b/src/Symfony/Component/Security/Http/Tests/Authentication/AuthenticatorManagerTest.php index f00009134eaaa..96dea2730aa24 100644 --- a/src/Symfony/Component/Security/Http/Tests/Authentication/AuthenticatorManagerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Authentication/AuthenticatorManagerTest.php @@ -12,6 +12,8 @@ namespace Symfony\Component\Security\Http\Tests\Authentication; use PHPUnit\Framework\TestCase; +use Psr\Log\AbstractLogger; +use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -22,6 +24,7 @@ use Symfony\Component\Security\Core\Exception\UserNotFoundException; use Symfony\Component\Security\Core\User\InMemoryUser; use Symfony\Component\Security\Http\Authentication\AuthenticatorManager; +use Symfony\Component\Security\Http\Authenticator\Debug\TraceableAuthenticator; use Symfony\Component\Security\Http\Authenticator\InteractiveAuthenticatorInterface; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; @@ -310,6 +313,44 @@ public function testAuthenticateRequestHidesInvalidUserExceptions() $this->assertSame($this->response, $response); } + public function testLogsUseTheDecoratedAuthenticatorWhenItIsTraceable() + { + $authenticator = $this->createMock(TestInteractiveAuthenticator::class); + $authenticator->expects($this->any())->method('isInteractive')->willReturn(true); + $this->request->attributes->set('_security_authenticators', [new TraceableAuthenticator($authenticator)]); + + $authenticator->expects($this->any())->method('authenticate')->willReturn(new SelfValidatingPassport(new UserBadge('wouter', function () { return $this->user; }))); + $authenticator->expects($this->any())->method('createToken')->willReturn($this->token); + + $this->tokenStorage->expects($this->once())->method('setToken')->with($this->token); + + $authenticator->expects($this->any()) + ->method('onAuthenticationSuccess') + ->with($this->anything(), $this->token, 'main') + ->willReturn($this->response); + + $authenticator->expects($this->any()) + ->method('onAuthenticationSuccess') + ->with($this->anything(), $this->token, 'main') + ->willReturn($this->response); + + $logger = new class() extends AbstractLogger { + public $logContexts = []; + + public function log($level, $message, array $context = []): void + { + if ($context['authenticator'] ?? false) { + $this->logContexts[] = $context; + } + } + }; + + $manager = $this->createManager([$authenticator], 'main', true, [], $logger); + $response = $manager->authenticateRequest($this->request); + $this->assertSame($this->response, $response); + $this->assertStringContainsString('Mock_TestInteractiveAuthenticator', $logger->logContexts[0]['authenticator']); + } + private function createAuthenticator($supports = true) { $authenticator = $this->createMock(TestInteractiveAuthenticator::class); @@ -318,9 +359,9 @@ private function createAuthenticator($supports = true) return $authenticator; } - private function createManager($authenticators, $firewallName = 'main', $eraseCredentials = true, array $requiredBadges = []) + private function createManager($authenticators, $firewallName = 'main', $eraseCredentials = true, array $requiredBadges = [], LoggerInterface $logger = null) { - return new AuthenticatorManager($authenticators, $this->tokenStorage, $this->eventDispatcher, $firewallName, null, $eraseCredentials, true, $requiredBadges); + return new AuthenticatorManager($authenticators, $this->tokenStorage, $this->eventDispatcher, $firewallName, $logger, $eraseCredentials, true, $requiredBadges); } } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy