vendor/symfony/symfony/src/Symfony/Component/Security/Core/Authorization/AccessDecisionManager.php line 88

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\Security\Core\Authorization;
  11. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  12. use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
  13. use Symfony\Component\Security\Core\Exception\LogicException;
  14. /**
  15.  * AccessDecisionManager is the base class for all access decision managers
  16.  * that use decision voters.
  17.  *
  18.  * @author Fabien Potencier <fabien@symfony.com>
  19.  */
  20. class AccessDecisionManager implements AccessDecisionManagerInterface
  21. {
  22.     const STRATEGY_AFFIRMATIVE 'affirmative';
  23.     const STRATEGY_CONSENSUS 'consensus';
  24.     const STRATEGY_UNANIMOUS 'unanimous';
  25.     private $voters;
  26.     private $strategy;
  27.     private $allowIfAllAbstainDecisions;
  28.     private $allowIfEqualGrantedDeniedDecisions;
  29.     /**
  30.      * @param iterable|VoterInterface[] $voters                             An iterator of VoterInterface instances
  31.      * @param string                    $strategy                           The vote strategy
  32.      * @param bool                      $allowIfAllAbstainDecisions         Whether to grant access if all voters abstained or not
  33.      * @param bool                      $allowIfEqualGrantedDeniedDecisions Whether to grant access if result are equals
  34.      *
  35.      * @throws \InvalidArgumentException
  36.      */
  37.     public function __construct($voters = [], $strategy self::STRATEGY_AFFIRMATIVE$allowIfAllAbstainDecisions false$allowIfEqualGrantedDeniedDecisions true)
  38.     {
  39.         $strategyMethod 'decide'.ucfirst($strategy);
  40.         if ('' === $strategy || !\is_callable([$this$strategyMethod])) {
  41.             throw new \InvalidArgumentException(sprintf('The strategy "%s" is not supported.'$strategy));
  42.         }
  43.         $this->voters $voters;
  44.         $this->strategy $strategyMethod;
  45.         $this->allowIfAllAbstainDecisions = (bool) $allowIfAllAbstainDecisions;
  46.         $this->allowIfEqualGrantedDeniedDecisions = (bool) $allowIfEqualGrantedDeniedDecisions;
  47.     }
  48.     /**
  49.      * Configures the voters.
  50.      *
  51.      * @param VoterInterface[] $voters An array of VoterInterface instances
  52.      *
  53.      * @deprecated since version 3.3, to be removed in 4.0. Pass the voters to the constructor instead.
  54.      */
  55.     public function setVoters(array $voters)
  56.     {
  57.         @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 3.3 and will be removed in 4.0. Pass the voters to the constructor instead.'__METHOD__), \E_USER_DEPRECATED);
  58.         $this->voters $voters;
  59.     }
  60.     /**
  61.      * {@inheritdoc}
  62.      */
  63.     public function decide(TokenInterface $token, array $attributes$object null)
  64.     {
  65.         return $this->{$this->strategy}($token$attributes$object);
  66.     }
  67.     /**
  68.      * Grants access if any voter returns an affirmative response.
  69.      *
  70.      * If all voters abstained from voting, the decision will be based on the
  71.      * allowIfAllAbstainDecisions property value (defaults to false).
  72.      */
  73.     private function decideAffirmative(TokenInterface $token, array $attributes$object null)
  74.     {
  75.         $deny 0;
  76.         foreach ($this->voters as $voter) {
  77.             $result $this->vote($voter$token$object$attributes);
  78.             if (VoterInterface::ACCESS_GRANTED === $result) {
  79.                 return true;
  80.             }
  81.             if (VoterInterface::ACCESS_DENIED === $result) {
  82.                 ++$deny;
  83.             }
  84.         }
  85.         if ($deny 0) {
  86.             return false;
  87.         }
  88.         return $this->allowIfAllAbstainDecisions;
  89.     }
  90.     /**
  91.      * Grants access if there is consensus of granted against denied responses.
  92.      *
  93.      * Consensus means majority-rule (ignoring abstains) rather than unanimous
  94.      * agreement (ignoring abstains). If you require unanimity, see
  95.      * UnanimousBased.
  96.      *
  97.      * If there were an equal number of grant and deny votes, the decision will
  98.      * be based on the allowIfEqualGrantedDeniedDecisions property value
  99.      * (defaults to true).
  100.      *
  101.      * If all voters abstained from voting, the decision will be based on the
  102.      * allowIfAllAbstainDecisions property value (defaults to false).
  103.      */
  104.     private function decideConsensus(TokenInterface $token, array $attributes$object null)
  105.     {
  106.         $grant 0;
  107.         $deny 0;
  108.         foreach ($this->voters as $voter) {
  109.             $result $this->vote($voter$token$object$attributes);
  110.             if (VoterInterface::ACCESS_GRANTED === $result) {
  111.                 ++$grant;
  112.             } elseif (VoterInterface::ACCESS_DENIED === $result) {
  113.                 ++$deny;
  114.             }
  115.         }
  116.         if ($grant $deny) {
  117.             return true;
  118.         }
  119.         if ($deny $grant) {
  120.             return false;
  121.         }
  122.         if ($grant 0) {
  123.             return $this->allowIfEqualGrantedDeniedDecisions;
  124.         }
  125.         return $this->allowIfAllAbstainDecisions;
  126.     }
  127.     /**
  128.      * Grants access if only grant (or abstain) votes were received.
  129.      *
  130.      * If all voters abstained from voting, the decision will be based on the
  131.      * allowIfAllAbstainDecisions property value (defaults to false).
  132.      */
  133.     private function decideUnanimous(TokenInterface $token, array $attributes$object null)
  134.     {
  135.         $grant 0;
  136.         foreach ($this->voters as $voter) {
  137.             foreach ($attributes as $attribute) {
  138.                 $result $this->vote($voter$token$object, [$attribute]);
  139.                 if (VoterInterface::ACCESS_DENIED === $result) {
  140.                     return false;
  141.                 }
  142.                 if (VoterInterface::ACCESS_GRANTED === $result) {
  143.                     ++$grant;
  144.                 }
  145.             }
  146.         }
  147.         // no deny votes
  148.         if ($grant 0) {
  149.             return true;
  150.         }
  151.         return $this->allowIfAllAbstainDecisions;
  152.     }
  153.     /**
  154.      * TokenInterface vote proxy method.
  155.      *
  156.      * Acts as a BC layer when the VoterInterface is not implemented on the voter.
  157.      *
  158.      * @deprecated as of 3.4 and will be removed in 4.0. Call the voter directly as the instance will always be a VoterInterface
  159.      */
  160.     private function vote($voterTokenInterface $token$subject$attributes)
  161.     {
  162.         if ($voter instanceof VoterInterface) {
  163.             return $voter->vote($token$subject$attributes);
  164.         }
  165.         if (method_exists($voter'vote')) {
  166.             @trigger_error(sprintf('Calling vote() on an voter without %1$s is deprecated as of 3.4 and will be removed in 4.0. Implement the %1$s on your voter.'VoterInterface::class), \E_USER_DEPRECATED);
  167.             // making the assumption that the signature matches
  168.             return $voter->vote($token$subject$attributes);
  169.         }
  170.         throw new LogicException(sprintf('"%s" should implement the "%s" interface when used as voter.', \get_class($voter), VoterInterface::class));
  171.     }
  172. }