src/Security/Api/Authorization/Voter/RoleVoter.php line 24

Open in your IDE?
  1. <?php
  2. namespace App\Security\Api\Authorization\Voter;
  3. use App\Entity\Api\CoreModule\User;
  4. use App\Helper\Api\Entity\RequestDataContainer;
  5. use App\Helper\Api\Translator\ApiTranslator;
  6. use App\Security\Api\Authorization\RoleConfiguration\RoleConfigurationServiceSubscriber;
  7. use App\Security\Api\Authorization\VoterAttribute\AbstractVoterAttribute;
  8. use LogicException;
  9. use Psr\Container\ContainerExceptionInterface;
  10. use Psr\Container\NotFoundExceptionInterface;
  11. use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
  12. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  13. /**
  14.  * API catch all role voter.
  15.  *
  16.  * Denies access unless role configuration allows access.
  17.  *
  18.  * @package API
  19.  * @internal
  20.  */
  21. class RoleVoter extends AbstractApiBaseVoter
  22. {
  23.     /**
  24.      * Role configuration service subscriber.
  25.      *
  26.      * @var RoleConfigurationServiceSubscriber
  27.      */
  28.     protected RoleConfigurationServiceSubscriber $roleConfigurationServiceSubscriber;
  29.     /**
  30.      * Translator for all API controllers.
  31.      *
  32.      * @var ApiTranslator
  33.      */
  34.     protected ApiTranslator $translator;
  35.     /**
  36.      * Constructor.
  37.      *
  38.      * @param ApiTranslator $translator API translator.
  39.      * @param RoleConfigurationServiceSubscriber $roleConfigurationServiceSubscriber Role configuration service
  40.      *                                                                               subscriber.
  41.      */
  42.     public function __construct(
  43.         ApiTranslator $translator,
  44.         RoleConfigurationServiceSubscriber $roleConfigurationServiceSubscriber
  45.     ) {
  46.         $this->translator $translator;
  47.         $this->roleConfigurationServiceSubscriber $roleConfigurationServiceSubscriber;
  48.     }
  49.     /**
  50.      * Determines if the attribute and subject are supported by this voter.
  51.      *
  52.      * @param string $attribute An attribute.
  53.      * @param mixed $subject The subject to secure, e.g. an object the user wants to access or any other PHP type.
  54.      *
  55.      * @return bool
  56.      */
  57.     protected function supports(string $attribute$subject): bool
  58.     {
  59.         // requires data container
  60.         if (!$subject instanceof RequestDataContainer) {
  61.             return false;
  62.         }
  63.         // votes then on every API call when attribute format is valid
  64.         return AbstractVoterAttribute::isValidAttribute($attribute);
  65.     }
  66.     /**
  67.      * Perform a single access check operation on a given attribute, subject and token.
  68.      * It is safe to assume that $attribute and $subject already passed the "supports()" method check.
  69.      *
  70.      * @param string $attribute An attribute.
  71.      * @param mixed $subject The subject to secure, e.g. an object the user wants to access or any other PHP type.
  72.      * @param TokenInterface $token The token interface.
  73.      * @return bool
  74.      */
  75.     protected function voteOnAttribute(string $attributemixed $subjectTokenInterface $token): bool
  76.     {
  77.         $user $token->getUser();
  78.         if (!$user instanceof User) {
  79.             // the user must be logged in, otherwise deny access
  80.             return false;
  81.         }
  82.         if (!$this->supports($attribute$subject)) {
  83.             throw new LogicException('This code should not be reached!');
  84.         }
  85.         if (!$subject instanceof RequestDataContainer) {
  86.             throw new LogicException('This voter requires a RequestDataContainer object passed as subject!');
  87.         }
  88.         try {
  89.             $roles $this->roleConfigurationServiceSubscriber->getRoles($attribute);
  90.             $allowed = !empty(array_intersect($user->getRoles(), $roles));
  91.             if (!$allowed) {
  92.                 $subject->setException(
  93.                     new AccessDeniedHttpException($this->translator->t('authorization.access_denied'))
  94.                 );
  95.             }
  96.             return $allowed;
  97.         } catch (NotFoundExceptionInterface|ContainerExceptionInterface $exception) {
  98.             $subject->setException(
  99.                 new AccessDeniedHttpException($this->translator->t('authorization.access_denied'), $exception)
  100.             );
  101.             return false;
  102.         }
  103.     }
  104. }