<?phpnamespace AppBundle\Security\Voter;use DomainBundle\Helper\ActorGetter;use Psr\Container\ContainerInterface;use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;use Symfony\Component\Security\Core\Authorization\Voter\Voter;use Symfony\Contracts\Service\ServiceSubscriberInterface;/** * Security voter that tests whether an operator is permitted * to access the requested resource. */class OperatorAccessVoter extends Voter implements ServiceSubscriberInterface{ const OPERATOR_ACCESS = 'OPERATOR_ACCESS'; /** * @var ContainerInterface */ protected ContainerInterface $container; /** * @param ContainerInterface $container */ public function __construct(ContainerInterface $container) { $this->container = $container; } /** * @inheritDoc */ public static function getSubscribedServices(): array { return [ ActorGetter::class, AuthorizationCheckerInterface::class, ]; } /** * Gets the list of supported attributes. */ protected function getSupportedAttributes(): array { return [ self::OPERATOR_ACCESS, ]; } /** * @inheritDoc */ public function supports($attribute, $subject): bool { if (!in_array($attribute, $this->getSupportedAttributes(), true)) { return false; } return true; } /** * @inheritDoc */ protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool { // Admins are always granted operator access if ($this->getAuthorizationChecker()->isGranted('ROLE_ADMIN')) { return true; } // Get the logged-in actor $user = $token->getUser(); $actor = $this->getActorGetter()->getActorByUser($user); // Deny access to non-operator users if (!isset($actor['operator']['uuid'])) { return false; } // Always grant access to null if ($subject === null) { return true; } // Get subject UUID $subject = (is_array($subject) && isset($subject['uuid'])) ? $subject['uuid'] : $subject; // Grant access if the actor and the subject are the same return $actor['operator']['uuid']->equalTo($subject); } /** * @return ActorGetter */ protected function getActorGetter(): ActorGetter { return $this->container->get(ActorGetter::class); } /** * @return AuthorizationCheckerInterface */ protected function getAuthorizationChecker(): AuthorizationCheckerInterface { return $this->container->get(AuthorizationCheckerInterface::class); }}