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

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