src/Security/AccessVoter.php line 71

Open in your IDE?
  1. <?php
  2. //------------------------------------------------------------------------------
  3. // src/Security/AccessVoter.php
  4. //------------------------------------------------------------------------------
  5. namespace App\Security;
  6. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  7. use Symfony\Component\Security\Core\Authorization\Voter\Voter;
  8. use Doctrine\Persistence\ManagerRegistry;
  9. use App\Entity\Access;
  10. use App\Entity\Config\Config;
  11. use App\Entity\Config\Module;
  12. use App\Entity\HR\AccessFunction;
  13. use App\Entity\Security\Acl;
  14. use App\Entity\Security\AclPermission;
  15. use App\Services\Config\ModuleTools;
  16. class AccessVoter extends Voter
  17. {
  18.     //--------------------------------------------------------------------------------
  19.     // is_granted constants
  20.     const IS_ACTIVE "access_is_active";
  21.     const EDIT "edit_access";
  22.     const ADD_FROM "add_access_from";
  23.     const LISTING "list_accesses";
  24.     const LISTING_SOCIETY "list_accesses_society";
  25.     const LISTING_ANY "list_accesses_any";
  26.     const ASSIGNING "assign_access_societies";
  27.     const ASSIGNING_SOCIETY "assign_access_societies_society";
  28.     const ASSIGNING_ANY "assign_access_societies_any";
  29.     const IS_GRANTED_CONSTANTS = array(
  30.         self::IS_ACTIVE,
  31.         self::EDIT,
  32.         self::ADD_FROM,
  33.         self::LISTING,
  34.         self::LISTING_SOCIETY,
  35.         self::LISTING_ANY,
  36.         self::ASSIGNING,
  37.         self::ASSIGNING_SOCIETY,
  38.         self::ASSIGNING_ANY,
  39.     );
  40.     //--------------------------------------------------------------------------------
  41.     const ACL_PERM_ADD_FROM "access_add_from";
  42.     const ACL_PERM_LISTING "access_list";
  43.     const ACL_PERM_LISTING_SOCIETY "access_list_society";
  44.     const ACL_PERM_ASSIGN "access_assign";
  45.     const ACL_PERM_ASSIGN_SOCIETY "access_assign_society";
  46.     const ACL_PERM_EDIT "access_edit";
  47.     const ACL_PERM_EDIT_SOCIETY "access_edit_society";
  48.     const ACL_PERM_EDIT_OWN "access_edit_own";
  49.     //--------------------------------------------------------------------------------
  50.     public function __construct(ManagerRegistry $doctrineModuleTools $moduleTools)
  51.     {
  52.         $this->em $doctrine->getManager();
  53.         $this->moduleTools $moduleTools;
  54.         $this->aclRepository $this->em->getRepository(Acl::class);
  55.         $this->aclPermissionRepository $this->em->getRepository(AclPermission::class);
  56.     }
  57.     // Plan.io Task #4453
  58.     // This method returns true if the voter applies to the given attribute;
  59.     // if it returns false, Symfony won't call it again for this attribute
  60.     // https://symfony.com/blog/new-in-symfony-5-4-faster-security-voters
  61.     // https://symfony.com/doc/current/security/voters.html#improving-voter-performance
  62.     public function supportsAttribute(string $attribute): bool
  63.     {
  64.         return in_array($attributeself::IS_GRANTED_CONSTANTStrue);
  65.     }
  66.     
  67.     protected function supports(string $attribute$subject): bool
  68.     {
  69.         // if the attribute isn't one we support, return false
  70.         if (!in_array($attributeself::IS_GRANTED_CONSTANTS))
  71.         {
  72.             return false;
  73.         }
  74.         // only vote on Access objects inside this voter
  75.         if ($subject !== null && !$subject instanceof Access)
  76.         {
  77.             return false;
  78.         }
  79.         return true;
  80.     }
  81.     protected function voteOnAttribute(string $attribute$subjectTokenInterface $token): bool
  82.     {
  83.         $user $token->getUser();
  84.         if (!$user instanceof Access)
  85.         {
  86.             // the user must be logged in; if not, deny access
  87.             return false;
  88.         }
  89.         // ROLE_USER must have a function; if not deny access
  90.         if ($user->isUser())
  91.         {
  92.             $function $user->getFunction();
  93.             if ($function === null)        return false;
  94.         }
  95.         // Plan.io Task #3710 : Get current group
  96.         $currentGroup $user->getSocietyGroup();
  97.         if ($currentGroup === null)
  98.             return false;
  99.         // Module activated ?
  100.         if ($this->moduleTools->isInactiveByCode($currentGroupModule::MODULE_ACCESS))
  101.         {
  102.             return false;
  103.         }
  104.         // Module human_resource should also be activated
  105.         if ($this->moduleTools->isInactiveByCode($currentGroupModule::MODULE_HUMAN_RESOURCE))
  106.         {
  107.             return false;
  108.         }
  109.         // you know $subject is an Access object, thanks to supports
  110.         /** @var Access $access */
  111.         $access $subject;
  112.         switch ($attribute)
  113.         {
  114.             case self::IS_ACTIVE:
  115.                 return true;
  116.             case self::EDIT:
  117.                 return $this->canEdit($access$user$function);
  118.             case self::ADD_FROM:
  119.                 return $this->canAddFrom($access$user$function);
  120.             case self::LISTING:
  121.                 return $this->canList($access$user$function);
  122.             case self::LISTING_SOCIETY:
  123.                 return $this->canListSociety($access$user$function);
  124.             case self::LISTING_ANY:
  125.                 return $this->canListAny($access$user$function);
  126.             case self::ASSIGNING:
  127.                 return $this->canAssign($access$user$function);
  128.             case self::ASSIGNING_SOCIETY:
  129.                 return $this->canAssignSociety($access$user$function);
  130.             case self::ASSIGNING_ANY:
  131.                 return $this->canAssignAny($access$user$function);
  132.         }
  133.         throw new \LogicException('This code should not be reached!');
  134.     }
  135.     // $access is the thing that we are doing stuff on
  136.     // $user is the logged in user
  137.     private function checkSociety(Access $accessAccess $user)
  138.     {
  139.         // Get all the societies of the user
  140.         $societies $user->getSocieties();
  141.         // Get the Society of the Access
  142.         $accessSociety $access->getSociety();
  143.         if ($accessSociety === null)
  144.             return false;
  145.         $found false;
  146.         foreach ($societies as $society)
  147.         {
  148.             if ($society->getId() == $accessSociety->getId())
  149.             {
  150.                 $found true;
  151.                 break;
  152.             }
  153.         }
  154.         return $found;
  155.     }
  156.     // $access is the thing that we are doing stuff on
  157.     // $user is the logged in user
  158.     private function canEdit(Access $accessAccess $user$function)
  159.     {
  160.         // Get Acl_Perdemands
  161.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_EDIT);
  162.         $aclPermSociety $this->aclPermissionRepository->findOneByName(self::ACL_PERM_EDIT_SOCIETY);
  163.         $aclPermOwn $this->aclPermissionRepository->findOneByName(self::ACL_PERM_EDIT_OWN);
  164.         // If all are null, exit
  165.         if ($aclPerm === null && $aclPermSociety === null && $aclPermOwn)
  166.             return false;
  167.         // Get First one
  168.         if ($aclPerm !== null)
  169.         {
  170.             $acl $this->aclRepository->findOneBy(array(
  171.                 'function'        =>    $function,
  172.                 'permission'    =>    $aclPerm
  173.             ));
  174.             if ($acl !== null)
  175.             {
  176.                 if ($acl->getValue())
  177.                 {
  178.                     // A single positive answer is enough
  179.                     return true;
  180.                 }
  181.             }
  182.         }
  183.         // If we are here it means that nothing good has been found
  184.         // Load second permission
  185.         if ($aclPermSociety !== null)
  186.         {
  187.             $acl $this->aclRepository->findOneBy(array(
  188.                 'function'        =>    $function,
  189.                 'permission'    =>    $aclPermSociety
  190.             ));
  191.             if ($acl !== null)
  192.             {
  193.                 if ($acl->getValue())
  194.                 {
  195.                     // Check Society
  196.                     if ($this->checkSociety($access$user))
  197.                     {
  198.                         return true;
  199.                     }
  200.                 }
  201.             }
  202.         }
  203.         // If we are here it means that nothing good has been found
  204.         // Load third permission
  205.         if ($aclPermOwn !== null)
  206.         {
  207.             $acl $this->aclRepository->findOneBy(array(
  208.                 'function'        =>    $function,
  209.                 'permission'    =>    $aclPermOwn
  210.             ));
  211.             if ($acl !== null)
  212.             {
  213.                 if ($acl->getValue())
  214.                 {
  215.                     // Check Own
  216.                     if ($user->equals($access$user))
  217.                     {
  218.                         return true;
  219.                     }
  220.                 }
  221.             }
  222.         }
  223.         // If we are here, all hope is lost
  224.         return false;
  225.     }
  226.     private function canAddFrom(Access $access nullAccess $userAccessFunction $function)
  227.     {
  228.         // Get Acl_Permission
  229.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_ADD_FROM);
  230.         if ($aclPerm === null)        return false;
  231.         // Get Acl
  232.         $acl $this->aclRepository->findOneBy(array(
  233.             'function'        =>    $function,
  234.             'permission'    =>    $aclPerm
  235.         ));
  236.         if ($acl === null)        return false;
  237.         // Since only one list type can exist for the Applications,
  238.         // we can return the result of the acl_permission
  239.         return $acl->getValue();
  240.     }
  241.     private function canAssign(Access $access nullAccess $userAccessFunction $function)
  242.     {
  243.         // Get Acl_Permission
  244.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_ASSIGN);
  245.         if ($aclPerm === null)        return false;
  246.         // Get Acl
  247.         $acl $this->aclRepository->findOneBy(array(
  248.             'function'        =>    $function,
  249.             'permission'    =>    $aclPerm
  250.         ));
  251.         if ($acl === null)        return false;
  252.         // Since only one list type can exist for the Applications,
  253.         // we can return the result of the acl_permission
  254.         return $acl->getValue();
  255.     }
  256.     private function canAssignSociety(Access $access nullAccess $userAccessFunction $function)
  257.     {
  258.         // Get Acl_Permission
  259.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_ASSIGN_SOCIETY);
  260.         if ($aclPerm === null)        return false;
  261.         // Get Acl
  262.         $acl $this->aclRepository->findOneBy(array(
  263.             'function'        =>    $function,
  264.             'permission'    =>    $aclPerm
  265.         ));
  266.         if ($acl === null)        return false;
  267.         // Further filtering is done in the Controller
  268.         return $acl->getValue();
  269.     }
  270.     private function canAssignAny(Access $access nullAccess $userAccessFunction $function)
  271.     {
  272.         // Two Acl_Permission may exist
  273.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_ASSIGN);
  274.         $aclPermSociety $this->aclPermissionRepository->findOneByName(self::ACL_PERM_ASSIGN_SOCIETY);
  275.         // If both are null, exit
  276.         if ($aclPerm === null && $aclPermSociety === null)
  277.             return false;
  278.         // Get First one
  279.         if ($aclPerm !== null)
  280.         {
  281.             $acl $this->aclRepository->findOneBy(array(
  282.                 'function'        =>    $function,
  283.                 'permission'    =>    $aclPerm
  284.             ));
  285.             if ($acl !== null)
  286.             {
  287.                 if ($acl->getValue())
  288.                 {
  289.                     // A single positive answer is enough
  290.                     return true;
  291.                 }
  292.             }
  293.         }
  294.         // If we are here it means that nothing good has been found
  295.         // Load second permission
  296.         if ($aclPermSociety !== null)
  297.         {
  298.             $acl $this->aclRepository->findOneBy(array(
  299.                 'function'        =>    $function,
  300.                 'permission'    =>    $aclPermSociety
  301.             ));
  302.             if ($acl !== null)
  303.             {
  304.                 if ($acl->getValue())
  305.                 {
  306.                     // A single positive answer is enough
  307.                     return true;
  308.                 }
  309.             }
  310.         }
  311.         // If we are here, all hope is lost
  312.         return false;
  313.     }
  314.     private function canList(Access $access nullAccess $userAccessFunction $function)
  315.     {
  316.         // Get Acl_Permission
  317.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_LISTING);
  318.         if ($aclPerm === null)        return false;
  319.         // Get Acl
  320.         $acl $this->aclRepository->findOneBy(array(
  321.             'function'        =>    $function,
  322.             'permission'    =>    $aclPerm
  323.         ));
  324.         if ($acl === null)        return false;
  325.         // Further filtering is done in the Controller
  326.         return $acl->getValue();
  327.     }
  328.     private function canListSociety(Access $access nullAccess $userAccessFunction $function)
  329.     {
  330.         // Get Acl_Permission
  331.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_LISTING_SOCIETY);
  332.         if ($aclPerm === null)        return false;
  333.         // Get Acl
  334.         $acl $this->aclRepository->findOneBy(array(
  335.             'function'        =>    $function,
  336.             'permission'    =>    $aclPerm
  337.         ));
  338.         if ($acl === null)        return false;
  339.         // Further filtering is done in the Controller
  340.         return $acl->getValue();
  341.     }
  342.     private function canListAny(Access $access nullAccess $userAccessFunction $function)
  343.     {
  344.         // Two Acl_Permission may exist
  345.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_LISTING);
  346.         $aclPermSociety $this->aclPermissionRepository->findOneByName(self::ACL_PERM_LISTING_SOCIETY);
  347.         // If both are null, exit
  348.         if ($aclPerm === null && $aclPermSociety === null)
  349.             return false;
  350.         // Get First one
  351.         if ($aclPerm !== null)
  352.         {
  353.             $acl $this->aclRepository->findOneBy(array(
  354.                 'function'        =>    $function,
  355.                 'permission'    =>    $aclPerm
  356.             ));
  357.             if ($acl !== null)
  358.             {
  359.                 if ($acl->getValue())
  360.                 {
  361.                     // A single positive answer is enough
  362.                     return true;
  363.                 }
  364.             }
  365.         }
  366.         // If we are here it means that nothing good has been found
  367.         // Load second permission
  368.         if ($aclPermSociety !== null)
  369.         {
  370.             $acl $this->aclRepository->findOneBy(array(
  371.                 'function'        =>    $function,
  372.                 'permission'    =>    $aclPermSociety
  373.             ));
  374.             if ($acl !== null)
  375.             {
  376.                 if ($acl->getValue())
  377.                 {
  378.                     // A single positive answer is enough
  379.                     return true;
  380.                 }
  381.             }
  382.         }
  383.         // If we are here, all hope is lost
  384.         return false;
  385.     }
  386. }