diff options
Diffstat (limited to 'Authorization/AccessDecisionManager.php')
-rw-r--r-- | Authorization/AccessDecisionManager.php | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/Authorization/AccessDecisionManager.php b/Authorization/AccessDecisionManager.php new file mode 100644 index 0000000..d458b89 --- /dev/null +++ b/Authorization/AccessDecisionManager.php @@ -0,0 +1,237 @@ +<?php + +namespace Symfony\Component\Security\Authorization; + +use Symfony\Component\Security\Authorization\Voter\VoterInterface; +use Symfony\Component\Security\Authentication\Token\TokenInterface; + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien.potencier@symfony-project.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * AccessDecisionManager is the base class for all access decision managers + * that use decision voters. + * + * @author Fabien Potencier <fabien.potencier@symfony-project.com> + */ +class AccessDecisionManager implements AccessDecisionManagerInterface +{ + protected $voters; + protected $allowIfAllAbstainDecisions; + protected $allowIfEqualGrantedDeniedDecisions; + protected $strategy; + + /** + * Constructor. + * + * @param VoterInterface[] $voters An array of VoterInterface instances + * @param string $strategy The vote strategy + * @param Boolean $allowIfAllAbstainDecisions Whether to grant access if all voters abstained or not + */ + public function __construct(array $voters = array(), $strategy = 'affirmative', $allowIfAllAbstainDecisions = false, $allowIfEqualGrantedDeniedDecisions = true) + { + $this->voters = $voters; + $this->strategy = 'decide'.ucfirst($strategy); + $this->allowIfAllAbstainDecisions = (Boolean) $allowIfAllAbstainDecisions; + $this->allowIfEqualGrantedDeniedDecisions = (Boolean) $allowIfEqualGrantedDeniedDecisions; + } + + /** + * {@inheritdoc} + */ + public function decide(TokenInterface $token, array $attributes, $object = null) + { + return $this->{$this->strategy}($token, $attributes, $object); + } + + /** + * Returns all voters. + * + * @return VoterInterface[] $voters An array of VoterInterface instances + */ + public function getVoters() + { + return $this->voters; + } + + /** + * Sets voters. + * + * @param VoterInterface[] $voters An array of VoterInterface instances + */ + public function setVoters(array $voters) + { + if (!count($voters)) { + throw new \LogicException('You must have at least one voter.'); + } + + $this->voters = array(); + foreach ($voters as $voter) { + $this->addVoter($voter); + } + } + + /** + * Adds a voter. + * + * @param VoterInterface $voter A VoterInterface instance + */ + public function addVoter(VoterInterface $voter) + { + $this->voters[] = $voter; + } + + /** + * {@inheritdoc} + */ + public function supportsAttribute($attribute) + { + foreach ($this->voters as $voter) { + if ($voter->supportsAttribute($attribute)) { + return true; + } + } + + return false; + } + + /** + * {@inheritdoc} + */ + public function supportsClass($class) { + foreach ($this->voters as $voter) { + if ($voter->supportsClass($class)) { + return true; + } + } + + return false; + } + + /** + * Grants access if any voter returns an affirmative response. + * + * If all voters abstained from voting, the decision will be based on the + * allowIfAllAbstainDecisions property value (defaults to false). + */ + protected function decideAffirmative(TokenInterface $token, array $attributes, $object = null) + { + $deny = 0; + foreach ($this->voters as $voter) { + $result = $voter->vote($token, $object, $attributes); + switch ($result) { + case VoterInterface::ACCESS_GRANTED: + return true; + + case VoterInterface::ACCESS_DENIED: + ++$deny; + + break; + + default: + break; + } + } + + if ($deny > 0) { + return false; + } + + return $this->allowIfAllAbstainDecisions; + } + + /** + * Grants access if there is consensus of granted against denied responses. + * + * Consensus means majority-rule (ignoring abstains) rather than unanimous agreement (ignoring abstains). + * If you require unanimity, see UnanimousBased. + * + * If there were an equal number of grant and deny votes, the decision will be based on the + * allowIfEqualGrantedDeniedDecisions property value (defaults to true). + * + * If all voters abstained from voting, the decision will be based on the + * allowIfAllAbstainDecisions property value (defaults to false). + */ + public function decideConsensus(TokenInterface $token, array $attributes, $object = null) + { + $grant = 0; + $deny = 0; + $abstain = 0; + foreach ($this->voters as $voter) { + $result = $voter->vote($token, $object, $attributes); + + switch ($result) { + case VoterInterface::ACCESS_GRANTED: + ++$grant; + + break; + + case VoterInterface::ACCESS_DENIED: + ++$deny; + + break; + + default: + ++$abstain; + + break; + } + } + + if ($grant > $deny) { + return; + } + + if ($deny > $grant) { + return false; + } + + if ($grant == $deny && $grant != 0) { + return $this->allowIfEqualGrantedDeniedDecisions; + } + + return $this->allowIfAllAbstainDecisions; + } + + /** + * Grants access if only grant (or abstain) votes were received. + * + * If all voters abstained from voting, the decision will be based on the + * allowIfAllAbstainDecisions property value (defaults to false). + */ + public function decideUnanimous(TokenInterface $token, array $attributes, $object = null) + { + $grant = 0; + foreach ($attributes as $attribute) { + foreach ($this->voters as $voter) { + $result = $voter->vote($token, $object, array($attribute)); + + switch ($result) { + case VoterInterface::ACCESS_GRANTED: + ++$grant; + + break; + + case VoterInterface::ACCESS_DENIED: + return false; + + default: + break; + } + } + } + + // no deny votes + if ($grant > 0) { + return true; + } + + return $this->allowIfAllAbstainDecisions; + } +} |