diff --git a/UPGRADE-2.8.md b/UPGRADE-2.8.md index ae8bb7fa4ac9..ba7a13617af3 100644 --- a/UPGRADE-2.8.md +++ b/UPGRADE-2.8.md @@ -442,38 +442,12 @@ FrameworkBundle 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: + * The `AbstractVoter` class was deprecated. Instead, extend the `Voter` class and + move your voting logic in the `supports($attribute, $subject)` and + `voteOnAttribute($attribute, $object, TokenInterface $token)` methods. - 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(); - // ... - } - } - ``` + * The `VoterInterface::supportsClass` and `supportsAttribute` methods were + deprecated and will be removed from the interface in 3.0. Config ------ diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/AbstractVoter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/AbstractVoter.php index 7b04222eae92..5dcf787c9968 100644 --- a/src/Symfony/Component/Security/Core/Authorization/Voter/AbstractVoter.php +++ b/src/Symfony/Component/Security/Core/Authorization/Voter/AbstractVoter.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Security\Core\Authorization\Voter; +@trigger_error('The '.__NAMESPACE__.'\AbstractVoter class is deprecated since version 2.8, to be removed in 3.0. Upgrade to Symfony\Component\Security\Core\Authorization\Voter\Voter instead.', E_USER_DEPRECATED); + use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; @@ -18,6 +20,8 @@ * Abstract Voter implementation that reduces boilerplate code required to create a custom Voter. * * @author Roman Marintšenko + * + * @deprecated since version 2.8, to be removed in 3.0. Upgrade to Symfony\Component\Security\Core\Authorization\Voter\Voter instead. */ abstract class AbstractVoter implements VoterInterface { @@ -26,8 +30,6 @@ abstract class AbstractVoter implements VoterInterface */ public function supportsAttribute($attribute) { - @trigger_error('The '.__METHOD__.' is deprecated since version 2.8 and will be removed in version 3.0.', E_USER_DEPRECATED); - return in_array($attribute, $this->getSupportedAttributes()); } @@ -36,8 +38,6 @@ public function supportsAttribute($attribute) */ public function supportsClass($class) { - @trigger_error('The '.__METHOD__.' is deprecated since version 2.8 and will be removed in version 3.0.', E_USER_DEPRECATED); - foreach ($this->getSupportedClasses() as $supportedClass) { if ($supportedClass === $class || is_subclass_of($class, $supportedClass)) { return true; @@ -62,7 +62,7 @@ public function supportsClass($class) */ public function vote(TokenInterface $token, $object, array $attributes) { - if (!$object) { + if (!$object || !$this->supportsClass(get_class($object))) { return self::ACCESS_ABSTAIN; } @@ -70,14 +70,14 @@ public function vote(TokenInterface $token, $object, array $attributes) $vote = self::ACCESS_ABSTAIN; foreach ($attributes as $attribute) { - if (!$this->supports($attribute, $object)) { + if (!$this->supportsAttribute($attribute)) { continue; } // as soon as at least one attribute is supported, default is to deny access $vote = self::ACCESS_DENIED; - if ($this->voteOnAttribute($attribute, $object, $token)) { + if ($this->isGranted($attribute, $object, $token->getUser())) { // grant access as soon as at least one voter returns a positive response return self::ACCESS_GRANTED; } @@ -86,62 +86,19 @@ public function vote(TokenInterface $token, $object, array $attributes) return $vote; } - /** - * Determines if the attribute and object are supported by this voter. - * - * This method will become abstract in 3.0. - * - * @param string $attribute An attribute - * @param string $object The object to secure - * - * @return bool True if the attribute and object is supported, false otherwise - */ - protected function supports($attribute, $object) - { - @trigger_error('The getSupportedClasses and getSupportedAttributes methods are deprecated since version 2.8 and will be removed in version 3.0. Overwrite supports instead.', E_USER_DEPRECATED); - - $classIsSupported = false; - foreach ($this->getSupportedClasses() as $supportedClass) { - if ($object instanceof $supportedClass) { - $classIsSupported = true; - break; - } - } - - if (!$classIsSupported) { - return false; - } - - if (!in_array($attribute, $this->getSupportedAttributes())) { - return false; - } - - return true; - } - /** * Return an array of supported classes. This will be called by supportsClass. * * @return array an array of supported classes, i.e. array('Acme\DemoBundle\Model\Product') - * - * @deprecated since version 2.8, to be removed in 3.0. Use supports() instead. */ - protected function getSupportedClasses() - { - @trigger_error('The '.__METHOD__.' is deprecated since version 2.8 and will be removed in version 3.0.', E_USER_DEPRECATED); - } + abstract protected function getSupportedClasses(); /** * Return an array of supported attributes. This will be called by supportsAttribute. * * @return array an array of supported attributes, i.e. array('CREATE', 'READ') - * - * @deprecated since version 2.8, to be removed in 3.0. Use supports() instead. */ - protected function getSupportedAttributes() - { - @trigger_error('The '.__METHOD__.' is deprecated since version 2.8 and will be removed in version 3.0.', E_USER_DEPRECATED); - } + abstract protected function getSupportedAttributes(); /** * Perform a single access check operation on a given attribute, object and (optionally) user @@ -154,33 +111,7 @@ protected function getSupportedAttributes() * @param object $object * @param UserInterface|string $user * - * @deprecated This method will be removed in 3.0 - override voteOnAttribute instead. - * - * @return bool - */ - protected function isGranted($attribute, $object, $user = null) - { - // forces isGranted() or voteOnAttribute() to be overridden - throw new \BadMethodCallException(sprintf('You must override the voteOnAttribute() method in "%s".', get_class($this))); - } - - /** - * Perform a single access check operation on a given attribute, object and token. - * It is safe to assume that $attribute and $object's class pass supports method call. - * - * 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) - { - // the user should override this method, and not rely on the deprecated isGranted() - @trigger_error(sprintf("The AbstractVoter::isGranted() method is deprecated since 2.8 and won't be called anymore in 3.0. Override voteOnAttribute() in %s instead.", get_class($this)), E_USER_DEPRECATED); - - return $this->isGranted($attribute, $object, $token->getUser()); - } + abstract protected function isGranted($attribute, $object, $user = null); } diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/Voter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/Voter.php new file mode 100644 index 000000000000..8d36fd8f8c91 --- /dev/null +++ b/src/Symfony/Component/Security/Core/Authorization/Voter/Voter.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Core\Authorization\Voter; + +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; + +/** + * Voter is an abstract default implementation of a voter. + * + * @author Roman Marintšenko + * @author Grégoire Pineau + */ +abstract class Voter implements VoterInterface +{ + /** + * {@inheritdoc} + */ + public function supportsAttribute($attribute) + { + throw new \BadMethodCallException('supportsAttribute method is deprecated since version 2.8, to be removed in 3.0'); + } + + /** + * {@inheritdoc} + */ + public function supportsClass($class) + { + throw new \BadMethodCallException('supportsClass method is deprecated since version 2.8, to be removed in 3.0'); + } + + /** + * {@inheritdoc} + */ + public function vote(TokenInterface $token, $object, array $attributes) + { + // abstain vote by default in case none of the attributes are supported + $vote = self::ACCESS_ABSTAIN; + + foreach ($attributes as $attribute) { + if (!$this->supports($attribute, $object)) { + continue; + } + + // as soon as at least one attribute is supported, default is to deny access + $vote = self::ACCESS_DENIED; + + if ($this->voteOnAttribute($attribute, $object, $token)) { + // grant access as soon as at least one attribute returns a positive response + return self::ACCESS_GRANTED; + } + } + + return $vote; + } + + /** + * Determines if the attribute and subject are supported by this voter. + * + * @param string $attribute An attribute + * @param mixed $subject The subject to secure, e.g. an object the user wants to access or any other PHP type + * + * @return bool True if the attribute and subject are supported, false otherwise + */ + abstract protected function supports($attribute, $subject); + + /** + * Perform a single access check operation on a given attribute, subject and token. + * + * @param string $attribute + * @param mixed $subject + * @param TokenInterface $token + * + * @return bool + */ + abstract protected function voteOnAttribute($attribute, $subject, TokenInterface $token); +} diff --git a/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/AbstractVoterTest.php b/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/AbstractVoterTest.php index 5ea77320cf61..b537c1b2effc 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/AbstractVoterTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/AbstractVoterTest.php @@ -11,10 +11,11 @@ namespace Symfony\Component\Security\Core\Tests\Authorization\Voter; -use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -use Symfony\Component\Security\Core\Authorization\Voter\AbstractVoter; use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; +/** + * @group legacy + */ class AbstractVoterTest extends \PHPUnit_Framework_TestCase { protected $token; @@ -50,75 +51,8 @@ public function getTests() */ public function testVote(array $attributes, $expectedVote, $object, $message) { - $voter = new AbstractVoterTest_Voter(); + $voter = new Fixtures\MyVoter(); $this->assertEquals($expectedVote, $voter->vote($this->token, $object, $attributes), $message); } - - /** - * @dataProvider getTests - * @group legacy - */ - public function testVoteLegacy(array $attributes, $expectedVote, $object, $message) - { - $voter = new AbstractVoterTest_LegacyVoter(); - - $this->assertEquals($expectedVote, $voter->vote($this->token, $object, $attributes), $message); - } - - /** - * @group legacy - * @expectedException \BadMethodCallException - */ - public function testNoOverriddenMethodsThrowsException() - { - $voter = new AbstractVoterTest_NothingImplementedVoter(); - $voter->vote($this->token, new \stdClass(), array('EDIT')); - } -} - -class AbstractVoterTest_Voter extends AbstractVoter -{ - protected function voteOnAttribute($attribute, $object, TokenInterface $token) - { - return 'EDIT' === $attribute; - } - - protected function supports($attribute, $object) - { - return $object instanceof \stdClass && in_array($attribute, array('EDIT', 'CREATE')); - } -} - -class AbstractVoterTest_LegacyVoter extends AbstractVoter -{ - protected function getSupportedClasses() - { - return array('stdClass'); - } - - protected function getSupportedAttributes() - { - return array('EDIT', 'CREATE'); - } - - protected function isGranted($attribute, $object, $user = null) - { - return 'EDIT' === $attribute; - } -} - -class AbstractVoterTest_NothingImplementedVoter extends AbstractVoter -{ - protected function getSupportedClasses() - { - return array('stdClass'); - } - - protected function getSupportedAttributes() - { - return array('EDIT', 'CREATE'); - } - - // this is a bad voter that hasn't overridden isGranted or voteOnAttribute } diff --git a/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/Fixtures/MyVoter.php b/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/Fixtures/MyVoter.php new file mode 100644 index 000000000000..b75f79851be9 --- /dev/null +++ b/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/Fixtures/MyVoter.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Core\Tests\Authorization\Voter; + +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\Voter\Voter; +use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; + +class VoterTest extends \PHPUnit_Framework_TestCase +{ + protected $token; + + protected function setUp() + { + $this->token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); + } + + public function getTests() + { + return array( + array(array('EDIT'), VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if attribute and class are supported and attribute grants access'), + array(array('CREATE'), VoterInterface::ACCESS_DENIED, new \stdClass(), 'ACCESS_DENIED if attribute and class are supported and attribute does not grant access'), + + array(array('DELETE', 'EDIT'), VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if one attribute is supported and grants access'), + array(array('DELETE', 'CREATE'), VoterInterface::ACCESS_DENIED, new \stdClass(), 'ACCESS_DENIED if one attribute is supported and denies access'), + + array(array('CREATE', 'EDIT'), VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if one attribute grants access'), + + array(array('DELETE'), VoterInterface::ACCESS_ABSTAIN, new \stdClass(), 'ACCESS_ABSTAIN if no attribute is supported'), + + array(array('EDIT'), VoterInterface::ACCESS_ABSTAIN, $this, 'ACCESS_ABSTAIN if class is not supported'), + + array(array('EDIT'), VoterInterface::ACCESS_ABSTAIN, null, 'ACCESS_ABSTAIN if object is null'), + + array(array(), VoterInterface::ACCESS_ABSTAIN, new \stdClass(), 'ACCESS_ABSTAIN if no attributes were provided'), + ); + } + + /** + * @dataProvider getTests + */ + public function testVote(array $attributes, $expectedVote, $object, $message) + { + $voter = new VoterTest_Voter(); + + $this->assertEquals($expectedVote, $voter->vote($this->token, $object, $attributes), $message); + } +} + +class VoterTest_Voter extends Voter +{ + protected function voteOnAttribute($attribute, $object, TokenInterface $token) + { + return 'EDIT' === $attribute; + } + + protected function supports($attribute, $object) + { + return $object instanceof \stdClass && in_array($attribute, array('EDIT', 'CREATE')); + } +} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

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:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy