[SecurityBundle] Fix referencing aliases from RegisterEntryPointPass

This commit is contained in:
Robin Chalas 2021-01-26 16:32:14 +01:00
parent fe57893025
commit 8dcc3d61c5
3 changed files with 107 additions and 2 deletions

View File

@ -12,6 +12,7 @@
namespace Symfony\Bundle\SecurityBundle\DependencyInjection\Compiler;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
@ -43,8 +44,13 @@ class RegisterEntryPointPass implements CompilerPassInterface
continue;
}
// because this pass runs before ResolveChildDefinitionPass, child definitions didn't inherit the parent class yet
$definition = $container->findDefinition($authenticatorId);
if (is_a($definition->getClass(), AuthenticationEntryPointInterface::class, true)) {
while (!($authenticatorClass = $definition->getClass()) && $definition instanceof ChildDefinition) {
$definition = $container->findDefinition($definition->getParent());
}
if (is_a($authenticatorClass, AuthenticationEntryPointInterface::class, true)) {
$entryPoints[$key] = $authenticatorId;
}
}

View File

@ -78,7 +78,7 @@ class SecurityBundle extends Bundle
$container->addCompilerPass(new RegisterCsrfFeaturesPass());
$container->addCompilerPass(new RegisterTokenUsageTrackingPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 200);
$container->addCompilerPass(new RegisterLdapLocatorPass());
$container->addCompilerPass(new RegisterEntryPointPass(), PassConfig::TYPE_BEFORE_REMOVING);
$container->addCompilerPass(new RegisterEntryPointPass());
// must be registered after RegisterListenersPass (in the FrameworkBundle)
$container->addCompilerPass(new RegisterGlobalSecurityEventListenersPass(), PassConfig::TYPE_BEFORE_REMOVING, -200);
// execute after ResolveChildDefinitionsPass optimization pass, to ensure class names are set

View File

@ -0,0 +1,99 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\DependencyInjection\Compiler;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Compiler\RegisterEntryPointPass;
use Symfony\Bundle\SecurityBundle\Security\FirewallConfig;
use Symfony\Component\DependencyInjection\Argument\AbstractArgument;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpFoundation\JsonResponse;
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\Exception\BadCredentialsException;
use Symfony\Component\Security\Http\Authentication\AuthenticatorManager;
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
use Symfony\Component\Security\Http\Firewall\ExceptionListener;
class RegisterEntryPointsPassTest extends TestCase
{
public function testProcessResolvesChildDefinitionsClass()
{
$container = new ContainerBuilder();
$container->setParameter('security.firewalls', ['main']);
$container->setParameter('security.main._indexed_authenticators', ['custom' => 'security.authenticator.custom_authenticator.main']);
$container->register('security.authenticator.manager.main', AuthenticatorManager::class);
$container->register('security.exception_listener.main', ExceptionListener::class)->setArguments([
new AbstractArgument(),
new AbstractArgument(),
new AbstractArgument(),
new AbstractArgument(),
null, // entry point
]);
$config = $container->register('security.firewall.map.config.main', FirewallConfig::class);
$config->setArguments([
new AbstractArgument(),
new AbstractArgument(),
new AbstractArgument(),
new AbstractArgument(),
new AbstractArgument(),
new AbstractArgument(),
new AbstractArgument(),
null, // entry point,
]);
$container->register('custom_authenticator', CustomAuthenticator::class)
->setAbstract(true);
$container->setDefinition('security.authenticator.custom_authenticator.main', new ChildDefinition('custom_authenticator'));
(new RegisterEntryPointPass())->process($container);
$this->assertSame('security.authenticator.custom_authenticator.main', $config->getArgument(7));
}
}
class CustomAuthenticator extends AbstractAuthenticator implements AuthenticationEntryPointInterface
{
public function supports(Request $request): ?bool
{
return false;
}
public function authenticate(Request $request): PassportInterface
{
throw new BadCredentialsException();
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
return null;
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
{
return new JsonResponse([
'error' => $exception->getMessageKey(),
], JsonResponse::HTTP_FORBIDDEN);
}
public function start(Request $request, AuthenticationException $authException = null)
{
}
}