src/Security/Voter/AclVoter.php line 16

Open in your IDE?
  1. <?php
  2. namespace App\Security\Voter;
  3. use App\AclPermission\AclPermissionManager;
  4. use App\AclPermission\AclPermissionProvider;
  5. use App\Entity\Hotel;
  6. use App\Entity\User;
  7. use Doctrine\Common\Util\ClassUtils;
  8. use Doctrine\ORM\EntityManagerInterface;
  9. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  10. use Symfony\Component\Security\Core\Authorization\Voter\Voter;
  11. use Symfony\Component\Security\Core\Security;
  12. use function Symfony\Component\String\u;
  13. class AclVoter extends Voter
  14. {
  15.     public const ANYONE_PERMISSION 'ACL_ANYONE';
  16.     private EntityManagerInterface $em;
  17.     private Security $security;
  18.     private AclPermissionProvider $aclPermissionProvider;
  19.     private AclPermissionManager $aclPermissionManager;
  20.     public function __construct(EntityManagerInterface $emSecurity $securityAclPermissionProvider $aclPermissionProviderAclPermissionManager $aclPermissionManager)
  21.     {
  22.         $this->em $em;
  23.         $this->security $security;
  24.         $this->aclPermissionProvider $aclPermissionProvider;
  25.         $this->aclPermissionManager $aclPermissionManager;
  26.     }
  27.     protected function supports(string $attribute$subject): bool
  28.     {
  29.         $subjectClassFcqn $this->getSubjectClassFcqn($subject);
  30.         if (!$subjectClassFcqn) {
  31.             return false;
  32.         }
  33.         $aclConfig $this->aclPermissionProvider->getConfigForDomainFcqn($subjectClassFcqn);
  34.         return !empty($aclConfig) && (in_array($attribute$aclConfig['permissions'], true) || $attribute === self::ANYONE_PERMISSION);
  35.     }
  36.     /**
  37.      * @param string $attribute
  38.      * @param $subject
  39.      * @param TokenInterface $token
  40.      * @return bool
  41.      */
  42.     protected function voteOnAttribute(string $attribute$subjectTokenInterface $token): bool
  43.     {
  44.         /** @var User $user */
  45.         $user $token->getUser();
  46.         // if the user is anonymous, do not grant access
  47.         if (!$user instanceof User || !$user->isActive()) {
  48.             return false;
  49.         }
  50.         if ($this->security->isGranted('ROLE_SUPER_ADMIN')) {
  51.             return true;
  52.         }
  53.         // Assigned users can do anything to hotels
  54.         if ($subject instanceof Hotel && $user->getAssignedHotels()->contains($subject)) {
  55.             return true;
  56.         }
  57.         $subjectClassFcqn $this->getSubjectClassFcqn($subject);
  58.         if (!$subjectClassFcqn) {
  59.             return false;
  60.         }
  61.         $scope is_object($subject) ? 'object' 'class';
  62.         $domainId is_object($subject) ? $subject->getId() : 'class';
  63.         foreach ($user->getGroups() as $group) {
  64.             $permissions $this->aclPermissionManager->getStructuredIdentityAclPermissions($group);
  65.             if ($this->hasPermission($permissions$subjectClassFcqn$scope$domainId$attribute)) {
  66.                 return true;
  67.             }
  68.         }
  69.         $permissions $this->aclPermissionManager->getStructuredIdentityAclPermissions($user);
  70.         return $this->hasPermission($permissions$subjectClassFcqn$scope$domainId$attribute);
  71.     }
  72.     private function hasPermission(array $permissionsstring $subjectClassFcqnstring $scopestring $domainIdstring $attribute): bool
  73.     {
  74.         if ($attribute === self::ANYONE_PERMISSION) {
  75.             return array_key_exists($subjectClassFcqn$permissions) && !empty($permissions[$subjectClassFcqn]);
  76.         }
  77.         if ($scope !== 'class') {
  78.             $classScope 'class';
  79.             $classDomainId 'class';
  80.             if (array_key_exists($subjectClassFcqn$permissions) &&
  81.                 array_key_exists($classScope$permissions[$subjectClassFcqn]) &&
  82.                 array_key_exists($classDomainId$permissions[$subjectClassFcqn][$classScope]) &&
  83.                 in_array($attribute$permissions[$subjectClassFcqn][$classScope][$classDomainId]['permissions'], true)
  84.             ) {
  85.                 return true;
  86.             }
  87.         }
  88.         return array_key_exists($subjectClassFcqn$permissions) &&
  89.             array_key_exists($scope$permissions[$subjectClassFcqn]) &&
  90.             array_key_exists($domainId$permissions[$subjectClassFcqn][$scope]) &&
  91.             in_array($attribute$permissions[$subjectClassFcqn][$scope][$domainId]['permissions'], true);
  92.     }
  93.     private function getSubjectClassFcqn($subject): ?string
  94.     {
  95.         if (is_object($subject)) {
  96.             // Sometimes we have proxy classes, thus we need to guess real class name.
  97.             return ClassUtils::getClass($subject);
  98.         }
  99.         if (u($subject)->containsAny('\\')) {
  100.             return $subject;
  101.         }
  102.         if (u($subject)->endsWith('::class')) {
  103.             $subject u($subject)->before('::class');
  104.         }
  105.         $metadatas $this->em->getMetadataFactory()->getAllMetadata();
  106.         foreach ($metadatas as $metadata) {
  107.             if ($metadata->getReflectionClass()->getShortName() === $subject) {
  108.                 return $metadata->getName();
  109.             }
  110.         }
  111.         return null;
  112.     }
  113. }