ModuleVoter.php 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Security\Voter;
  4. use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
  5. use App\Entity\Access\Access;
  6. use App\Entity\Organization\Organization;
  7. use App\Service\Security\Module;
  8. use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
  9. use Symfony\Component\Security\Core\Authentication\Token\NullToken;
  10. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  11. use Symfony\Component\Security\Core\Authorization\Voter\Voter;
  12. /**
  13. * Class ModuleVoter : permet d'assurer que la resource appelée est comprise dans l'un des modules de la structure
  14. * @package App\Security
  15. */
  16. class ModuleVoter extends Voter
  17. {
  18. const HAVING_MODULE = 'IS_HAVING_MODULE';
  19. public function __construct(private Module $module, private ResourceMetadataCollectionFactoryInterface $resourceMetadataFactory)
  20. { }
  21. protected function supports(string $attribute, $subject): bool
  22. {
  23. if (!in_array($attribute, [self::HAVING_MODULE])) {
  24. return false;
  25. }
  26. return true;
  27. }
  28. /**
  29. * @param string $attribute
  30. * @param mixed $subject
  31. * @param TokenInterface $token
  32. * @return bool
  33. * @throws \ApiPlatform\Exception\ResourceClassNotFoundException
  34. */
  35. protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
  36. {
  37. if (!$subject->attributes->get('_api_resource_class')) {
  38. throw new AccessDeniedHttpException(sprintf('Missing resource class'));
  39. }
  40. if ($token instanceof NullToken) {
  41. return false;
  42. }
  43. $resourceMetadata = $this->resourceMetadataFactory->create($subject->attributes->get('_api_resource_class'));
  44. $module = $this->module->getModuleByResourceName($resourceMetadata->getOperation()->getShortName());
  45. //Check if there is a module for this entity : eq configuration problem
  46. if (null === $module) {
  47. throw new AccessDeniedHttpException(sprintf('There are no module for the entity (%s) !', $resourceMetadata->getOperation()->getShortName()));
  48. }
  49. /** @var Access $currentAccess */
  50. $currentAccess = $token->getUser();
  51. /** @var Organization $organization */
  52. $organization = $currentAccess->getOrganization();
  53. if (!$this->isOrganizationHaveThisModule($organization, $module)) {
  54. throw new AccessDeniedHttpException(
  55. sprintf("The organization doesn't have the module '%s'", $module)
  56. );
  57. }
  58. return true;
  59. }
  60. /**
  61. * Test si l'organisation possède le module parmis les modules possédés via le produit souscrit, les options souscrites
  62. * ou les modules possédées via des conditions particulières (isCmf par exemple)
  63. *
  64. * @param Organization $organization
  65. * @param string $module
  66. * @return bool
  67. */
  68. private function isOrganizationHaveThisModule(Organization $organization, string $module): bool
  69. {
  70. $organizationModules = $this->module->getOrganizationModules($organization);
  71. return in_array($module, $organizationModules);
  72. }
  73. }