<?php
//----------------------------------------------------------------------
// src/Security/AdminVoter.php
//----------------------------------------------------------------------
namespace App\Security;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\Security;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken;
use Symfony\Component\Security\Core\Role\SwitchUserRole;
use App\Entity\Access;
use App\Entity\Security\Acl;
class AdminVoter extends Voter
{
const ROLE_ADMIN = "is_admin";
const CAN_BE_IMPERSONATED = "can_be_impersonated";
const IS_GRANTED_CONSTANTS = array(
self::ROLE_ADMIN,
self::CAN_BE_IMPERSONATED,
);
public function __construct(ManagerRegistry $doctrine)
{
$this->em = $doctrine->getManager();
}
// Plan.io Task #4453 [See AccessVoter for details]
public function supportsAttribute(string $attribute): bool
{
return in_array($attribute, self::IS_GRANTED_CONSTANTS, true);
}
protected function supports(string $attribute, $subject): bool
{
// if the attribute isn't one we support, return false
if (!in_array($attribute, self::IS_GRANTED_CONSTANTS))
{
return false;
}
return true;
}
protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
{
$user = $token->getUser();
if (!$user instanceof Access)
{
// the user must be logged in; if not, deny access
return false;
}
if (!$user->hasRoleAdmin())
{
return false;
}
switch ($attribute)
{
case self::ROLE_ADMIN:
return $this->isAdmin($user, $token);
case self::CAN_BE_IMPERSONATED:
return $this->canBeImpersonated($user, $subject, $token);
}
throw new \LogicException('This code should not be reached!');
}
// https://symfony.com/doc/5.4/security/impersonating_user.html
private function getOriginalUser($access, $token)
{
$originalUser = null;
if ($token instanceof SwitchUserToken)
{
$originalUser = $token->getOriginalToken()->getUser();
}
if ($originalUser !== null)
{
return $originalUser;
}
return $access;
}
private function isAdmin(Access $access, $token)
{
// Make sure we are looking at the right user
// This ensures that a ROLE_ADMIN with canSwitch
// cannot have access to stuff limited to true ROLE_ADMIN
$originalUser = $this->getOriginalUser($access, $token);
if ($originalUser !== null)
{
if ($originalUser->isAdmin())
{
return true;
}
else
{
return false;
}
}
// We already know that this Access is a true ROLE_ADMIN
return true;
}
private function canBeImpersonated(Access $theOneWhoWantsToSwitch, Access $theOneBeingImpersonated, $token)
{
if ($this->isAdmin($theOneWhoWantsToSwitch, $token))
{
if ($theOneBeingImpersonated->isActive())
{
return true;
}
}
return false;
}
}