src/Security/Voter/BatchRequestVoter.php line 18

Open in your IDE?
  1. <?php
  2. namespace MedBrief\MSR\Security\Voter;
  3. use InvalidArgumentException;
  4. use MedBrief\MSR\Entity\BatchRequest;
  5. use MedBrief\MSR\Entity\Project;
  6. use MedBrief\MSR\Entity\ServiceOption;
  7. use MedBrief\MSR\Entity\ServiceRequest;
  8. use MedBrief\MSR\Entity\User;
  9. use MedBrief\MSR\Traits\Security\Authorization\Voter\ClientSortingSessionTrait;
  10. use Override;
  11. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  12. use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
  13. use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
  14. use Symfony\Component\Security\Core\User\UserInterface;
  15. class BatchRequestVoter implements VoterInterface
  16. {
  17. use ClientSortingSessionTrait;
  18. public const CREATE = 'CREATE';
  19. public const READ = 'READ';
  20. public const UPDATE = 'UPDATE';
  21. public const UPDATE_SIMPLE = 'UPDATE_SIMPLE';
  22. public const DELETE = 'DELETE';
  23. public const ADMINISTRATION = 'ADMINISTRATION';
  24. public const DUPLICATE = 'DUPLICATE';
  25. public const DOWNLOAD = 'DOWNLOAD';
  26. public const UPLOAD_DOCUMENT = 'UPLOAD_DOCUMENT';
  27. public function __construct(private AuthorizationCheckerInterface $authorizationChecker)
  28. {
  29. }
  30. public function supportsAttribute($attribute): bool
  31. {
  32. return in_array($attribute, [
  33. self::CREATE,
  34. self::READ,
  35. self::UPDATE,
  36. self::UPDATE_SIMPLE,
  37. self::DELETE,
  38. self::ADMINISTRATION,
  39. self::DUPLICATE,
  40. self::DOWNLOAD,
  41. self::UPLOAD_DOCUMENT,
  42. ]);
  43. }
  44. public function supportsClass($class): bool
  45. {
  46. $supportedClass = BatchRequest::class;
  47. return $supportedClass === $class || is_subclass_of($class, $supportedClass);
  48. }
  49. /**
  50. *
  51. * @param mixed $entity
  52. */
  53. #[Override]
  54. public function vote(TokenInterface $token, $entity, array $attributes)
  55. {
  56. /**
  57. * START: This is common code for all Voter::vote() methods
  58. */
  59. // check if class of this object is supported by this voter
  60. if (!$this->supportsClass($entity && !is_array($entity) ? $entity::class : '')) {
  61. return VoterInterface::ACCESS_ABSTAIN;
  62. }
  63. // check if the voter is used correct, only allow one attribute
  64. // this isn't a requirement, it's just one easy way for you to
  65. // design your voter
  66. if (1 !== count($attributes)) {
  67. throw new InvalidArgumentException(
  68. 'Only one attribute is allowed for Medbrief Voters.'
  69. );
  70. }
  71. // set the attribute to check against
  72. $attribute = $attributes[0];
  73. // check if the given attribute is covered by this voter
  74. if (!$this->supportsAttribute($attribute)) {
  75. return VoterInterface::ACCESS_ABSTAIN;
  76. }
  77. /** @var BatchRequest $batchRequest */
  78. $batchRequest = $entity;
  79. // get current logged in user
  80. /** @var User $user */
  81. $user = $token->getUser();
  82. // Grab Project this BatchRequest belongs to, so we can do permission checks at the Project level.
  83. /** @var Project $project */
  84. $project = $batchRequest->getProject();
  85. /** @var ServiceRequest $serviceRequest */
  86. $serviceRequest = $batchRequest->getServiceRequest();
  87. $batchRequest->getSortingSession();
  88. // make sure there is a user object (i.e. that the user is logged in)
  89. if (!$user instanceof UserInterface) {
  90. return VoterInterface::ACCESS_DENIED;
  91. }
  92. // Admin users can do everything
  93. if ($this->authorizationChecker->isGranted('ROLE_ADMIN')) {
  94. return VoterInterface::ACCESS_GRANTED;
  95. }
  96. /**
  97. * END: Common code for all Voter:vote() methods. Put custom logic below.
  98. */
  99. // If you can READ the project, you can read the BatchRequest.
  100. if ($attribute === self::READ && $this->authorizationChecker->isGranted('READ', $project)) {
  101. return VoterInterface::ACCESS_GRANTED;
  102. }
  103. $permissionGroup = [
  104. self::UPDATE_SIMPLE,
  105. self::UPLOAD_DOCUMENT,
  106. ];
  107. // if user is client, grant permission to update
  108. // Only grant permission if service option applies to simple batch request.
  109. if (in_array($attribute, $permissionGroup) && $this->hasClientSessionAccess($project, $user) && ($serviceRequest && $serviceRequest->getServiceOption()->getAppliesTo() === ServiceOption::APPLIES_TO_BATCH_REQUEST_SIMPLE)) {
  110. return VoterInterface::ACCESS_GRANTED;
  111. }
  112. if ($attribute === self::DOWNLOAD) {
  113. $clientId = $project->getAccount()->getId();
  114. if (
  115. $this->authorizationChecker->isGranted('ROLE_ACCOUNT_' . $clientId . '_ADMINISTRATOR')
  116. || $this->authorizationChecker->isGranted('ROLE_ACCOUNT_' . $clientId . '_SUPERADMINISTRATOR')
  117. || $this->authorizationChecker->isGranted('ROLE_ACCOUNT_' . $clientId . '_SORTER')
  118. || $this->authorizationChecker->isGranted('ROLE_ACCOUNT_' . $clientId . '_PROJECTMANAGER')
  119. // Include Project level Project Managers in this vote.
  120. || $this->authorizationChecker->isGranted('ROLE_PROJECT_' . $project->getId() . '_PROJECTMANAGER')
  121. ) {
  122. return VoterInterface::ACCESS_GRANTED;
  123. }
  124. }
  125. // If we get to the end of this function, then no decisions have been
  126. // made so we deny access
  127. return VoterInterface::ACCESS_DENIED;
  128. }
  129. }