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

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <[email protected]>
  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. /**
  14.  * AccessDecisionManager is the base class for all access decision managers
  15.  * that use decision voters.
  16.  *
  17.  * @author Fabien Potencier <[email protected]>
  18.  */
  19. class AccessDecisionManager implements AccessDecisionManagerInterface
  20. {
  21.     const STRATEGY_AFFIRMATIVE 'affirmative';
  22.     const STRATEGY_CONSENSUS 'consensus';
  23.     const STRATEGY_UNANIMOUS 'unanimous';
  24.     private $voters;
  25.     private $strategy;
  26.     private $allowIfAllAbstainDecisions;
  27.     private $allowIfEqualGrantedDeniedDecisions;
  28.     /**
  29.      * @param iterable|VoterInterface[] $voters                             An array or an iterator of VoterInterface instances
  30.      * @param string                    $strategy                           The vote strategy
  31.      * @param bool                      $allowIfAllAbstainDecisions         Whether to grant access if all voters abstained or not
  32.      * @param bool                      $allowIfEqualGrantedDeniedDecisions Whether to grant access if result are equals
  33.      *
  34.      * @throws \InvalidArgumentException
  35.      */
  36.     public function __construct(iterable $voters = [], string $strategy self::STRATEGY_AFFIRMATIVEbool $allowIfAllAbstainDecisions falsebool $allowIfEqualGrantedDeniedDecisions true)
  37.     {
  38.         $strategyMethod 'decide'.ucfirst($strategy);
  39.         if ('' === $strategy || !\is_callable([$this$strategyMethod])) {
  40.             throw new \InvalidArgumentException(sprintf('The strategy "%s" is not supported.'$strategy));
  41.         }
  42.         $this->voters $voters;
  43.         $this->strategy $strategyMethod;
  44.         $this->allowIfAllAbstainDecisions $allowIfAllAbstainDecisions;
  45.         $this->allowIfEqualGrantedDeniedDecisions $allowIfEqualGrantedDeniedDecisions;
  46.     }
  47.     /**
  48.      * @param bool $allowMultipleAttributes Whether to allow passing multiple values to the $attributes array
  49.      *
  50.      * {@inheritdoc}
  51.      */
  52.     public function decide(TokenInterface $token, array $attributes$object null/*, bool $allowMultipleAttributes = false*/)
  53.     {
  54.         $allowMultipleAttributes < \func_num_args() && func_get_arg(3);
  55.         // Special case for AccessListener, do not remove the right side of the condition before 6.0
  56.         if (\count($attributes) > && !$allowMultipleAttributes) {
  57.             @trigger_error(sprintf('Passing more than one Security attribute to "%s()" is deprecated since Symfony 4.4. Use multiple "decide()" calls or the expression language (e.g. "is_granted(...) or is_granted(...)") instead.'__METHOD__), E_USER_DEPRECATED);
  58.         }
  59.         return $this->{$this->strategy}($token$attributes$object);
  60.     }
  61.     /**
  62.      * Grants access if any voter returns an affirmative response.
  63.      *
  64.      * If all voters abstained from voting, the decision will be based on the
  65.      * allowIfAllAbstainDecisions property value (defaults to false).
  66.      */
  67.     private function decideAffirmative(TokenInterface $token, array $attributes$object null): bool
  68.     {
  69.         $deny 0;
  70.         foreach ($this->voters as $voter) {
  71.             $result $voter->vote($token$object$attributes);
  72.             if (VoterInterface::ACCESS_GRANTED === $result) {
  73.                 return true;
  74.             }
  75.             if (VoterInterface::ACCESS_DENIED === $result) {
  76.                 ++$deny;
  77.             }
  78.         }
  79.         if ($deny 0) {
  80.             return false;
  81.         }
  82.         return $this->allowIfAllAbstainDecisions;
  83.     }
  84.     /**
  85.      * Grants access if there is consensus of granted against denied responses.
  86.      *
  87.      * Consensus means majority-rule (ignoring abstains) rather than unanimous
  88.      * agreement (ignoring abstains). If you require unanimity, see
  89.      * UnanimousBased.
  90.      *
  91.      * If there were an equal number of grant and deny votes, the decision will
  92.      * be based on the allowIfEqualGrantedDeniedDecisions property value
  93.      * (defaults to true).
  94.      *
  95.      * If all voters abstained from voting, the decision will be based on the
  96.      * allowIfAllAbstainDecisions property value (defaults to false).
  97.      */
  98.     private function decideConsensus(TokenInterface $token, array $attributes$object null): bool
  99.     {
  100.         $grant 0;
  101.         $deny 0;
  102.         foreach ($this->voters as $voter) {
  103.             $result $voter->vote($token$object$attributes);
  104.             if (VoterInterface::ACCESS_GRANTED === $result) {
  105.                 ++$grant;
  106.             } elseif (VoterInterface::ACCESS_DENIED === $result) {
  107.                 ++$deny;
  108.             }
  109.         }
  110.         if ($grant $deny) {
  111.             return true;
  112.         }
  113.         if ($deny $grant) {
  114.             return false;
  115.         }
  116.         if ($grant 0) {
  117.             return $this->allowIfEqualGrantedDeniedDecisions;
  118.         }
  119.         return $this->allowIfAllAbstainDecisions;
  120.     }
  121.     /**
  122.      * Grants access if only grant (or abstain) votes were received.
  123.      *
  124.      * If all voters abstained from voting, the decision will be based on the
  125.      * allowIfAllAbstainDecisions property value (defaults to false).
  126.      */
  127.     private function decideUnanimous(TokenInterface $token, array $attributes$object null): bool
  128.     {
  129.         $grant 0;
  130.         foreach ($this->voters as $voter) {
  131.             foreach ($attributes as $attribute) {
  132.                 $result $voter->vote($token$object, [$attribute]);
  133.                 if (VoterInterface::ACCESS_DENIED === $result) {
  134.                     return false;
  135.                 }
  136.                 if (VoterInterface::ACCESS_GRANTED === $result) {
  137.                     ++$grant;
  138.                 }
  139.             }
  140.         }
  141.         // no deny votes
  142.         if ($grant 0) {
  143.             return true;
  144.         }
  145.         return $this->allowIfAllAbstainDecisions;
  146.     }
  147. }