Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Security] Deprecated supportsAttribute and supportsClass methods #15151

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions UPGRADE-3.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,43 @@ UPGRADE FROM 2.x to 3.0
));
```

* The `AbstractVoter::getSupportedAttributes()` and `AbstractVoter::getSupportedClasses()`
methods have been removed in favor of `AbstractVoter::supports()`.

Before:

```php
class MyVoter extends AbstractVoter
{
protected function getSupportedAttributes()
{
return array('CREATE', 'EDIT');
}

protected function getSupportedClasses()
{
return array('AppBundle\Entity\Post');
}

// ...
}
```

After:

```php
class MyVoter extends AbstractVoter
{
protected function supports($attribute, $class)
{
return $this->isClassInstanceOf($class, 'AppBundle\Entity\Post')
&& in_array($attribute, array('CREATE', 'EDIT'));
}

// ...
}
```

### Translator

* The `Translator::setFallbackLocale()` method has been removed in favor of
Expand Down
5 changes: 5 additions & 0 deletions src/Symfony/Component/Security/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ CHANGELOG
`Symfony\Component\Security\Http\Authentication\SimpleFormAuthenticatorInterface` instead
* deprecated `Symfony\Component\Security\Core\Util\ClassUtils`, use
`Symfony\Component\Security\Acl\Util\ClassUtils` instead
* deprecated `supportsAttribute()` and `supportsClass()` methods of
`Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface` and
`Symfony\Component\Security\Core\Authorization\Voter\VoterInterface`.
* deprecated `getSupportedAttributes()` and `getSupportedClasses()` methods of
`Symfony\Component\Security\Core\Authorization\Voter\AbstractVoter`, use `supports()` instead.

2.7.0
-----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ public function decide(TokenInterface $token, array $attributes, $object = null)
*/
public function supportsAttribute($attribute)
{
@trigger_error('The '.__METHOD__.' is deprecated since version 2.8 and will be removed in version 3.0.');

foreach ($this->voters as $voter) {
if ($voter->supportsAttribute($attribute)) {
return true;
Expand All @@ -91,6 +93,8 @@ 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.');

foreach ($this->voters as $voter) {
if ($voter->supportsClass($class)) {
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ public function decide(TokenInterface $token, array $attributes, $object = null)
* @param string $attribute An attribute
*
* @return bool true if this decision manager supports the attribute, false otherwise
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function supportsAttribute($attribute);

Expand All @@ -46,6 +48,8 @@ public function supportsAttribute($attribute);
* @param string $class A class name
*
* @return true if this decision manager can process the class
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function supportsClass($class);
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ 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.');

return in_array($attribute, $this->getSupportedAttributes());
}

Expand All @@ -34,6 +36,8 @@ 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.');

foreach ($this->getSupportedClasses() as $supportedClass) {
if ($supportedClass === $class || is_subclass_of($class, $supportedClass)) {
return true;
Expand All @@ -58,12 +62,13 @@ public function supportsClass($class)
*/
public function vote(TokenInterface $token, $object, array $attributes)
{
if (!$object || !$this->supportsClass(get_class($object))) {
if (!$object) {
return self::ACCESS_ABSTAIN;
}

// abstain vote by default in case none of the attributes are supported
$vote = self::ACCESS_ABSTAIN;
$class = get_class($object);

$reflector = new \ReflectionMethod($this, 'voteOnAttribute');
$isNewOverwritten = $reflector->getDeclaringClass()->getName() !== 'Symfony\Component\Security\Core\Authorization\Voter\AbstractVoter';
Expand All @@ -72,7 +77,7 @@ public function vote(TokenInterface $token, $object, array $attributes)
}

foreach ($attributes as $attribute) {
if (!$this->supportsAttribute($attribute)) {
if (!$this->supports($attribute, $class)) {
continue;
}

Expand All @@ -95,19 +100,79 @@ public function vote(TokenInterface $token, $object, array $attributes)
return $vote;
}

/**
* Determines if the attribute and class are supported by this voter.
*
* To determine if the passed class is instance of the supported class, the
* isClassInstanceOf() method can be used.
*
* This method will become abstract in 3.0.
*
* @param string $attribute An attribute
* @param string $class The fully qualified class name of the passed object
*
* @return bool True if the attribute and class is supported, false otherwise
*/
protected function supports($attribute, $class)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this method will turn abstract on 3.0 ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes it will. And this is why there is a deprecation warning in the provided implementation.

@wouterj please add a comment in the phpdoc saying it will become abstract in 3.0

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

{
@trigger_error('The getSupportedClasses and getSupportedAttributes methods are deprecated since version 2.8 and will be removed in version 3.0. Overwrite supports instead.');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why this trigger here ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

People have to override the supports method to see if the attribute and class are supported. If they didn't, this code will be executed and they will recieve a deprecation notice. If they did, this code is overriden and the deprecation notice isn't triggered.

The triggers in the getSupported* classes are there in case someone is executing this methods directly, to indicate that they have to use supports.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, if this method is executed, then wouldn't the other deprecations also be triggered ? So basically here we will have at least 2 (and at most 3) deprecations warnings (one for the call on supports, which triggers this as BC, and one or two for the usage of getSupported* methods)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but if we remove one of them, we'll loose information or we didn't cover all BC breaks. There are more cases in which you get 2 or more deprecation messages by using 1 deprecated feature (every deprecated setting configurable in yaml/xml/php for example)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting the 2 deprecation messages for the deprecated calls to getSupported* are fine IMO, but I think the deprecation warning for this method is not necessary, that was my point.


$classIsSupported = false;
foreach ($this->getSupportedClasses() as $supportedClass) {
if ($this->isClassInstanceOf($class, $supportedClass)) {
$classIsSupported = true;
break;
}
}

if (!$classIsSupported) {
return false;
}

if (!in_array($attribute, $this->getSupportedAttributes())) {
return false;
}

return true;
}

/**
* A helper method to test if the actual class is instanceof or equal
* to the expected class.
*
* @param string $actualClass The actual class name
* @param string $expectedClass The expected class name
*
* @return bool
*/
protected function isClassInstanceOf($actualClass, $expectedClass)
{
return $expectedClass === $actualClass || is_subclass_of($actualClass, $expectedClass);
}

/**
* 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.
*/
abstract protected function getSupportedClasses();
protected function getSupportedClasses()
{
@trigger_error('The '.__METHOD__.' is deprecated since version 2.8 and will be removed in version 3.0.');
}

/**
* 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.
*/
abstract protected function getSupportedAttributes();
protected function getSupportedAttributes()
{
@trigger_error('The '.__METHOD__.' is deprecated since version 2.8 and will be removed in version 3.0.');
}

/**
* Perform a single access check operation on a given attribute, object and (optionally) user
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ interface VoterInterface
* @param string $attribute An attribute
*
* @return bool true if this Voter supports the attribute, false otherwise
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function supportsAttribute($attribute);

Expand All @@ -39,6 +41,8 @@ public function supportsAttribute($attribute);
* @param string $class A class name
*
* @return bool true if this Voter can process the class
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function supportsClass($class);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

class AccessDecisionManagerTest extends \PHPUnit_Framework_TestCase
{
/**
* @group legacy
*/
public function testSupportsClass()
{
$manager = new AccessDecisionManager(array(
Expand All @@ -31,6 +34,9 @@ public function testSupportsClass()
$this->assertFalse($manager->supportsClass('FooClass'));
}

/**
* @group legacy
*/
public function testSupportsAttribute()
{
$manager = new AccessDecisionManager(array(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

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;

class AbstractVoterTest_Voter extends AbstractVoter
{
protected function voteOnAttribute($attribute, $object, TokenInterface $token)
{
return 'EDIT' === $attribute;
}

protected function supports($attribute, $class)
{
return $this->isClassInstanceOf($class, 'AbstractVoterTest_Object')
&& in_array($attribute, array('EDIT', 'CREATE'));
}
}

class AbstractVoterTest extends \PHPUnit_Framework_TestCase
{
protected $voter;
protected $object;
protected $token;

protected function setUp()
{
$this->voter = new AbstractVoterTest_Voter();
$this->object = $this->getMock('AbstractVoterTest_Object');
$this->token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
}

public function testAttributeAndClassSupported()
{
$this->assertEquals(VoterInterface::ACCESS_GRANTED, $this->voter->vote($this->token, $this->object, array('EDIT')), 'ACCESS_GRANTED if attribute grants access');
$this->assertEquals(VoterInterface::ACCESS_DENIED, $this->voter->vote($this->token, $this->object, array('CREATE')), 'ACESS_DENIED if attribute denies access');
}

public function testOneAttributeSupported()
{
$this->assertEquals(VoterInterface::ACCESS_GRANTED, $this->voter->vote($this->token, $this->object, array('DELETE', 'EDIT')), 'ACCESS_GRANTED if supported attribute grants access');
$this->assertEquals(VoterInterface::ACCESS_DENIED, $this->voter->vote($this->token, $this->object, array('DELETE', 'CREATE')), 'ACCESS_DENIED if supported attribute denies access');
}

public function testOneAttributeGrantsAccess()
{
$this->assertEquals(VoterInterface::ACCESS_GRANTED, $this->voter->vote($this->token, $this->object, array('CREATE', 'EDIT')), 'ACCESS_GRANTED');
}

public function testNoAttributeSupported()
{
$this->assertEquals(VoterInterface::ACCESS_ABSTAIN, $this->voter->vote($this->token, $this->object, array('DELETE')), 'ACCESS_ABSTAIN');
}

public function testClassNotSupported()
{
$this->assertEquals(VoterInterface::ACCESS_ABSTAIN, $this->voter->vote($this->token, $this->getMock('AbstractVoterTest_Object1'), array('EDIT')), 'ACCESS_ABSTAIN');
}

public function testNullObject()
{
$this->assertEquals(VoterInterface::ACCESS_ABSTAIN, $this->voter->vote($this->token, null, array('EDIT')), 'ACCESS_ABSTAIN');
}

public function testNoAttributes()
{
$this->assertEquals(VoterInterface::ACCESS_ABSTAIN, $this->voter->vote($this->token, $this->object, array()), 'ACCESS_ABSTAIN');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace Symfony\Component\Security\Core\Tests\Authorization\Voter;

use Symfony\Component\Security\Core\Authorization\Voter\AbstractVoter;

class LegacyAbstractVoterTest_Voter extends AbstractVoter
{
protected function getSupportedClasses()
{
return array('AbstractVoterTest_Object');
}

protected function getSupportedAttributes()
{
return array('EDIT', 'CREATE');
}

protected function isGranted($attribute, $object, $user = null)
{
return 'EDIT' === $attribute;
}
}

class LegacyAbstractVoterTest extends AbstractVoterTest
{
protected function setUp()
{
parent::setUp();

$this->voter = new LegacyAbstractVoterTest_Voter();
}
}
Loading