src/Security/Voter/PersonVoter.php line 16

Open in your IDE?
  1. <?php
  2. namespace App\Security\Voter;
  3. use App\Entity\Person;
  4. use App\Repository\OAuth\ClientRepository;
  5. use App\User\Entity\Client;
  6. use App\User\Entity\User;
  7. use League\Bundle\OAuth2ServerBundle\Security\User\NullUser;
  8. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  9. use Symfony\Component\Security\Core\Authorization\Voter\Voter;
  10. /**
  11.  * Security voter to control access to Person entities based on client ownership.
  12.  */
  13. class PersonVoter extends Voter
  14. {
  15.     public const VIEW 'view';
  16.     public const EDIT 'edit';
  17.     public const DELETE 'delete';
  18.     private ClientRepository $clientRepository;
  19.     public function __construct(ClientRepository $clientRepository)
  20.     {
  21.         $this->clientRepository $clientRepository;
  22.     }
  23.     protected function supports(string $attribute$subject): bool
  24.     {
  25.         return in_array($attribute, [self::VIEWself::EDITself::DELETE], true)
  26.             && $subject instanceof Person;
  27.     }
  28.     protected function voteOnAttribute(string $attribute$subjectTokenInterface $token): bool
  29.     {
  30.         $user $token->getUser();
  31.         // Determine the client based on user type
  32.         $userClient null;
  33.         
  34.         if ($user instanceof User) {
  35.             $userClient $user->getClient();
  36.             
  37.             // ROLE_SUPER_USER can access everything
  38.             if (in_array('ROLE_SUPER_USER'$user->getRoles(), true)) {
  39.                 return true;
  40.             }
  41.         } elseif ($user instanceof NullUser) {
  42.             // OAuth2 client credentials flow - get client from token
  43.             $oauthClientId $token->getAttribute('oauth_client_id');
  44.             if ($oauthClientId) {
  45.                 $oauthClient $this->clientRepository->find($oauthClientId);
  46.                 if ($oauthClient) {
  47.                     $userClient $oauthClient->getApplicationClient();
  48.                 }
  49.             }
  50.         } else {
  51.             // Unknown user type
  52.             return false;
  53.         }
  54.         /** @var Person $person */
  55.         $person $subject;
  56.         // Check if we have a valid user client
  57.         if (!$userClient) {
  58.             return false;
  59.         }
  60.         // Get the client of the person
  61.         $personClient $this->getPersonClient($person);
  62.         if (!$personClient) {
  63.             return false;
  64.         }
  65.         // Check if both belong to the same client
  66.         if ($userClient->getId() !== $personClient->getId()) {
  67.             return false;
  68.         }
  69.         // For OAuth2 NullUser (API access), if client matches, allow VIEW access
  70.         if ($user instanceof NullUser && $attribute === self::VIEW) {
  71.             return true;
  72.         }
  73.         // For regular User, check roles
  74.         if ($user instanceof User) {
  75.             // User needs at least ROLE_MANAGER or ROLE_ADMIN to access persons
  76.             return in_array('ROLE_MANAGER'$user->getRoles(), true
  77.                 || in_array('ROLE_ADMIN'$user->getRoles(), true);
  78.         }
  79.         return false;
  80.     }
  81.     /**
  82.      * Gets the client of a person.
  83.      * Person can have a client through:
  84.      * 1. Direct user relationship
  85.      * 2. Family member relationship
  86.      */
  87.     private function getPersonClient(Person $person): ?Client
  88.     {
  89.         // Try to get client through user
  90.         if ($person->getUser()) {
  91.             return $person->getUser()->getClient();
  92.         }
  93.         // Try to get client through family member relationship
  94.         if ($person->getFamilyMemberOf()) {
  95.             return $this->getPersonClient($person->getFamilyMemberOf());
  96.         }
  97.         return null;
  98.     }
  99. }