diff --git a/UPGRADE-2.8.md b/UPGRADE-2.8.md index 6a7282172db12..ad54880fd0000 100644 --- a/UPGRADE-2.8.md +++ b/UPGRADE-2.8.md @@ -406,3 +406,39 @@ FrameworkBundle session: cookie_httponly: false ``` + +Security +-------- + + * The AbstractToken::isGranted() method was deprecated. Instead, + override the voteOnAttribute() method. This method has one small + difference: it's passed the TokenInterface instead of the user: + + Before: + + ```php + class MyCustomVoter extends AbstractVoter + { + // ... + + protected function isGranted($attribute, $object, $user = null) + { + // ... + } + } + ``` + + After: + + ```php + class MyCustomVoter extends AbstractVoter + { + // ... + + protected function voteOnAttribute($attribute, $object, TokenInterface $token) + { + $user = $token->getUser(); + // ... + } + } + ``` diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/AbstractVoter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/AbstractVoter.php index efa156228e227..6bbea361fd098 100644 --- a/src/Symfony/Component/Security/Core/Authorization/Voter/AbstractVoter.php +++ b/src/Symfony/Component/Security/Core/Authorization/Voter/AbstractVoter.php @@ -65,6 +65,12 @@ public function vote(TokenInterface $token, $object, array $attributes) // abstain vote by default in case none of the attributes are supported $vote = self::ACCESS_ABSTAIN; + $reflector = new \ReflectionMethod($this, 'voteOnAttribute'); + $isNewOverwritten = $reflector->getDeclaringClass()->getName() !== 'Symfony\Component\Security\Core\Authorization\Voter\AbstractVoter'; + if (!$isNewOverwritten) { + @trigger_error(sprintf("The AbstractVoter::isGranted method is deprecated since 2.8 and won't be called anymore in 3.0. Override voteOnAttribute() instead.", $reflector->class), E_USER_DEPRECATED); + } + foreach ($attributes as $attribute) { if (!$this->supportsAttribute($attribute)) { continue; @@ -73,9 +79,16 @@ public function vote(TokenInterface $token, $object, array $attributes) // as soon as at least one attribute is supported, default is to deny access $vote = self::ACCESS_DENIED; - if ($this->isGranted($attribute, $object, $token->getUser())) { - // grant access as soon as at least one voter returns a positive response - return self::ACCESS_GRANTED; + if ($isNewOverwritten) { + if ($this->voteOnAttribute($attribute, $object, $token)) { + // grant access as soon as at least one voter returns a positive response + return self::ACCESS_GRANTED; + } + } else { + if ($this->isGranted($attribute, $object, $token->getUser())) { + // grant access as soon as at least one voter returns a positive response + return self::ACCESS_GRANTED; + } } } @@ -107,7 +120,32 @@ abstract protected function getSupportedAttributes(); * @param object $object * @param UserInterface|string $user * + * @deprecated This method will be removed in 3.0 - override voteOnAttribute instead. + * * @return bool */ - abstract protected function isGranted($attribute, $object, $user = null); + protected function isGranted($attribute, $object, $user = null) + { + return false; + } + + /** + * Perform a single access check operation on a given attribute, object and (optionally) user + * It is safe to assume that $attribute and $object's class pass supportsAttribute/supportsClass + * $user can be one of the following: + * a UserInterface object (fully authenticated user) + * a string (anonymously authenticated user). + * + * This method will become abstract in 3.0. + * + * @param string $attribute + * @param object $object + * @param TokenInterface $token + * + * @return bool + */ + protected function voteOnAttribute($attribute, $object, TokenInterface $token) + { + return false; + } } diff --git a/src/Symfony/Component/Security/Tests/Core/Authentication/Voter/AbstractVoterTest.php b/src/Symfony/Component/Security/Tests/Core/Authentication/Voter/AbstractVoterTest.php index af7b82f35d5a2..ecf82fbfe49f1 100644 --- a/src/Symfony/Component/Security/Tests/Core/Authentication/Voter/AbstractVoterTest.php +++ b/src/Symfony/Component/Security/Tests/Core/Authentication/Voter/AbstractVoterTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Security\Tests\Core\Authentication\Voter; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authorization\Voter\AbstractVoter; /** @@ -46,6 +47,17 @@ public function testVote($expectedVote, $object, $attributes, $message) $this->assertEquals($expectedVote, $this->voter->vote($this->token, $object, $attributes), $message); } + /** + * @dataProvider getData + * @group legacy + */ + public function testVoteUsingDeprecatedIsGranted($expectedVote, $object, $attributes, $message) + { + $voter = new DeprecatedVoterFixture(); + + $this->assertEquals($expectedVote, $voter->vote($this->token, $object, $attributes), $message); + } + public function getData() { return array( @@ -75,6 +87,26 @@ protected function getSupportedAttributes() return array('foo', 'bar', 'baz'); } + protected function voteOnAttribute($attribute, $object, TokenInterface $token) + { + return $attribute === 'foo'; + } +} + +class DeprecatedVoterFixture extends AbstractVoter +{ + protected function getSupportedClasses() + { + return array( + 'Symfony\Component\Security\Tests\Core\Authentication\Voter\ObjectFixture', + ); + } + + protected function getSupportedAttributes() + { + return array('foo', 'bar', 'baz'); + } + protected function isGranted($attribute, $object, $user = null) { return $attribute === 'foo';
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: