* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ 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; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; /** * @author Wouter de Jong */ class RegisterEntryPointPass implements CompilerPassInterface { public function process(ContainerBuilder $container) { if (!$container->hasParameter('security.firewalls')) { return; } $firewalls = $container->getParameter('security.firewalls'); foreach ($firewalls as $firewallName) { if (!$container->hasDefinition('security.authenticator.manager.'.$firewallName) || !$container->hasParameter('security.'.$firewallName.'._indexed_authenticators')) { continue; } $entryPoints = []; $indexedAuthenticators = $container->getParameter('security.'.$firewallName.'._indexed_authenticators'); // this is a compile-only parameter, removing it cleans up space and avoids unintended usage $container->getParameterBag()->remove('security.'.$firewallName.'._indexed_authenticators'); foreach ($indexedAuthenticators as $key => $authenticatorId) { if (!$container->has($authenticatorId)) { continue; } // because this pass runs before ResolveChildDefinitionPass, child definitions didn't inherit the parent class yet $definition = $container->findDefinition($authenticatorId); while (!($authenticatorClass = $definition->getClass()) && $definition instanceof ChildDefinition) { $definition = $container->findDefinition($definition->getParent()); } if (is_a($authenticatorClass, AuthenticationEntryPointInterface::class, true)) { $entryPoints[$key] = $authenticatorId; } } if (!$entryPoints) { continue; } $config = $container->getDefinition('security.firewall.map.config.'.$firewallName); $configuredEntryPoint = $config->getArgument(7); if (null !== $configuredEntryPoint) { // allow entry points to be configured by authenticator key (e.g. "http_basic") $entryPoint = $entryPoints[$configuredEntryPoint] ?? $configuredEntryPoint; } elseif (1 === \count($entryPoints)) { $entryPoint = array_shift($entryPoints); } else { $entryPointNames = []; foreach ($entryPoints as $key => $serviceId) { $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)); } $config->replaceArgument(7, $entryPoint); $container->getDefinition('security.exception_listener.'.$firewallName)->replaceArgument(4, new Reference($entryPoint)); } } }