vendor/easycorp/easyadmin-bundle/src/Security/SecurityVoter.php line 18

Open in your IDE?
  1. <?php
  2. namespace EasyCorp\Bundle\EasyAdminBundle\Security;
  3. use EasyCorp\Bundle\EasyAdminBundle\Dto\ActionDto;
  4. use EasyCorp\Bundle\EasyAdminBundle\Dto\CrudDto;
  5. use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto;
  6. use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;
  7. use EasyCorp\Bundle\EasyAdminBundle\Dto\MenuItemDto;
  8. use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProvider;
  9. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  10. use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
  11. use Symfony\Component\Security\Core\Authorization\Voter\Voter;
  12. /*
  13. * @author Javier Eguiluz <javier.eguiluz@gmail.com>
  14. */
  15. final class SecurityVoter extends Voter
  16. {
  17. private AuthorizationCheckerInterface $authorizationChecker;
  18. private AdminContextProvider $adminContextProvider;
  19. public function __construct(AuthorizationCheckerInterface $authorizationChecker, AdminContextProvider $adminContextProvider)
  20. {
  21. $this->authorizationChecker = $authorizationChecker;
  22. $this->adminContextProvider = $adminContextProvider;
  23. }
  24. protected function supports(string $permissionName, mixed $subject): bool
  25. {
  26. return Permission::exists($permissionName);
  27. }
  28. protected function voteOnAttribute($permissionName, $subject, TokenInterface $token): bool
  29. {
  30. if (Permission::EA_VIEW_MENU_ITEM === $permissionName) {
  31. return $this->voteOnViewMenuItemPermission($subject);
  32. }
  33. if (Permission::EA_EXECUTE_ACTION === $permissionName) {
  34. return $this->voteOnExecuteActionPermission($this->adminContextProvider->getContext()->getCrud(), $subject['action'] ?? null, $subject['entity'] ?? null);
  35. }
  36. if (Permission::EA_VIEW_FIELD === $permissionName) {
  37. return $this->voteOnViewPropertyPermission($subject);
  38. }
  39. if (Permission::EA_ACCESS_ENTITY === $permissionName) {
  40. return $this->voteOnViewEntityPermission($subject);
  41. }
  42. if (Permission::EA_EXIT_IMPERSONATION === $permissionName) {
  43. return $this->voteOnExitImpersonationPermission();
  44. }
  45. return true;
  46. }
  47. private function voteOnViewMenuItemPermission(MenuItemDto $menuItemDto): bool
  48. {
  49. // users can see the menu item if they have the permission required by the menu item
  50. return $this->authorizationChecker->isGranted($menuItemDto->getPermission(), $menuItemDto);
  51. }
  52. private function voteOnExecuteActionPermission(CrudDto $crudDto, ActionDto|string $actionNameOrDto, ?EntityDto $entityDto): bool
  53. {
  54. // users can run the Crud action if:
  55. // * they have the required permission to execute the action on the given entity instance
  56. // * the action is not disabled
  57. $actionName = \is_string($actionNameOrDto) ? $actionNameOrDto : $actionNameOrDto->getName();
  58. $actionPermission = $crudDto->getActionsConfig()->getActionPermissions()[$actionName] ?? null;
  59. $disabledActionNames = $crudDto->getActionsConfig()->getDisabledActions();
  60. $subject = null === $entityDto ? null : $entityDto->getInstance();
  61. return $this->authorizationChecker->isGranted($actionPermission, $subject) && !\in_array($actionName, $disabledActionNames, true);
  62. }
  63. private function voteOnViewPropertyPermission(FieldDto $field): bool
  64. {
  65. // users can see the field if they have the permission required by the field
  66. return $this->authorizationChecker->isGranted($field->getPermission(), $field);
  67. }
  68. private function voteOnViewEntityPermission(EntityDto $entityDto): bool
  69. {
  70. // users can see the entity if they have the required permission on the specific entity instance
  71. return $this->authorizationChecker->isGranted($entityDto->getPermission(), $entityDto->getInstance());
  72. }
  73. private function voteOnExitImpersonationPermission(): bool
  74. {
  75. // users can exit impersonation if they are currently impersonating another user.
  76. // In Symfony, that means that current user has the special impersonator permission
  77. if (\defined('Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter::IS_IMPERSONATOR')) {
  78. $impersonatorPermission = 'IS_IMPERSONATOR';
  79. } else {
  80. $impersonatorPermission = 'ROLE_PREVIOUS_ADMIN';
  81. }
  82. return $this->authorizationChecker->isGranted($impersonatorPermission);
  83. }
  84. }