vendor/symfony/security-http/Firewall/AccessListener.php line 85

Open in your IDE?
  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\Component\Security\Http\Firewall;
  11. use Symfony\Component\HttpFoundation\Request;
  12. use Symfony\Component\HttpKernel\Event\RequestEvent;
  13. use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
  14. use Symfony\Component\Security\Core\Authentication\Token\NullToken;
  15. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  16. use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
  17. use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter;
  18. use Symfony\Component\Security\Core\Exception\AccessDeniedException;
  19. use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException;
  20. use Symfony\Component\Security\Http\AccessMapInterface;
  21. use Symfony\Component\Security\Http\Authentication\NoopAuthenticationManager;
  22. use Symfony\Component\Security\Http\Event\LazyResponseEvent;
  23. /**
  24. * AccessListener enforces access control rules.
  25. *
  26. * @author Fabien Potencier <fabien@symfony.com>
  27. *
  28. * @final
  29. */
  30. class AccessListener extends AbstractListener
  31. {
  32. private $tokenStorage;
  33. private $accessDecisionManager;
  34. private $map;
  35. private $authManager;
  36. private $exceptionOnNoToken;
  37. public function __construct(TokenStorageInterface $tokenStorage, AccessDecisionManagerInterface $accessDecisionManager, AccessMapInterface $map, /* bool */ $exceptionOnNoToken = true)
  38. {
  39. if ($exceptionOnNoToken instanceof AuthenticationManagerInterface) {
  40. trigger_deprecation('symfony/security-http', '5.4', 'The $authManager argument of "%s" is deprecated.', __METHOD__);
  41. $authManager = $exceptionOnNoToken;
  42. $exceptionOnNoToken = \func_num_args() > 4 ? func_get_arg(4) : true;
  43. }
  44. if (false !== $exceptionOnNoToken) {
  45. trigger_deprecation('symfony/security-http', '5.4', 'Not setting the $exceptionOnNoToken argument of "%s" to "false" is deprecated.', __METHOD__);
  46. }
  47. $this->tokenStorage = $tokenStorage;
  48. $this->accessDecisionManager = $accessDecisionManager;
  49. $this->map = $map;
  50. $this->authManager = $authManager ?? (class_exists(AuthenticationManagerInterface::class) ? new NoopAuthenticationManager() : null);
  51. $this->exceptionOnNoToken = $exceptionOnNoToken;
  52. }
  53. /**
  54. * {@inheritdoc}
  55. */
  56. public function supports(Request $request): ?bool
  57. {
  58. [$attributes] = $this->map->getPatterns($request);
  59. $request->attributes->set('_access_control_attributes', $attributes);
  60. if ($attributes && (
  61. (\defined(AuthenticatedVoter::class.'::IS_AUTHENTICATED_ANONYMOUSLY') ? [AuthenticatedVoter::IS_AUTHENTICATED_ANONYMOUSLY] !== $attributes : true)
  62. && [AuthenticatedVoter::PUBLIC_ACCESS] !== $attributes
  63. )) {
  64. return true;
  65. }
  66. return null;
  67. }
  68. /**
  69. * Handles access authorization.
  70. *
  71. * @throws AccessDeniedException
  72. * @throws AuthenticationCredentialsNotFoundException when the token storage has no authentication token and $exceptionOnNoToken is set to true
  73. */
  74. public function authenticate(RequestEvent $event)
  75. {
  76. if (!$event instanceof LazyResponseEvent && null === ($token = $this->tokenStorage->getToken()) && $this->exceptionOnNoToken) {
  77. throw new AuthenticationCredentialsNotFoundException('A Token was not found in the TokenStorage.');
  78. }
  79. $request = $event->getRequest();
  80. $attributes = $request->attributes->get('_access_control_attributes');
  81. $request->attributes->remove('_access_control_attributes');
  82. if (!$attributes || ((
  83. (\defined(AuthenticatedVoter::class.'::IS_AUTHENTICATED_ANONYMOUSLY') ? [AuthenticatedVoter::IS_AUTHENTICATED_ANONYMOUSLY] === $attributes : false)
  84. || [AuthenticatedVoter::PUBLIC_ACCESS] === $attributes
  85. ) && $event instanceof LazyResponseEvent)) {
  86. return;
  87. }
  88. if ($event instanceof LazyResponseEvent) {
  89. $token = $this->tokenStorage->getToken();
  90. }
  91. if (null === $token) {
  92. if ($this->exceptionOnNoToken) {
  93. throw new AuthenticationCredentialsNotFoundException('A Token was not found in the TokenStorage.');
  94. }
  95. $token = new NullToken();
  96. }
  97. // @deprecated since Symfony 5.4
  98. if (method_exists($token, 'isAuthenticated') && !$token->isAuthenticated(false)) {
  99. trigger_deprecation('symfony/core', '5.4', 'Returning false from "%s::isAuthenticated()" is deprecated, return null from "getUser()" instead.', get_debug_type($token));
  100. if ($this->authManager) {
  101. $token = $this->authManager->authenticate($token);
  102. $this->tokenStorage->setToken($token);
  103. }
  104. }
  105. if (!$this->accessDecisionManager->decide($token, $attributes, $request, true)) {
  106. throw $this->createAccessDeniedException($request, $attributes);
  107. }
  108. }
  109. private function createAccessDeniedException(Request $request, array $attributes)
  110. {
  111. $exception = new AccessDeniedException();
  112. $exception->setAttributes($attributes);
  113. $exception->setSubject($request);
  114. return $exception;
  115. }
  116. public static function getPriority(): int
  117. {
  118. return -255;
  119. }
  120. }