From 9bbf5a76d51d5947f53f3064c47b68e2d499cb57 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 21 May 2024 14:34:30 +0200 Subject: [PATCH 01/23] [SecurityBundle] Allow configuring the secret used to sign login links --- CHANGELOG.md | 5 +++++ DependencyInjection/Security/Factory/LoginLinkFactory.php | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index abc0c497..ba27f213 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +7.2 +--- + + * Allow configuring the secret used to sign login links + 7.1 --- diff --git a/DependencyInjection/Security/Factory/LoginLinkFactory.php b/DependencyInjection/Security/Factory/LoginLinkFactory.php index 9a03a0f0..bfd4eb0d 100644 --- a/DependencyInjection/Security/Factory/LoginLinkFactory.php +++ b/DependencyInjection/Security/Factory/LoginLinkFactory.php @@ -69,6 +69,10 @@ public function addConfiguration(NodeDefinition $node): void ->scalarNode('provider') ->info('The user provider to load users from.') ->end() + ->scalarNode('secret') + ->cannotBeEmpty() + ->defaultValue('%kernel.secret%') + ->end() ; foreach (array_merge($this->defaultSuccessHandlerOptions, $this->defaultFailureHandlerOptions) as $name => $default) { @@ -113,6 +117,7 @@ public function createAuthenticator(ContainerBuilder $container, string $firewal $container ->setDefinition($signatureHasherId, new ChildDefinition('security.authenticator.abstract_login_link_signature_hasher')) ->replaceArgument(1, $config['signature_properties']) + ->replaceArgument(2, $config['secret']) ->replaceArgument(3, $expiredStorageId ? new Reference($expiredStorageId) : null) ->replaceArgument(4, $config['max_uses'] ?? null) ; From 1f8f54f8e5371471637449f8827c8d7ed6e2f819 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 21 May 2024 11:22:57 +0200 Subject: [PATCH 02/23] [Security] Deprecate argument $secret of RememberMeToken and RememberMeAuthenticator --- DependencyInjection/Security/Factory/RememberMeFactory.php | 2 +- Resources/config/security_authenticator_remember_me.php | 1 - composer.json | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/DependencyInjection/Security/Factory/RememberMeFactory.php b/DependencyInjection/Security/Factory/RememberMeFactory.php index d474e96c..a5ba19e9 100644 --- a/DependencyInjection/Security/Factory/RememberMeFactory.php +++ b/DependencyInjection/Security/Factory/RememberMeFactory.php @@ -107,7 +107,7 @@ public function createAuthenticator(ContainerBuilder $container, string $firewal $container ->setDefinition($authenticatorId, new ChildDefinition('security.authenticator.remember_me')) ->replaceArgument(0, new Reference($rememberMeHandlerId)) - ->replaceArgument(3, $config['name'] ?? $this->options['name']) + ->replaceArgument(2, $config['name'] ?? $this->options['name']) ; return $authenticatorId; diff --git a/Resources/config/security_authenticator_remember_me.php b/Resources/config/security_authenticator_remember_me.php index b861d0de..ecf93e50 100644 --- a/Resources/config/security_authenticator_remember_me.php +++ b/Resources/config/security_authenticator_remember_me.php @@ -85,7 +85,6 @@ ->abstract() ->args([ abstract_arg('remember me handler'), - param('kernel.secret'), service('security.token_storage'), abstract_arg('options'), service('logger')->nullOnInvalid(), diff --git a/composer.json b/composer.json index b335e73e..ca85d486 100644 --- a/composer.json +++ b/composer.json @@ -26,9 +26,9 @@ "symfony/http-kernel": "^6.4|^7.0", "symfony/http-foundation": "^6.4|^7.0", "symfony/password-hasher": "^6.4|^7.0", - "symfony/security-core": "^6.4|^7.0", + "symfony/security-core": "^7.2", "symfony/security-csrf": "^6.4|^7.0", - "symfony/security-http": "^7.1", + "symfony/security-http": "^7.2", "symfony/service-contracts": "^2.5|^3" }, "require-dev": { From 97e729b84070d353b7a7b0f42b5f74fe606d04e8 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 24 May 2024 11:59:23 +0200 Subject: [PATCH 03/23] use constructor property promotion --- CacheWarmer/ExpressionCacheWarmer.php | 11 ++++------- Command/DebugFirewallCommand.php | 18 ++++++------------ DataCollector/SecurityDataCollector.php | 22 ++++++++-------------- DependencyInjection/MainConfiguration.php | 11 ++++------- EventListener/FirewallListener.php | 13 +++++-------- EventListener/VoteListener.php | 8 +++----- RememberMe/DecoratedRememberMeHandler.php | 8 +++----- Security/FirewallContext.php | 17 ++++++----------- Security/FirewallMap.php | 11 ++++------- Security/LazyFirewallContext.php | 13 +++++++------ 10 files changed, 50 insertions(+), 82 deletions(-) diff --git a/CacheWarmer/ExpressionCacheWarmer.php b/CacheWarmer/ExpressionCacheWarmer.php index 5b146871..748d0b28 100644 --- a/CacheWarmer/ExpressionCacheWarmer.php +++ b/CacheWarmer/ExpressionCacheWarmer.php @@ -20,16 +20,13 @@ */ class ExpressionCacheWarmer implements CacheWarmerInterface { - private iterable $expressions; - private ExpressionLanguage $expressionLanguage; - /** * @param iterable $expressions */ - public function __construct(iterable $expressions, ExpressionLanguage $expressionLanguage) - { - $this->expressions = $expressions; - $this->expressionLanguage = $expressionLanguage; + public function __construct( + private iterable $expressions, + private ExpressionLanguage $expressionLanguage, + ) { } public function isOptional(): bool diff --git a/Command/DebugFirewallCommand.php b/Command/DebugFirewallCommand.php index ffc3035a..c5920337 100644 --- a/Command/DebugFirewallCommand.php +++ b/Command/DebugFirewallCommand.php @@ -32,22 +32,16 @@ #[AsCommand(name: 'debug:firewall', description: 'Display information about your security firewall(s)')] final class DebugFirewallCommand extends Command { - private array $firewallNames; - private ContainerInterface $contexts; - private ContainerInterface $eventDispatchers; - private array $authenticators; - /** * @param string[] $firewallNames * @param AuthenticatorInterface[][] $authenticators */ - public function __construct(array $firewallNames, ContainerInterface $contexts, ContainerInterface $eventDispatchers, array $authenticators) - { - $this->firewallNames = $firewallNames; - $this->contexts = $contexts; - $this->eventDispatchers = $eventDispatchers; - $this->authenticators = $authenticators; - + public function __construct( + private array $firewallNames, + private ContainerInterface $contexts, + private ContainerInterface $eventDispatchers, + private array $authenticators, + ) { parent::__construct(); } diff --git a/DataCollector/SecurityDataCollector.php b/DataCollector/SecurityDataCollector.php index 2c0562e4..3812f365 100644 --- a/DataCollector/SecurityDataCollector.php +++ b/DataCollector/SecurityDataCollector.php @@ -36,22 +36,16 @@ */ class SecurityDataCollector extends DataCollector implements LateDataCollectorInterface { - private ?TokenStorageInterface $tokenStorage; - private ?RoleHierarchyInterface $roleHierarchy; - private ?LogoutUrlGenerator $logoutUrlGenerator; - private ?AccessDecisionManagerInterface $accessDecisionManager; - private ?FirewallMapInterface $firewallMap; - private ?TraceableFirewallListener $firewall; private bool $hasVarDumper; - public function __construct(?TokenStorageInterface $tokenStorage = null, ?RoleHierarchyInterface $roleHierarchy = null, ?LogoutUrlGenerator $logoutUrlGenerator = null, ?AccessDecisionManagerInterface $accessDecisionManager = null, ?FirewallMapInterface $firewallMap = null, ?TraceableFirewallListener $firewall = null) - { - $this->tokenStorage = $tokenStorage; - $this->roleHierarchy = $roleHierarchy; - $this->logoutUrlGenerator = $logoutUrlGenerator; - $this->accessDecisionManager = $accessDecisionManager; - $this->firewallMap = $firewallMap; - $this->firewall = $firewall; + public function __construct( + private ?TokenStorageInterface $tokenStorage = null, + private ?RoleHierarchyInterface $roleHierarchy = null, + private ?LogoutUrlGenerator $logoutUrlGenerator = null, + private ?AccessDecisionManagerInterface $accessDecisionManager = null, + private ?FirewallMapInterface $firewallMap = null, + private ?TraceableFirewallListener $firewall = null, + ) { $this->hasVarDumper = class_exists(ClassStub::class); } diff --git a/DependencyInjection/MainConfiguration.php b/DependencyInjection/MainConfiguration.php index bfd96d7c..2eee2f43 100644 --- a/DependencyInjection/MainConfiguration.php +++ b/DependencyInjection/MainConfiguration.php @@ -36,16 +36,13 @@ class MainConfiguration implements ConfigurationInterface /** @internal */ public const STRATEGY_PRIORITY = 'priority'; - private array $factories; - private array $userProviderFactories; - /** * @param array $factories */ - public function __construct(array $factories, array $userProviderFactories) - { - $this->factories = $factories; - $this->userProviderFactories = $userProviderFactories; + public function __construct( + private array $factories, + private array $userProviderFactories, + ) { } /** diff --git a/EventListener/FirewallListener.php b/EventListener/FirewallListener.php index 4c63ec18..391a4b31 100644 --- a/EventListener/FirewallListener.php +++ b/EventListener/FirewallListener.php @@ -25,14 +25,11 @@ */ class FirewallListener extends Firewall { - private FirewallMapInterface $map; - private LogoutUrlGenerator $logoutUrlGenerator; - - public function __construct(FirewallMapInterface $map, EventDispatcherInterface $dispatcher, LogoutUrlGenerator $logoutUrlGenerator) - { - $this->map = $map; - $this->logoutUrlGenerator = $logoutUrlGenerator; - + public function __construct( + private FirewallMapInterface $map, + EventDispatcherInterface $dispatcher, + private LogoutUrlGenerator $logoutUrlGenerator, + ) { parent::__construct($map, $dispatcher); } diff --git a/EventListener/VoteListener.php b/EventListener/VoteListener.php index 34ca91c3..54eac438 100644 --- a/EventListener/VoteListener.php +++ b/EventListener/VoteListener.php @@ -24,11 +24,9 @@ */ class VoteListener implements EventSubscriberInterface { - private TraceableAccessDecisionManager $traceableAccessDecisionManager; - - public function __construct(TraceableAccessDecisionManager $traceableAccessDecisionManager) - { - $this->traceableAccessDecisionManager = $traceableAccessDecisionManager; + public function __construct( + private TraceableAccessDecisionManager $traceableAccessDecisionManager, + ) { } public function onVoterVote(VoteEvent $event): void diff --git a/RememberMe/DecoratedRememberMeHandler.php b/RememberMe/DecoratedRememberMeHandler.php index ed6d0ed2..dd607245 100644 --- a/RememberMe/DecoratedRememberMeHandler.php +++ b/RememberMe/DecoratedRememberMeHandler.php @@ -24,11 +24,9 @@ */ final class DecoratedRememberMeHandler implements RememberMeHandlerInterface { - private RememberMeHandlerInterface $handler; - - public function __construct(RememberMeHandlerInterface $handler) - { - $this->handler = $handler; + public function __construct( + private RememberMeHandlerInterface $handler, + ) { } public function createRememberMeCookie(UserInterface $user): void diff --git a/Security/FirewallContext.php b/Security/FirewallContext.php index c100d353..63648bd6 100644 --- a/Security/FirewallContext.php +++ b/Security/FirewallContext.php @@ -22,20 +22,15 @@ */ class FirewallContext { - private iterable $listeners; - private ?ExceptionListener $exceptionListener; - private ?LogoutListener $logoutListener; - private ?FirewallConfig $config; - /** * @param iterable $listeners */ - public function __construct(iterable $listeners, ?ExceptionListener $exceptionListener = null, ?LogoutListener $logoutListener = null, ?FirewallConfig $config = null) - { - $this->listeners = $listeners; - $this->exceptionListener = $exceptionListener; - $this->logoutListener = $logoutListener; - $this->config = $config; + public function __construct( + private iterable $listeners, + private ?ExceptionListener $exceptionListener = null, + private ?LogoutListener $logoutListener = null, + private ?FirewallConfig $config = null, + ) { } public function getConfig(): ?FirewallConfig diff --git a/Security/FirewallMap.php b/Security/FirewallMap.php index fbb44cae..f02b4c2d 100644 --- a/Security/FirewallMap.php +++ b/Security/FirewallMap.php @@ -24,13 +24,10 @@ */ class FirewallMap implements FirewallMapInterface { - private ContainerInterface $container; - private iterable $map; - - public function __construct(ContainerInterface $container, iterable $map) - { - $this->container = $container; - $this->map = $map; + public function __construct( + private ContainerInterface $container, + private iterable $map, + ) { } public function getListeners(Request $request): array diff --git a/Security/LazyFirewallContext.php b/Security/LazyFirewallContext.php index 500b29b1..68357623 100644 --- a/Security/LazyFirewallContext.php +++ b/Security/LazyFirewallContext.php @@ -25,13 +25,14 @@ */ class LazyFirewallContext extends FirewallContext { - private TokenStorage $tokenStorage; - - public function __construct(iterable $listeners, ?ExceptionListener $exceptionListener, ?LogoutListener $logoutListener, ?FirewallConfig $config, TokenStorage $tokenStorage) - { + public function __construct( + iterable $listeners, + ?ExceptionListener $exceptionListener, + ?LogoutListener $logoutListener, + ?FirewallConfig $config, + private TokenStorage $tokenStorage, + ) { parent::__construct($listeners, $exceptionListener, $logoutListener, $config); - - $this->tokenStorage = $tokenStorage; } public function getListeners(): iterable From 9ff05d330b3cb012c91863690279aefb157c958c Mon Sep 17 00:00:00 2001 From: MatTheCat Date: Sat, 15 Jun 2024 18:49:04 +0200 Subject: [PATCH 04/23] =?UTF-8?q?[SecurityBundle]=20Improve=20profiler?= =?UTF-8?q?=E2=80=99s=20data?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Debug/TraceableFirewallListener.php | 78 +++++++++----------- Resources/views/Collector/security.html.twig | 4 +- 2 files changed, 38 insertions(+), 44 deletions(-) diff --git a/Debug/TraceableFirewallListener.php b/Debug/TraceableFirewallListener.php index 16805009..45f4f498 100644 --- a/Debug/TraceableFirewallListener.php +++ b/Debug/TraceableFirewallListener.php @@ -27,78 +27,72 @@ final class TraceableFirewallListener extends FirewallListener implements ResetInterface { private array $wrappedListeners = []; - private array $authenticatorsInfo = []; + private ?TraceableAuthenticatorManagerListener $authenticatorManagerListener = null; public function getWrappedListeners(): array { - return $this->wrappedListeners; + return array_map( + static fn (WrappedListener|WrappedLazyListener $listener) => $listener->getInfo(), + $this->wrappedListeners + ); } public function getAuthenticatorsInfo(): array { - return $this->authenticatorsInfo; + return $this->authenticatorManagerListener?->getAuthenticatorsInfo() ?? []; } public function reset(): void { $this->wrappedListeners = []; - $this->authenticatorsInfo = []; + $this->authenticatorManagerListener = null; } protected function callListeners(RequestEvent $event, iterable $listeners): void { - $wrappedListeners = []; - $wrappedLazyListeners = []; - $authenticatorManagerListener = null; - + $requestListeners = []; foreach ($listeners as $listener) { if ($listener instanceof LazyFirewallContext) { - \Closure::bind(function () use (&$wrappedLazyListeners, &$wrappedListeners, &$authenticatorManagerListener) { - $listeners = []; + $contextWrappedListeners = []; + $contextAuthenticatorManagerListener = null; + + \Closure::bind(function () use (&$contextWrappedListeners, &$contextAuthenticatorManagerListener) { foreach ($this->listeners as $listener) { - if (!$authenticatorManagerListener && $listener instanceof TraceableAuthenticatorManagerListener) { - $authenticatorManagerListener = $listener; - } - if ($listener instanceof FirewallListenerInterface) { - $listener = new WrappedLazyListener($listener); - $listeners[] = $listener; - $wrappedLazyListeners[] = $listener; - } else { - $listeners[] = function (RequestEvent $event) use ($listener, &$wrappedListeners) { - $wrappedListener = new WrappedListener($listener); - $wrappedListener($event); - $wrappedListeners[] = $wrappedListener->getInfo(); - }; + if ($listener instanceof TraceableAuthenticatorManagerListener) { + $contextAuthenticatorManagerListener ??= $listener; } + $contextWrappedListeners[] = $listener instanceof FirewallListenerInterface + ? new WrappedLazyListener($listener) + : new WrappedListener($listener) + ; } - $this->listeners = $listeners; + $this->listeners = $contextWrappedListeners; }, $listener, FirewallContext::class)(); - $listener($event); + $this->authenticatorManagerListener ??= $contextAuthenticatorManagerListener; + $this->wrappedListeners = array_merge($this->wrappedListeners, $contextWrappedListeners); + + $requestListeners[] = $listener; } else { - $wrappedListener = $listener instanceof FirewallListenerInterface ? new WrappedLazyListener($listener) : new WrappedListener($listener); - $wrappedListener($event); - $wrappedListeners[] = $wrappedListener->getInfo(); - if (!$authenticatorManagerListener && $listener instanceof TraceableAuthenticatorManagerListener) { - $authenticatorManagerListener = $listener; + if ($listener instanceof TraceableAuthenticatorManagerListener) { + $this->authenticatorManagerListener ??= $listener; } - } + $wrappedListener = $listener instanceof FirewallListenerInterface + ? new WrappedLazyListener($listener) + : new WrappedListener($listener) + ; + $this->wrappedListeners[] = $wrappedListener; - if ($event->hasResponse()) { - break; + $requestListeners[] = $wrappedListener; } } - if ($wrappedLazyListeners) { - foreach ($wrappedLazyListeners as $lazyListener) { - $this->wrappedListeners[] = $lazyListener->getInfo(); - } - } - - $this->wrappedListeners = array_merge($this->wrappedListeners, $wrappedListeners); + foreach ($requestListeners as $listener) { + $listener($event); - if ($authenticatorManagerListener) { - $this->authenticatorsInfo = $authenticatorManagerListener->getAuthenticatorsInfo(); + if ($event->hasResponse()) { + break; + } } } } diff --git a/Resources/views/Collector/security.html.twig b/Resources/views/Collector/security.html.twig index 4dd0b021..4fe1140e 100644 --- a/Resources/views/Collector/security.html.twig +++ b/Resources/views/Collector/security.html.twig @@ -318,7 +318,7 @@ {{ profiler_dump(listener.stub) }} - {{ '%0.2f'|format(listener.time * 1000) }} ms + {{ listener.time is null ? '(none)' : '%0.2f ms'|format(listener.time * 1000) }} {{ listener.response ? profiler_dump(listener.response) : '(none)' }} @@ -362,7 +362,7 @@ {{ profiler_dump(authenticator.stub) }} {{ source('@WebProfiler/Icon/' ~ (authenticator.supports ? 'yes' : 'no') ~ '.svg') }} {{ authenticator.authenticated is not null ? source('@WebProfiler/Icon/' ~ (authenticator.authenticated ? 'yes' : 'no') ~ '.svg') : '' }} - {{ '%0.2f'|format(authenticator.duration * 1000) }} ms + {{ authenticator.duration is null ? '(none)' : '%0.2f ms'|format(authenticator.duration * 1000) }} {{ authenticator.passport ? profiler_dump(authenticator.passport) : '(none)' }} {% for badge in authenticator.badges ?? [] %} From e7ff37b830fbd7e47307fc5862b917672715f7d6 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Thu, 20 Jun 2024 17:52:34 +0200 Subject: [PATCH 05/23] Prefix all sprintf() calls --- Command/DebugFirewallCommand.php | 30 +++++++++---------- DataCollector/SecurityDataCollector.php | 2 +- .../Compiler/AddSecurityVotersPass.php | 2 +- .../AddSessionDomainConstraintPass.php | 6 ++-- .../Compiler/RegisterEntryPointPass.php | 2 +- .../ReplaceDecoratedRememberMeHandlerPass.php | 2 +- .../Compiler/SortFirewallListenersPass.php | 2 +- DependencyInjection/MainConfiguration.php | 8 ++--- .../AccessToken/OidcTokenHandlerFactory.php | 2 +- .../Security/Factory/AccessTokenFactory.php | 6 ++-- .../Security/Factory/LoginLinkFactory.php | 4 +-- .../Factory/LoginThrottlingFactory.php | 4 +-- .../Security/Factory/RememberMeFactory.php | 4 +-- DependencyInjection/SecurityExtension.php | 24 +++++++-------- Security.php | 10 +++---- Security/FirewallAwareTrait.php | 2 +- .../Factory/AccessTokenFactoryTest.php | 2 +- Tests/Functional/AccessTokenTest.php | 2 +- .../Controller/FooController.php | 2 +- .../Http/JsonAuthenticationSuccessHandler.php | 2 +- .../Controller/TestController.php | 2 +- .../Http/JsonAuthenticationSuccessHandler.php | 2 +- .../TestCustomLoginLinkSuccessHandler.php | 2 +- .../Security/Core/User/ArrayUserProvider.php | 4 +-- Tests/Functional/SecurityTest.php | 4 +-- Tests/Functional/app/AppKernel.php | 6 ++-- 26 files changed, 69 insertions(+), 69 deletions(-) diff --git a/Command/DebugFirewallCommand.php b/Command/DebugFirewallCommand.php index c5920337..3f8b088f 100644 --- a/Command/DebugFirewallCommand.php +++ b/Command/DebugFirewallCommand.php @@ -69,7 +69,7 @@ protected function configure(): void EOF ) ->setDefinition([ - new InputArgument('name', InputArgument::OPTIONAL, sprintf('A firewall name (for example "%s")', $exampleName)), + new InputArgument('name', InputArgument::OPTIONAL, \sprintf('A firewall name (for example "%s")', $exampleName)), new InputOption('events', null, InputOption::VALUE_NONE, 'Include a list of event listeners (only available in combination with the "name" argument)'), ]); } @@ -86,10 +86,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int return 0; } - $serviceId = sprintf('security.firewall.map.context.%s', $name); + $serviceId = \sprintf('security.firewall.map.context.%s', $name); if (!$this->contexts->has($serviceId)) { - $io->error(sprintf('Firewall %s was not found. Available firewalls are: %s', $name, implode(', ', $this->firewallNames))); + $io->error(\sprintf('Firewall %s was not found. Available firewalls are: %s', $name, implode(', ', $this->firewallNames))); return 1; } @@ -97,7 +97,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int /** @var FirewallContext $context */ $context = $this->contexts->get($serviceId); - $io->title(sprintf('Firewall "%s"', $name)); + $io->title(\sprintf('Firewall "%s"', $name)); $this->displayFirewallSummary($name, $context, $io); @@ -119,7 +119,7 @@ protected function displayFirewallList(SymfonyStyle $io): void $io->listing($this->firewallNames); - $io->comment(sprintf('To view details of a specific firewall, re-run this command with a firewall name. (e.g. debug:firewall %s)', $this->getExampleName())); + $io->comment(\sprintf('To view details of a specific firewall, re-run this command with a firewall name. (e.g. debug:firewall %s)', $this->getExampleName())); } protected function displayFirewallSummary(string $name, FirewallContext $context, SymfonyStyle $io): void @@ -163,9 +163,9 @@ private function displaySwitchUser(FirewallContext $context, SymfonyStyle $io): protected function displayEventListeners(string $name, FirewallContext $context, SymfonyStyle $io): void { - $io->title(sprintf('Event listeners for firewall "%s"', $name)); + $io->title(\sprintf('Event listeners for firewall "%s"', $name)); - $dispatcherId = sprintf('security.event_dispatcher.%s', $name); + $dispatcherId = \sprintf('security.event_dispatcher.%s', $name); if (!$this->eventDispatchers->has($dispatcherId)) { $io->text('No event dispatcher has been registered for this firewall.'); @@ -177,12 +177,12 @@ protected function displayEventListeners(string $name, FirewallContext $context, $dispatcher = $this->eventDispatchers->get($dispatcherId); foreach ($dispatcher->getListeners() as $event => $listeners) { - $io->section(sprintf('"%s" event', $event)); + $io->section(\sprintf('"%s" event', $event)); $rows = []; foreach ($listeners as $order => $listener) { $rows[] = [ - sprintf('#%d', $order + 1), + \sprintf('#%d', $order + 1), $this->formatCallable($listener), $dispatcher->getListenerPriority($event, $listener), ]; @@ -197,7 +197,7 @@ protected function displayEventListeners(string $name, FirewallContext $context, private function displayAuthenticators(string $name, SymfonyStyle $io): void { - $io->title(sprintf('Authenticators for firewall "%s"', $name)); + $io->title(\sprintf('Authenticators for firewall "%s"', $name)); $authenticators = $this->authenticators[$name] ?? []; @@ -220,14 +220,14 @@ private function formatCallable(mixed $callable): string { if (\is_array($callable)) { if (\is_object($callable[0])) { - return sprintf('%s::%s()', $callable[0]::class, $callable[1]); + return \sprintf('%s::%s()', $callable[0]::class, $callable[1]); } - return sprintf('%s::%s()', $callable[0], $callable[1]); + return \sprintf('%s::%s()', $callable[0], $callable[1]); } if (\is_string($callable)) { - return sprintf('%s()', $callable); + return \sprintf('%s()', $callable); } if ($callable instanceof \Closure) { @@ -236,14 +236,14 @@ private function formatCallable(mixed $callable): string return 'Closure()'; } if ($class = $r->getClosureCalledClass()) { - return sprintf('%s::%s()', $class->name, $r->name); + return \sprintf('%s::%s()', $class->name, $r->name); } return $r->name.'()'; } if (method_exists($callable, '__invoke')) { - return sprintf('%s::__invoke()', $callable::class); + return \sprintf('%s::__invoke()', $callable::class); } throw new \InvalidArgumentException('Callable is not describable.'); diff --git a/DataCollector/SecurityDataCollector.php b/DataCollector/SecurityDataCollector.php index 3812f365..826d6c99 100644 --- a/DataCollector/SecurityDataCollector.php +++ b/DataCollector/SecurityDataCollector.php @@ -181,7 +181,7 @@ public function collect(Request $request, Response $response, ?\Throwable $excep if ($this->data['impersonated'] && null !== $switchUserConfig = $firewallConfig->getSwitchUser()) { $exitPath = $request->getRequestUri(); $exitPath .= null === $request->getQueryString() ? '?' : '&'; - $exitPath .= sprintf('%s=%s', urlencode($switchUserConfig['parameter']), SwitchUserListener::EXIT_VALUE); + $exitPath .= \sprintf('%s=%s', urlencode($switchUserConfig['parameter']), SwitchUserListener::EXIT_VALUE); $this->data['impersonation_exit_path'] = $exitPath; } diff --git a/DependencyInjection/Compiler/AddSecurityVotersPass.php b/DependencyInjection/Compiler/AddSecurityVotersPass.php index 1664f8e7..f118a626 100644 --- a/DependencyInjection/Compiler/AddSecurityVotersPass.php +++ b/DependencyInjection/Compiler/AddSecurityVotersPass.php @@ -49,7 +49,7 @@ public function process(ContainerBuilder $container): void $class = $container->getParameterBag()->resolveValue($definition->getClass()); if (!is_a($class, VoterInterface::class, true)) { - throw new LogicException(sprintf('"%s" must implement the "%s" when used as a voter.', $class, VoterInterface::class)); + throw new LogicException(\sprintf('"%s" must implement the "%s" when used as a voter.', $class, VoterInterface::class)); } if ($debug) { diff --git a/DependencyInjection/Compiler/AddSessionDomainConstraintPass.php b/DependencyInjection/Compiler/AddSessionDomainConstraintPass.php index 8bab747d..38d89b47 100644 --- a/DependencyInjection/Compiler/AddSessionDomainConstraintPass.php +++ b/DependencyInjection/Compiler/AddSessionDomainConstraintPass.php @@ -28,10 +28,10 @@ public function process(ContainerBuilder $container): void } $sessionOptions = $container->getParameter('session.storage.options'); - $domainRegexp = empty($sessionOptions['cookie_domain']) ? '%%s' : sprintf('(?:%%%%s|(?:.+\.)?%s)', preg_quote(trim($sessionOptions['cookie_domain'], '.'))); + $domainRegexp = empty($sessionOptions['cookie_domain']) ? '%%s' : \sprintf('(?:%%%%s|(?:.+\.)?%s)', preg_quote(trim($sessionOptions['cookie_domain'], '.'))); if ('auto' === ($sessionOptions['cookie_secure'] ?? null)) { - $secureDomainRegexp = sprintf('{^https://%s$}i', $domainRegexp); + $secureDomainRegexp = \sprintf('{^https://%s$}i', $domainRegexp); $domainRegexp = 'https?://'.$domainRegexp; } else { $secureDomainRegexp = null; @@ -39,7 +39,7 @@ public function process(ContainerBuilder $container): void } $container->findDefinition('security.http_utils') - ->addArgument(sprintf('{^%s$}i', $domainRegexp)) + ->addArgument(\sprintf('{^%s$}i', $domainRegexp)) ->addArgument($secureDomainRegexp); } } diff --git a/DependencyInjection/Compiler/RegisterEntryPointPass.php b/DependencyInjection/Compiler/RegisterEntryPointPass.php index 4dc4c4c9..6a1a8f25 100644 --- a/DependencyInjection/Compiler/RegisterEntryPointPass.php +++ b/DependencyInjection/Compiler/RegisterEntryPointPass.php @@ -73,7 +73,7 @@ public function process(ContainerBuilder $container): void $entryPointNames[] = is_numeric($key) ? $serviceId : $key; } - throw new InvalidConfigurationException(sprintf('Because you have multiple authenticators in firewall "%s", you need to set the "entry_point" key to one of your authenticators ("%s") or a service ID implementing "%s". The "entry_point" determines what should happen (e.g. redirect to "/login") when an anonymous user tries to access a protected page.', $firewallName, implode('", "', $entryPointNames), AuthenticationEntryPointInterface::class)); + throw new InvalidConfigurationException(\sprintf('Because you have multiple authenticators in firewall "%s", you need to set the "entry_point" key to one of your authenticators ("%s") or a service ID implementing "%s". The "entry_point" determines what should happen (e.g. redirect to "/login") when an anonymous user tries to access a protected page.', $firewallName, implode('", "', $entryPointNames), AuthenticationEntryPointInterface::class)); } $config->replaceArgument(7, $entryPoint); diff --git a/DependencyInjection/Compiler/ReplaceDecoratedRememberMeHandlerPass.php b/DependencyInjection/Compiler/ReplaceDecoratedRememberMeHandlerPass.php index 4727e62f..742d3c08 100644 --- a/DependencyInjection/Compiler/ReplaceDecoratedRememberMeHandlerPass.php +++ b/DependencyInjection/Compiler/ReplaceDecoratedRememberMeHandlerPass.php @@ -38,7 +38,7 @@ public function process(ContainerBuilder $container): void // get the actual custom remember me handler definition (passed to the decorator) $realRememberMeHandler = $container->findDefinition((string) $definition->getArgument(0)); if (null === $realRememberMeHandler) { - throw new \LogicException(sprintf('Invalid service definition for custom remember me handler; no service found with ID "%s".', (string) $definition->getArgument(0))); + throw new \LogicException(\sprintf('Invalid service definition for custom remember me handler; no service found with ID "%s".', (string) $definition->getArgument(0))); } foreach ($rememberMeHandlerTags as $rememberMeHandlerTag) { diff --git a/DependencyInjection/Compiler/SortFirewallListenersPass.php b/DependencyInjection/Compiler/SortFirewallListenersPass.php index 7f0301a3..2c3e14fe 100644 --- a/DependencyInjection/Compiler/SortFirewallListenersPass.php +++ b/DependencyInjection/Compiler/SortFirewallListenersPass.php @@ -62,7 +62,7 @@ private function getListenerPriorities(IteratorArgument $listeners, ContainerBui $class = $def->getClass(); if (!$r = $container->getReflectionClass($class)) { - throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); + throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); } $priority = 0; diff --git a/DependencyInjection/MainConfiguration.php b/DependencyInjection/MainConfiguration.php index 2eee2f43..98ef9e9f 100644 --- a/DependencyInjection/MainConfiguration.php +++ b/DependencyInjection/MainConfiguration.php @@ -190,7 +190,7 @@ private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $facto ->scalarNode('pattern') ->beforeNormalization() ->ifArray() - ->then(fn ($v) => sprintf('(?:%s)', implode('|', $v))) + ->then(fn ($v) => \sprintf('(?:%s)', implode('|', $v))) ->end() ->end() ->scalarNode('host')->end() @@ -208,7 +208,7 @@ private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $facto ->scalarNode('access_denied_url')->end() ->scalarNode('access_denied_handler')->end() ->scalarNode('entry_point') - ->info(sprintf('An enabled authenticator name or a service id that implements "%s"', AuthenticationEntryPointInterface::class)) + ->info(\sprintf('An enabled authenticator name or a service id that implements "%s"', AuthenticationEntryPointInterface::class)) ->end() ->scalarNode('provider')->end() ->booleanNode('stateless')->defaultFalse()->end() @@ -294,7 +294,7 @@ private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $facto } } - throw new InvalidConfigurationException(sprintf('Undefined security Badge class "%s" set in "security.firewall.required_badges".', $requiredBadge)); + throw new InvalidConfigurationException(\sprintf('Undefined security Badge class "%s" set in "security.firewall.required_badges".', $requiredBadge)); }, $requiredBadges); }) ->end() @@ -328,7 +328,7 @@ private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $facto } if (str_contains($firewall[$k]['check_path'], '/') && !preg_match('#'.$firewall['pattern'].'#', $firewall[$k]['check_path'])) { - throw new \LogicException(sprintf('The check_path "%s" for login method "%s" is not matched by the firewall pattern "%s".', $firewall[$k]['check_path'], $k, $firewall['pattern'])); + throw new \LogicException(\sprintf('The check_path "%s" for login method "%s" is not matched by the firewall pattern "%s".', $firewall[$k]['check_path'], $k, $firewall['pattern'])); } } diff --git a/DependencyInjection/Security/AccessToken/OidcTokenHandlerFactory.php b/DependencyInjection/Security/AccessToken/OidcTokenHandlerFactory.php index a1b41812..e3d8db49 100644 --- a/DependencyInjection/Security/AccessToken/OidcTokenHandlerFactory.php +++ b/DependencyInjection/Security/AccessToken/OidcTokenHandlerFactory.php @@ -79,7 +79,7 @@ public function addConfiguration(NodeBuilder $node): void if (isset($v['keyset'])) { throw new InvalidConfigurationException('You cannot use both "key" and "keyset" at the same time.'); } - $v['keyset'] = sprintf('{"keys":[%s]}', $v['key']); + $v['keyset'] = \sprintf('{"keys":[%s]}', $v['key']); return $v; }) diff --git a/DependencyInjection/Security/Factory/AccessTokenFactory.php b/DependencyInjection/Security/Factory/AccessTokenFactory.php index 50395522..371049c8 100644 --- a/DependencyInjection/Security/Factory/AccessTokenFactory.php +++ b/DependencyInjection/Security/Factory/AccessTokenFactory.php @@ -107,7 +107,7 @@ public function createAuthenticator(ContainerBuilder $container, string $firewal { $successHandler = isset($config['success_handler']) ? new Reference($this->createAuthenticationSuccessHandler($container, $firewallName, $config)) : null; $failureHandler = isset($config['failure_handler']) ? new Reference($this->createAuthenticationFailureHandler($container, $firewallName, $config)) : null; - $authenticatorId = sprintf('security.authenticator.access_token.%s', $firewallName); + $authenticatorId = \sprintf('security.authenticator.access_token.%s', $firewallName); $extractorId = $this->createExtractor($container, $firewallName, $config['token_extractors']); $tokenHandlerId = $this->createTokenHandler($container, $firewallName, $config['token_handler'], $userProviderId); @@ -139,7 +139,7 @@ private function createExtractor(ContainerBuilder $container, string $firewallNa if (1 === \count($extractors)) { return current($extractors); } - $extractorId = sprintf('security.authenticator.access_token.chain_extractor.%s', $firewallName); + $extractorId = \sprintf('security.authenticator.access_token.chain_extractor.%s', $firewallName); $container ->setDefinition($extractorId, new ChildDefinition('security.authenticator.access_token.chain_extractor')) ->replaceArgument(0, array_map(fn (string $extractorId): Reference => new Reference($extractorId), $extractors)) @@ -151,7 +151,7 @@ private function createExtractor(ContainerBuilder $container, string $firewallNa private function createTokenHandler(ContainerBuilder $container, string $firewallName, array $config, ?string $userProviderId): string { $key = array_keys($config)[0]; - $id = sprintf('security.access_token_handler.%s', $firewallName); + $id = \sprintf('security.access_token_handler.%s', $firewallName); foreach ($this->tokenHandlerFactories as $factory) { if ($key !== $factory->getKey()) { diff --git a/DependencyInjection/Security/Factory/LoginLinkFactory.php b/DependencyInjection/Security/Factory/LoginLinkFactory.php index bfd4eb0d..854cb972 100644 --- a/DependencyInjection/Security/Factory/LoginLinkFactory.php +++ b/DependencyInjection/Security/Factory/LoginLinkFactory.php @@ -61,10 +61,10 @@ public function addConfiguration(NodeDefinition $node): void ->info('Cache service id used to expired links of max_uses is set.') ->end() ->scalarNode('success_handler') - ->info(sprintf('A service id that implements %s.', AuthenticationSuccessHandlerInterface::class)) + ->info(\sprintf('A service id that implements %s.', AuthenticationSuccessHandlerInterface::class)) ->end() ->scalarNode('failure_handler') - ->info(sprintf('A service id that implements %s.', AuthenticationFailureHandlerInterface::class)) + ->info(\sprintf('A service id that implements %s.', AuthenticationFailureHandlerInterface::class)) ->end() ->scalarNode('provider') ->info('The user provider to load users from.') diff --git a/DependencyInjection/Security/Factory/LoginThrottlingFactory.php b/DependencyInjection/Security/Factory/LoginThrottlingFactory.php index bb96484a..cc20b5db 100644 --- a/DependencyInjection/Security/Factory/LoginThrottlingFactory.php +++ b/DependencyInjection/Security/Factory/LoginThrottlingFactory.php @@ -49,7 +49,7 @@ public function addConfiguration(NodeDefinition $builder): void { $builder ->children() - ->scalarNode('limiter')->info(sprintf('A service id implementing "%s".', RequestRateLimiterInterface::class))->end() + ->scalarNode('limiter')->info(\sprintf('A service id implementing "%s".', RequestRateLimiterInterface::class))->end() ->integerNode('max_attempts')->defaultValue(5)->end() ->scalarNode('interval')->defaultValue('1 minute')->end() ->scalarNode('lock_factory')->info('The service ID of the lock factory used by the login rate limiter (or null to disable locking)')->defaultNull()->end() @@ -98,7 +98,7 @@ private function registerRateLimiter(ContainerBuilder $container, string $name, if (null !== $limiterConfig['lock_factory']) { if (!interface_exists(LockInterface::class)) { - throw new LogicException(sprintf('Rate limiter "%s" requires the Lock component to be installed. Try running "composer require symfony/lock".', $name)); + throw new LogicException(\sprintf('Rate limiter "%s" requires the Lock component to be installed. Try running "composer require symfony/lock".', $name)); } $limiter->replaceArgument(2, new Reference($limiterConfig['lock_factory'])); diff --git a/DependencyInjection/Security/Factory/RememberMeFactory.php b/DependencyInjection/Security/Factory/RememberMeFactory.php index a5ba19e9..c62c01d4 100644 --- a/DependencyInjection/Security/Factory/RememberMeFactory.php +++ b/DependencyInjection/Security/Factory/RememberMeFactory.php @@ -58,7 +58,7 @@ public function createAuthenticator(ContainerBuilder $container, string $firewal // create remember me handler (which manage the remember-me cookies) $rememberMeHandlerId = 'security.authenticator.remember_me_handler.'.$firewallName; if (isset($config['service']) && isset($config['token_provider'])) { - throw new InvalidConfigurationException(sprintf('You cannot use both "service" and "token_provider" in "security.firewalls.%s.remember_me".', $firewallName)); + throw new InvalidConfigurationException(\sprintf('You cannot use both "service" and "token_provider" in "security.firewalls.%s.remember_me".', $firewallName)); } if (isset($config['service'])) { @@ -203,7 +203,7 @@ private function createTokenProvider(ContainerBuilder $container, string $firewa } if (!$tokenProviderId) { - throw new InvalidConfigurationException(sprintf('No token provider was set for firewall "%s". Either configure a service ID or set "remember_me.token_provider.doctrine" to true.', $firewallName)); + throw new InvalidConfigurationException(\sprintf('No token provider was set for firewall "%s". Either configure a service ID or set "remember_me.token_provider.doctrine" to true.', $firewallName)); } return $tokenProviderId; diff --git a/DependencyInjection/SecurityExtension.php b/DependencyInjection/SecurityExtension.php index 383c7c41..2fd97987 100644 --- a/DependencyInjection/SecurityExtension.php +++ b/DependencyInjection/SecurityExtension.php @@ -191,7 +191,7 @@ private function createStrategyDefinition(string $strategy, bool $allowIfAllAbst MainConfiguration::STRATEGY_CONSENSUS => new Definition(ConsensusStrategy::class, [$allowIfAllAbstainDecisions, $allowIfEqualGrantedDeniedDecisions]), MainConfiguration::STRATEGY_UNANIMOUS => new Definition(UnanimousStrategy::class, [$allowIfAllAbstainDecisions]), MainConfiguration::STRATEGY_PRIORITY => new Definition(PriorityStrategy::class, [$allowIfAllAbstainDecisions]), - default => throw new InvalidConfigurationException(sprintf('The strategy "%s" is not supported.', $strategy)), + default => throw new InvalidConfigurationException(\sprintf('The strategy "%s" is not supported.', $strategy)), }; } @@ -380,7 +380,7 @@ private function createFirewall(ContainerBuilder $container, string $id, array $ $defaultProvider = null; if (isset($firewall['provider'])) { if (!isset($providerIds[$normalizedName = str_replace('-', '_', $firewall['provider'])])) { - throw new InvalidConfigurationException(sprintf('Invalid firewall "%s": user provider "%s" not found.', $id, $firewall['provider'])); + throw new InvalidConfigurationException(\sprintf('Invalid firewall "%s": user provider "%s" not found.', $id, $firewall['provider'])); } $defaultProvider = $providerIds[$normalizedName]; @@ -611,7 +611,7 @@ private function createAuthenticationListeners(ContainerBuilder $container, stri $userProvider = $this->getUserProvider($container, $id, $firewall, $key, $defaultProvider, $providerIds); if (!$factory instanceof AuthenticatorFactoryInterface) { - throw new InvalidConfigurationException(sprintf('Authenticator factory "%s" ("%s") must implement "%s".', get_debug_type($factory), $key, AuthenticatorFactoryInterface::class)); + throw new InvalidConfigurationException(\sprintf('Authenticator factory "%s" ("%s") must implement "%s".', get_debug_type($factory), $key, AuthenticatorFactoryInterface::class)); } if (null === $userProvider && !$factory instanceof StatelessAuthenticatorFactoryInterface) { @@ -648,7 +648,7 @@ private function getUserProvider(ContainerBuilder $container, string $id, array { if (isset($firewall[$factoryKey]['provider'])) { if (!isset($providerIds[$normalizedName = str_replace('-', '_', $firewall[$factoryKey]['provider'])])) { - throw new InvalidConfigurationException(sprintf('Invalid firewall "%s": user provider "%s" not found.', $id, $firewall[$factoryKey]['provider'])); + throw new InvalidConfigurationException(\sprintf('Invalid firewall "%s": user provider "%s" not found.', $id, $firewall[$factoryKey]['provider'])); } return $providerIds[$normalizedName]; @@ -670,12 +670,12 @@ private function getUserProvider(ContainerBuilder $container, string $id, array return 'security.user_providers'; } - throw new InvalidConfigurationException(sprintf('Not configuring explicitly the provider for the "%s" authenticator on "%s" firewall is ambiguous as there is more than one registered provider. Set the "provider" key to one of the configured providers, even if your custom authenticators don\'t use it.', $factoryKey, $id)); + throw new InvalidConfigurationException(\sprintf('Not configuring explicitly the provider for the "%s" authenticator on "%s" firewall is ambiguous as there is more than one registered provider. Set the "provider" key to one of the configured providers, even if your custom authenticators don\'t use it.', $factoryKey, $id)); } private function createMissingUserProvider(ContainerBuilder $container, string $id, string $factoryKey): string { - $userProvider = sprintf('security.user.provider.missing.%s', $factoryKey); + $userProvider = \sprintf('security.user.provider.missing.%s', $factoryKey); $container->setDefinition( $userProvider, (new ChildDefinition('security.user.provider.missing'))->replaceArgument(0, $id) @@ -755,7 +755,7 @@ private function createHasher(array $config): Reference|array $config['algorithm'] = 'native'; $config['native_algorithm'] = \PASSWORD_ARGON2I; } else { - throw new InvalidConfigurationException(sprintf('Algorithm "argon2i" is not available; use "%s" instead.', \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13') ? 'argon2id" or "auto' : 'auto')); + throw new InvalidConfigurationException(\sprintf('Algorithm "argon2i" is not available; use "%s" instead.', \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13') ? 'argon2id" or "auto' : 'auto')); } return $this->createHasher($config); @@ -768,7 +768,7 @@ private function createHasher(array $config): Reference|array $config['algorithm'] = 'native'; $config['native_algorithm'] = \PASSWORD_ARGON2ID; } else { - throw new InvalidConfigurationException(sprintf('Algorithm "argon2id" is not available; use "%s" or libsodium 1.0.15+ instead.', \defined('PASSWORD_ARGON2I') || $hasSodium ? 'argon2i", "auto' : 'auto')); + throw new InvalidConfigurationException(\sprintf('Algorithm "argon2id" is not available; use "%s" or libsodium 1.0.15+ instead.', \defined('PASSWORD_ARGON2I') || $hasSodium ? 'argon2i", "auto' : 'auto')); } return $this->createHasher($config); @@ -852,7 +852,7 @@ private function createUserDaoProvider(string $name, array $provider, ContainerB return $name; } - throw new InvalidConfigurationException(sprintf('Unable to create definition for "%s" user provider.', $name)); + throw new InvalidConfigurationException(\sprintf('Unable to create definition for "%s" user provider.', $name)); } private function getUserProviderId(string $name): string @@ -883,10 +883,10 @@ private function createSwitchUserListener(ContainerBuilder $container, string $i $userProvider = isset($config['provider']) ? $this->getUserProviderId($config['provider']) : $defaultProvider; 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)); + 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_route']) { - throw new InvalidConfigurationException(sprintf('Cannot set a "target_route" for the "switch_user" listener on the "%s" firewall as it is stateless.', $id)); + throw new InvalidConfigurationException(\sprintf('Cannot set a "target_route" for the "switch_user" listener on the "%s" firewall as it is stateless.', $id)); } $switchUserListenerId = 'security.authentication.switchuser_listener.'.$id; @@ -931,7 +931,7 @@ private function createRequestMatcher(ContainerBuilder $container, ?string $path $container->resolveEnvPlaceholders($ip, null, $usedEnvs); if (!$usedEnvs && !$this->isValidIps($ip)) { - throw new \LogicException(sprintf('The given value "%s" in the "security.access_control" config option is not a valid IP address.', $ip)); + throw new \LogicException(\sprintf('The given value "%s" in the "security.access_control" config option is not a valid IP address.', $ip)); } $usedEnvs = null; diff --git a/Security.php b/Security.php index c4b505d8..3d0b5d18 100644 --- a/Security.php +++ b/Security.php @@ -130,7 +130,7 @@ public function logout(bool $validateCsrfToken = true): ?Response if ($validateCsrfToken) { if (!$this->container->has('security.csrf.token_manager') || !$logoutConfig = $firewallConfig->getLogout()) { - throw new LogicException(sprintf('Unable to logout with CSRF token validation. Either make sure that CSRF protection is enabled and "logout" is configured on the "%s" firewall, or bypass CSRF token validation explicitly by passing false to the $validateCsrfToken argument of this method.', $firewallConfig->getName())); + throw new LogicException(\sprintf('Unable to logout with CSRF token validation. Either make sure that CSRF protection is enabled and "logout" is configured on the "%s" firewall, or bypass CSRF token validation explicitly by passing false to the $validateCsrfToken argument of this method.', $firewallConfig->getName())); } $csrfToken = ParameterBagUtils::getRequestParameterValue($request, $logoutConfig['csrf_parameter']); if (!\is_string($csrfToken) || !$this->container->get('security.csrf.token_manager')->isTokenValid(new CsrfToken($logoutConfig['csrf_token_id'], $csrfToken))) { @@ -149,7 +149,7 @@ public function logout(bool $validateCsrfToken = true): ?Response private function getAuthenticator(?string $authenticatorName, string $firewallName): AuthenticatorInterface { if (!isset($this->authenticators[$firewallName])) { - throw new LogicException(sprintf('No authenticators found for firewall "%s".', $firewallName)); + throw new LogicException(\sprintf('No authenticators found for firewall "%s".', $firewallName)); } /** @var ServiceProviderInterface $firewallAuthenticatorLocator */ @@ -159,10 +159,10 @@ private function getAuthenticator(?string $authenticatorName, string $firewallNa $authenticatorIds = array_keys($firewallAuthenticatorLocator->getProvidedServices()); if (!$authenticatorIds) { - throw new LogicException(sprintf('No authenticator was found for the firewall "%s".', $firewallName)); + throw new LogicException(\sprintf('No authenticator was found for the firewall "%s".', $firewallName)); } if (1 < \count($authenticatorIds)) { - throw new LogicException(sprintf('Too many authenticators were found for the current firewall "%s". You must provide an instance of "%s" to login programmatically. The available authenticators for the firewall "%s" are "%s".', $firewallName, AuthenticatorInterface::class, $firewallName, implode('" ,"', $authenticatorIds))); + throw new LogicException(\sprintf('Too many authenticators were found for the current firewall "%s". You must provide an instance of "%s" to login programmatically. The available authenticators for the firewall "%s" are "%s".', $firewallName, AuthenticatorInterface::class, $firewallName, implode('" ,"', $authenticatorIds))); } return $firewallAuthenticatorLocator->get($authenticatorIds[0]); @@ -175,7 +175,7 @@ private function getAuthenticator(?string $authenticatorName, string $firewallNa $authenticatorId = 'security.authenticator.'.$authenticatorName.'.'.$firewallName; if (!$firewallAuthenticatorLocator->has($authenticatorId)) { - throw new LogicException(sprintf('Unable to find an authenticator named "%s" for the firewall "%s". Available authenticators: "%s".', $authenticatorName, $firewallName, implode('", "', array_keys($firewallAuthenticatorLocator->getProvidedServices())))); + throw new LogicException(\sprintf('Unable to find an authenticator named "%s" for the firewall "%s". Available authenticators: "%s".', $authenticatorName, $firewallName, implode('", "', array_keys($firewallAuthenticatorLocator->getProvidedServices())))); } return $firewallAuthenticatorLocator->get($authenticatorId); diff --git a/Security/FirewallAwareTrait.php b/Security/FirewallAwareTrait.php index d4226753..f930d372 100644 --- a/Security/FirewallAwareTrait.php +++ b/Security/FirewallAwareTrait.php @@ -44,7 +44,7 @@ private function getForFirewall(): object if (!$this->locator->has($firewallName)) { $message = 'No '.$serviceIdentifier.' found for this firewall.'; if (\defined(static::class.'::FIREWALL_OPTION')) { - $message .= sprintf('Did you forget to add a "'.static::FIREWALL_OPTION.'" key under your "%s" firewall?', $firewallName); + $message .= \sprintf('Did you forget to add a "'.static::FIREWALL_OPTION.'" key under your "%s" firewall?', $firewallName); } throw new \LogicException($message); diff --git a/Tests/DependencyInjection/Security/Factory/AccessTokenFactoryTest.php b/Tests/DependencyInjection/Security/Factory/AccessTokenFactoryTest.php index 65e54af3..ce105759 100644 --- a/Tests/DependencyInjection/Security/Factory/AccessTokenFactoryTest.php +++ b/Tests/DependencyInjection/Security/Factory/AccessTokenFactoryTest.php @@ -214,7 +214,7 @@ public function testOidcTokenHandlerConfigurationWithSingleAlgorithm() 'index_0' => (new ChildDefinition('security.access_token_handler.oidc.signature')) ->replaceArgument(0, ['RS256']), 'index_1' => (new ChildDefinition('security.access_token_handler.oidc.jwkset')) - ->replaceArgument(0, sprintf('{"keys":[%s]}', $jwk)), + ->replaceArgument(0, \sprintf('{"keys":[%s]}', $jwk)), 'index_2' => 'audience', 'index_3' => ['https://www.example.com'], 'index_4' => 'sub', diff --git a/Tests/Functional/AccessTokenTest.php b/Tests/Functional/AccessTokenTest.php index 00c11bf4..8e87cd54 100644 --- a/Tests/Functional/AccessTokenTest.php +++ b/Tests/Functional/AccessTokenTest.php @@ -378,7 +378,7 @@ public function testOidcSuccess() ); $client = $this->createClient(['test_case' => 'AccessToken', 'root_config' => 'config_oidc.yml']); - $client->request('GET', '/foo', [], [], ['HTTP_AUTHORIZATION' => sprintf('Bearer %s', $token)]); + $client->request('GET', '/foo', [], [], ['HTTP_AUTHORIZATION' => \sprintf('Bearer %s', $token)]); $response = $client->getResponse(); $this->assertInstanceOf(Response::class, $response); diff --git a/Tests/Functional/Bundle/AccessTokenBundle/Controller/FooController.php b/Tests/Functional/Bundle/AccessTokenBundle/Controller/FooController.php index 7bc8e735..034c1d41 100644 --- a/Tests/Functional/Bundle/AccessTokenBundle/Controller/FooController.php +++ b/Tests/Functional/Bundle/AccessTokenBundle/Controller/FooController.php @@ -18,6 +18,6 @@ class FooController { public function __invoke(UserInterface $user): JsonResponse { - return new JsonResponse(['message' => sprintf('Welcome @%s!', $user->getUserIdentifier())]); + return new JsonResponse(['message' => \sprintf('Welcome @%s!', $user->getUserIdentifier())]); } } diff --git a/Tests/Functional/Bundle/AccessTokenBundle/Security/Http/JsonAuthenticationSuccessHandler.php b/Tests/Functional/Bundle/AccessTokenBundle/Security/Http/JsonAuthenticationSuccessHandler.php index d6148158..2d5139ed 100644 --- a/Tests/Functional/Bundle/AccessTokenBundle/Security/Http/JsonAuthenticationSuccessHandler.php +++ b/Tests/Functional/Bundle/AccessTokenBundle/Security/Http/JsonAuthenticationSuccessHandler.php @@ -21,6 +21,6 @@ class JsonAuthenticationSuccessHandler implements AuthenticationSuccessHandlerIn { public function onAuthenticationSuccess(Request $request, TokenInterface $token): ?Response { - return new JsonResponse(['message' => sprintf('Good game @%s!', $token->getUserIdentifier())]); + return new JsonResponse(['message' => \sprintf('Good game @%s!', $token->getUserIdentifier())]); } } diff --git a/Tests/Functional/Bundle/JsonLoginBundle/Controller/TestController.php b/Tests/Functional/Bundle/JsonLoginBundle/Controller/TestController.php index 6bd571d1..33cec70a 100644 --- a/Tests/Functional/Bundle/JsonLoginBundle/Controller/TestController.php +++ b/Tests/Functional/Bundle/JsonLoginBundle/Controller/TestController.php @@ -21,6 +21,6 @@ class TestController { public function loginCheckAction(UserInterface $user) { - return new JsonResponse(['message' => sprintf('Welcome @%s!', $user->getUserIdentifier())]); + return new JsonResponse(['message' => \sprintf('Welcome @%s!', $user->getUserIdentifier())]); } } diff --git a/Tests/Functional/Bundle/JsonLoginBundle/Security/Http/JsonAuthenticationSuccessHandler.php b/Tests/Functional/Bundle/JsonLoginBundle/Security/Http/JsonAuthenticationSuccessHandler.php index b7dd3fd3..d045636b 100644 --- a/Tests/Functional/Bundle/JsonLoginBundle/Security/Http/JsonAuthenticationSuccessHandler.php +++ b/Tests/Functional/Bundle/JsonLoginBundle/Security/Http/JsonAuthenticationSuccessHandler.php @@ -21,6 +21,6 @@ class JsonAuthenticationSuccessHandler implements AuthenticationSuccessHandlerIn { public function onAuthenticationSuccess(Request $request, TokenInterface $token): ?Response { - return new JsonResponse(['message' => sprintf('Good game @%s!', $token->getUserIdentifier())]); + return new JsonResponse(['message' => \sprintf('Good game @%s!', $token->getUserIdentifier())]); } } diff --git a/Tests/Functional/Bundle/LoginLink/TestCustomLoginLinkSuccessHandler.php b/Tests/Functional/Bundle/LoginLink/TestCustomLoginLinkSuccessHandler.php index 06997641..04caf251 100644 --- a/Tests/Functional/Bundle/LoginLink/TestCustomLoginLinkSuccessHandler.php +++ b/Tests/Functional/Bundle/LoginLink/TestCustomLoginLinkSuccessHandler.php @@ -21,6 +21,6 @@ class TestCustomLoginLinkSuccessHandler implements AuthenticationSuccessHandlerI { public function onAuthenticationSuccess(Request $request, TokenInterface $token): ?Response { - return new JsonResponse(['message' => sprintf('Welcome %s!', $token->getUserIdentifier())]); + return new JsonResponse(['message' => \sprintf('Welcome %s!', $token->getUserIdentifier())]); } } diff --git a/Tests/Functional/Bundle/SecuredPageBundle/Security/Core/User/ArrayUserProvider.php b/Tests/Functional/Bundle/SecuredPageBundle/Security/Core/User/ArrayUserProvider.php index 55b411da..784a0327 100644 --- a/Tests/Functional/Bundle/SecuredPageBundle/Security/Core/User/ArrayUserProvider.php +++ b/Tests/Functional/Bundle/SecuredPageBundle/Security/Core/User/ArrayUserProvider.php @@ -48,7 +48,7 @@ public function loadUserByIdentifier(string $identifier): UserInterface $user = $this->getUser($identifier); if (null === $user) { - $e = new UserNotFoundException(sprintf('User "%s" not found.', $identifier)); + $e = new UserNotFoundException(\sprintf('User "%s" not found.', $identifier)); $e->setUsername($identifier); throw $e; @@ -60,7 +60,7 @@ public function loadUserByIdentifier(string $identifier): UserInterface public function refreshUser(UserInterface $user): UserInterface { if (!$user instanceof UserInterface) { - throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_debug_type($user))); + throw new UnsupportedUserException(\sprintf('Instances of "%s" are not supported.', get_debug_type($user))); } $storedUser = $this->getUser($user->getUserIdentifier()); diff --git a/Tests/Functional/SecurityTest.php b/Tests/Functional/SecurityTest.php index 201c2a53..5345abee 100644 --- a/Tests/Functional/SecurityTest.php +++ b/Tests/Functional/SecurityTest.php @@ -250,7 +250,7 @@ public function welcome() $user = new InMemoryUser('chalasr', 'the-password', ['ROLE_FOO']); $this->security->login($user, $this->authenticator); - return new JsonResponse(['message' => sprintf('Welcome @%s!', $this->security->getUser()->getUserIdentifier())]); + return new JsonResponse(['message' => \sprintf('Welcome @%s!', $this->security->getUser()->getUserIdentifier())]); } } @@ -274,6 +274,6 @@ class LoggedInController { public function __invoke(UserInterface $user) { - return new JsonResponse(['message' => sprintf('Welcome back @%s', $user->getUserIdentifier())]); + return new JsonResponse(['message' => \sprintf('Welcome back @%s', $user->getUserIdentifier())]); } } diff --git a/Tests/Functional/app/AppKernel.php b/Tests/Functional/app/AppKernel.php index edac38dd..6fa8aedb 100644 --- a/Tests/Functional/app/AppKernel.php +++ b/Tests/Functional/app/AppKernel.php @@ -29,7 +29,7 @@ class AppKernel extends Kernel public function __construct($varDir, $testCase, $rootConfig, $environment, $debug) { if (!is_dir(__DIR__.'/'.$testCase)) { - throw new \InvalidArgumentException(sprintf('The test case "%s" does not exist.', $testCase)); + throw new \InvalidArgumentException(\sprintf('The test case "%s" does not exist.', $testCase)); } $this->varDir = $varDir; $this->testCase = $testCase; @@ -37,7 +37,7 @@ public function __construct($varDir, $testCase, $rootConfig, $environment, $debu $fs = new Filesystem(); foreach ((array) $rootConfig as $config) { if (!$fs->isAbsolutePath($config) && !is_file($config = __DIR__.'/'.$testCase.'/'.$config)) { - throw new \InvalidArgumentException(sprintf('The root config "%s" does not exist.', $config)); + throw new \InvalidArgumentException(\sprintf('The root config "%s" does not exist.', $config)); } $this->rootConfig[] = $config; @@ -54,7 +54,7 @@ public function getContainerClass(): string public function registerBundles(): iterable { if (!is_file($filename = $this->getProjectDir().'/'.$this->testCase.'/bundles.php')) { - throw new \RuntimeException(sprintf('The bundles file "%s" does not exist.', $filename)); + throw new \RuntimeException(\sprintf('The bundles file "%s" does not exist.', $filename)); } return include $filename; From adea9a15108c1854f59136da9c81f504598a7b54 Mon Sep 17 00:00:00 2001 From: Dariusz Ruminski Date: Sun, 16 Jun 2024 17:17:26 +0200 Subject: [PATCH 06/23] chore: CS fixes --- Resources/config/security_authenticator.php | 2 +- Tests/Functional/RememberMeCookieTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Resources/config/security_authenticator.php b/Resources/config/security_authenticator.php index 92c91e98..1ea4ef55 100644 --- a/Resources/config/security_authenticator.php +++ b/Resources/config/security_authenticator.php @@ -67,7 +67,7 @@ // Listeners ->set('security.listener.check_authenticator_credentials', CheckCredentialsListener::class) ->args([ - service('security.password_hasher_factory'), + service('security.password_hasher_factory'), ]) ->tag('kernel.event_subscriber') diff --git a/Tests/Functional/RememberMeCookieTest.php b/Tests/Functional/RememberMeCookieTest.php index d91b321b..34fbca10 100644 --- a/Tests/Functional/RememberMeCookieTest.php +++ b/Tests/Functional/RememberMeCookieTest.php @@ -24,7 +24,7 @@ public function testSessionRememberMeSecureCookieFlagAuto($https, $expectedSecur '_username' => 'test', '_password' => 'test', ], [], [ - 'HTTPS' => (int) $https, + 'HTTPS' => (int) $https, ]); $cookies = $client->getResponse()->headers->getCookies(ResponseHeaderBag::COOKIES_ARRAY); From 5b56a831c59d0b4c9dfc3a8462d1d69cc73a0914 Mon Sep 17 00:00:00 2001 From: MatTheCat Date: Wed, 19 Jun 2024 18:59:55 +0200 Subject: [PATCH 07/23] [Security] Display authenticators in the profiler even if they are all skipped --- Command/DebugFirewallCommand.php | 3 ++- DependencyInjection/SecurityExtension.php | 10 ++++++++++ Resources/views/Collector/security.html.twig | 2 +- Tests/Debug/TraceableFirewallListenerTest.php | 3 ++- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Command/DebugFirewallCommand.php b/Command/DebugFirewallCommand.php index 3f8b088f..e5994510 100644 --- a/Command/DebugFirewallCommand.php +++ b/Command/DebugFirewallCommand.php @@ -25,6 +25,7 @@ use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface; +use Symfony\Component\Security\Http\Authenticator\Debug\TraceableAuthenticator; /** * @author Timo Bakx @@ -210,7 +211,7 @@ private function displayAuthenticators(string $name, SymfonyStyle $io): void $io->table( ['Classname'], array_map( - fn ($authenticator) => [$authenticator::class], + fn ($authenticator) => [($authenticator instanceof TraceableAuthenticator ? $authenticator->getAuthenticator() : $authenticator)::class], $authenticators ) ); diff --git a/DependencyInjection/SecurityExtension.php b/DependencyInjection/SecurityExtension.php index 2fd97987..d6f65839 100644 --- a/DependencyInjection/SecurityExtension.php +++ b/DependencyInjection/SecurityExtension.php @@ -58,6 +58,7 @@ use Symfony\Component\Security\Core\User\ChainUserProvider; use Symfony\Component\Security\Core\User\UserCheckerInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; +use Symfony\Component\Security\Http\Authenticator\Debug\TraceableAuthenticator; use Symfony\Component\Security\Http\Authenticator\Debug\TraceableAuthenticatorManagerListener; use Symfony\Component\Security\Http\Event\CheckPassportEvent; use Symfony\Flex\Command\InstallRecipesCommand; @@ -638,6 +639,15 @@ private function createAuthenticationListeners(ContainerBuilder $container, stri } } + if ($container->hasDefinition('debug.security.firewall')) { + foreach ($authenticationProviders as $authenticatorId) { + $container->register('debug.'.$authenticatorId, TraceableAuthenticator::class) + ->setDecoratedService($authenticatorId) + ->setArguments([new Reference('debug.'.$authenticatorId.'.inner')]) + ; + } + } + // the actual entry point is configured by the RegisterEntryPointPass $container->setParameter('security.'.$id.'._indexed_authenticators', $entryPoints); diff --git a/Resources/views/Collector/security.html.twig b/Resources/views/Collector/security.html.twig index 4fe1140e..2715ed6a 100644 --- a/Resources/views/Collector/security.html.twig +++ b/Resources/views/Collector/security.html.twig @@ -360,7 +360,7 @@ {{ profiler_dump(authenticator.stub) }} - {{ source('@WebProfiler/Icon/' ~ (authenticator.supports ? 'yes' : 'no') ~ '.svg') }} + {{ source('@WebProfiler/Icon/' ~ (authenticator.supports is same as (false) ? 'no' : 'yes') ~ '.svg') }} {{ authenticator.authenticated is not null ? source('@WebProfiler/Icon/' ~ (authenticator.authenticated ? 'yes' : 'no') ~ '.svg') : '' }} {{ authenticator.duration is null ? '(none)' : '%0.2f ms'|format(authenticator.duration * 1000) }} {{ authenticator.passport ? profiler_dump(authenticator.passport) : '(none)' }} diff --git a/Tests/Debug/TraceableFirewallListenerTest.php b/Tests/Debug/TraceableFirewallListenerTest.php index 6dad1f3a..cdf53c20 100644 --- a/Tests/Debug/TraceableFirewallListenerTest.php +++ b/Tests/Debug/TraceableFirewallListenerTest.php @@ -22,6 +22,7 @@ use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Http\Authentication\AuthenticatorManager; +use Symfony\Component\Security\Http\Authenticator\Debug\TraceableAuthenticator; use Symfony\Component\Security\Http\Authenticator\Debug\TraceableAuthenticatorManagerListener; use Symfony\Component\Security\Http\Authenticator\InteractiveAuthenticatorInterface; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; @@ -99,7 +100,7 @@ public function testOnKernelRequestRecordsAuthenticatorsInfo() $tokenStorage = $this->createMock(TokenStorageInterface::class); $dispatcher = new EventDispatcher(); $authenticatorManager = new AuthenticatorManager( - [$notSupportingAuthenticator, $supportingAuthenticator], + [new TraceableAuthenticator($notSupportingAuthenticator), new TraceableAuthenticator($supportingAuthenticator)], $tokenStorage, $dispatcher, 'main' From 81e893c9cf5e714ca3f62716d581adf35528b1ff Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Thu, 20 Jun 2024 08:01:34 -0400 Subject: [PATCH 08/23] Lazy kernel.secret parameter resolving --- Resources/config/security_authenticator_login_link.php | 3 ++- Resources/config/security_authenticator_remember_me.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Resources/config/security_authenticator_login_link.php b/Resources/config/security_authenticator_login_link.php index 9a46a092..cb08d61b 100644 --- a/Resources/config/security_authenticator_login_link.php +++ b/Resources/config/security_authenticator_login_link.php @@ -12,6 +12,7 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; use Symfony\Bundle\SecurityBundle\LoginLink\FirewallAwareLoginLinkHandler; +use Symfony\Component\DependencyInjection\Parameter; use Symfony\Component\Security\Core\Signature\ExpiredSignatureStorage; use Symfony\Component\Security\Core\Signature\SignatureHasher; use Symfony\Component\Security\Http\Authenticator\LoginLinkAuthenticator; @@ -43,7 +44,7 @@ ->args([ service('property_accessor'), abstract_arg('signature properties'), - '%kernel.secret%', + new Parameter('kernel.secret'), abstract_arg('expired signature storage'), abstract_arg('max signature uses'), ]) diff --git a/Resources/config/security_authenticator_remember_me.php b/Resources/config/security_authenticator_remember_me.php index ecf93e50..d45c26df 100644 --- a/Resources/config/security_authenticator_remember_me.php +++ b/Resources/config/security_authenticator_remember_me.php @@ -12,6 +12,7 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; use Symfony\Bundle\SecurityBundle\RememberMe\FirewallAwareRememberMeHandler; +use Symfony\Component\DependencyInjection\Parameter; use Symfony\Component\Security\Core\Signature\SignatureHasher; use Symfony\Component\Security\Http\Authenticator\RememberMeAuthenticator; use Symfony\Component\Security\Http\EventListener\CheckRememberMeConditionsListener; @@ -30,7 +31,7 @@ ->args([ service('property_accessor'), abstract_arg('signature properties'), - '%kernel.secret%', + new Parameter('kernel.secret'), null, null, ]) From c99d9df97cb7b432e734465b7a3c0dbbb9189d4d Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 6 Jul 2024 09:57:16 +0200 Subject: [PATCH 09/23] Update .gitattributes --- .gitattributes | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitattributes b/.gitattributes index 84c7add0..14c3c359 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,3 @@ /Tests export-ignore /phpunit.xml.dist export-ignore -/.gitattributes export-ignore -/.gitignore export-ignore +/.git* export-ignore From 0491189bc2d8290d92d85a5483df028e8fc9e409 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 6 Jul 2024 07:42:08 +0200 Subject: [PATCH 10/23] do not use uniqid() in tests --- Tests/Functional/CsrfFormLoginTest.php | 2 +- Tests/Functional/LogoutTest.php | 2 +- Tests/Functional/SecurityTest.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/Functional/CsrfFormLoginTest.php b/Tests/Functional/CsrfFormLoginTest.php index 6df9aa5f..ee8cc60a 100644 --- a/Tests/Functional/CsrfFormLoginTest.php +++ b/Tests/Functional/CsrfFormLoginTest.php @@ -142,7 +142,7 @@ private function callInRequestContext(KernelBrowser $client, callable $callable) $eventDispatcher->addListener(KernelEvents::REQUEST, $wrappedCallable); try { - $client->request('GET', '/'.uniqid('', true)); + $client->request('GET', '/not-existent'); } finally { $eventDispatcher->removeListener(KernelEvents::REQUEST, $wrappedCallable); } diff --git a/Tests/Functional/LogoutTest.php b/Tests/Functional/LogoutTest.php index 50473ed8..d11c535d 100644 --- a/Tests/Functional/LogoutTest.php +++ b/Tests/Functional/LogoutTest.php @@ -90,7 +90,7 @@ private function callInRequestContext(KernelBrowser $client, callable $callable) $eventDispatcher->addListener(KernelEvents::REQUEST, $wrappedCallable); try { - $client->request('GET', '/'.uniqid('', true)); + $client->request('GET', '/not-existent'); } finally { $eventDispatcher->removeListener(KernelEvents::REQUEST, $wrappedCallable); } diff --git a/Tests/Functional/SecurityTest.php b/Tests/Functional/SecurityTest.php index 5345abee..dadd0d69 100644 --- a/Tests/Functional/SecurityTest.php +++ b/Tests/Functional/SecurityTest.php @@ -134,7 +134,7 @@ public function testLogoutWithCsrf() }; $eventDispatcher->addListener(KernelEvents::REQUEST, $setCsrfToken); try { - $client->request('GET', '/'.uniqid('', true)); + $client->request('GET', '/not-existent'); } finally { $eventDispatcher->removeListener(KernelEvents::REQUEST, $setCsrfToken); } From 0b67ba03155ec87dcbd2666a6d45b1c05a6fca35 Mon Sep 17 00:00:00 2001 From: Florent Morselli Date: Tue, 9 Jul 2024 16:59:11 +0200 Subject: [PATCH 11/23] Update web-token/jwt-library version and adjust checker parameters The web-token/jwt-library has been updated to allow versions up to 4.0 across multiple components. Additionally, the parameters for the IssuedAtChecker, NotBeforeChecker, and ExpirationTimeChecker in the OidcTokenHandler have been adjusted to support named arguments as required by the new version of the library. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index ca85d486..7267fa75 100644 --- a/composer.json +++ b/composer.json @@ -51,7 +51,7 @@ "symfony/validator": "^6.4|^7.0", "symfony/yaml": "^6.4|^7.0", "twig/twig": "^3.0.4", - "web-token/jwt-library": "^3.3.2" + "web-token/jwt-library": "^3.3.2|^4.0" }, "conflict": { "symfony/browser-kit": "<6.4", From f0b504e6927dfb02f6fa91a6ec955e197b7f34d4 Mon Sep 17 00:00:00 2001 From: MatTheCat Date: Tue, 9 Jul 2024 19:18:49 +0200 Subject: [PATCH 12/23] [SecurityBundle] Link to the profile the token was (de)authenticated --- DataCollector/SecurityDataCollector.php | 32 ++++++++++++++++++++ Resources/views/Collector/security.html.twig | 21 ++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/DataCollector/SecurityDataCollector.php b/DataCollector/SecurityDataCollector.php index 826d6c99..1bfcdcbf 100644 --- a/DataCollector/SecurityDataCollector.php +++ b/DataCollector/SecurityDataCollector.php @@ -13,6 +13,7 @@ use Symfony\Bundle\SecurityBundle\Debug\TraceableFirewallListener; use Symfony\Bundle\SecurityBundle\Security\FirewallMap; +use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\DataCollector\DataCollector; @@ -195,6 +196,27 @@ public function collect(Request $request, Response $response, ?\Throwable $excep } $this->data['authenticators'] = $this->firewall ? $this->firewall->getAuthenticatorsInfo() : []; + + if ($this->data['listeners'] && !($this->data['firewall']['stateless'] ?? true)) { + $authCookieName = "{$this->data['firewall']['name']}_auth_profile_token"; + $deauthCookieName = "{$this->data['firewall']['name']}_deauth_profile_token"; + $profileToken = $response->headers->get('X-Debug-Token'); + + $this->data['auth_profile_token'] = $request->cookies->get($authCookieName); + $this->data['deauth_profile_token'] = $request->cookies->get($deauthCookieName); + + if ($this->data['authenticated'] && !$this->data['auth_profile_token']) { + $response->headers->setCookie(new Cookie($authCookieName, $profileToken)); + + $this->data['deauth_profile_token'] = null; + $response->headers->clearCookie($deauthCookieName); + } elseif(!$this->data['authenticated'] && !$this->data['deauth_profile_token']) { + $response->headers->setCookie(new Cookie($deauthCookieName, $profileToken)); + + $this->data['auth_profile_token'] = null; + $response->headers->clearCookie($authCookieName); + } + } } public function reset(): void @@ -339,6 +361,16 @@ public function getAuthenticators(): array|Data return $this->data['authenticators']; } + public function getAuthProfileToken(): string|Data|null + { + return $this->data['auth_profile_token'] ?? null; + } + + public function getDeauthProfileToken(): string|Data|null + { + return $this->data['deauth_profile_token'] ?? null; + } + public function getName(): string { return 'security'; diff --git a/Resources/views/Collector/security.html.twig b/Resources/views/Collector/security.html.twig index 2715ed6a..ecb08283 100644 --- a/Resources/views/Collector/security.html.twig +++ b/Resources/views/Collector/security.html.twig @@ -181,6 +181,17 @@ {{ source('@WebProfiler/Icon/' ~ (collector.authenticated ? 'yes' : 'no') ~ '.svg') }} Authenticated + + {% if collector.authProfileToken %} + + {% endif %} @@ -219,7 +230,15 @@
{% elseif collector.enabled %}
-

There is no security token.

+

+ There is no security token. + {% if collector.deauthProfileToken %} + It was removed in + + {{- collector.deauthProfileToken -}} + . + {% endif %} +

{% endif %} From ff7e40d779ed83cf7725f8a459d97362bf6b78db Mon Sep 17 00:00:00 2001 From: MatTheCat Date: Mon, 24 Jun 2024 16:29:05 +0200 Subject: [PATCH 13/23] [SecurityBundle] Improve authenticators tab --- Resources/views/Collector/security.html.twig | 161 ++++++++++++++----- 1 file changed, 118 insertions(+), 43 deletions(-) diff --git a/Resources/views/Collector/security.html.twig b/Resources/views/Collector/security.html.twig index ecb08283..635d61e2 100644 --- a/Resources/views/Collector/security.html.twig +++ b/Resources/views/Collector/security.html.twig @@ -29,10 +29,50 @@ padding: 0 0 8px 0; } + #collector-content .authenticator-name { + align-items: center; + display: flex; + gap: 16px; + } + + #collector-content .authenticators .toggle-button { + margin-left: auto; + } + #collector-content .authenticators .sf-toggle-on .toggle-button { + transform: rotate(180deg); + } + #collector-content .authenticators .toggle-button svg { + display: block; + } + + #collector-content .authenticators th, + #collector-content .authenticators td { + vertical-align: baseline; + } + #collector-content .authenticators th, + #collector-content .authenticators td { + vertical-align: baseline; + } + + #collector-content .authenticators .label { + display: block; + text-align: center; + } + + #collector-content .authenticator-data { + box-shadow: none; + margin: 0; + } + + #collector-content .authenticator-data tr:first-child th, + #collector-content .authenticator-data tr:first-child td { + border-top: 0; + } + #collector-content .authenticators .badge { color: var(--white); display: inline-block; - text-align: center; + margin: 4px 0; } #collector-content .authenticators .badge.badge-resolved { background-color: var(--green-500); @@ -40,13 +80,6 @@ #collector-content .authenticators .badge.badge-not_resolved { background-color: var(--yellow-500); } - - #collector-content .authenticators svg[data-icon-name="icon-tabler-check"] { - color: var(--green-500); - } - #collector-content .authenticators svg[data-icon-name="icon-tabler-x"] { - color: var(--red-500); - } {% endblock %} @@ -355,48 +388,90 @@
{% if collector.authenticators|default([]) is not empty %} + + + + - - - - - - + + - - {% set previous_event = (collector.listeners|first) %} - {% for authenticator in collector.authenticators %} - {% if loop.first or authenticator != previous_event %} - {% if not loop.first %} - - {% endif %} - - - {% set previous_event = authenticator %} - {% endif %} - - - - - - - - + + - - {% if loop.last %} - - {% endif %} {% endfor %}
AuthenticatorSupportsAuthenticatedDurationPassportBadgesStatusAuthenticator
{{ profiler_dump(authenticator.stub) }}{{ source('@WebProfiler/Icon/' ~ (authenticator.supports is same as (false) ? 'no' : 'yes') ~ '.svg') }}{{ authenticator.authenticated is not null ? source('@WebProfiler/Icon/' ~ (authenticator.authenticated ? 'yes' : 'no') ~ '.svg') : '' }}{{ authenticator.duration is null ? '(none)' : '%0.2f ms'|format(authenticator.duration * 1000) }}{{ authenticator.passport ? profiler_dump(authenticator.passport) : '(none)' }} - {% for badge in authenticator.badges ?? [] %} - - {{ badge.stub|abbr_class }} - + {% for i, authenticator in collector.authenticators %} +
+ {% if authenticator.authenticated %} + {% set status_text, label_status = 'success', 'success' %} + {% elseif authenticator.authenticated is null %} + {% set status_text, label_status = 'skipped', false %} {% else %} - (none) - {% endfor %} + {% set status_text, label_status = 'failure', 'error' %} + {% endif %} + {{ status_text }} + + + {{ profiler_dump(authenticator.stub) }} + + +
+ {% if authenticator.supports is same as(false) %} +
+

This authenticator did not support the request.

+
+ {% elseif authenticator.authenticated is null %} +
+

An authenticator ran before this one.

+
+ {% else %} + + + + + + + + + + + + + + {% if authenticator.passport %} + + + + + {% endif %} + {% if authenticator.badges %} + + + + + {% endif %} + {% if authenticator.exception %} + + + + + {% endif %} +
Lazy{{ authenticator.supports is null ? 'yes' : 'no' }}
Duration{{ '%0.2f ms'|format(authenticator.duration * 1000) }}
Passport{{ profiler_dump(authenticator.passport) }}
Badges + {% for badge in authenticator.badges %} + + {{ badge.stub|abbr_class }} + + {% endfor %} +
Exception{{ profiler_dump(authenticator.exception) }}
+ {% endif %} +
{% else %} From 1ea963704664f323ca01bf16492cf977b169a84e Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 5 Aug 2024 09:12:25 +0200 Subject: [PATCH 14/23] Fix multiple CS errors --- DataCollector/SecurityDataCollector.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DataCollector/SecurityDataCollector.php b/DataCollector/SecurityDataCollector.php index 1bfcdcbf..f3c1cd1f 100644 --- a/DataCollector/SecurityDataCollector.php +++ b/DataCollector/SecurityDataCollector.php @@ -210,7 +210,7 @@ public function collect(Request $request, Response $response, ?\Throwable $excep $this->data['deauth_profile_token'] = null; $response->headers->clearCookie($deauthCookieName); - } elseif(!$this->data['authenticated'] && !$this->data['deauth_profile_token']) { + } elseif (!$this->data['authenticated'] && !$this->data['deauth_profile_token']) { $response->headers->setCookie(new Cookie($deauthCookieName, $profileToken)); $this->data['auth_profile_token'] = null; From 13c964c39ceb113c8b1e27b949ca99d6d90d4c3d Mon Sep 17 00:00:00 2001 From: Roy de Vos Burchart Date: Thu, 1 Aug 2024 17:21:17 +0200 Subject: [PATCH 15/23] Code style change in `@PER-CS2.0` affecting `@Symfony` (parentheses for anonymous classes) --- Tests/DataCollector/SecurityDataCollectorTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/DataCollector/SecurityDataCollectorTest.php b/Tests/DataCollector/SecurityDataCollectorTest.php index e4173b1f..21161d28 100644 --- a/Tests/DataCollector/SecurityDataCollectorTest.php +++ b/Tests/DataCollector/SecurityDataCollectorTest.php @@ -226,7 +226,7 @@ public function testCollectCollectsDecisionLogWhenStrategyIsAffirmative() $voter1 = new DummyVoter(); $voter2 = new DummyVoter(); - $decoratedVoter1 = new TraceableVoter($voter1, new class() implements EventDispatcherInterface { + $decoratedVoter1 = new TraceableVoter($voter1, new class implements EventDispatcherInterface { public function dispatch(object $event, ?string $eventName = null): object { return new \stdClass(); @@ -301,7 +301,7 @@ public function testCollectCollectsDecisionLogWhenStrategyIsUnanimous() $voter1 = new DummyVoter(); $voter2 = new DummyVoter(); - $decoratedVoter1 = new TraceableVoter($voter1, new class() implements EventDispatcherInterface { + $decoratedVoter1 = new TraceableVoter($voter1, new class implements EventDispatcherInterface { public function dispatch(object $event, ?string $eventName = null): object { return new \stdClass(); From f138aa3536d32dc8523027268035bc03d7fdfac6 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 29 Jul 2024 09:33:48 +0200 Subject: [PATCH 16/23] Remove useless code --- DependencyInjection/SecurityExtension.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DependencyInjection/SecurityExtension.php b/DependencyInjection/SecurityExtension.php index 27cb4062..622b853d 100644 --- a/DependencyInjection/SecurityExtension.php +++ b/DependencyInjection/SecurityExtension.php @@ -307,7 +307,7 @@ private function createFirewalls(array $config, ContainerBuilder $container): vo $configId = 'security.firewall.map.config.'.$name; - [$matcher, $listeners, $exceptionListener, $logoutListener, $firewallAuthenticators] = $this->createFirewall($container, $name, $firewall, $authenticationProviders, $providerIds, $configId); + [$matcher, $listeners, $exceptionListener, $logoutListener, $firewallAuthenticators] = $this->createFirewall($container, $name, $firewall, $providerIds, $configId); if (!$firewallAuthenticators) { $authenticators[$name] = null; @@ -348,7 +348,7 @@ private function createFirewalls(array $config, ContainerBuilder $container): vo } } - private function createFirewall(ContainerBuilder $container, string $id, array $firewall, array &$authenticationProviders, array $providerIds, string $configId): array + private function createFirewall(ContainerBuilder $container, string $id, array $firewall, array $providerIds, string $configId): array { $config = $container->setDefinition($configId, new ChildDefinition('security.firewall.config')); $config->replaceArgument(0, $id); From 095f4d59b45459996a6ef8645b787ec2b08f0dc1 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 29 Aug 2024 10:25:47 +0200 Subject: [PATCH 17/23] bump requirement for Twig to 3.12+ --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 075fd35e..8660196a 100644 --- a/composer.json +++ b/composer.json @@ -50,7 +50,7 @@ "symfony/twig-bridge": "^6.4|^7.0", "symfony/validator": "^6.4|^7.0", "symfony/yaml": "^6.4|^7.0", - "twig/twig": "^3.0.4", + "twig/twig": "^3.12", "web-token/jwt-library": "^3.3.2|^4.0" }, "conflict": { From b686c477b1a797bb391d3cb2ace2cbbc1f52b48a Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 2 Sep 2024 14:07:48 +0200 Subject: [PATCH 18/23] Fix configurations info consistency --- DependencyInjection/MainConfiguration.php | 4 ++-- .../Security/Factory/CustomAuthenticatorFactory.php | 2 +- .../Security/Factory/LoginThrottlingFactory.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/DependencyInjection/MainConfiguration.php b/DependencyInjection/MainConfiguration.php index 98ef9e9f..a4527606 100644 --- a/DependencyInjection/MainConfiguration.php +++ b/DependencyInjection/MainConfiguration.php @@ -135,7 +135,7 @@ private function addAccessControlSection(ArrayNodeDefinition $rootNode): void ->scalarNode('requires_channel')->defaultNull()->end() ->scalarNode('path') ->defaultNull() - ->info('use the urldecoded format') + ->info('Use the urldecoded format.') ->example('^/path to resource/') ->end() ->scalarNode('host')->defaultNull()->end() @@ -208,7 +208,7 @@ private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $facto ->scalarNode('access_denied_url')->end() ->scalarNode('access_denied_handler')->end() ->scalarNode('entry_point') - ->info(\sprintf('An enabled authenticator name or a service id that implements "%s"', AuthenticationEntryPointInterface::class)) + ->info(\sprintf('An enabled authenticator name or a service id that implements "%s".', AuthenticationEntryPointInterface::class)) ->end() ->scalarNode('provider')->end() ->booleanNode('stateless')->defaultFalse()->end() diff --git a/DependencyInjection/Security/Factory/CustomAuthenticatorFactory.php b/DependencyInjection/Security/Factory/CustomAuthenticatorFactory.php index e443122e..ee9899ea 100644 --- a/DependencyInjection/Security/Factory/CustomAuthenticatorFactory.php +++ b/DependencyInjection/Security/Factory/CustomAuthenticatorFactory.php @@ -38,7 +38,7 @@ public function getKey(): string public function addConfiguration(NodeDefinition $builder): void { $builder - ->info('An array of service ids for all of your "authenticators"') + ->info('An array of service ids for all of your "authenticators".') ->requiresAtLeastOneElement() ->prototype('scalar')->end(); diff --git a/DependencyInjection/Security/Factory/LoginThrottlingFactory.php b/DependencyInjection/Security/Factory/LoginThrottlingFactory.php index cc20b5db..93818f5a 100644 --- a/DependencyInjection/Security/Factory/LoginThrottlingFactory.php +++ b/DependencyInjection/Security/Factory/LoginThrottlingFactory.php @@ -52,7 +52,7 @@ public function addConfiguration(NodeDefinition $builder): void ->scalarNode('limiter')->info(\sprintf('A service id implementing "%s".', RequestRateLimiterInterface::class))->end() ->integerNode('max_attempts')->defaultValue(5)->end() ->scalarNode('interval')->defaultValue('1 minute')->end() - ->scalarNode('lock_factory')->info('The service ID of the lock factory used by the login rate limiter (or null to disable locking)')->defaultNull()->end() + ->scalarNode('lock_factory')->info('The service ID of the lock factory used by the login rate limiter (or null to disable locking).')->defaultNull()->end() ->end(); } From ea9cd5371efb0625dbcaab35704da85dd5f84106 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 30 Aug 2024 09:35:32 +0200 Subject: [PATCH 19/23] allow Twig 4 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 8660196a..daef38d0 100644 --- a/composer.json +++ b/composer.json @@ -50,7 +50,7 @@ "symfony/twig-bridge": "^6.4|^7.0", "symfony/validator": "^6.4|^7.0", "symfony/yaml": "^6.4|^7.0", - "twig/twig": "^3.12", + "twig/twig": "^3.12|^4.0", "web-token/jwt-library": "^3.3.2|^4.0" }, "conflict": { From 2972115a218cecc2e0ad4f74dffe95d0b80a52e4 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Tue, 3 Sep 2024 21:44:45 +0200 Subject: [PATCH 20/23] [Security][SecurityBundle] Allow passing attributes to passport via `Security::login()` --- CHANGELOG.md | 1 + Security.php | 13 +++++++------ Security/UserAuthenticator.php | 4 ++-- Tests/SecurityTest.php | 6 ++++-- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba27f213..43c17dc2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG --- * Allow configuring the secret used to sign login links + * Allow passing optional passport attributes to `Security::login()` 7.1 --- diff --git a/Security.php b/Security.php index 95a16bc2..915f766f 100644 --- a/Security.php +++ b/Security.php @@ -74,14 +74,15 @@ public function getFirewallConfig(Request $request): ?FirewallConfig } /** - * @param UserInterface $user The user to authenticate - * @param string|null $authenticatorName The authenticator name (e.g. "form_login") or service id (e.g. SomeApiKeyAuthenticator::class) - required only if multiple authenticators are configured - * @param string|null $firewallName The firewall name - required only if multiple firewalls are configured - * @param BadgeInterface[] $badges Badges to add to the user's passport + * @param UserInterface $user The user to authenticate + * @param string|null $authenticatorName The authenticator name (e.g. "form_login") or service id (e.g. SomeApiKeyAuthenticator::class) - required only if multiple authenticators are configured + * @param string|null $firewallName The firewall name - required only if multiple firewalls are configured + * @param BadgeInterface[] $badges Badges to add to the user's passport + * @param array $attributes Attributes to add to the user's passport * * @return Response|null The authenticator success response if any */ - public function login(UserInterface $user, ?string $authenticatorName = null, ?string $firewallName = null, array $badges = []): ?Response + public function login(UserInterface $user, ?string $authenticatorName = null, ?string $firewallName = null, array $badges = [], array $attributes = []): ?Response { $request = $this->container->get('request_stack')->getCurrentRequest(); if (null === $request) { @@ -99,7 +100,7 @@ public function login(UserInterface $user, ?string $authenticatorName = null, ?s $userCheckerLocator = $this->container->get('security.user_checker_locator'); $userCheckerLocator->get($firewallName)->checkPreAuth($user); - return $this->container->get('security.authenticator.managers_locator')->get($firewallName)->authenticateUser($user, $authenticator, $request, $badges); + return $this->container->get('security.authenticator.managers_locator')->get($firewallName)->authenticateUser($user, $authenticator, $request, $badges, $attributes); } /** diff --git a/Security/UserAuthenticator.php b/Security/UserAuthenticator.php index 78645780..8989d895 100644 --- a/Security/UserAuthenticator.php +++ b/Security/UserAuthenticator.php @@ -38,8 +38,8 @@ public function __construct(FirewallMap $firewallMap, ContainerInterface $userAu $this->requestStack = $requestStack; } - public function authenticateUser(UserInterface $user, AuthenticatorInterface $authenticator, Request $request, array $badges = []): ?Response + public function authenticateUser(UserInterface $user, AuthenticatorInterface $authenticator, Request $request, array $badges = [], array $attributes = []): ?Response { - return $this->getForFirewall()->authenticateUser($user, $authenticator, $request, $badges); + return $this->getForFirewall()->authenticateUser($user, $authenticator, $request, $badges, $attributes); } } diff --git a/Tests/SecurityTest.php b/Tests/SecurityTest.php index b7df6e09..d4b336b4 100644 --- a/Tests/SecurityTest.php +++ b/Tests/SecurityTest.php @@ -33,6 +33,7 @@ use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; use Symfony\Component\Security\Http\Authentication\UserAuthenticatorInterface; use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface; +use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; use Symfony\Component\Security\Http\Event\LogoutEvent; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; use Symfony\Contracts\Service\ServiceProviderInterface; @@ -135,6 +136,7 @@ public function testLogin() $userAuthenticator = $this->createMock(UserAuthenticatorInterface::class); $user = $this->createMock(UserInterface::class); $userChecker = $this->createMock(UserCheckerInterface::class); + $badge = new UserBadge('foo'); $container = new Container(); $container->set('request_stack', $requestStack); @@ -143,7 +145,7 @@ public function testLogin() $container->set('security.user_checker_locator', $this->createContainer('main', $userChecker)); $firewallMap->expects($this->once())->method('getFirewallConfig')->willReturn($firewall); - $userAuthenticator->expects($this->once())->method('authenticateUser')->with($user, $authenticator, $request); + $userAuthenticator->expects($this->once())->method('authenticateUser')->with($user, $authenticator, $request, [$badge], ['foo' => 'bar']); $userChecker->expects($this->once())->method('checkPreAuth')->with($user); $firewallAuthenticatorLocator = $this->createMock(ServiceProviderInterface::class); @@ -161,7 +163,7 @@ public function testLogin() $security = new Security($container, ['main' => $firewallAuthenticatorLocator]); - $security->login($user); + $security->login($user, badges: [$badge], attributes: ['foo' => 'bar']); } public function testLoginReturnsAuthenticatorResponse() From c4652f9a702f7f365909dc16e8b011a98e149b1e Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Thu, 26 Sep 2024 10:09:09 +0200 Subject: [PATCH 21/23] Remove unused imports --- Tests/DependencyInjection/XmlCustomAuthenticatorTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Tests/DependencyInjection/XmlCustomAuthenticatorTest.php b/Tests/DependencyInjection/XmlCustomAuthenticatorTest.php index de3db233..e57cda13 100644 --- a/Tests/DependencyInjection/XmlCustomAuthenticatorTest.php +++ b/Tests/DependencyInjection/XmlCustomAuthenticatorTest.php @@ -14,7 +14,6 @@ use PHPUnit\Framework\TestCase; use Symfony\Bundle\SecurityBundle\DependencyInjection\SecurityExtension; use Symfony\Bundle\SecurityBundle\Tests\DependencyInjection\Fixtures\Authenticator\CustomAuthenticator; -use Symfony\Bundle\SecurityBundle\Tests\DependencyInjection\Fixtures\UserProvider\CustomProvider; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; From 697da80f01b65bde46776fc6085ead8b04560c2a Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Fri, 18 Oct 2024 16:04:52 +0200 Subject: [PATCH 22/23] Remove always true/false occurrences --- .../Compiler/ReplaceDecoratedRememberMeHandlerPass.php | 3 --- .../Security/Core/User/ArrayUserProvider.php | 5 ----- 2 files changed, 8 deletions(-) diff --git a/DependencyInjection/Compiler/ReplaceDecoratedRememberMeHandlerPass.php b/DependencyInjection/Compiler/ReplaceDecoratedRememberMeHandlerPass.php index 742d3c08..371617bd 100644 --- a/DependencyInjection/Compiler/ReplaceDecoratedRememberMeHandlerPass.php +++ b/DependencyInjection/Compiler/ReplaceDecoratedRememberMeHandlerPass.php @@ -37,9 +37,6 @@ public function process(ContainerBuilder $container): void // get the actual custom remember me handler definition (passed to the decorator) $realRememberMeHandler = $container->findDefinition((string) $definition->getArgument(0)); - if (null === $realRememberMeHandler) { - throw new \LogicException(\sprintf('Invalid service definition for custom remember me handler; no service found with ID "%s".', (string) $definition->getArgument(0))); - } foreach ($rememberMeHandlerTags as $rememberMeHandlerTag) { // some custom handlers may be used on multiple firewalls in the same application diff --git a/Tests/Functional/Bundle/SecuredPageBundle/Security/Core/User/ArrayUserProvider.php b/Tests/Functional/Bundle/SecuredPageBundle/Security/Core/User/ArrayUserProvider.php index 784a0327..553cff38 100644 --- a/Tests/Functional/Bundle/SecuredPageBundle/Security/Core/User/ArrayUserProvider.php +++ b/Tests/Functional/Bundle/SecuredPageBundle/Security/Core/User/ArrayUserProvider.php @@ -12,7 +12,6 @@ namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\SecuredPageBundle\Security\Core\User; use Symfony\Bundle\SecurityBundle\Tests\Functional\UserWithoutEquatable; -use Symfony\Component\Security\Core\Exception\UnsupportedUserException; use Symfony\Component\Security\Core\Exception\UserNotFoundException; use Symfony\Component\Security\Core\User\InMemoryUser; use Symfony\Component\Security\Core\User\UserInterface; @@ -59,10 +58,6 @@ public function loadUserByIdentifier(string $identifier): UserInterface public function refreshUser(UserInterface $user): UserInterface { - if (!$user instanceof UserInterface) { - throw new UnsupportedUserException(\sprintf('Instances of "%s" are not supported.', get_debug_type($user))); - } - $storedUser = $this->getUser($user->getUserIdentifier()); $class = $storedUser::class; From 97bb7921ae763bb44355464c6cd28d92b220b162 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 23 Oct 2024 10:11:04 +0200 Subject: [PATCH 23/23] revert allowing Twig 4 As Twig 4 will not be released before Symfony 7.2 we should not claim compatibility before a stable Twig 4 release. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index daef38d0..8660196a 100644 --- a/composer.json +++ b/composer.json @@ -50,7 +50,7 @@ "symfony/twig-bridge": "^6.4|^7.0", "symfony/validator": "^6.4|^7.0", "symfony/yaml": "^6.4|^7.0", - "twig/twig": "^3.12|^4.0", + "twig/twig": "^3.12", "web-token/jwt-library": "^3.3.2|^4.0" }, "conflict": {