vendor/symfony/security-http/EventListener/IsGrantedAttributeListener.php line 38

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\EventListener;
  11. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  12. use Symfony\Component\ExpressionLanguage\Expression;
  13. use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
  14. use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent;
  15. use Symfony\Component\HttpKernel\Exception\HttpException;
  16. use Symfony\Component\HttpKernel\KernelEvents;
  17. use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
  18. use Symfony\Component\Security\Core\Exception\AccessDeniedException;
  19. use Symfony\Component\Security\Core\Exception\RuntimeException;
  20. use Symfony\Component\Security\Http\Attribute\IsGranted;
  21. /**
  22.  * Handles the IsGranted attribute on controllers.
  23.  *
  24.  * @author Ryan Weaver <ryan@knpuniversity.com>
  25.  */
  26. class IsGrantedAttributeListener implements EventSubscriberInterface
  27. {
  28.     public function __construct(
  29.         private readonly AuthorizationCheckerInterface $authChecker,
  30.         private ?ExpressionLanguage $expressionLanguage null,
  31.     ) {
  32.     }
  33.     public function onKernelControllerArguments(ControllerArgumentsEvent $event)
  34.     {
  35.         /** @var IsGranted[] $attributes */
  36.         if (!\is_array($attributes $event->getAttributes()[IsGranted::class] ?? null)) {
  37.             return;
  38.         }
  39.         $arguments $event->getNamedArguments();
  40.         foreach ($attributes as $attribute) {
  41.             $subject null;
  42.             if ($subjectRef $attribute->subject) {
  43.                 if (\is_array($subjectRef)) {
  44.                     foreach ($subjectRef as $refKey => $ref) {
  45.                         $subject[\is_string($refKey) ? $refKey : (string) $ref] = $this->getIsGrantedSubject($ref$arguments);
  46.                     }
  47.                 } else {
  48.                     $subject $this->getIsGrantedSubject($subjectRef$arguments);
  49.                 }
  50.             }
  51.             if (!$this->authChecker->isGranted($attribute->attribute$subject)) {
  52.                 $message $attribute->message ?: sprintf('Access Denied by #[IsGranted(%s)] on controller'$this->getIsGrantedString($attribute));
  53.                 if ($statusCode $attribute->statusCode) {
  54.                     throw new HttpException($statusCode$message);
  55.                 }
  56.                 $accessDeniedException = new AccessDeniedException($message);
  57.                 $accessDeniedException->setAttributes($attribute->attribute);
  58.                 $accessDeniedException->setSubject($subject);
  59.                 throw $accessDeniedException;
  60.             }
  61.         }
  62.     }
  63.     public static function getSubscribedEvents(): array
  64.     {
  65.         return [KernelEvents::CONTROLLER_ARGUMENTS => ['onKernelControllerArguments'10]];
  66.     }
  67.     private function getIsGrantedSubject(string|Expression $subjectRef, array $arguments): mixed
  68.     {
  69.         if ($subjectRef instanceof Expression) {
  70.             $this->expressionLanguage ??= new ExpressionLanguage();
  71.             return $this->expressionLanguage->evaluate($subjectRef, [
  72.                 'args' => $arguments,
  73.             ]);
  74.         }
  75.         if (!\array_key_exists($subjectRef$arguments)) {
  76.             throw new RuntimeException(sprintf('Could not find the subject "%s" for the #[IsGranted] attribute. Try adding a "$%s" argument to your controller method.'$subjectRef$subjectRef));
  77.         }
  78.         return $arguments[$subjectRef];
  79.     }
  80.     private function getIsGrantedString(IsGranted $isGranted): string
  81.     {
  82.         $processValue = fn ($value) => sprintf($value instanceof Expression 'new Expression("%s")' '"%s"'$value);
  83.         $argsString $processValue($isGranted->attribute);
  84.         if (null !== $subject $isGranted->subject) {
  85.             $subject = !\is_array($subject) ? $processValue($subject) : array_map(function ($key$value) use ($processValue) {
  86.                 $value $processValue($value);
  87.                 return \is_string($key) ? sprintf('"%s" => %s'$key$value) : $value;
  88.             }, array_keys($subject), $subject);
  89.             $argsString .= ', '.(!\is_array($subject) ? $subject '['.implode(', '$subject).']');
  90.         }
  91.         return $argsString;
  92.     }
  93. }