From 4b1a99aaf07dd1cf8553f3fda578be213a34cfe3 Mon Sep 17 00:00:00 2001 From: eltharin Date: Thu, 11 Jul 2024 13:04:38 +0200 Subject: [PATCH 1/8] add security.firewalls.not_full_fledged_handler option if not authenticated at all use callback instead boolean --- .../Bundle/SecurityBundle/CHANGELOG.md | 1 + .../DataCollector/SecurityDataCollector.php | 1 + .../DependencyInjection/MainConfiguration.php | 9 +++ .../DependencyInjection/SecurityExtension.php | 6 ++ .../Resources/config/security.php | 4 + .../Resources/config/security_listeners.php | 1 + .../views/Collector/security.html.twig | 4 + .../Security/FirewallConfig.php | 6 ++ .../CompleteConfigurationTestCase.php | 4 + .../NotFullFledgedHandlerInterface.php | 35 ++++++++ .../SameAsNotFullFledgedHandle.php | 43 ++++++++++ .../Http/Firewall/ExceptionListener.php | 33 +++++--- .../Tests/Firewall/ExceptionListenerTest.php | 81 ++++++++++++++++++- 13 files changed, 216 insertions(+), 12 deletions(-) create mode 100644 src/Symfony/Component/Security/Http/Authorization/NotFullFledgedHandlerInterface.php create mode 100644 src/Symfony/Component/Security/Http/Authorization/SameAsNotFullFledgedHandle.php diff --git a/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md b/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md index ffb44752149b4..8eb0e421e5e8e 100644 --- a/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md @@ -11,6 +11,7 @@ CHANGELOG * Allow configuring the secret used to sign login links * Allow passing optional passport attributes to `Security::login()` + * Add `security.firewalls.not_full_fledged_handler` option to configure behavior where user is not full fledged 7.1 --- diff --git a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php index f3c1cd1fe34af..23d031087b2db 100644 --- a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php +++ b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php @@ -176,6 +176,7 @@ public function collect(Request $request, Response $response, ?\Throwable $excep 'access_denied_url' => $firewallConfig->getAccessDeniedUrl(), 'user_checker' => $firewallConfig->getUserChecker(), 'authenticators' => $firewallConfig->getAuthenticators(), + 'not_full_fledged_handler' => $firewallConfig->getNotFullFledgedHandler(), ]; // generate exit impersonation path from current request diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php index a45276066484c..23308bff5bf64 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php @@ -19,6 +19,7 @@ use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy; +use Symfony\Component\Security\Http\Authorization\SameAsNotFullFledgedHandle; /** * SecurityExtension configuration structure. @@ -214,6 +215,14 @@ private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $facto ->booleanNode('stateless')->defaultFalse()->end() ->booleanNode('lazy')->defaultFalse()->end() ->scalarNode('context')->cannotBeEmpty()->end() + ->scalarNode('not_full_fledged_handler') + ->beforeNormalization() + ->ifTrue(fn ($v): bool => $v == 'original') + ->then(fn ($v) => null) + ->ifTrue(fn ($v): bool => $v == 'same') + ->then(fn ($v) => SameAsNotFullFledgedHandle::class) + ->end() + ->end() ->arrayNode('logout') ->treatTrueLike([]) ->canBeUnset() diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index f454b9318c183..0c4fd6ebc19c3 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -582,6 +582,7 @@ private function createFirewall(ContainerBuilder $container, string $id, array $ $config->replaceArgument(10, $listenerKeys); $config->replaceArgument(11, $firewall['switch_user'] ?? null); + $config->replaceArgument(13, $firewall['not_full_fledged_handler'] ?? null); return [$matcher, $listeners, $exceptionListener, null !== $logoutListenerId ? new Reference($logoutListenerId) : null, $firewallAuthenticationProviders]; } @@ -890,6 +891,11 @@ private function createExceptionListener(ContainerBuilder $container, array $con $listener->replaceArgument(5, $config['access_denied_url']); } + // not full fledged handler setup + if (isset($config['not_full_fledged_handler'])) { + $listener->replaceArgument(9, new Reference($config['not_full_fledged_handler'])); + } + return $exceptionListenerId; } diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.php b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.php index bd879973b49a3..194852c915fe2 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.php +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.php @@ -45,6 +45,7 @@ use Symfony\Component\Security\Core\User\MissingUserProvider; use Symfony\Component\Security\Core\Validator\Constraints\UserPasswordValidator; use Symfony\Component\Security\Http\Authentication\AuthenticationUtils; +use Symfony\Component\Security\Http\Authorization\SameAsNotFullFledgedHandle; use Symfony\Component\Security\Http\Controller\SecurityTokenValueResolver; use Symfony\Component\Security\Http\Controller\UserValueResolver; use Symfony\Component\Security\Http\EventListener\IsGrantedAttributeListener; @@ -230,6 +231,7 @@ [], // listeners null, // switch_user null, // logout + null, //not_full_fledged_handler ]) ->set('security.logout_url_generator', LogoutUrlGenerator::class) @@ -322,5 +324,7 @@ ->set('cache.security_is_csrf_token_valid_attribute_expression_language') ->parent('cache.system') ->tag('cache.pool') + + ->set('security.same_as_not_full_fledged_handle', SameAsNotFullFledgedHandle::class) ; }; diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.php b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.php index 952b1d75625ad..a378e393773df 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.php +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.php @@ -139,6 +139,7 @@ service('security.access.denied_handler')->nullOnInvalid(), service('logger')->nullOnInvalid(), false, // Stateless + service('security.not.full.fledged_handler')->nullOnInvalid(), ]) ->tag('monolog.logger', ['channel' => 'security']) diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig b/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig index 635d61e2dd2c8..5694ef3f42754 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig +++ b/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig @@ -334,6 +334,10 @@ authenticators {{ collector.firewall.authenticators is empty ? '(none)' : profiler_dump(collector.firewall.authenticators, maxDepth=1) }} + + not_full_fledged_handler + {{ collector.firewall.not_full_fledged_handler ?: '(none)' }} + {% endif %} diff --git a/src/Symfony/Bundle/SecurityBundle/Security/FirewallConfig.php b/src/Symfony/Bundle/SecurityBundle/Security/FirewallConfig.php index 16edc6319a806..c4615b6be2fd5 100644 --- a/src/Symfony/Bundle/SecurityBundle/Security/FirewallConfig.php +++ b/src/Symfony/Bundle/SecurityBundle/Security/FirewallConfig.php @@ -30,6 +30,7 @@ public function __construct( private readonly array $authenticators = [], private readonly ?array $switchUser = null, private readonly ?array $logout = null, + private readonly ?string $notFullFledgedHandler = null, ) { } @@ -104,4 +105,9 @@ public function getLogout(): ?array { return $this->logout; } + + public function getNotFullFledgedHandler(): ?string + { + return $this->notFullFledgedHandler; + } } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTestCase.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTestCase.php index 04fba9fe584d3..312a8e7611440 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTestCase.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTestCase.php @@ -149,6 +149,7 @@ public function testFirewalls() [], null, null, + null, ], [ 'secure', @@ -184,6 +185,7 @@ public function testFirewalls() 'enable_csrf' => null, 'clear_site_data' => [], ], + null, ], [ 'host', @@ -201,6 +203,7 @@ public function testFirewalls() ], null, null, + null, ], [ 'with_user_checker', @@ -218,6 +221,7 @@ public function testFirewalls() ], null, null, + null, ], ], $configs); diff --git a/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedHandlerInterface.php b/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedHandlerInterface.php new file mode 100644 index 0000000000000..c9094314a7bfc --- /dev/null +++ b/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedHandlerInterface.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Http\Authorization; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Exception\AccessDeniedException; + +/** + * This is used by the ExceptionListener to translate an AccessDeniedException + * to a Response object. + * + * @author Roman JOLY + */ +interface NotFullFledgedHandlerInterface +{ + /** + * Handles a not full fledged case for acces denied failure. + * @return null|Response + * null: throw original AcessDeniedException + * Response: you can return your own response, AccesDeniedException wil be ignored + */ + public function handle(Request $request, AccessDeniedException $accessDeniedException, AuthenticationTrustResolverInterface $trustResolver, ?TokenInterface $token, callable $reauthenticateResponse): ?Response; +} diff --git a/src/Symfony/Component/Security/Http/Authorization/SameAsNotFullFledgedHandle.php b/src/Symfony/Component/Security/Http/Authorization/SameAsNotFullFledgedHandle.php new file mode 100644 index 0000000000000..59cec8da72fb8 --- /dev/null +++ b/src/Symfony/Component/Security/Http/Authorization/SameAsNotFullFledgedHandle.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Http\Authorization; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter; +use Symfony\Component\Security\Core\Exception\AccessDeniedException; + +/** + * This is a basic NotFullFledgedHandle + * If IS_AUTHENTICATED_FULLY is in access denied Exception Attrribute, behavior will be as before, + * Otherwise The original AccessDeniedException is throw + * + * @author Roman JOLY + */ +class SameAsNotFullFledgedHandle implements NotFullFledgedHandlerInterface +{ + public function handle(Request $request, AccessDeniedException $accessDeniedException, AuthenticationTrustResolverInterface $trustResolver, ?TokenInterface $token, callable $reauthenticateResponse): ?Response + { + if( !$trustResolver->isAuthenticated($token)) { + $reauthenticateResponse(); + } + + foreach($accessDeniedException->getAttributes() as $attribute) { + if(in_array($attribute, [AuthenticatedVoter::IS_AUTHENTICATED_FULLY])) { + $reauthenticateResponse(); + } + } + return null; + } +} diff --git a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php index a85ff958f2049..811be3eb3ab9b 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php @@ -29,6 +29,7 @@ use Symfony\Component\Security\Core\Exception\LazyResponseException; use Symfony\Component\Security\Core\Exception\LogoutException; use Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface; +use Symfony\Component\Security\Http\Authorization\NotFullFledgedHandlerInterface; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; use Symfony\Component\Security\Http\EntryPoint\Exception\NotAnEntryPointException; use Symfony\Component\Security\Http\HttpUtils; @@ -57,6 +58,7 @@ public function __construct( private ?AccessDeniedHandlerInterface $accessDeniedHandler = null, private ?LoggerInterface $logger = null, private bool $stateless = false, + private ?NotFullFledgedHandlerInterface $notFullFledgedHandler = null, ) { } @@ -127,20 +129,33 @@ private function handleAccessDeniedException(ExceptionEvent $event, AccessDenied $token = $this->tokenStorage->getToken(); if (!$this->authenticationTrustResolver->isFullFledged($token)) { - $this->logger?->debug('Access denied, the user is not fully authenticated; redirecting to authentication entry point.', ['exception' => $exception]); - try { - $insufficientAuthenticationException = new InsufficientAuthenticationException('Full authentication is required to access this resource.', 0, $exception); - if (null !== $token) { - $insufficientAuthenticationException->setToken($token); + $starAuthenticationResponse = function () use($exception, $event, $token) { + $this->logger?->debug('Access denied, the user is not fully authenticated; redirecting to authentication entry point.', ['exception' => $exception]); + + try { + $insufficientAuthenticationException = new InsufficientAuthenticationException('Full authentication is required to access this resource.', 0, $exception); + if (null !== $token) { + $insufficientAuthenticationException->setToken($token); + } + + $event->setResponse($this->startAuthentication($event->getRequest(), $insufficientAuthenticationException)); + } catch (\Exception $e) { + $event->setThrowable($e); } + }; - $event->setResponse($this->startAuthentication($event->getRequest(), $insufficientAuthenticationException)); - } catch (\Exception $e) { - $event->setThrowable($e); + if(null === $this->notFullFledgedHandler) { + $starAuthenticationResponse(); + return; } - return; + $response = $this->notFullFledgedHandler->handle($event->getRequest(), $exception,$this->authenticationTrustResolver, $token, $starAuthenticationResponse); + + if ($response instanceof Response) { + $event->setResponse($response); + return; + } } $this->logger?->debug('Access denied, the user is neither anonymous, nor remember-me.', ['exception' => $exception]); diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php index 8bcc958854275..949deeb5b2aa7 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php @@ -21,10 +21,13 @@ use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter; use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Exception\LogoutException; use Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface; +use Symfony\Component\Security\Http\Authorization\NotFullFledgedHandlerInterface; +use Symfony\Component\Security\Http\Authorization\SameAsNotFullFledgedHandle; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; use Symfony\Component\Security\Http\Firewall\ExceptionListener; use Symfony\Component\Security\Http\HttpUtils; @@ -146,6 +149,58 @@ public function testAccessDeniedExceptionNotFullFledged(\Exception $exception, ? $this->assertSame($eventException ?? $exception, $event->getThrowable()->getPrevious()); } + /** + * @dataProvider getAccessDeniedExceptionProvider + */ + public function testAccessDeniedExceptionNotFullFledgedWithHandlerResponseCustomNotAuthenticated(\Exception $exception, ?\Exception $eventException = null) + { + $event = $this->createEvent($exception); + + $tokenStorage = $this->createMock(TokenStorageInterface::class); + $tokenStorage->expects($this->once())->method('getToken')->willReturn($this->createMock(TokenInterface::class)); + + $listener = $this->createExceptionListener($tokenStorage, $this->createTrustResolver(false,false), null, $this->createEntryPointWithoutStartCalled(), null, null, $this->createNotFullFledgedHandler(new Response('Full Fledged Response', 401))); + $listener->onKernelException($event); + + $this->assertEquals('Full Fledged Response', $event->getResponse()->getContent()); + $this->assertSame($eventException ?? $exception, $event->getThrowable()->getPrevious()); + } + + /** + * @dataProvider getAccessDeniedExceptionProvider + */ + public function testAccessDeniedExceptionNotFullFledgedWithoutHandlerResponseAuthenticated(\Exception $exception, ?\Exception $eventException = null) + { + $event = $this->createEvent($exception); + + $tokenStorage = $this->createMock(TokenStorageInterface::class); + $tokenStorage->expects($this->once())->method('getToken')->willReturn($this->createMock(TokenInterface::class)); + + $listener = $this->createExceptionListener($tokenStorage, $this->createTrustResolver(false,true), null, $this->createEntryPointWithoutStartCalled(), null, null, $this->createNotFullFledgedHandler(null)); + $listener->onKernelException($event); + + $this->assertNull($event->getResponse()); + $this->assertEquals($eventException?->getMessage() ?? $exception->getMessage(),$event->getThrowable()->getMessage()); + } + + /** + * @dataProvider getAccessDeniedExceptionProvider + */ + public function testAccessDeniedExceptionNotFullFledgedWithHandlerResponseCustomAuthenticated(\Exception $exception, ?\Exception $eventException = null) + { + $event = $this->createEvent($exception); + + $tokenStorage = $this->createMock(TokenStorageInterface::class); + $tokenStorage->expects($this->once())->method('getToken')->willReturn($this->createMock(TokenInterface::class)); + + $listener = $this->createExceptionListener($tokenStorage, $this->createTrustResolver(false,true), null, $this->createEntryPointWithoutStartCalled(), null, null, $this->createNotFullFledgedHandler(new Response('Full Fledged Response', 401))); + $listener->onKernelException($event); + + $this->assertEquals('Full Fledged Response', $event->getResponse()->getContent()); + $this->assertEquals(401, $event->getResponse()->getStatusCode()); + $this->assertSame($eventException ?? $exception, $event->getThrowable()->getPrevious()); + } + public function testLogoutException() { $event = $this->createEvent(new LogoutException('Invalid CSRF.')); @@ -188,10 +243,19 @@ private function createEntryPoint(?Response $response = null) return $entryPoint; } - private function createTrustResolver($fullFledged) + private function createEntryPointWithoutStartCalled() + { + $entryPoint = $this->createMock(AuthenticationEntryPointInterface::class); + $entryPoint->expects($this->never())->method('start'); + + return $entryPoint; + } + + private function createTrustResolver($fullFledged, $authenticate = false) { $trustResolver = $this->createMock(AuthenticationTrustResolverInterface::class); $trustResolver->expects($this->once())->method('isFullFledged')->willReturn($fullFledged); + $trustResolver->method('isAuthenticated')->willReturn($authenticate); return $trustResolver; } @@ -203,7 +267,7 @@ private function createEvent(\Exception $exception, $kernel = null) return new ExceptionEvent($kernel, Request::create('/'), HttpKernelInterface::MAIN_REQUEST, $exception); } - private function createExceptionListener(?TokenStorageInterface $tokenStorage = null, ?AuthenticationTrustResolverInterface $trustResolver = null, ?HttpUtils $httpUtils = null, ?AuthenticationEntryPointInterface $authenticationEntryPoint = null, $errorPage = null, ?AccessDeniedHandlerInterface $accessDeniedHandler = null) + private function createExceptionListener(?TokenStorageInterface $tokenStorage = null, ?AuthenticationTrustResolverInterface $trustResolver = null, ?HttpUtils $httpUtils = null, ?AuthenticationEntryPointInterface $authenticationEntryPoint = null, $errorPage = null, ?AccessDeniedHandlerInterface $accessDeniedHandler = null, ?NotFullFledgedHandlerInterface $notFullFledgedHandle = null) { return new ExceptionListener( $tokenStorage ?? $this->createMock(TokenStorageInterface::class), @@ -212,7 +276,18 @@ private function createExceptionListener(?TokenStorageInterface $tokenStorage = 'key', $authenticationEntryPoint, $errorPage, - $accessDeniedHandler + $accessDeniedHandler, + null, + false, + $notFullFledgedHandle, ); } + + private function createNotFullFledgedHandler(?Response $response = null) + { + $entryPoint = $this->createMock(NotFullFledgedHandlerInterface::class); + $entryPoint->method('handle')->willReturn($response); + + return $entryPoint; + } } From 588566a4b5d49c9bbf4b6d23dac65143b5bf7e86 Mon Sep 17 00:00:00 2001 From: eltharin Date: Fri, 26 Jul 2024 13:35:55 +0200 Subject: [PATCH 2/8] review changes add r to handleR --- .../DependencyInjection/MainConfiguration.php | 4 ++-- .../SecurityBundle/Resources/config/security.php | 4 ++-- ...gedHandle.php => SameAsNotFullFledgedHandler.php} | 4 ++-- .../Http/Tests/Firewall/ExceptionListenerTest.php | 12 ++++++------ 4 files changed, 12 insertions(+), 12 deletions(-) rename src/Symfony/Component/Security/Http/Authorization/{SameAsNotFullFledgedHandle.php => SameAsNotFullFledgedHandler.php} (92%) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php index 23308bff5bf64..f61548d223341 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php @@ -19,7 +19,7 @@ use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy; -use Symfony\Component\Security\Http\Authorization\SameAsNotFullFledgedHandle; +use Symfony\Component\Security\Http\Authorization\SameAsNotFullFledgedHandler; /** * SecurityExtension configuration structure. @@ -220,7 +220,7 @@ private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $facto ->ifTrue(fn ($v): bool => $v == 'original') ->then(fn ($v) => null) ->ifTrue(fn ($v): bool => $v == 'same') - ->then(fn ($v) => SameAsNotFullFledgedHandle::class) + ->then(fn ($v) => SameAsNotFullFledgedHandler::class) ->end() ->end() ->arrayNode('logout') diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.php b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.php index 194852c915fe2..2cc1f1be21be5 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.php +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.php @@ -45,7 +45,7 @@ use Symfony\Component\Security\Core\User\MissingUserProvider; use Symfony\Component\Security\Core\Validator\Constraints\UserPasswordValidator; use Symfony\Component\Security\Http\Authentication\AuthenticationUtils; -use Symfony\Component\Security\Http\Authorization\SameAsNotFullFledgedHandle; +use Symfony\Component\Security\Http\Authorization\SameAsNotFullFledgedHandler; use Symfony\Component\Security\Http\Controller\SecurityTokenValueResolver; use Symfony\Component\Security\Http\Controller\UserValueResolver; use Symfony\Component\Security\Http\EventListener\IsGrantedAttributeListener; @@ -325,6 +325,6 @@ ->parent('cache.system') ->tag('cache.pool') - ->set('security.same_as_not_full_fledged_handle', SameAsNotFullFledgedHandle::class) + ->set('security.same_as_not_full_fledged_handle', SameAsNotFullFledgedHandler::class) ; }; diff --git a/src/Symfony/Component/Security/Http/Authorization/SameAsNotFullFledgedHandle.php b/src/Symfony/Component/Security/Http/Authorization/SameAsNotFullFledgedHandler.php similarity index 92% rename from src/Symfony/Component/Security/Http/Authorization/SameAsNotFullFledgedHandle.php rename to src/Symfony/Component/Security/Http/Authorization/SameAsNotFullFledgedHandler.php index 59cec8da72fb8..0e17b1cced30e 100644 --- a/src/Symfony/Component/Security/Http/Authorization/SameAsNotFullFledgedHandle.php +++ b/src/Symfony/Component/Security/Http/Authorization/SameAsNotFullFledgedHandler.php @@ -19,13 +19,13 @@ use Symfony\Component\Security\Core\Exception\AccessDeniedException; /** - * This is a basic NotFullFledgedHandle + * This is a basic NotFullFledgedHandler * If IS_AUTHENTICATED_FULLY is in access denied Exception Attrribute, behavior will be as before, * Otherwise The original AccessDeniedException is throw * * @author Roman JOLY */ -class SameAsNotFullFledgedHandle implements NotFullFledgedHandlerInterface +class SameAsNotFullFledgedHandler implements NotFullFledgedHandlerInterface { public function handle(Request $request, AccessDeniedException $accessDeniedException, AuthenticationTrustResolverInterface $trustResolver, ?TokenInterface $token, callable $reauthenticateResponse): ?Response { diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php index 949deeb5b2aa7..4485ebcae919a 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php @@ -27,7 +27,7 @@ use Symfony\Component\Security\Core\Exception\LogoutException; use Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface; use Symfony\Component\Security\Http\Authorization\NotFullFledgedHandlerInterface; -use Symfony\Component\Security\Http\Authorization\SameAsNotFullFledgedHandle; +use Symfony\Component\Security\Http\Authorization\SameAsNotFullFledgedHandler; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; use Symfony\Component\Security\Http\Firewall\ExceptionListener; use Symfony\Component\Security\Http\HttpUtils; @@ -267,7 +267,7 @@ private function createEvent(\Exception $exception, $kernel = null) return new ExceptionEvent($kernel, Request::create('/'), HttpKernelInterface::MAIN_REQUEST, $exception); } - private function createExceptionListener(?TokenStorageInterface $tokenStorage = null, ?AuthenticationTrustResolverInterface $trustResolver = null, ?HttpUtils $httpUtils = null, ?AuthenticationEntryPointInterface $authenticationEntryPoint = null, $errorPage = null, ?AccessDeniedHandlerInterface $accessDeniedHandler = null, ?NotFullFledgedHandlerInterface $notFullFledgedHandle = null) + private function createExceptionListener(?TokenStorageInterface $tokenStorage = null, ?AuthenticationTrustResolverInterface $trustResolver = null, ?HttpUtils $httpUtils = null, ?AuthenticationEntryPointInterface $authenticationEntryPoint = null, $errorPage = null, ?AccessDeniedHandlerInterface $accessDeniedHandler = null, ?NotFullFledgedHandlerInterface $notFullFledgedHandler = null) { return new ExceptionListener( $tokenStorage ?? $this->createMock(TokenStorageInterface::class), @@ -279,15 +279,15 @@ private function createExceptionListener(?TokenStorageInterface $tokenStorage = $accessDeniedHandler, null, false, - $notFullFledgedHandle, + $notFullFledgedHandler, ); } private function createNotFullFledgedHandler(?Response $response = null) { - $entryPoint = $this->createMock(NotFullFledgedHandlerInterface::class); - $entryPoint->method('handle')->willReturn($response); + $handler = $this->createMock(NotFullFledgedHandlerInterface::class); + $handler->method('handle')->willReturn($response); - return $entryPoint; + return $handler; } } From d170f59368b8ffe8b31e43c56234a47890ed4fa6 Mon Sep 17 00:00:00 2001 From: eltharin Date: Wed, 7 Aug 2024 14:50:51 +0200 Subject: [PATCH 3/8] change follow review --- .../DependencyInjection/MainConfiguration.php | 16 +++-- .../Resources/config/security.php | 6 +- .../CompleteConfigurationTestCase.php | 7 +- .../NotFullFledgedEqualNormalLoginHandler.php | 65 +++++++++++++++++++ .../NotFullFledgedHandlerInterface.php | 13 ++-- ...edRedirectToStartAuthenticationHandler.php | 55 ++++++++++++++++ .../SameAsNotFullFledgedHandler.php | 43 ------------ .../Http/Firewall/ExceptionListener.php | 32 +-------- .../Tests/Firewall/ExceptionListenerTest.php | 20 +++--- 9 files changed, 157 insertions(+), 100 deletions(-) create mode 100644 src/Symfony/Component/Security/Http/Authorization/NotFullFledgedEqualNormalLoginHandler.php create mode 100644 src/Symfony/Component/Security/Http/Authorization/NotFullFledgedRedirectToStartAuthenticationHandler.php delete mode 100644 src/Symfony/Component/Security/Http/Authorization/SameAsNotFullFledgedHandler.php diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php index f61548d223341..7a63f0b351a7b 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php @@ -19,7 +19,8 @@ use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy; -use Symfony\Component\Security\Http\Authorization\SameAsNotFullFledgedHandler; +use Symfony\Component\Security\Http\Authorization\NotFullFledgedEqualNormalLoginHandler; +use Symfony\Component\Security\Http\Authorization\NotFullFledgedRedirectToStartAuthenticationHandler; /** * SecurityExtension configuration structure. @@ -216,13 +217,16 @@ private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $facto ->booleanNode('lazy')->defaultFalse()->end() ->scalarNode('context')->cannotBeEmpty()->end() ->scalarNode('not_full_fledged_handler') + ->defaultValue(NotFullFledgedRedirectToStartAuthenticationHandler::class) ->beforeNormalization() - ->ifTrue(fn ($v): bool => $v == 'original') - ->then(fn ($v) => null) - ->ifTrue(fn ($v): bool => $v == 'same') - ->then(fn ($v) => SameAsNotFullFledgedHandler::class) - ->end() + ->ifTrue(fn ($v): bool => $v == 'redirect') + ->then(fn ($v) => NotFullFledgedRedirectToStartAuthenticationHandler::class) + ->end() + ->beforeNormalization() + ->ifTrue(fn ($v): bool => $v == 'equal') + ->then(fn ($v) => NotFullFledgedEqualNormalLoginHandler::class) ->end() + ->end() ->arrayNode('logout') ->treatTrueLike([]) ->canBeUnset() diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.php b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.php index 2cc1f1be21be5..b6388559f2f1a 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.php +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.php @@ -45,7 +45,8 @@ use Symfony\Component\Security\Core\User\MissingUserProvider; use Symfony\Component\Security\Core\Validator\Constraints\UserPasswordValidator; use Symfony\Component\Security\Http\Authentication\AuthenticationUtils; -use Symfony\Component\Security\Http\Authorization\SameAsNotFullFledgedHandler; +use Symfony\Component\Security\Http\Authorization\NotFullFledgedEqualNormalLoginHandler; +use Symfony\Component\Security\Http\Authorization\NotFullFledgedRedirectToStartAuthenticationHandler; use Symfony\Component\Security\Http\Controller\SecurityTokenValueResolver; use Symfony\Component\Security\Http\Controller\UserValueResolver; use Symfony\Component\Security\Http\EventListener\IsGrantedAttributeListener; @@ -325,6 +326,7 @@ ->parent('cache.system') ->tag('cache.pool') - ->set('security.same_as_not_full_fledged_handle', SameAsNotFullFledgedHandler::class) + ->set(NotFullFledgedRedirectToStartAuthenticationHandler::class) + ->set(NotFullFledgedEqualNormalLoginHandler::class) ; }; diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTestCase.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTestCase.php index 312a8e7611440..bc8a468a237b9 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTestCase.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTestCase.php @@ -35,6 +35,7 @@ use Symfony\Component\Security\Http\Authentication\AuthenticatorManager; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge; +use Symfony\Component\Security\Http\Authorization\NotFullFledgedRedirectToStartAuthenticationHandler; abstract class CompleteConfigurationTestCase extends TestCase { @@ -185,7 +186,7 @@ public function testFirewalls() 'enable_csrf' => null, 'clear_site_data' => [], ], - null, + NotFullFledgedRedirectToStartAuthenticationHandler::class, ], [ 'host', @@ -203,7 +204,7 @@ public function testFirewalls() ], null, null, - null, + NotFullFledgedRedirectToStartAuthenticationHandler::class, ], [ 'with_user_checker', @@ -221,7 +222,7 @@ public function testFirewalls() ], null, null, - null, + NotFullFledgedRedirectToStartAuthenticationHandler::class, ], ], $configs); diff --git a/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedEqualNormalLoginHandler.php b/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedEqualNormalLoginHandler.php new file mode 100644 index 0000000000000..57cbdd6466077 --- /dev/null +++ b/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedEqualNormalLoginHandler.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Http\Authorization; + +use Psr\Log\LoggerInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Event\ExceptionEvent; +use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter; +use Symfony\Component\Security\Core\Exception\AccessDeniedException; +use Symfony\Component\Security\Core\Exception\InsufficientAuthenticationException; + +/** + * NotFullFledgedHandler for considering NotFullFledged Login equal to Normal Login except if IS_AUTHENTICATED_FULLY is asked + * If IS_AUTHENTICATED_FULLY is in access denied Exception Attrribute, user is redirect to + * startAuthentication function in AuthenticationTrustResolver + * Otherwise The original AccessDeniedException is passing to accessDeniedHandler or ErrorPage or Thrown + * + * @author Roman JOLY + */ +class NotFullFledgedEqualNormalLoginHandler implements NotFullFledgedHandlerInterface +{ + public function handle( ExceptionEvent $event, AccessDeniedException $exception, AuthenticationTrustResolverInterface $trustResolver, ?TokenInterface $token, ?LoggerInterface $logger, callable $starAuthenticationCallback): bool + { + if( !$trustResolver->isAuthenticated($token)) { + $this->reauthenticate($starAuthenticationCallback, $event, $token, $exception, $logger); + } + + foreach($exception->getAttributes() as $attribute) { + if(in_array($attribute, [AuthenticatedVoter::IS_AUTHENTICATED_FULLY])) { + $this->reauthenticate($starAuthenticationCallback, $event, $token, $exception, $logger); + return true; + } + } + + return false; + } + + private function reauthenticate(callable $starAuthenticationCallback, ExceptionEvent $event, ?TokenInterface $token, AccessDeniedException $exception, ?LoggerInterface$logger): void + { + $logger?->debug('Access denied, the user is not fully authenticated; redirecting to authentication entry point.', ['exception' => $exception]); + + try { + $insufficientAuthenticationException = new InsufficientAuthenticationException('Full authentication is required to access this resource.', 0, $exception); + if (null !== $token) { + $insufficientAuthenticationException->setToken($token); + } + + $event->setResponse($starAuthenticationCallback($event->getRequest(), $insufficientAuthenticationException)); + } catch (\Exception $e) { + $event->setThrowable($e); + } + } +} diff --git a/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedHandlerInterface.php b/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedHandlerInterface.php index c9094314a7bfc..42c12d5cc13ab 100644 --- a/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedHandlerInterface.php +++ b/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedHandlerInterface.php @@ -11,8 +11,10 @@ namespace Symfony\Component\Security\Http\Authorization; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\AccessDeniedException; @@ -26,10 +28,11 @@ interface NotFullFledgedHandlerInterface { /** - * Handles a not full fledged case for acces denied failure. - * @return null|Response - * null: throw original AcessDeniedException - * Response: you can return your own response, AccesDeniedException wil be ignored + * Allow to manage NotFullFledged cases when ExceptionListener catch AccessDeniedException + * + * @param $starAuthenticationCallback callable for call start function from + * + * @return boolean break handleAccessDeniedException function in ExceptionListener after handle */ - public function handle(Request $request, AccessDeniedException $accessDeniedException, AuthenticationTrustResolverInterface $trustResolver, ?TokenInterface $token, callable $reauthenticateResponse): ?Response; + public function handle( ExceptionEvent $event, AccessDeniedException $exception, AuthenticationTrustResolverInterface $trustResolver, ?TokenInterface $token, ?LoggerInterface $logger, callable $starAuthenticationCallback): bool; } diff --git a/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedRedirectToStartAuthenticationHandler.php b/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedRedirectToStartAuthenticationHandler.php new file mode 100644 index 0000000000000..9ff941a25c5fe --- /dev/null +++ b/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedRedirectToStartAuthenticationHandler.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Http\Authorization; + +use Psr\Log\LoggerInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Event\ExceptionEvent; +use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter; +use Symfony\Component\Security\Core\Exception\AccessDeniedException; + +use Symfony\Component\Security\Core\Exception\InsufficientAuthenticationException; + +/** + * NotFullFledgedHandler for considering NotFullFledged Login has to be redirect to login page if AccessDeniedException is thrown + * When an AccessDeniedException is thrown and user is not full fledged logged, he is redirected to login page with + * start function from authenticationEntryPoint + * + * @author Roman JOLY + */ +class NotFullFledgedRedirectToStartAuthenticationHandler implements NotFullFledgedHandlerInterface +{ + public function handle( ExceptionEvent $event, AccessDeniedException $exception, AuthenticationTrustResolverInterface $trustResolver, ?TokenInterface $token, ?LoggerInterface $logger, callable $starAuthenticationCallback): bool + { + if (!$trustResolver->isFullFledged($token)) { + $logger?->debug('Access denied, the user is not fully authenticated; redirecting to authentication entry point.', ['exception' => $exception]); + + try { + $insufficientAuthenticationException = new InsufficientAuthenticationException('Full authentication is required to access this resource.', 0, $exception); + if (null !== $token) { + $insufficientAuthenticationException->setToken($token); + } + + $event->setResponse($starAuthenticationCallback($event->getRequest(), $insufficientAuthenticationException)); + } catch (\Exception $e) { + $event->setThrowable($e); + } + + return true; + } + + return false; + } +} diff --git a/src/Symfony/Component/Security/Http/Authorization/SameAsNotFullFledgedHandler.php b/src/Symfony/Component/Security/Http/Authorization/SameAsNotFullFledgedHandler.php deleted file mode 100644 index 0e17b1cced30e..0000000000000 --- a/src/Symfony/Component/Security/Http/Authorization/SameAsNotFullFledgedHandler.php +++ /dev/null @@ -1,43 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Http\Authorization; - -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface; -use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter; -use Symfony\Component\Security\Core\Exception\AccessDeniedException; - -/** - * This is a basic NotFullFledgedHandler - * If IS_AUTHENTICATED_FULLY is in access denied Exception Attrribute, behavior will be as before, - * Otherwise The original AccessDeniedException is throw - * - * @author Roman JOLY - */ -class SameAsNotFullFledgedHandler implements NotFullFledgedHandlerInterface -{ - public function handle(Request $request, AccessDeniedException $accessDeniedException, AuthenticationTrustResolverInterface $trustResolver, ?TokenInterface $token, callable $reauthenticateResponse): ?Response - { - if( !$trustResolver->isAuthenticated($token)) { - $reauthenticateResponse(); - } - - foreach($accessDeniedException->getAttributes() as $attribute) { - if(in_array($attribute, [AuthenticatedVoter::IS_AUTHENTICATED_FULLY])) { - $reauthenticateResponse(); - } - } - return null; - } -} diff --git a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php index 811be3eb3ab9b..9bab1790d0803 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php @@ -25,7 +25,6 @@ use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\Security\Core\Exception\AccountStatusException; use Symfony\Component\Security\Core\Exception\AuthenticationException; -use Symfony\Component\Security\Core\Exception\InsufficientAuthenticationException; use Symfony\Component\Security\Core\Exception\LazyResponseException; use Symfony\Component\Security\Core\Exception\LogoutException; use Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface; @@ -126,36 +125,11 @@ private function handleAuthenticationException(ExceptionEvent $event, Authentica private function handleAccessDeniedException(ExceptionEvent $event, AccessDeniedException $exception): void { $event->setThrowable(new AccessDeniedHttpException($exception->getMessage(), $exception)); - $token = $this->tokenStorage->getToken(); - if (!$this->authenticationTrustResolver->isFullFledged($token)) { - - $starAuthenticationResponse = function () use($exception, $event, $token) { - $this->logger?->debug('Access denied, the user is not fully authenticated; redirecting to authentication entry point.', ['exception' => $exception]); - - try { - $insufficientAuthenticationException = new InsufficientAuthenticationException('Full authentication is required to access this resource.', 0, $exception); - if (null !== $token) { - $insufficientAuthenticationException->setToken($token); - } - $event->setResponse($this->startAuthentication($event->getRequest(), $insufficientAuthenticationException)); - } catch (\Exception $e) { - $event->setThrowable($e); - } - }; - - if(null === $this->notFullFledgedHandler) { - $starAuthenticationResponse(); - return; - } - - $response = $this->notFullFledgedHandler->handle($event->getRequest(), $exception,$this->authenticationTrustResolver, $token, $starAuthenticationResponse); - - if ($response instanceof Response) { - $event->setResponse($response); - return; - } + if($this->notFullFledgedHandler?->handle($event, $exception,$this->authenticationTrustResolver, $token, $this->logger, function ($request, $exception) {return $this->startAuthentication($request, $exception);} )) + { + return; } $this->logger?->debug('Access denied, the user is neither anonymous, nor remember-me.', ['exception' => $exception]); diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php index 4485ebcae919a..22be7412155b5 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php @@ -27,7 +27,7 @@ use Symfony\Component\Security\Core\Exception\LogoutException; use Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface; use Symfony\Component\Security\Http\Authorization\NotFullFledgedHandlerInterface; -use Symfony\Component\Security\Http\Authorization\SameAsNotFullFledgedHandler; +use Symfony\Component\Security\Http\Authorization\NotFullFledgedEqualNormalLoginHandler; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; use Symfony\Component\Security\Http\Firewall\ExceptionListener; use Symfony\Component\Security\Http\HttpUtils; @@ -145,7 +145,6 @@ public function testAccessDeniedExceptionNotFullFledged(\Exception $exception, ? $listener = $this->createExceptionListener($tokenStorage, $this->createTrustResolver(false), null, $this->createEntryPoint()); $listener->onKernelException($event); - $this->assertEquals('OK', $event->getResponse()->getContent()); $this->assertSame($eventException ?? $exception, $event->getThrowable()->getPrevious()); } @@ -159,10 +158,9 @@ public function testAccessDeniedExceptionNotFullFledgedWithHandlerResponseCustom $tokenStorage = $this->createMock(TokenStorageInterface::class); $tokenStorage->expects($this->once())->method('getToken')->willReturn($this->createMock(TokenInterface::class)); - $listener = $this->createExceptionListener($tokenStorage, $this->createTrustResolver(false,false), null, $this->createEntryPointWithoutStartCalled(), null, null, $this->createNotFullFledgedHandler(new Response('Full Fledged Response', 401))); + $listener = $this->createExceptionListener($tokenStorage, $this->createTrustResolver(false,false), null, $this->createEntryPointWithoutStartCalled(), null, null, $this->createNotFullFledgedHandler(true)); $listener->onKernelException($event); - $this->assertEquals('Full Fledged Response', $event->getResponse()->getContent()); $this->assertSame($eventException ?? $exception, $event->getThrowable()->getPrevious()); } @@ -176,7 +174,7 @@ public function testAccessDeniedExceptionNotFullFledgedWithoutHandlerResponseAut $tokenStorage = $this->createMock(TokenStorageInterface::class); $tokenStorage->expects($this->once())->method('getToken')->willReturn($this->createMock(TokenInterface::class)); - $listener = $this->createExceptionListener($tokenStorage, $this->createTrustResolver(false,true), null, $this->createEntryPointWithoutStartCalled(), null, null, $this->createNotFullFledgedHandler(null)); + $listener = $this->createExceptionListener($tokenStorage, $this->createTrustResolver(false,true), null, $this->createEntryPointWithoutStartCalled(), null, null, $this->createNotFullFledgedHandler(false)); $listener->onKernelException($event); $this->assertNull($event->getResponse()); @@ -193,11 +191,9 @@ public function testAccessDeniedExceptionNotFullFledgedWithHandlerResponseCustom $tokenStorage = $this->createMock(TokenStorageInterface::class); $tokenStorage->expects($this->once())->method('getToken')->willReturn($this->createMock(TokenInterface::class)); - $listener = $this->createExceptionListener($tokenStorage, $this->createTrustResolver(false,true), null, $this->createEntryPointWithoutStartCalled(), null, null, $this->createNotFullFledgedHandler(new Response('Full Fledged Response', 401))); + $listener = $this->createExceptionListener($tokenStorage, $this->createTrustResolver(false,true), null, $this->createEntryPointWithoutStartCalled(), null, null, $this->createNotFullFledgedHandler(true)); $listener->onKernelException($event); - $this->assertEquals('Full Fledged Response', $event->getResponse()->getContent()); - $this->assertEquals(401, $event->getResponse()->getStatusCode()); $this->assertSame($eventException ?? $exception, $event->getThrowable()->getPrevious()); } @@ -238,7 +234,7 @@ public static function getAccessDeniedExceptionProvider() private function createEntryPoint(?Response $response = null) { $entryPoint = $this->createMock(AuthenticationEntryPointInterface::class); - $entryPoint->expects($this->once())->method('start')->willReturn($response ?? new Response('OK')); + $entryPoint->method('start')->willReturn($response ?? new Response('OK')); return $entryPoint; } @@ -254,7 +250,7 @@ private function createEntryPointWithoutStartCalled() private function createTrustResolver($fullFledged, $authenticate = false) { $trustResolver = $this->createMock(AuthenticationTrustResolverInterface::class); - $trustResolver->expects($this->once())->method('isFullFledged')->willReturn($fullFledged); + $trustResolver->method('isFullFledged')->willReturn($fullFledged); $trustResolver->method('isAuthenticated')->willReturn($authenticate); return $trustResolver; @@ -283,10 +279,10 @@ private function createExceptionListener(?TokenStorageInterface $tokenStorage = ); } - private function createNotFullFledgedHandler(?Response $response = null) + private function createNotFullFledgedHandler(bool $break = false) { $handler = $this->createMock(NotFullFledgedHandlerInterface::class); - $handler->method('handle')->willReturn($response); + $handler->method('handle')->willReturn($break); return $handler; } From 8e80350a8d3a035e24560c15dc042081c22c15fa Mon Sep 17 00:00:00 2001 From: eltharin Date: Thu, 8 Aug 2024 16:35:04 +0200 Subject: [PATCH 4/8] changing descritpion --- .../Http/Authorization/NotFullFledgedHandlerInterface.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedHandlerInterface.php b/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedHandlerInterface.php index 42c12d5cc13ab..2d8077d0588de 100644 --- a/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedHandlerInterface.php +++ b/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedHandlerInterface.php @@ -29,6 +29,8 @@ interface NotFullFledgedHandlerInterface { /** * Allow to manage NotFullFledged cases when ExceptionListener catch AccessDeniedException + * This function can make checks and event / exception changes to change the Response + * It returns a boolean for break or not after that or continue the ExceptionListener process to decorate Exception and their response * * @param $starAuthenticationCallback callable for call start function from * From bcc1a41a156a25b62a21ed21ca0072af41afd09a Mon Sep 17 00:00:00 2001 From: eltharin Date: Mon, 12 Aug 2024 11:48:31 +0200 Subject: [PATCH 5/8] Update src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php Co-authored-by: Oskar Stark --- .../SecurityBundle/DependencyInjection/SecurityExtension.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 0c4fd6ebc19c3..e834df36b6002 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -891,7 +891,6 @@ private function createExceptionListener(ContainerBuilder $container, array $con $listener->replaceArgument(5, $config['access_denied_url']); } - // not full fledged handler setup if (isset($config['not_full_fledged_handler'])) { $listener->replaceArgument(9, new Reference($config['not_full_fledged_handler'])); } From 38a442b8f05e238bbced38176a6b110519b9c51b Mon Sep 17 00:00:00 2001 From: eltharin Date: Tue, 13 Aug 2024 23:17:10 +0200 Subject: [PATCH 6/8] fabbot comments --- .../DependencyInjection/MainConfiguration.php | 8 ++++---- .../SecurityBundle/Resources/config/security.php | 2 +- .../NotFullFledgedEqualNormalLoginHandler.php | 15 +++++++-------- .../NotFullFledgedHandlerInterface.php | 14 ++++++-------- ...ledgedRedirectToStartAuthenticationHandler.php | 8 ++------ .../Security/Http/Firewall/ExceptionListener.php | 3 +-- .../Http/Tests/Firewall/ExceptionListenerTest.php | 10 ++++------ 7 files changed, 25 insertions(+), 35 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php index 7a63f0b351a7b..2d5fb8cf53f75 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php @@ -17,10 +17,10 @@ use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; -use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; -use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy; use Symfony\Component\Security\Http\Authorization\NotFullFledgedEqualNormalLoginHandler; use Symfony\Component\Security\Http\Authorization\NotFullFledgedRedirectToStartAuthenticationHandler; +use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; +use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy; /** * SecurityExtension configuration structure. @@ -219,11 +219,11 @@ private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $facto ->scalarNode('not_full_fledged_handler') ->defaultValue(NotFullFledgedRedirectToStartAuthenticationHandler::class) ->beforeNormalization() - ->ifTrue(fn ($v): bool => $v == 'redirect') + ->ifTrue(fn ($v): bool => 'redirect' == $v) ->then(fn ($v) => NotFullFledgedRedirectToStartAuthenticationHandler::class) ->end() ->beforeNormalization() - ->ifTrue(fn ($v): bool => $v == 'equal') + ->ifTrue(fn ($v): bool => 'equal' == $v) ->then(fn ($v) => NotFullFledgedEqualNormalLoginHandler::class) ->end() ->end() diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.php b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.php index b6388559f2f1a..0d60bbd2091ac 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.php +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.php @@ -232,7 +232,7 @@ [], // listeners null, // switch_user null, // logout - null, //not_full_fledged_handler + null, // not_full_fledged_handler ]) ->set('security.logout_url_generator', LogoutUrlGenerator::class) diff --git a/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedEqualNormalLoginHandler.php b/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedEqualNormalLoginHandler.php index 57cbdd6466077..e6e002f66996d 100644 --- a/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedEqualNormalLoginHandler.php +++ b/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedEqualNormalLoginHandler.php @@ -12,8 +12,6 @@ namespace Symfony\Component\Security\Http\Authorization; use Psr\Log\LoggerInterface; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; @@ -25,21 +23,22 @@ * NotFullFledgedHandler for considering NotFullFledged Login equal to Normal Login except if IS_AUTHENTICATED_FULLY is asked * If IS_AUTHENTICATED_FULLY is in access denied Exception Attrribute, user is redirect to * startAuthentication function in AuthenticationTrustResolver - * Otherwise The original AccessDeniedException is passing to accessDeniedHandler or ErrorPage or Thrown + * Otherwise The original AccessDeniedException is passing to accessDeniedHandler or ErrorPage or Thrown. * * @author Roman JOLY */ class NotFullFledgedEqualNormalLoginHandler implements NotFullFledgedHandlerInterface { - public function handle( ExceptionEvent $event, AccessDeniedException $exception, AuthenticationTrustResolverInterface $trustResolver, ?TokenInterface $token, ?LoggerInterface $logger, callable $starAuthenticationCallback): bool + public function handle(ExceptionEvent $event, AccessDeniedException $exception, AuthenticationTrustResolverInterface $trustResolver, ?TokenInterface $token, ?LoggerInterface $logger, callable $starAuthenticationCallback): bool { - if( !$trustResolver->isAuthenticated($token)) { + if (!$trustResolver->isAuthenticated($token)) { $this->reauthenticate($starAuthenticationCallback, $event, $token, $exception, $logger); } - foreach($exception->getAttributes() as $attribute) { - if(in_array($attribute, [AuthenticatedVoter::IS_AUTHENTICATED_FULLY])) { + foreach ($exception->getAttributes() as $attribute) { + if (\in_array($attribute, [AuthenticatedVoter::IS_AUTHENTICATED_FULLY])) { $this->reauthenticate($starAuthenticationCallback, $event, $token, $exception, $logger); + return true; } } @@ -47,7 +46,7 @@ public function handle( ExceptionEvent $event, AccessDeniedException $exception, return false; } - private function reauthenticate(callable $starAuthenticationCallback, ExceptionEvent $event, ?TokenInterface $token, AccessDeniedException $exception, ?LoggerInterface$logger): void + private function reauthenticate(callable $starAuthenticationCallback, ExceptionEvent $event, ?TokenInterface $token, AccessDeniedException $exception, ?LoggerInterface $logger): void { $logger?->debug('Access denied, the user is not fully authenticated; redirecting to authentication entry point.', ['exception' => $exception]); diff --git a/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedHandlerInterface.php b/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedHandlerInterface.php index 2d8077d0588de..82522c51d793c 100644 --- a/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedHandlerInterface.php +++ b/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedHandlerInterface.php @@ -12,8 +12,6 @@ namespace Symfony\Component\Security\Http\Authorization; use Psr\Log\LoggerInterface; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; @@ -30,11 +28,11 @@ interface NotFullFledgedHandlerInterface /** * Allow to manage NotFullFledged cases when ExceptionListener catch AccessDeniedException * This function can make checks and event / exception changes to change the Response - * It returns a boolean for break or not after that or continue the ExceptionListener process to decorate Exception and their response - * - * @param $starAuthenticationCallback callable for call start function from - * - * @return boolean break handleAccessDeniedException function in ExceptionListener after handle + * It returns a boolean for break or not after that or continue the ExceptionListener process to decorate Exception and their response. + * + * @param $starAuthenticationCallback callable for call start function from + * + * @return bool break handleAccessDeniedException function in ExceptionListener after handle */ - public function handle( ExceptionEvent $event, AccessDeniedException $exception, AuthenticationTrustResolverInterface $trustResolver, ?TokenInterface $token, ?LoggerInterface $logger, callable $starAuthenticationCallback): bool; + public function handle(ExceptionEvent $event, AccessDeniedException $exception, AuthenticationTrustResolverInterface $trustResolver, ?TokenInterface $token, ?LoggerInterface $logger, callable $starAuthenticationCallback): bool; } diff --git a/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedRedirectToStartAuthenticationHandler.php b/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedRedirectToStartAuthenticationHandler.php index 9ff941a25c5fe..61c4a6f90c2fa 100644 --- a/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedRedirectToStartAuthenticationHandler.php +++ b/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedRedirectToStartAuthenticationHandler.php @@ -12,26 +12,22 @@ namespace Symfony\Component\Security\Http\Authorization; use Psr\Log\LoggerInterface; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter; use Symfony\Component\Security\Core\Exception\AccessDeniedException; - use Symfony\Component\Security\Core\Exception\InsufficientAuthenticationException; /** * NotFullFledgedHandler for considering NotFullFledged Login has to be redirect to login page if AccessDeniedException is thrown * When an AccessDeniedException is thrown and user is not full fledged logged, he is redirected to login page with - * start function from authenticationEntryPoint + * start function from authenticationEntryPoint. * * @author Roman JOLY */ class NotFullFledgedRedirectToStartAuthenticationHandler implements NotFullFledgedHandlerInterface { - public function handle( ExceptionEvent $event, AccessDeniedException $exception, AuthenticationTrustResolverInterface $trustResolver, ?TokenInterface $token, ?LoggerInterface $logger, callable $starAuthenticationCallback): bool + public function handle(ExceptionEvent $event, AccessDeniedException $exception, AuthenticationTrustResolverInterface $trustResolver, ?TokenInterface $token, ?LoggerInterface $logger, callable $starAuthenticationCallback): bool { if (!$trustResolver->isFullFledged($token)) { $logger?->debug('Access denied, the user is not fully authenticated; redirecting to authentication entry point.', ['exception' => $exception]); diff --git a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php index 9bab1790d0803..220b9991e0ccd 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php @@ -127,8 +127,7 @@ private function handleAccessDeniedException(ExceptionEvent $event, AccessDenied $event->setThrowable(new AccessDeniedHttpException($exception->getMessage(), $exception)); $token = $this->tokenStorage->getToken(); - if($this->notFullFledgedHandler?->handle($event, $exception,$this->authenticationTrustResolver, $token, $this->logger, function ($request, $exception) {return $this->startAuthentication($request, $exception);} )) - { + if ($this->notFullFledgedHandler?->handle($event, $exception, $this->authenticationTrustResolver, $token, $this->logger, function ($request, $exception) {return $this->startAuthentication($request, $exception); })) { return; } diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php index 22be7412155b5..bf0b881224bb0 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php @@ -21,13 +21,11 @@ use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter; use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Exception\LogoutException; use Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface; use Symfony\Component\Security\Http\Authorization\NotFullFledgedHandlerInterface; -use Symfony\Component\Security\Http\Authorization\NotFullFledgedEqualNormalLoginHandler; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; use Symfony\Component\Security\Http\Firewall\ExceptionListener; use Symfony\Component\Security\Http\HttpUtils; @@ -158,7 +156,7 @@ public function testAccessDeniedExceptionNotFullFledgedWithHandlerResponseCustom $tokenStorage = $this->createMock(TokenStorageInterface::class); $tokenStorage->expects($this->once())->method('getToken')->willReturn($this->createMock(TokenInterface::class)); - $listener = $this->createExceptionListener($tokenStorage, $this->createTrustResolver(false,false), null, $this->createEntryPointWithoutStartCalled(), null, null, $this->createNotFullFledgedHandler(true)); + $listener = $this->createExceptionListener($tokenStorage, $this->createTrustResolver(false, false), null, $this->createEntryPointWithoutStartCalled(), null, null, $this->createNotFullFledgedHandler(true)); $listener->onKernelException($event); $this->assertSame($eventException ?? $exception, $event->getThrowable()->getPrevious()); @@ -174,11 +172,11 @@ public function testAccessDeniedExceptionNotFullFledgedWithoutHandlerResponseAut $tokenStorage = $this->createMock(TokenStorageInterface::class); $tokenStorage->expects($this->once())->method('getToken')->willReturn($this->createMock(TokenInterface::class)); - $listener = $this->createExceptionListener($tokenStorage, $this->createTrustResolver(false,true), null, $this->createEntryPointWithoutStartCalled(), null, null, $this->createNotFullFledgedHandler(false)); + $listener = $this->createExceptionListener($tokenStorage, $this->createTrustResolver(false, true), null, $this->createEntryPointWithoutStartCalled(), null, null, $this->createNotFullFledgedHandler(false)); $listener->onKernelException($event); $this->assertNull($event->getResponse()); - $this->assertEquals($eventException?->getMessage() ?? $exception->getMessage(),$event->getThrowable()->getMessage()); + $this->assertEquals($eventException?->getMessage() ?? $exception->getMessage(), $event->getThrowable()->getMessage()); } /** @@ -191,7 +189,7 @@ public function testAccessDeniedExceptionNotFullFledgedWithHandlerResponseCustom $tokenStorage = $this->createMock(TokenStorageInterface::class); $tokenStorage->expects($this->once())->method('getToken')->willReturn($this->createMock(TokenInterface::class)); - $listener = $this->createExceptionListener($tokenStorage, $this->createTrustResolver(false,true), null, $this->createEntryPointWithoutStartCalled(), null, null, $this->createNotFullFledgedHandler(true)); + $listener = $this->createExceptionListener($tokenStorage, $this->createTrustResolver(false, true), null, $this->createEntryPointWithoutStartCalled(), null, null, $this->createNotFullFledgedHandler(true)); $listener->onKernelException($event); $this->assertSame($eventException ?? $exception, $event->getThrowable()->getPrevious()); From 91e23d0ca20f47c833f1341172d495c00e018e5c Mon Sep 17 00:00:00 2001 From: eltharin Date: Wed, 11 Sep 2024 17:26:35 +0200 Subject: [PATCH 7/8] starTAuthentication --- .../NotFullFledgedEqualNormalLoginHandler.php | 10 +++++----- .../Authorization/NotFullFledgedHandlerInterface.php | 4 ++-- ...FullFledgedRedirectToStartAuthenticationHandler.php | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedEqualNormalLoginHandler.php b/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedEqualNormalLoginHandler.php index e6e002f66996d..19759ed5fbf93 100644 --- a/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedEqualNormalLoginHandler.php +++ b/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedEqualNormalLoginHandler.php @@ -29,15 +29,15 @@ */ class NotFullFledgedEqualNormalLoginHandler implements NotFullFledgedHandlerInterface { - public function handle(ExceptionEvent $event, AccessDeniedException $exception, AuthenticationTrustResolverInterface $trustResolver, ?TokenInterface $token, ?LoggerInterface $logger, callable $starAuthenticationCallback): bool + public function handle(ExceptionEvent $event, AccessDeniedException $exception, AuthenticationTrustResolverInterface $trustResolver, ?TokenInterface $token, ?LoggerInterface $logger, callable $startAuthenticationCallback): bool { if (!$trustResolver->isAuthenticated($token)) { - $this->reauthenticate($starAuthenticationCallback, $event, $token, $exception, $logger); + $this->reauthenticate($startAuthenticationCallback, $event, $token, $exception, $logger); } foreach ($exception->getAttributes() as $attribute) { if (\in_array($attribute, [AuthenticatedVoter::IS_AUTHENTICATED_FULLY])) { - $this->reauthenticate($starAuthenticationCallback, $event, $token, $exception, $logger); + $this->reauthenticate($startAuthenticationCallback, $event, $token, $exception, $logger); return true; } @@ -46,7 +46,7 @@ public function handle(ExceptionEvent $event, AccessDeniedException $exception, return false; } - private function reauthenticate(callable $starAuthenticationCallback, ExceptionEvent $event, ?TokenInterface $token, AccessDeniedException $exception, ?LoggerInterface $logger): void + private function reauthenticate(callable $startAuthenticationCallback, ExceptionEvent $event, ?TokenInterface $token, AccessDeniedException $exception, ?LoggerInterface $logger): void { $logger?->debug('Access denied, the user is not fully authenticated; redirecting to authentication entry point.', ['exception' => $exception]); @@ -56,7 +56,7 @@ private function reauthenticate(callable $starAuthenticationCallback, ExceptionE $insufficientAuthenticationException->setToken($token); } - $event->setResponse($starAuthenticationCallback($event->getRequest(), $insufficientAuthenticationException)); + $event->setResponse($startAuthenticationCallback($event->getRequest(), $insufficientAuthenticationException)); } catch (\Exception $e) { $event->setThrowable($e); } diff --git a/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedHandlerInterface.php b/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedHandlerInterface.php index 82522c51d793c..bffaf9c2ab7bb 100644 --- a/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedHandlerInterface.php +++ b/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedHandlerInterface.php @@ -30,9 +30,9 @@ interface NotFullFledgedHandlerInterface * This function can make checks and event / exception changes to change the Response * It returns a boolean for break or not after that or continue the ExceptionListener process to decorate Exception and their response. * - * @param $starAuthenticationCallback callable for call start function from + * @param $startAuthenticationCallback callable for call start function from * * @return bool break handleAccessDeniedException function in ExceptionListener after handle */ - public function handle(ExceptionEvent $event, AccessDeniedException $exception, AuthenticationTrustResolverInterface $trustResolver, ?TokenInterface $token, ?LoggerInterface $logger, callable $starAuthenticationCallback): bool; + public function handle(ExceptionEvent $event, AccessDeniedException $exception, AuthenticationTrustResolverInterface $trustResolver, ?TokenInterface $token, ?LoggerInterface $logger, callable $startAuthenticationCallback): bool; } diff --git a/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedRedirectToStartAuthenticationHandler.php b/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedRedirectToStartAuthenticationHandler.php index 61c4a6f90c2fa..d959b017d5e65 100644 --- a/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedRedirectToStartAuthenticationHandler.php +++ b/src/Symfony/Component/Security/Http/Authorization/NotFullFledgedRedirectToStartAuthenticationHandler.php @@ -27,7 +27,7 @@ */ class NotFullFledgedRedirectToStartAuthenticationHandler implements NotFullFledgedHandlerInterface { - public function handle(ExceptionEvent $event, AccessDeniedException $exception, AuthenticationTrustResolverInterface $trustResolver, ?TokenInterface $token, ?LoggerInterface $logger, callable $starAuthenticationCallback): bool + public function handle(ExceptionEvent $event, AccessDeniedException $exception, AuthenticationTrustResolverInterface $trustResolver, ?TokenInterface $token, ?LoggerInterface $logger, callable $startAuthenticationCallback): bool { if (!$trustResolver->isFullFledged($token)) { $logger?->debug('Access denied, the user is not fully authenticated; redirecting to authentication entry point.', ['exception' => $exception]); @@ -38,7 +38,7 @@ public function handle(ExceptionEvent $event, AccessDeniedException $exception, $insufficientAuthenticationException->setToken($token); } - $event->setResponse($starAuthenticationCallback($event->getRequest(), $insufficientAuthenticationException)); + $event->setResponse($startAuthenticationCallback($event->getRequest(), $insufficientAuthenticationException)); } catch (\Exception $e) { $event->setThrowable($e); } From 0fb0b246c991156525dd8cac00fa14de35e2c238 Mon Sep 17 00:00:00 2001 From: eltharin Date: Thu, 9 Jan 2025 21:16:02 +0100 Subject: [PATCH 8/8] change target version --- src/Symfony/Bundle/SecurityBundle/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md b/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md index 8eb0e421e5e8e..3750985e24a29 100644 --- a/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md @@ -5,13 +5,13 @@ CHANGELOG --- * Add `Security::isGrantedForUser()` to test user authorization without relying on the session. For example, users not currently logged in, or while processing a message from a message queue + * Add `security.firewalls.not_full_fledged_handler` option to configure behavior where user is not full fledged 7.2 --- * Allow configuring the secret used to sign login links * Allow passing optional passport attributes to `Security::login()` - * Add `security.firewalls.not_full_fledged_handler` option to configure behavior where user is not full fledged 7.1 ---