src/Security/Voter/UserRequest/UserMayPostToStatus.php line 15

Open in your IDE?
  1. <?php
  2. namespace App\Security\Voter\UserRequest;
  3. use App\DTO\UserRequest\StatusPostDTO;
  4. use App\Entity\User;
  5. use App\Manager\UserRightsManagerInterface;
  6. use App\Security\Voter\UserRequest\UserOwnsRequestVoter;
  7. use Psr\Log\LoggerInterface;
  8. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  9. use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
  10. use Symfony\Component\Security\Core\Authorization\Voter\Voter;
  11. use WebServiceCollectionBundle\Model\AtlasPce\UserRequestRequestModel;
  12. class UserMayPostToStatus extends Voter
  13. {
  14.     public const POST_STATUS_ATTR   'POST_STATUS';
  15.     public const ROLES_REQUIREMENTS = [
  16.         'to_qualify'      => [
  17.             UserRightsManagerInterface::ROLE_CLIENT,
  18.             UserRightsManagerInterface::ROLE_SUEZ
  19.         ],
  20.         'to_specify'      => [ UserRightsManagerInterface::ROLE_SUEZ ],
  21.         'to_plan'         => [ UserRightsManagerInterface::ROLE_SUEZ ],
  22.         'planned'         => [ UserRightsManagerInterface::ROLE_SUEZ ],
  23.         'ongoing'         => [ UserRightsManagerInterface::ROLE_SUEZ ],
  24.         'done'            => [ UserRightsManagerInterface::ROLE_SUEZ ],
  25.         'closed_rejected' => [ UserRightsManagerInterface::ROLE_ADMIN ],
  26.         'closed'          => [ UserRightsManagerInterface::ROLE_ADMIN ],
  27.     ];
  28.     /**
  29.      * @var AuthorizationCheckerInterface
  30.      */
  31.     protected $authChecker;
  32.     /**
  33.      * @var LoggerInterface
  34.      */
  35.     protected $logger;
  36.     /**
  37.      * @param AuthorizationCheckerInterface $authChecker
  38.      * @param LoggerInterface               $logger
  39.      */
  40.     public function __construct(
  41.         AuthorizationCheckerInterface $authChecker,
  42.         LoggerInterface $logger
  43.     ) {
  44.         $this->authChecker       $authChecker;
  45.         $this->logger            $logger;
  46.     }
  47.     /**
  48.      * {@inheritdoc}
  49.      */
  50.     public function supports($attribute$subject)
  51.     {
  52.         $isPostStatus           = static::POST_STATUS_ATTR === $attribute;
  53.         $subjectIsStatusPostDTO $subject instanceof StatusPostDTO;
  54.         return $isPostStatus && $subjectIsStatusPostDTO;
  55.     }
  56.     /**
  57.      * {@inheritdoc}
  58.      */
  59.     public function voteOnAttribute($attribute$subjectTokenInterface $token)
  60.     {
  61.         $user $token->getUser();
  62.         switch ($attribute) {
  63.             case static::POST_STATUS_ATTR:
  64.                 return $this->mayPost($subject$user);
  65.         }
  66.         throw new \LogicException('This code should not be reached!');
  67.     }
  68.     /**
  69.      * Test if a user is allowed to view a request.
  70.      *
  71.      * @param  StatusPostDTO  $dto
  72.      * @param  User           $tokenAttributes
  73.      *
  74.      * @return bool
  75.      */
  76.     protected function mayPost(StatusPostDTO $dtoUser $user): bool
  77.     {
  78.         $status  $dto->getTargetStatus();
  79.         if (!array_key_exists($status, static::ROLES_REQUIREMENTS)) {
  80.             $this->logger->warning('[UserMayPostToStatus] Unknown status requirements: {status}.', [
  81.                 'status' => $status,
  82.             ]);
  83.             return false;
  84.         }
  85.         $requiredRoles = static::ROLES_REQUIREMENTS[$status];
  86.         $roles        $user->getRoles();
  87.         $hasRole      = (bool) count(array_intersect($requiredRoles$roles));
  88.         if (!$hasRole) {
  89.             $this->logger->info('[UserMayPostToStatus] User cannot modify status to {status}, because one of the following roles is required {roles}', [
  90.                 'status' => $status,
  91.                 'roles'  => json_encode($requiredRoles),
  92.             ]);
  93.             return false;
  94.         }
  95.         /*
  96.             Things get tricky here. There are two use cases:
  97.             1. the user is Suez, and then only the role check is needed. Suez user can act on every request just on a role-based checked.
  98.             2. the user is client, we need to check both the role, but also if the client is the creator or an admin to avoid one client posting status of another client.
  99.          */
  100.         if (in_array(UserRightsManagerInterface::ROLE_SUEZ$roles)) {
  101.             $this->logger->info('[UserMayPostToStatus] User can modify status to {status}, since only it only requires a Suez role to do so. Required roles: {roles}', [
  102.                 'status' => $status,
  103.                 'roles'  => json_encode($requiredRoles),
  104.             ]);
  105.             // Suez role is needed here, so we just need to check if the user has the role. 
  106.             return true;
  107.         }
  108.         // Below this point, we must check both the role and the creator id.
  109.         $request            $dto->getRequest();
  110.         $userIsOwnerOrAdmin $this->authChecker->isGranted(UserOwnsRequestVoter::USER_OWNS_REQUEST$request);
  111.         if ($userIsOwnerOrAdmin) {
  112.             $this->logger->info('[UserMayPostToStatus] User can modify status to {status}, since user is either creator or admin.', [
  113.                 'status' => $status,
  114.                 'roles'  => json_encode($requiredRoles),
  115.             ]);
  116.             return true;
  117.         }
  118.         // No need to log anything more in this voter, UserOwnsRequestVoter will already have logged everything relevant.
  119.         return false;
  120.     }
  121. }