diff --git a/Menu/PersonMenuBuilder.php b/Menu/PersonMenuBuilder.php index c7470fe2a..130622c2c 100644 --- a/Menu/PersonMenuBuilder.php +++ b/Menu/PersonMenuBuilder.php @@ -2,21 +2,15 @@ namespace Chill\EventBundle\Menu; -use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Security\Core\Role\Role; use Knp\Menu\MenuItem; use Chill\MainBundle\Routing\LocalMenuBuilderInterface; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\EventBundle\Security\Authorization\EventVoter; class PersonMenuBuilder implements LocalMenuBuilderInterface { - /** - * - * @var TokenStorageInterface - */ - protected $tokenStorage; /** * @@ -26,18 +20,16 @@ class PersonMenuBuilder implements LocalMenuBuilderInterface /** * - * @var AuthorizationHelper + * @var AuthorizationCheckerInterface */ - protected $authorizationHelper; + protected $authorizationChecker; public function __construct( - AuthorizationHelper $authorizationHelper, - TokenStorageInterface $tokenStorage, + AuthorizationCheckerInterface $authorizationChecker, TranslatorInterface $translator ) { - $this->tokenStorage = $tokenStorage; + $this->authorizationChecker = $authorizationChecker; $this->translator = $translator; - $this->authorizationHelper = $authorizationHelper; } @@ -46,11 +38,7 @@ class PersonMenuBuilder implements LocalMenuBuilderInterface /* @var $person \Chill\PersonBundle\Entity\Person */ $person = $parameters['person']; - $user = $this->tokenStorage->getToken()->getUser(); - $roleSee = new Role(EventVoter::SEE); - - // ASK use authorizationHelper or authorizationChecker ?? - if ($this->authorizationHelper->userHasAccess($user, $person, $roleSee)) { + if ($this->authorizationChecker->isGranted(EventVoter::SEE, $person)) { $menu->addChild($this->translator->trans('Events participation'), [ 'route' => 'chill_event__list_by_person', diff --git a/Resources/config/services/authorization.yml b/Resources/config/services/authorization.yml index d44f1e9d9..131469f65 100644 --- a/Resources/config/services/authorization.yml +++ b/Resources/config/services/authorization.yml @@ -2,7 +2,9 @@ services: chill_event.event_voter: class: Chill\EventBundle\Security\Authorization\EventVoter arguments: + - "@security.access.decision_manager" - "@chill.main.security.authorization.helper" + - "@logger" tags: - { name: chill.role } - { name: security.voter } diff --git a/Resources/config/services/menu.yml b/Resources/config/services/menu.yml index 209d208a7..a2451122f 100644 --- a/Resources/config/services/menu.yml +++ b/Resources/config/services/menu.yml @@ -1,8 +1,7 @@ services: Chill\EventBundle\Menu\PersonMenuBuilder: arguments: - $authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper' - $tokenStorage: '@Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface' + $authorizationChecker: '@Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface' $translator: '@Symfony\Component\Translation\TranslatorInterface' tags: - { name: 'chill.menu_builder' } \ No newline at end of file diff --git a/Resources/views/Event/listByPerson.html.twig b/Resources/views/Event/listByPerson.html.twig index 9c174bb92..cc99cff4f 100644 --- a/Resources/views/Event/listByPerson.html.twig +++ b/Resources/views/Event/listByPerson.html.twig @@ -50,7 +50,8 @@ diff --git a/Security/Authorization/EventVoter.php b/Security/Authorization/EventVoter.php index 8f74e649a..77548f1a5 100644 --- a/Security/Authorization/EventVoter.php +++ b/Security/Authorization/EventVoter.php @@ -9,6 +9,10 @@ use Chill\MainBundle\Security\ProvideRoleHierarchyInterface; use Chill\EventBundle\Entity\Event; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Entity\User; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; +use Psr\Log\LoggerInterface; + /** * Description of EventVoter @@ -18,53 +22,114 @@ use Chill\MainBundle\Entity\User; */ class EventVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface { - const SEE = 'CHILL_EVENT_SEE'; const SEE_DETAILS = 'CHILL_EVENT_SEE_DETAILS'; const CREATE = 'CHILL_EVENT_CREATE'; const UPDATE = 'CHILL_EVENT_UPDATE'; + const ROLES = [ + self::SEE, + self::SEE_DETAILS, + self::CREATE, + self::UPDATE + ]; + + /** + * @var AuthorizationHelper + */ protected $authorizationHelper; - public function __construct(AuthorizationHelper $helper) + /** + * @var AccessDecisionManagerInterface + */ + protected $accessDecisionManager; + + /** + * @var LoggerInterface + */ + protected $logger; + + public function __construct( + AccessDecisionManagerInterface $accessDecisionManager, + AuthorizationHelper $authorizationHelper, + LoggerInterface $logger + ) { - $this->authorizationHelper = $helper; + $this->accessDecisionManager = $accessDecisionManager; + $this->authorizationHelper = $authorizationHelper; + $this->logger = $logger; } - protected function getSupportedAttributes() + public function supports($attribute, $subject) { - return array(self::SEE, self::SEE_DETAILS, - self::CREATE, self::UPDATE); + return ($subject instanceof Event && in_array($attribute, self::ROLES)) + || + ($subject instanceof Person && \in_array($attribute, [ self::CREATE, self::SEE ])) + || + (NULL === $subject && $attribute === self::SEE ) + ; } - - protected function getSupportedClasses() + + /** + * + * @param string $attribute + * @param Event $subject + * @param TokenInterface $token + * @return boolean + */ + protected function voteOnAttribute($attribute, $subject, TokenInterface $token) { - return array(Event::class); - } - - protected function isGranted($attribute, $event, $user = null) - { - if (!$user instanceof User) { - return false; - } + $this->logger->debug(sprintf("Voting from %s class", self::class)); - return $this->authorizationHelper->userHasAccess($user, $event, $attribute); + if (!$token->getUser() instanceof User) { + return false; + } + + if ($subject instanceof Event) { + if ($subject->getPerson() === null) { + throw new \LogicException("You should associate a person with event " + . "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; + } + + return $this->authorizationHelper->userHasAccess( + $token->getUser(), + $subject, + $attribute + ); } - + + public function getRoles() { - return $this->getSupportedAttributes(); + return self::ROLES; + } + + public function getRolesWithHierarchy() + { + return [ + 'Event' => self::ROLES + ]; } public function getRolesWithoutScope() { - return null; + return []; } - - public function getRolesWithHierarchy() - { - return [ 'Event' => $this->getRoles() ]; - } - }