From 2872b97835d60b7e5ffc227422cd867145326680 Mon Sep 17 00:00:00 2001 From: Antoine Makdessi Date: Thu, 12 May 2022 23:26:03 +0200 Subject: [PATCH] [Security] Allow configuring a target url when switching user --- .../DependencyInjection/MainConfiguration.php | 1 + .../DependencyInjection/SecurityExtension.php | 4 ++++ .../SecurityBundle/Resources/config/security_listeners.php | 1 + .../Component/Security/Http/Firewall/SwitchUserListener.php | 6 ++++-- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php index dec107d65dc18..dd54d0aa8cfb5 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php @@ -244,6 +244,7 @@ private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $facto ->scalarNode('provider')->end() ->scalarNode('parameter')->defaultValue('_switch_user')->end() ->scalarNode('role')->defaultValue('ROLE_ALLOWED_TO_SWITCH')->end() + ->scalarNode('target_url')->defaultValue(null)->end() ->end() ->end() ->arrayNode('required_badges') diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index e4f1fddc61f30..b7bc6dfb84cb7 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -843,6 +843,9 @@ private function createSwitchUserListener(ContainerBuilder $container, string $i if (!$userProvider) { throw new InvalidConfigurationException(sprintf('Not configuring explicitly the provider for the "switch_user" listener on "%s" firewall is ambiguous as there is more than one registered provider.', $id)); } + if ($stateless && null !== $config['target_url']) { + throw new InvalidConfigurationException(sprintf('Cannot set a "target_url" for the "switch_user" listener on the "%s" firewall as it is stateless.', $id)); + } $switchUserListenerId = 'security.authentication.switchuser_listener.'.$id; $listener = $container->setDefinition($switchUserListenerId, new ChildDefinition('security.authentication.switchuser_listener')); @@ -852,6 +855,7 @@ private function createSwitchUserListener(ContainerBuilder $container, string $i $listener->replaceArgument(6, $config['parameter']); $listener->replaceArgument(7, $config['role']); $listener->replaceArgument(9, $stateless); + $listener->replaceArgument(10, $config['target_url']); return $switchUserListenerId; } diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.php b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.php index 9b7ef071d84e6..0d4c069b43913 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.php +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.php @@ -151,6 +151,7 @@ 'ROLE_ALLOWED_TO_SWITCH', service('event_dispatcher')->nullOnInvalid(), false, // Stateless + abstract_arg('Target Url'), ]) ->tag('monolog.logger', ['channel' => 'security']) diff --git a/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php b/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php index 1cb0c70454abf..07f684f467d99 100644 --- a/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php @@ -51,8 +51,9 @@ class SwitchUserListener extends AbstractListener private ?LoggerInterface $logger; private ?EventDispatcherInterface $dispatcher; private bool $stateless; + private ?string $targetUrl; - public function __construct(TokenStorageInterface $tokenStorage, UserProviderInterface $provider, UserCheckerInterface $userChecker, string $firewallName, AccessDecisionManagerInterface $accessDecisionManager, LoggerInterface $logger = null, string $usernameParameter = '_switch_user', string $role = 'ROLE_ALLOWED_TO_SWITCH', EventDispatcherInterface $dispatcher = null, bool $stateless = false) + public function __construct(TokenStorageInterface $tokenStorage, UserProviderInterface $provider, UserCheckerInterface $userChecker, string $firewallName, AccessDecisionManagerInterface $accessDecisionManager, LoggerInterface $logger = null, string $usernameParameter = '_switch_user', string $role = 'ROLE_ALLOWED_TO_SWITCH', EventDispatcherInterface $dispatcher = null, bool $stateless = false, ?string $targetUrl = null) { if ('' === $firewallName) { throw new \InvalidArgumentException('$firewallName must not be empty.'); @@ -68,6 +69,7 @@ public function __construct(TokenStorageInterface $tokenStorage, UserProviderInt $this->logger = $logger; $this->dispatcher = $dispatcher; $this->stateless = $stateless; + $this->targetUrl = $targetUrl; } /** @@ -122,7 +124,7 @@ public function authenticate(RequestEvent $event) if (!$this->stateless) { $request->query->remove($this->usernameParameter); $request->server->set('QUERY_STRING', http_build_query($request->query->all(), '', '&')); - $response = new RedirectResponse($request->getUri(), 302); + $response = new RedirectResponse($this->targetUrl ?? $request->getUri(), 302); $event->setResponse($response); }