From c8c76e5a8d8ba2475a4f7a8cd47a4b44ed377bf3 Mon Sep 17 00:00:00 2001 From: nobohan Date: Thu, 23 Jul 2020 12:34:53 +0200 Subject: [PATCH] sf4 deprecations: new supports and voteOnAttribute methods implemented in ParticipationVoter --- Resources/config/services/authorization.yml | 2 + Security/Authorization/EventVoter.php | 3 +- Security/Authorization/ParticipationVoter.php | 124 +++++++++++++----- 3 files changed, 96 insertions(+), 33 deletions(-) diff --git a/Resources/config/services/authorization.yml b/Resources/config/services/authorization.yml index 131469f65..ca1eb789b 100644 --- a/Resources/config/services/authorization.yml +++ b/Resources/config/services/authorization.yml @@ -12,7 +12,9 @@ services: chill_event.event_participation: class: Chill\EventBundle\Security\Authorization\ParticipationVoter arguments: + - "@security.access.decision_manager" - "@chill.main.security.authorization.helper" + - "@logger" tags: - { name: chill.role } - { name: security.voter } diff --git a/Security/Authorization/EventVoter.php b/Security/Authorization/EventVoter.php index ead7917a7..c62767fa9 100644 --- a/Security/Authorization/EventVoter.php +++ b/Security/Authorization/EventVoter.php @@ -1,6 +1,6 @@ + * Copyright (C) 2020 Champs Libres Cooperative * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -27,6 +27,7 @@ use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Security\Authorization\PersonVoter; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; +use Symfony\Component\Security\Core\Role\Role; use Psr\Log\LoggerInterface; /** diff --git a/Security/Authorization/ParticipationVoter.php b/Security/Authorization/ParticipationVoter.php index 385796a71..50e05e279 100644 --- a/Security/Authorization/ParticipationVoter.php +++ b/Security/Authorization/ParticipationVoter.php @@ -1,7 +1,6 @@ + * Copyright (C) 2020 Champs-Libres * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -24,6 +23,12 @@ use Chill\MainBundle\Security\Authorization\AbstractChillVoter; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\EventBundle\Entity\Participation; use Chill\MainBundle\Entity\User; +use Chill\PersonBundle\Entity\Person; +use Chill\PersonBundle\Security\Authorization\PersonVoter; +use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Role\Role; +use Psr\Log\LoggerInterface; /** * @@ -32,56 +37,111 @@ use Chill\MainBundle\Entity\User; */ class ParticipationVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface { + const SEE = 'CHILL_EVENT_PARTICIPATION_SEE'; + const SEE_DETAILS = 'CHILL_EVENT_PARTICIPATION_SEE_DETAILS'; + const CREATE = 'CHILL_EVENT_PARTICIPATION_CREATE'; + const UPDATE = 'CHILL_EVENT_PARTICIPATION_UPDATE'; + + const ROLES = [ + self::SEE, + self::SEE_DETAILS, + self::CREATE, + self::UPDATE + ]; + /** - * * @var AuthorizationHelper */ protected $authorizationHelper; - - const CREATE = 'CHILL_EVENT_PARTICIPATION_CREATE'; - const UPDATE = 'CHILL_EVENT_PARTICIPATION_UPDATE'; - - 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; - } - - protected function getSupportedAttributes() - { - return array( - self::CREATE, self::UPDATE - ); + $this->accessDecisionManager = $accessDecisionManager; + $this->authorizationHelper = $authorizationHelper; + $this->logger = $logger; } - protected function getSupportedClasses() + public function supports($attribute, $subject) { - return array( - Participation::class - ); + return ($subject instanceof Participation && in_array($attribute, self::ROLES)) + || + ($subject instanceof Person && \in_array($attribute, [ self::CREATE, self::SEE ])) + || + (NULL === $subject && $attribute === self::SEE ) + ; } - protected function isGranted($attribute, $participation, $user = null) + /** + * + * @param string $attribute + * @param Participation $subject + * @param TokenInterface $token + * @return boolean + */ + protected function voteOnAttribute($attribute, $subject, TokenInterface $token) { - if (!$user instanceof User) { + $this->logger->debug(sprintf("Voting from %s class", self::class)); + + if (!$token->getUser() instanceof User) { return false; - } - - return $this->authorizationHelper->userHasAccess($user, $participation, $attribute); + } + + if ($subject instanceof Participation) { + return $this->authorizationHelper->userHasAccess($token->getUser(), $subject, $attribute); + + } elseif ($subject instanceof Person) { + return $this->authorizationHelper->userHasAccess($token->getUser(), $subject, $attribute); + + } 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; - } - - public function getRolesWithHierarchy() - { - return [ 'Event' => $this->getRoles() ]; + return []; } }