vendor/api-platform/core/src/Symfony/EventListener/DenyAccessListener.php line 89

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the API Platform project.
  4.  *
  5.  * (c) Kévin Dunglas <dunglas@gmail.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. declare(strict_types=1);
  11. namespace ApiPlatform\Symfony\EventListener;
  12. use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
  13. use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
  14. use ApiPlatform\Symfony\Security\ExpressionLanguage;
  15. use ApiPlatform\Symfony\Security\ResourceAccessChecker;
  16. use ApiPlatform\Symfony\Security\ResourceAccessCheckerInterface;
  17. use ApiPlatform\Util\OperationRequestInitiatorTrait;
  18. use ApiPlatform\Util\RequestAttributesExtractor;
  19. use Symfony\Component\HttpFoundation\Request;
  20. use Symfony\Component\HttpKernel\Event\RequestEvent;
  21. use Symfony\Component\HttpKernel\Event\ViewEvent;
  22. use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
  23. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  24. use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
  25. use Symfony\Component\Security\Core\Exception\AccessDeniedException;
  26. use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
  27. /**
  28.  * Denies access to the current resource if the logged user doesn't have sufficient permissions.
  29.  *
  30.  * @author Kévin Dunglas <dunglas@gmail.com>
  31.  */
  32. final class DenyAccessListener
  33. {
  34.     use OperationRequestInitiatorTrait;
  35.     /**
  36.      * @var ResourceMetadataFactoryInterface|ResourceMetadataCollectionFactoryInterface
  37.      */
  38.     private $resourceMetadataFactory;
  39.     /**
  40.      * @var ResourceAccessCheckerInterface
  41.      */
  42.     private $resourceAccessChecker;
  43.     public function __construct($resourceMetadataFactory/* ResourceAccessCheckerInterface */ $resourceAccessCheckerOrExpressionLanguage nullAuthenticationTrustResolverInterface $authenticationTrustResolver nullRoleHierarchyInterface $roleHierarchy nullTokenStorageInterface $tokenStorage nullAuthorizationCheckerInterface $authorizationChecker null)
  44.     {
  45.         $this->resourceMetadataFactory $resourceMetadataFactory;
  46.         if ($resourceAccessCheckerOrExpressionLanguage instanceof ResourceAccessCheckerInterface) {
  47.             $this->resourceAccessChecker $resourceAccessCheckerOrExpressionLanguage;
  48.             return;
  49.         }
  50.         $this->resourceAccessChecker = new ResourceAccessChecker($resourceAccessCheckerOrExpressionLanguage$authenticationTrustResolver$roleHierarchy$tokenStorage$authorizationChecker);
  51.         @trigger_error(sprintf('Passing an instance of "%s" or null as second argument of "%s" is deprecated since API Platform 2.2 and will not be possible anymore in API Platform 3. Pass an instance of "%s" and no extra argument instead.'ExpressionLanguage::class, self::class, ResourceAccessCheckerInterface::class), \E_USER_DEPRECATED);
  52.         if (!$resourceMetadataFactory instanceof ResourceMetadataCollectionFactoryInterface) {
  53.             trigger_deprecation('api-platform/core''2.7'sprintf('Use "%s" instead of "%s".'ResourceMetadataCollectionFactoryInterface::class, ResourceMetadataFactoryInterface::class));
  54.         } else {
  55.             $this->resourceMetadataCollectionFactory $resourceMetadataFactory;
  56.         }
  57.     }
  58.     public function onKernelRequest(RequestEvent $event): void
  59.     {
  60.         @trigger_error(sprintf('Method "%1$s::onKernelRequest" is deprecated since API Platform 2.4 and will not be available anymore in API Platform 3. Prefer calling "%1$s::onSecurity" instead.'self::class), \E_USER_DEPRECATED);
  61.         $this->onSecurityPostDenormalize($event);
  62.     }
  63.     public function onSecurity(RequestEvent $event): void
  64.     {
  65.         $this->checkSecurity($event->getRequest(), 'security'false);
  66.     }
  67.     public function onSecurityPostDenormalize(RequestEvent $event): void
  68.     {
  69.         $request $event->getRequest();
  70.         $this->checkSecurity($request'security_post_denormalize'true, [
  71.             'previous_object' => $request->attributes->get('previous_data'),
  72.         ]);
  73.     }
  74.     public function onSecurityPostValidation(ViewEvent $event): void
  75.     {
  76.         $request $event->getRequest();
  77.         $this->checkSecurity($request'security_post_validation'false, [
  78.             'previous_object' => $request->attributes->get('previous_data'),
  79.         ]);
  80.     }
  81.     /**
  82.      * @throws AccessDeniedException
  83.      */
  84.     private function checkSecurity(Request $requeststring $attributebool $backwardCompatibility, array $extraVariables = []): void
  85.     {
  86.         if (!$attributes RequestAttributesExtractor::extractAttributes($request)) {
  87.             return;
  88.         }
  89.         $resourceMetadata null;
  90.         $isGranted null;
  91.         $message $attributes[$attribute.'_message'] ?? 'Access Denied.';
  92.         if ($this->resourceMetadataFactory instanceof ResourceMetadataFactoryInterface) {
  93.             $resourceMetadata $this->resourceMetadataFactory->create($attributes['resource_class']);
  94.             $isGranted $resourceMetadata->getOperationAttribute($attributes$attributenulltrue);
  95.             if ($backwardCompatibility && null === $isGranted) {
  96.                 // Backward compatibility
  97.                 $isGranted $resourceMetadata->getOperationAttribute($attributes'access_control'nulltrue);
  98.                 if (null !== $isGranted) {
  99.                     @trigger_error('Using "access_control" attribute is deprecated since API Platform 2.4 and will not be possible anymore in API Platform 3. Use "security" attribute instead.'\E_USER_DEPRECATED);
  100.                 }
  101.             }
  102.             $message $resourceMetadata->getOperationAttribute($attributes$attribute.'_message''Access Denied.'true);
  103.         } elseif ($this->resourceMetadataFactory instanceof ResourceMetadataCollectionFactoryInterface) {
  104.             $operation $this->initializeOperation($request);
  105.             if (!$operation) {
  106.                 return;
  107.             }
  108.             switch ($attribute) {
  109.                 case 'security_post_denormalize':
  110.                     $isGranted $operation->getSecurityPostDenormalize();
  111.                     $message $operation->getSecurityPostDenormalizeMessage();
  112.                     break;
  113.                 case 'security_post_validation':
  114.                     $isGranted $operation->getSecurityPostValidation();
  115.                     $message $operation->getSecurityPostValidationMessage();
  116.                     break;
  117.                 default:
  118.                     $isGranted $operation->getSecurity();
  119.                     $message $operation->getSecurityMessage();
  120.             }
  121.         }
  122.         if (null === $isGranted) {
  123.             return;
  124.         }
  125.         $extraVariables += $request->attributes->all();
  126.         $extraVariables['object'] = $request->attributes->get('data');
  127.         $extraVariables['previous_object'] = $request->attributes->get('previous_data');
  128.         $extraVariables['request'] = $request;
  129.         if (!$this->resourceAccessChecker->isGranted($attributes['resource_class'], $isGranted$extraVariables)) {
  130.             throw new AccessDeniedException($message ?? 'Access Denied.');
  131.         }
  132.     }
  133. }
  134. class_alias(DenyAccessListener::class, \ApiPlatform\Core\Security\EventListener\DenyAccessListener::class);