diff --git a/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md b/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md index ae7c1d9164702..852d518d7fdbc 100644 --- a/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +5.2.0 +----- + + * Added `FirewallListenerFactoryInterface`, which can be implemented by security factories to add firewall listeners + 5.1.0 ----- diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FirewallListenerFactoryInterface.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FirewallListenerFactoryInterface.php new file mode 100644 index 0000000000000..c4842010a779f --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FirewallListenerFactoryInterface.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory; + +use Symfony\Component\DependencyInjection\ContainerBuilder; + +/** + * Can be implemented by a security factory to add a listener to the firewall. + * + * @author Christian Scheb + */ +interface FirewallListenerFactoryInterface +{ + /** + * Creates the firewall listener services for the provided configuration. + * + * @return string[] The listener service IDs to be used by the firewall + */ + public function createListeners(ContainerBuilder $container, string $firewallName, array $config): array; +} diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index dd80c5c3b163b..c1f63abd17efe 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -13,6 +13,7 @@ use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AuthenticatorFactoryInterface; use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\EntryPointFactoryInterface; +use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\FirewallListenerFactoryInterface; use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\RememberMeFactory; use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface; use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider\UserProviderFactoryInterface; @@ -570,6 +571,14 @@ private function createAuthenticationListeners(ContainerBuilder $container, stri $listeners[] = new Reference($listenerId); $authenticationProviders[] = $provider; } + + if ($factory instanceof FirewallListenerFactoryInterface) { + $firewallListenerIds = $factory->createListeners($container, $id, $firewall[$key]); + foreach ($firewallListenerIds as $firewallListenerId) { + $listeners[] = new Reference($firewallListenerId); + } + } + $hasListeners = true; } } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php index b2595dc4346c1..13b37df75f28f 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php @@ -13,11 +13,14 @@ use PHPUnit\Framework\TestCase; use Symfony\Bundle\FrameworkBundle\DependencyInjection\FrameworkExtension; +use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\FirewallListenerFactoryInterface; +use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface; use Symfony\Bundle\SecurityBundle\DependencyInjection\SecurityExtension; use Symfony\Bundle\SecurityBundle\SecurityBundle; use Symfony\Bundle\SecurityBundle\Tests\DependencyInjection\Fixtures\UserProvider\DummyProvider; use Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\FirewallEntryPointBundle\Security\EntryPointStub; use Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\GuardedBundle\AppCustomAuthenticator; +use Symfony\Component\Config\Definition\Builder\NodeDefinition; use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -601,6 +604,29 @@ public function testCompilesWithSessionListenerWithStatefulllFirewallWithAuthent $this->assertTrue($container->has('security.listener.session.'.$firewallId)); } + public function testConfigureCustomFirewallListener(): void + { + $container = $this->getRawContainer(); + /** @var SecurityExtension $extension */ + $extension = $container->getExtension('security'); + $extension->addSecurityListenerFactory(new TestFirewallListenerFactory()); + + $container->loadFromExtension('security', [ + 'firewalls' => [ + 'main' => [ + 'custom_listener' => true, + ], + ], + ]); + + $container->compile(); + + /** @var IteratorArgument $listenersIteratorArgument */ + $listenersIteratorArgument = $container->getDefinition('security.firewall.map.context.main')->getArgument(0); + $firewallListeners = array_map('strval', $listenersIteratorArgument->getValues()); + $this->assertContains('custom_firewall_listener_id', $firewallListeners); + } + protected function getRawContainer() { $container = new ContainerBuilder(); @@ -689,3 +715,30 @@ public function supportsRememberMe() { } } + +class TestFirewallListenerFactory implements SecurityFactoryInterface, FirewallListenerFactoryInterface +{ + public function createListeners(ContainerBuilder $container, string $firewallName, array $config): array + { + return ['custom_firewall_listener_id']; + } + + public function create(ContainerBuilder $container, string $id, array $config, string $userProvider, ?string $defaultEntryPoint) + { + return ['provider_id', 'listener_id', $defaultEntryPoint]; + } + + public function getPosition() + { + return 'form'; + } + + public function getKey() + { + return 'custom_listener'; + } + + public function addConfiguration(NodeDefinition $builder) + { + } +}