diff --git a/src/Symfony/Component/Security/Core/Authorization/AccessDecisionManager.php b/src/Symfony/Component/Security/Core/Authorization/AccessDecisionManager.php index b8b6a776e9b8e..abd6cb802787a 100644 --- a/src/Symfony/Component/Security/Core/Authorization/AccessDecisionManager.php +++ b/src/Symfony/Component/Security/Core/Authorization/AccessDecisionManager.php @@ -30,6 +30,7 @@ class AccessDecisionManager implements AccessDecisionManagerInterface private $strategy; private $allowIfAllAbstainDecisions; private $allowIfEqualGrantedDeniedDecisions; + private $areVotersPrepared = false; /** * Constructor. @@ -102,6 +103,7 @@ public function supportsClass($class) */ private function decideAffirmative(TokenInterface $token, array $attributes, $object = null) { + $this->prepareVoters(); $deny = 0; foreach ($this->voters as $voter) { $result = $voter->vote($token, $object, $attributes); @@ -142,6 +144,7 @@ private function decideAffirmative(TokenInterface $token, array $attributes, $ob */ private function decideConsensus(TokenInterface $token, array $attributes, $object = null) { + $this->prepareVoters(); $grant = 0; $deny = 0; $abstain = 0; @@ -189,6 +192,7 @@ private function decideConsensus(TokenInterface $token, array $attributes, $obje */ private function decideUnanimous(TokenInterface $token, array $attributes, $object = null) { + $this->prepareVoters(); $grant = 0; foreach ($attributes as $attribute) { foreach ($this->voters as $voter) { @@ -216,4 +220,23 @@ private function decideUnanimous(TokenInterface $token, array $attributes, $obje return $this->allowIfAllAbstainDecisions; } + + /** + * Guarantees that AccessDecisionManagerAwareInterface voters have + * been prepared properly. + */ + private function prepareVoters() + { + if ($this->areVotersPrepared) { + return; + } + + // inject this AccessDecisionManager into any voters that want it + foreach ($this->voters as $voter) { + if ($voter instanceof AccessDecisionManagerAwareInterface) { + $voter->setAccessDecisionManager($this); + } + } + $this->areVotersPrepared = true; + } } diff --git a/src/Symfony/Component/Security/Core/Authorization/AccessDecisionManagerAwareInterface.php b/src/Symfony/Component/Security/Core/Authorization/AccessDecisionManagerAwareInterface.php new file mode 100644 index 0000000000000..e4c74f0ec2b0a --- /dev/null +++ b/src/Symfony/Component/Security/Core/Authorization/AccessDecisionManagerAwareInterface.php @@ -0,0 +1,21 @@ +getVoter(VoterInterface::ACCESS_GRANTED)), 'fooBar'); } + public function testAccessDecisionManagerInterfaceSetting() + { + $strategies = array('affirmative', 'consensus', 'unanimous'); + + $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); + foreach ($strategies as $strategy) { + // mock our stub voter that implements the AccessDecisionManagerAwareInterface + $voter = $this->getMock('Symfony\Component\Security\Core\Tests\Authorization\VoterWithAccessDecisionManagerAwareInterfaceStub'); + + $manager = new AccessDecisionManager(array($voter), $strategy); + + $voter->expects($this->once()) + ->method('setAccessDecisionManager') + ->with($manager); + + $manager->decide($token, array('ROLE_DOES_NOT_MATTER')); + } + } + /** * @dataProvider getStrategyTests */ @@ -196,3 +216,8 @@ protected function getVoterSupportsAttribute($ret) return $voter; } } + +// stub class that implements AccessDecisionManagerAwareInterface +abstract class VoterWithAccessDecisionManagerAwareInterfaceStub implements VoterInterface, AccessDecisionManagerAwareInterface +{ +}