<?php
declare(strict_types=1);
namespace Crea\SecurityBundle\Voter;
use Crea\SecurityBundle\Entity\User;
use Crea\SecurityBundle\Entity\UserInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
/**
* @extends Voter<string, User>
*/
class UserVoter extends Voter
{
public const USER_LIST = 'SECURITY_USER_LIST';
public const USER_CREATE = 'SECURITY_USER_CREATE';
public const USER_UPDATE_PASSWORD = 'SECURITY_USER_UPDATE_PASSWORD';
public const USER_UPDATE = 'SECURITY_USER_UPDATE';
public const USER_REMOVE = 'SECURITY_USER_REMOVE';
public const USER_IMPERSONATE = 'SECURITY_USER_IMPERSONATE';
public const USER_CONNECT = 'SECURITY_USER_CONNECT';
public const USER_DETAIL = 'SECURITY_USER_DETAIL';
public const USER_ACTIVE = 'SECURITY_USER_ACTIVE';
protected function supports($attribute, $subject): bool
{
return in_array($attribute, [
self::USER_LIST,
self::USER_CREATE,
self::USER_UPDATE_PASSWORD,
self::USER_UPDATE,
self::USER_REMOVE,
self::USER_IMPERSONATE,
self::USER_CONNECT,
self::USER_DETAIL,
self::USER_ACTIVE,
]) && (null === $subject || $subject instanceof User);
}
protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool
{
/** @var User $loggedUser */
$loggedUser = $token->getUser();
if (!$loggedUser instanceof UserInterface) {
return false;
}
switch ($attribute) {
case self::USER_DETAIL:
return $this->voteOnDetail($subject, $loggedUser);
case self::USER_LIST:
return $this->voteOnList($loggedUser);
case self::USER_ACTIVE:
return $this->voteOnActive($loggedUser);
case self::USER_CREATE:
return $this->voteOnCreate($loggedUser);
case self::USER_UPDATE_PASSWORD:
return $this->voteOnpassword($loggedUser);
case self::USER_UPDATE:
return $this->voteOnUpdate($subject, $loggedUser);
case self::USER_REMOVE:
return $this->voteOnRemove($subject, $loggedUser);
case self::USER_IMPERSONATE:
return $this->voteOnImpersonate($subject, $loggedUser);
case self::USER_CONNECT:
return $this->voteOnConnect($subject);
}
return false;
}
private function voteOnImpersonate(?User $subject, UserInterface $loggedUser): bool
{
if (null === $subject) {
if (in_array(self::USER_IMPERSONATE, $loggedUser->getRoles())) {
return true;
}
} else {
/** @var User $user */
$user = $subject;
if (
in_array(self::USER_IMPERSONATE, $loggedUser->getRoles())
&& $user->getLogin() !== $loggedUser->getUsername()
&& $this->voteOnConnect($user)
) {
return true;
}
}
return false;
}
public function voteOnConnect(?UserInterface $subject): bool
{
return null !== $subject && null !== $subject->getProfile() && $subject->isEnabled();
}
private function voteOnList(UserInterface $loggedUser): bool
{
if (in_array(self::USER_LIST, $loggedUser->getRoles())) {
return true;
}
return false;
}
private function voteOnCreate(UserInterface $loggedUser): bool
{
if (in_array(self::USER_CREATE, $loggedUser->getRoles())) {
return true;
}
return false;
}
private function voteOnPassword(UserInterface $loggedUser): bool
{
if (in_array(self::USER_UPDATE_PASSWORD, $loggedUser->getRoles())) {
return true;
}
return false;
}
private function voteOnUpdate(?UserInterface $subject, UserInterface $loggedUser): bool
{
if (!in_array(self::USER_UPDATE, $loggedUser->getRoles())) {
return false;
}
if (null === $subject) {
return true;
}
if ($loggedUser !== $subject) {
return true;
}
if (in_array('ROLE_ADMIN', $loggedUser->getRoles())) {
return true;
}
return false;
}
private function voteOnRemove(?UserInterface $subject, UserInterface $loggedUser): bool
{
if (!in_array(self::USER_REMOVE, $loggedUser->getRoles())) {
return false;
}
if (null === $subject) {
return true;
}
if ($loggedUser !== $subject) {
return true;
}
return false;
}
/**
* By default, a user can see its own detail, the right let him see the other details.
*/
private function voteOnDetail(UserInterface $subject, UserInterface $loggedUser): bool
{
if ($subject->getUsername() === $loggedUser->getUsername()) {
return true;
}
if (in_array(self::USER_DETAIL, $loggedUser->getRoles())) {
return true;
}
return false;
}
private function voteOnActive(UserInterface $loggedUser): bool
{
if (in_array(self::USER_ACTIVE, $loggedUser->getRoles())) {
return true;
}
return false;
}
}