*/ protected static array $allowedOperations = [ self::READ, self::EDIT, self::CREATE, self::DELETE, ]; public function __construct( protected Security $security, protected Utils $accessUtils, private InternalRequestsService $internalRequestsService, private EntityManagerInterface $em, private SwitchUser $switchUser, ) { } /** * Default `supports` method, that uses self::entityClass and self::allowedOperations to determine if the voter * supports the subject and attribute. */ protected function supports(string $attribute, mixed $subject): bool { if (static::$entityClass === null) { throw new \RuntimeException('Setup the self::$entityClass property, or override the supports() method'); } return $subject !== null && $subject instanceof static::$entityClass && in_array($attribute, static::$allowedOperations); } /** * Default `voteOnAttribute` method, calling one of the `canXxxx()` method, according to the attribute. */ protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool { switch ($attribute) { case self::READ: return $this->canView($subject); case self::EDIT: return $this->canEdit($subject); case self::CREATE: return $this->canCreate($subject); case self::DELETE: return $this->canDelete($subject); } return false; } /** * Does the client have the right to view this resource? */ protected function canView(object $subject): bool { return false; } /** * Does the client have the right to edit this resource? */ protected function canEdit(object $subject): bool { return false; } /** * Does the client have the right to create this resource? */ protected function canCreate(object $subject): bool { return false; } /** * Does the client have the right to delete this resource? */ protected function canDelete(object $subject): bool { return false; } /** * Returns the current logged in user. */ protected function getUser(): ?Access { if ($this->user === null) { /** @var Access $user */ $user = $this->security->getUser(); // <-- Special case of impersonated users: the switch user is not setup yet by symfony, we have to do it "manually" $switchHeaderId = $_SERVER['HTTP_X_SWITCH_USER'] ?? null; if ($switchHeaderId !== null) { $switchAs = $this->em->find(Access::class, $switchHeaderId); if ( $switchAs && ( $this->security->isGranted('ROLE_ALLOWED_TO_SWITCH') || $this->switchUser->isAllowedToSwitch($user, $switchAs) ) ) { $user = $switchAs; } } // --> // If the user is not anonymous, remember it $this->user = $user instanceof Access ? $user : false; } return $this->user !== false ? $this->user : null; } /** * Is the client an authenticated user ? */ protected function isUserLoggedIn(): bool { return $this->getUser() !== null; } /** * Is the current request a valid internal request? * * @see doc/internal_requests.md * @see doc/security.md */ protected function isValidInternalRequest(): bool { $clientIp = $_SERVER['REMOTE_ADDR'] ?? null; $internalRequestToken = $_SERVER['HTTP_INTERNAL_REQUESTS_TOKEN'] ?? ''; return $this->internalRequestsService->isAllowed($clientIp, $internalRequestToken); } }