diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/CustomAuthenticatorFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/CustomAuthenticatorFactory.php index 35984ca8be..d9245b0616 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/CustomAuthenticatorFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/CustomAuthenticatorFactory.php @@ -35,7 +35,7 @@ class CustomAuthenticatorFactory implements AuthenticatorFactoryInterface, Secur public function getKey(): string { - return 'custom_authenticator'; + return 'custom_authenticators'; } /** @@ -44,19 +44,27 @@ class CustomAuthenticatorFactory implements AuthenticatorFactoryInterface, Secur public function addConfiguration(NodeDefinition $builder) { $builder - ->fixXmlConfig('service') - ->children() - ->arrayNode('services') - ->info('An array of service ids for all of your "authenticators"') - ->requiresAtLeastOneElement() - ->prototype('scalar')->end() - ->end() + ->info('An array of service ids for all of your "authenticators"') + ->requiresAtLeastOneElement() + ->prototype('scalar')->end(); + + // get the parent array node builder ("firewalls") from inside the children builder + $factoryRootNode = $builder->end()->end(); + $factoryRootNode + ->fixXmlConfig('custom_authenticator') + ->validate() + ->ifTrue(function ($v) { return isset($v['custom_authenticators']) && empty($v['custom_authenticators']); }) + ->then(function ($v) { + unset($v['custom_authenticators']); + + return $v; + }) ->end() ; } public function createAuthenticator(ContainerBuilder $container, string $firewallName, array $config, string $userProviderId): array { - return $config['services']; + return $config; } } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php index c9328c841d..b7063f42a0 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php @@ -24,11 +24,15 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\ExpressionLanguage\Expression; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; -use Symfony\Component\Security\Guard\AuthenticatorInterface; +use Symfony\Component\Security\Guard\AuthenticatorInterface as GuardAuthenticatorInterface; +use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface; +use Symfony\Component\Security\Http\Authenticator\HttpBasicAuthenticator; +use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface; class SecurityExtensionTest extends TestCase { @@ -520,6 +524,41 @@ class SecurityExtensionTest extends TestCase $container->compile(); } + /** + * @dataProvider provideConfigureCustomAuthenticatorData + */ + public function testConfigureCustomAuthenticator(array $firewall, array $expectedAuthenticators) + { + $container = $this->getRawContainer(); + $container->loadFromExtension('security', [ + 'enable_authenticator_manager' => true, + 'providers' => [ + 'first' => ['id' => 'users'], + ], + + 'firewalls' => [ + 'main' => $firewall, + ], + ]); + + $container->compile(); + + $this->assertEquals($expectedAuthenticators, array_map('strval', $container->getDefinition('security.authenticator.manager.main')->getArgument(0))); + } + + public function provideConfigureCustomAuthenticatorData() + { + yield [ + ['custom_authenticator' => TestAuthenticator::class], + [TestAuthenticator::class], + ]; + + yield [ + ['custom_authenticators' => [TestAuthenticator::class, HttpBasicAuthenticator::class]], + [TestAuthenticator::class, HttpBasicAuthenticator::class], + ]; + } + protected function getRawContainer() { $container = new ContainerBuilder(); @@ -547,7 +586,30 @@ class SecurityExtensionTest extends TestCase } } -class NullAuthenticator implements AuthenticatorInterface +class TestAuthenticator implements AuthenticatorInterface +{ + public function supports(Request $request): ?bool + { + } + + public function authenticate(Request $request): PassportInterface + { + } + + public function createAuthenticatedToken(PassportInterface $passport, string $firewallName): TokenInterface + { + } + + public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response + { + } + + public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response + { + } +} + +class NullAuthenticator implements GuardAuthenticatorInterface { public function start(Request $request, AuthenticationException $authException = null) {