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

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