vendor/netgen/layouts-ibexa/lib/Security/Authorization/Voter/RepositoryAccessVoter.php line 22

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Netgen\Layouts\Ibexa\Security\Authorization\Voter;
  4. use Ibexa\Core\MVC\Symfony\Security\Authorization\Attribute;
  5. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  6. use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
  7. use Symfony\Component\Security\Core\Authorization\Voter\Voter;
  8. use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
  9. use function is_string;
  10. use function str_starts_with;
  11. /**
  12. * Votes on Netgen Layouts attributes (ROLE_NGLAYOUTS_*) by matching corresponding access
  13. * rights in Ibexa CMS Repository.
  14. *
  15. * @extends \Symfony\Component\Security\Core\Authorization\Voter\Voter<string, \Netgen\Layouts\API\Values\Value|null>
  16. */
  17. final class RepositoryAccessVoter extends Voter
  18. {
  19. /**
  20. * Identifier of the Ibexa CMS module used for creating Netgen Layouts permissions.
  21. */
  22. private const MODULE = 'nglayouts';
  23. /**
  24. * Map of supported attributes to corresponding functions in the Ibexa CMS module.
  25. */
  26. private const ATTRIBUTE_TO_POLICY_MAP = [
  27. 'ROLE_NGLAYOUTS_ADMIN' => 'admin',
  28. 'ROLE_NGLAYOUTS_EDITOR' => 'editor',
  29. 'ROLE_NGLAYOUTS_API' => 'api',
  30. ];
  31. public function __construct(
  32. private RoleHierarchyInterface $roleHierarchy,
  33. private AccessDecisionManagerInterface $accessDecisionManager,
  34. ) {}
  35. /**
  36. * @param mixed[] $attributes
  37. */
  38. public function vote(TokenInterface $token, mixed $subject, array $attributes): int
  39. {
  40. // abstain vote by default in case none of the attributes are supported
  41. $vote = self::ACCESS_ABSTAIN;
  42. foreach ($attributes as $attribute) {
  43. if (!is_string($attribute) || !$this->supports($attribute, $subject)) {
  44. continue;
  45. }
  46. $reachableAttributes = $this->roleHierarchy->getReachableRoleNames([$attribute]);
  47. // rely on vote resolved by parent implementation
  48. $vote = parent::vote($token, $subject, $reachableAttributes);
  49. // return only if granted
  50. if ($vote === self::ACCESS_GRANTED) {
  51. return self::ACCESS_GRANTED;
  52. }
  53. }
  54. return $vote;
  55. }
  56. protected function supports(string $attribute, mixed $subject): bool
  57. {
  58. return str_starts_with($attribute, 'ROLE_NGLAYOUTS_');
  59. }
  60. protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
  61. {
  62. if (!isset(self::ATTRIBUTE_TO_POLICY_MAP[$attribute])) {
  63. return false;
  64. }
  65. $function = self::ATTRIBUTE_TO_POLICY_MAP[$attribute];
  66. return $this->accessDecisionManager->decide(
  67. $token,
  68. [new Attribute(self::MODULE, $function)],
  69. $subject,
  70. );
  71. }
  72. }