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

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.             } elseif (VoterInterface::ACCESS_ABSTAIN !== $result) {
  80.                 trigger_deprecation('symfony/security-core''5.3''Returning "%s" in "%s::vote()" is deprecated, return one of "%s" constants: "ACCESS_GRANTED", "ACCESS_DENIED" or "ACCESS_ABSTAIN".'var_export($resulttrue), get_debug_type($voter), VoterInterface::class);
  81.             }
  82.         }
  83.         if ($deny 0) {
  84.             return false;
  85.         }
  86.         return $this->allowIfAllAbstainDecisions;
  87.     }
  88.     /**
  89.      * Grants access if there is consensus of granted against denied responses.
  90.      *
  91.      * Consensus means majority-rule (ignoring abstains) rather than unanimous
  92.      * agreement (ignoring abstains). If you require unanimity, see
  93.      * UnanimousBased.
  94.      *
  95.      * If there were an equal number of grant and deny votes, the decision will
  96.      * be based on the allowIfEqualGrantedDeniedDecisions property value
  97.      * (defaults to true).
  98.      *
  99.      * If all voters abstained from voting, the decision will be based on the
  100.      * allowIfAllAbstainDecisions property value (defaults to false).
  101.      */
  102.     private function decideConsensus(TokenInterface $token, array $attributes$object null): bool
  103.     {
  104.         $grant 0;
  105.         $deny 0;
  106.         foreach ($this->voters as $voter) {
  107.             $result $voter->vote($token$object$attributes);
  108.             if (VoterInterface::ACCESS_GRANTED === $result) {
  109.                 ++$grant;
  110.             } elseif (VoterInterface::ACCESS_DENIED === $result) {
  111.                 ++$deny;
  112.             } elseif (VoterInterface::ACCESS_ABSTAIN !== $result) {
  113.                 trigger_deprecation('symfony/security-core''5.3''Returning "%s" in "%s::vote()" is deprecated, return one of "%s" constants: "ACCESS_GRANTED", "ACCESS_DENIED" or "ACCESS_ABSTAIN".'var_export($resulttrue), get_debug_type($voter), VoterInterface::class);
  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): bool
  134.     {
  135.         $grant 0;
  136.         foreach ($this->voters as $voter) {
  137.             foreach ($attributes as $attribute) {
  138.                 $result $voter->vote($token$object, [$attribute]);
  139.                 if (VoterInterface::ACCESS_DENIED === $result) {
  140.                     return false;
  141.                 }
  142.                 if (VoterInterface::ACCESS_GRANTED === $result) {
  143.                     ++$grant;
  144.                 } elseif (VoterInterface::ACCESS_ABSTAIN !== $result) {
  145.                     trigger_deprecation('symfony/security-core''5.3''Returning "%s" in "%s::vote()" is deprecated, return one of "%s" constants: "ACCESS_GRANTED", "ACCESS_DENIED" or "ACCESS_ABSTAIN".'var_export($resulttrue), get_debug_type($voter), VoterInterface::class);
  146.                 }
  147.             }
  148.         }
  149.         // no deny votes
  150.         if ($grant 0) {
  151.             return true;
  152.         }
  153.         return $this->allowIfAllAbstainDecisions;
  154.     }
  155.     /**
  156.      * Grant or deny access depending on the first voter that does not abstain.
  157.      * The priority of voters can be used to overrule a decision.
  158.      *
  159.      * If all voters abstained from voting, the decision will be based on the
  160.      * allowIfAllAbstainDecisions property value (defaults to false).
  161.      */
  162.     private function decidePriority(TokenInterface $token, array $attributes$object null)
  163.     {
  164.         foreach ($this->voters as $voter) {
  165.             $result $voter->vote($token$object$attributes);
  166.             if (VoterInterface::ACCESS_GRANTED === $result) {
  167.                 return true;
  168.             }
  169.             if (VoterInterface::ACCESS_DENIED === $result) {
  170.                 return false;
  171.             }
  172.             if (VoterInterface::ACCESS_ABSTAIN !== $result) {
  173.                 trigger_deprecation('symfony/security-core''5.3''Returning "%s" in "%s::vote()" is deprecated, return one of "%s" constants: "ACCESS_GRANTED", "ACCESS_DENIED" or "ACCESS_ABSTAIN".'var_export($resulttrue), get_debug_type($voter), VoterInterface::class);
  174.             }
  175.         }
  176.         return $this->allowIfAllAbstainDecisions;
  177.     }
  178. }