refactor ACL for easy voter. Apply on TaskVoter

This commit is contained in:
2021-09-03 12:43:12 +02:00
parent 5b70fb2ee5
commit dc09c9424a
14 changed files with 411 additions and 139 deletions

View File

@@ -18,7 +18,12 @@
namespace Chill\TaskBundle\Security\Authorization;
use Chill\EventBundle\Entity\Event;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Security\Authorization\AbstractChillVoter;
use Chill\MainBundle\Security\Authorization\VoterFactoryInterface;
use Chill\MainBundle\Security\Authorization\VoterInterface;
use Chill\MainBundle\Security\Resolver\CenterResolverDispatcher;
use Chill\TaskBundle\Entity\AbstractTask;
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
@@ -32,12 +37,7 @@ use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Chill\TaskBundle\Security\Authorization\AuthorizationEvent;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class TaskVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface
final class TaskVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface
{
const CREATE = 'CHILL_TASK_TASK_CREATE';
const UPDATE = 'CHILL_TASK_TASK_UPDATE';
@@ -51,50 +51,52 @@ class TaskVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterf
self::DELETE
];
/**
*
* @var AuthorizationHelper
*/
protected $authorizationHelper;
protected AuthorizationHelper $authorizationHelper;
/**
*
* @var AccessDecisionManagerInterface
*/
protected $accessDecisionManager;
protected AccessDecisionManagerInterface $accessDecisionManager;
/**
*
* @var LoggerInterface
*/
protected $logger;
/**
*
* @var EventDispatcherInterface
*/
protected $eventDispatcher;
protected LoggerInterface $logger;
protected EventDispatcherInterface $eventDispatcher;
protected CenterResolverDispatcher $centerResolverDispatcher;
protected VoterInterface $voter;
public function __construct(
AccessDecisionManagerInterface $accessDecisionManager,
AuthorizationHelper $authorizationHelper,
EventDispatcherInterface $eventDispatcher,
LoggerInterface $logger
LoggerInterface $logger,
CenterResolverDispatcher $centerResolverDispatcher,
VoterFactoryInterface $voterFactory
) {
$this->accessDecisionManager = $accessDecisionManager;
$this->authorizationHelper = $authorizationHelper;
$this->eventDispatcher = $eventDispatcher;
$this->logger = $logger;
$this->centerResolverDispatcher = $centerResolverDispatcher;
$this->voter = $voterFactory
->generate(AbstractTask::class)
->addCheckFor(AbstractTask::class, self::ROLES)
->addCheckFor(Person::class, [self::SHOW])
->addCheckFor(null, [self::SHOW])
->build()
;
}
public function supports($attribute, $subject)
{
return $this->voter->supports($attribute, $subject);
/*
return ($subject instanceof AbstractTask && in_array($attribute, self::ROLES))
||
($subject instanceof Person && \in_array($attribute, [ self::CREATE, self::SHOW ]))
||
(NULL === $subject && $attribute === self::SHOW )
;
*/
}
/**
@@ -111,40 +113,60 @@ class TaskVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterf
if (!$token->getUser() instanceof User) {
return false;
}
$event = new AuthorizationEvent($subject, $attribute, $token);
$this->eventDispatcher->dispatch(AuthorizationEvent::VOTE, $event);
if ($event->hasVote()) {
$this->logger->debug("The TaskVoter is overriding by "
.AuthorizationEvent::VOTE, [
'vote' => $event->getVote(),
'task_id' => $subject->getId()
]);
return $event->getVote();
}
// do pre-flight check, relying on other decision manager
// those pre-flight check concern associated entities
if ($subject instanceof AbstractTask) {
if (NULL !== $person = $subject->getPerson()) {
if (!$this->accessDecisionManager->decide($token, [PersonVoter::SEE], $person)) {
return false;
}
} elseif (false) {
// here will come the test if the task is associated to an accompanying course
}
}
// do regular check.
return $this->voter->voteOnAttribute($attribute, $subject, $token);
/*
if ($subject instanceof AbstractTask) {
if ($subject->getPerson() === null) {
throw new \LogicException("You should associate a person with task "
. "in order to check autorizations");
}
$person = $subject->getPerson();
} elseif ($subject instanceof Person) {
$person = $subject;
} else {
// subject is null. We check that at least one center is reachable
$centers = $this->authorizationHelper->getReachableCenters($token->getUser(), new Role($attribute));
return count($centers) > 0;
}
if (!$this->accessDecisionManager->decide($token, [PersonVoter::SEE], $person)) {
return false;
}
$center = $this->centerResolverDispatcher->resolveCenter($subject);
if (NULL === $center) {
return false;
}
@@ -153,6 +175,7 @@ class TaskVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterf
$subject,
$attribute
);
*/
}
public function getRoles()