vendor/symfony/security-core/Authorization/AccessDecisionManager.php line 24

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\InvalidArgumentException;
  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.     public const STRATEGY_AFFIRMATIVE 'affirmative';
  23.     public const STRATEGY_CONSENSUS 'consensus';
  24.     public const STRATEGY_UNANIMOUS 'unanimous';
  25.     public const STRATEGY_PRIORITY 'priority';
  26.     private $voters;
  27.     private $strategy;
  28.     private $allowIfAllAbstainDecisions;
  29.     private $allowIfEqualGrantedDeniedDecisions;
  30.     /**
  31.      * @param iterable|VoterInterface[] $voters                             An array or an iterator of VoterInterface instances
  32.      * @param string                    $strategy                           The vote strategy
  33.      * @param bool                      $allowIfAllAbstainDecisions         Whether to grant access if all voters abstained or not
  34.      * @param bool                      $allowIfEqualGrantedDeniedDecisions Whether to grant access if result are equals
  35.      *
  36.      * @throws \InvalidArgumentException
  37.      */
  38.     public function __construct(iterable $voters = [], string $strategy self::STRATEGY_AFFIRMATIVEbool $allowIfAllAbstainDecisions falsebool $allowIfEqualGrantedDeniedDecisions true)
  39.     {
  40.         $strategyMethod 'decide'.ucfirst($strategy);
  41.         if ('' === $strategy || !\is_callable([$this$strategyMethod])) {
  42.             throw new \InvalidArgumentException(sprintf('The strategy "%s" is not supported.'$strategy));
  43.         }
  44.         $this->voters $voters;
  45.         $this->strategy $strategyMethod;
  46.         $this->allowIfAllAbstainDecisions $allowIfAllAbstainDecisions;
  47.         $this->allowIfEqualGrantedDeniedDecisions $allowIfEqualGrantedDeniedDecisions;
  48.     }
  49.     /**
  50.      * @param bool $allowMultipleAttributes Whether to allow passing multiple values to the $attributes array
  51.      *
  52.      * {@inheritdoc}
  53.      */
  54.     public function decide(TokenInterface $token, array $attributes$object null/*, bool $allowMultipleAttributes = false*/)
  55.     {
  56.         $allowMultipleAttributes < \func_num_args() && func_get_arg(3);
  57.         // Special case for AccessListener, do not remove the right side of the condition before 6.0
  58.         if (\count($attributes) > && !$allowMultipleAttributes) {
  59.             throw new InvalidArgumentException(sprintf('Passing more than one Security attribute to "%s()" is not supported.'__METHOD__));
  60.         }
  61.         return $this->{$this->strategy}($token$attributes$object);
  62.     }
  63.     /**
  64.      * Grants access if any voter returns an affirmative response.
  65.      *
  66.      * If all voters abstained from voting, the decision will be based on the
  67.      * allowIfAllAbstainDecisions property value (defaults to false).
  68.      */
  69.     private function decideAffirmative(TokenInterface $token, array $attributes$object null): bool
  70.     {
  71.         $deny 0;
  72.         foreach ($this->voters as $voter) {
  73.             $result $voter->vote($token$object$attributes);
  74.             if (VoterInterface::ACCESS_GRANTED === $result) {
  75.                 return true;
  76.             }
  77.             if (VoterInterface::ACCESS_DENIED === $result) {
  78.                 ++$deny;
  79.             }
  80.         }
  81.         if ($deny 0) {
  82.             return false;
  83.         }
  84.         return $this->allowIfAllAbstainDecisions;
  85.     }
  86.     /**
  87.      * Grants access if there is consensus of granted against denied responses.
  88.      *
  89.      * Consensus means majority-rule (ignoring abstains) rather than unanimous
  90.      * agreement (ignoring abstains). If you require unanimity, see
  91.      * UnanimousBased.
  92.      *
  93.      * If there were an equal number of grant and deny votes, the decision will
  94.      * be based on the allowIfEqualGrantedDeniedDecisions property value
  95.      * (defaults to true).
  96.      *
  97.      * If all voters abstained from voting, the decision will be based on the
  98.      * allowIfAllAbstainDecisions property value (defaults to false).
  99.      */
  100.     private function decideConsensus(TokenInterface $token, array $attributes$object null): bool
  101.     {
  102.         $grant 0;
  103.         $deny 0;
  104.         foreach ($this->voters as $voter) {
  105.             $result $voter->vote($token$object$attributes);
  106.             if (VoterInterface::ACCESS_GRANTED === $result) {
  107.                 ++$grant;
  108.             } elseif (VoterInterface::ACCESS_DENIED === $result) {
  109.                 ++$deny;
  110.             }
  111.         }
  112.         if ($grant $deny) {
  113.             return true;
  114.         }
  115.         if ($deny $grant) {
  116.             return false;
  117.         }
  118.         if ($grant 0) {
  119.             return $this->allowIfEqualGrantedDeniedDecisions;
  120.         }
  121.         return $this->allowIfAllAbstainDecisions;
  122.     }
  123.     /**
  124.      * Grants access if only grant (or abstain) votes were received.
  125.      *
  126.      * If all voters abstained from voting, the decision will be based on the
  127.      * allowIfAllAbstainDecisions property value (defaults to false).
  128.      */
  129.     private function decideUnanimous(TokenInterface $token, array $attributes$object null): bool
  130.     {
  131.         $grant 0;
  132.         foreach ($this->voters as $voter) {
  133.             foreach ($attributes as $attribute) {
  134.                 $result $voter->vote($token$object, [$attribute]);
  135.                 if (VoterInterface::ACCESS_DENIED === $result) {
  136.                     return false;
  137.                 }
  138.                 if (VoterInterface::ACCESS_GRANTED === $result) {
  139.                     ++$grant;
  140.                 }
  141.             }
  142.         }
  143.         // no deny votes
  144.         if ($grant 0) {
  145.             return true;
  146.         }
  147.         return $this->allowIfAllAbstainDecisions;
  148.     }
  149.     /**
  150.      * Grant or deny access depending on the first voter that does not abstain.
  151.      * The priority of voters can be used to overrule a decision.
  152.      *
  153.      * If all voters abstained from voting, the decision will be based on the
  154.      * allowIfAllAbstainDecisions property value (defaults to false).
  155.      */
  156.     private function decidePriority(TokenInterface $token, array $attributes$object null)
  157.     {
  158.         foreach ($this->voters as $voter) {
  159.             $result $voter->vote($token$object$attributes);
  160.             if (VoterInterface::ACCESS_GRANTED === $result) {
  161.                 return true;
  162.             }
  163.             if (VoterInterface::ACCESS_DENIED === $result) {
  164.                 return false;
  165.             }
  166.         }
  167.         return $this->allowIfAllAbstainDecisions;
  168.     }
  169. }