RegisterEntryPointPass.php 3.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Bundle\SecurityBundle\DependencyInjection\Compiler;
  11. use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
  12. use Symfony\Component\DependencyInjection\ChildDefinition;
  13. use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
  14. use Symfony\Component\DependencyInjection\ContainerBuilder;
  15. use Symfony\Component\DependencyInjection\Reference;
  16. use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
  17. /**
  18. * @author Wouter de Jong <wouter@wouterj.nl>
  19. */
  20. class RegisterEntryPointPass implements CompilerPassInterface
  21. {
  22. public function process(ContainerBuilder $container)
  23. {
  24. if (!$container->hasParameter('security.firewalls')) {
  25. return;
  26. }
  27. $firewalls = $container->getParameter('security.firewalls');
  28. foreach ($firewalls as $firewallName) {
  29. if (!$container->hasDefinition('security.authenticator.manager.'.$firewallName) || !$container->hasParameter('security.'.$firewallName.'._indexed_authenticators')) {
  30. continue;
  31. }
  32. $entryPoints = [];
  33. $indexedAuthenticators = $container->getParameter('security.'.$firewallName.'._indexed_authenticators');
  34. // this is a compile-only parameter, removing it cleans up space and avoids unintended usage
  35. $container->getParameterBag()->remove('security.'.$firewallName.'._indexed_authenticators');
  36. foreach ($indexedAuthenticators as $key => $authenticatorId) {
  37. if (!$container->has($authenticatorId)) {
  38. continue;
  39. }
  40. // because this pass runs before ResolveChildDefinitionPass, child definitions didn't inherit the parent class yet
  41. $definition = $container->findDefinition($authenticatorId);
  42. while (!($authenticatorClass = $definition->getClass()) && $definition instanceof ChildDefinition) {
  43. $definition = $container->findDefinition($definition->getParent());
  44. }
  45. if (is_a($authenticatorClass, AuthenticationEntryPointInterface::class, true)) {
  46. $entryPoints[$key] = $authenticatorId;
  47. }
  48. }
  49. if (!$entryPoints) {
  50. continue;
  51. }
  52. $config = $container->getDefinition('security.firewall.map.config.'.$firewallName);
  53. $configuredEntryPoint = $config->getArgument(7);
  54. if (null !== $configuredEntryPoint) {
  55. // allow entry points to be configured by authenticator key (e.g. "http_basic")
  56. $entryPoint = $entryPoints[$configuredEntryPoint] ?? $configuredEntryPoint;
  57. } elseif (1 === \count($entryPoints)) {
  58. $entryPoint = array_shift($entryPoints);
  59. } else {
  60. $entryPointNames = [];
  61. foreach ($entryPoints as $key => $serviceId) {
  62. $entryPointNames[] = is_numeric($key) ? $serviceId : $key;
  63. }
  64. 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));
  65. }
  66. $config->replaceArgument(7, $entryPoint);
  67. $container->getDefinition('security.exception_listener.'.$firewallName)->replaceArgument(4, new Reference($entryPoint));
  68. }
  69. }
  70. }