vendor/shopware/core/Framework/DataAbstractionLayer/EntityProtection/EntityProtectionValidator.php line 49

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Framework\DataAbstractionLayer\EntityProtection;
  3. use Shopware\Core\Framework\Context;
  4. use Shopware\Core\Framework\DataAbstractionLayer\EntityDefinition;
  5. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntitySearchedEvent;
  6. use Shopware\Core\Framework\DataAbstractionLayer\Field\AssociationField;
  7. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  8. use Shopware\Core\Framework\DataAbstractionLayer\Write\Validation\PreWriteValidationEvent;
  9. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  10. use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
  11. class EntityProtectionValidator implements EventSubscriberInterface
  12. {
  13.     /**
  14.      * @return array<string, string|array{0: string, 1: int}|list<array{0: string, 1?: int}>>
  15.      */
  16.     public static function getSubscribedEvents()
  17.     {
  18.         return [
  19.             PreWriteValidationEvent::class => 'validateWriteCommands',
  20.             EntitySearchedEvent::class => 'validateEntitySearch',
  21.         ];
  22.     }
  23.     /**
  24.      * @param array<string> $protections FQCN of the protections that need to be validated
  25.      */
  26.     public function validateEntityPath(array $pathSegments, array $protectionsContext $context): void
  27.     {
  28.         foreach ($pathSegments as $pathSegment) {
  29.             /** @var EntityDefinition $definition */
  30.             $definition $pathSegment['definition'];
  31.             foreach ($protections as $protection) {
  32.                 $protectionInstance $definition->getProtections()->get($protection);
  33.                 if (!$protectionInstance || $protectionInstance->isAllowed($context->getScope())) {
  34.                     continue;
  35.                 }
  36.                 throw new AccessDeniedHttpException(
  37.                     sprintf('API access for entity "%s" not allowed.'$pathSegment['entity'])
  38.                 );
  39.             }
  40.         }
  41.     }
  42.     public function validateEntitySearch(EntitySearchedEvent $event): void
  43.     {
  44.         $definition $event->getDefinition();
  45.         $readProtection $definition->getProtections()->get(ReadProtection::class);
  46.         $context $event->getContext();
  47.         if ($readProtection && !$readProtection->isAllowed($context->getScope())) {
  48.             throw new AccessDeniedHttpException(
  49.                 sprintf(
  50.                     'Read access to entity "%s" not allowed for scope "%s".',
  51.                     $definition->getEntityName(),
  52.                     $context->getScope()
  53.                 )
  54.             );
  55.         }
  56.         $this->validateCriteriaAssociation(
  57.             $definition,
  58.             $event->getCriteria()->getAssociations(),
  59.             $context
  60.         );
  61.     }
  62.     public function validateWriteCommands(PreWriteValidationEvent $event): void
  63.     {
  64.         foreach ($event->getCommands() as $command) {
  65.             // Don't validate commands that fake operations on DB level, e.g. cascade deletes
  66.             if (!$command->isValid()) {
  67.                 continue;
  68.             }
  69.             $writeProtection $command->getDefinition()->getProtections()->get(WriteProtection::class);
  70.             if ($writeProtection && !$writeProtection->isAllowed($event->getContext()->getScope())) {
  71.                 throw new AccessDeniedHttpException(
  72.                     sprintf(
  73.                         'Write access to entity "%s" are not allowed in scope "%s".',
  74.                         $command->getDefinition()->getEntityName(),
  75.                         $event->getContext()->getScope()
  76.                     )
  77.                 );
  78.             }
  79.         }
  80.     }
  81.     private function validateCriteriaAssociation(EntityDefinition $definition, array $associationsContext $context): void
  82.     {
  83.         /** @var Criteria $criteria */
  84.         foreach ($associations as $associationName => $criteria) {
  85.             $field $definition->getField($associationName);
  86.             if (!$field instanceof AssociationField) {
  87.                 continue;
  88.             }
  89.             $associationDefinition $field->getReferenceDefinition();
  90.             $readProtection $associationDefinition->getProtections()->get(ReadProtection::class);
  91.             if ($readProtection && !$readProtection->isAllowed($context->getScope())) {
  92.                 throw new AccessDeniedHttpException(
  93.                     sprintf(
  94.                         'Read access to nested association "%s" on entity "%s" not allowed for scope "%s".',
  95.                         $associationName,
  96.                         $definition->getEntityName(),
  97.                         $context->getScope()
  98.                     )
  99.                 );
  100.             }
  101.             $this->validateCriteriaAssociation($associationDefinition$criteria->getAssociations(), $context);
  102.         }
  103.     }
  104. }