feature #15870 Updating AbstractVoter so that the method receives the TokenInterface (weaverryan)
This PR was squashed before being merged into the 2.8 branch (closes #15870).
Discussion
----------
Updating AbstractVoter so that the method receives the TokenInterface
| Q | A
| ------------- | ---
| Bug fix? | no
| New feature? | yes
| BC breaks? | no
| Deprecations? | yes
| Tests pass? | yes
| Fixed tickets | #12360
| License | MIT
| Doc PR | not yet
This fixes #12360, and along with already-merged #14733, this would make it possible to make calls back to the `AccessDecisionManager` inside a voter (e.g. you might check to see if `IS_AUTHENTICATED_FULLY` from inside your voter).
We originally passed the User instead of the token to be nice, but it's a limitation, and since we never sanitized the User (i.e. a string may be passed to `AbstractToken::isGranted()`), it's not helpful anyways.
Thanks!
Commits
-------
948ccec
Updating AbstractVoter so that the method receives the TokenInterface
This commit is contained in:
commit
5b8b429795
@ -406,3 +406,39 @@ FrameworkBundle
|
|||||||
session:
|
session:
|
||||||
cookie_httponly: false
|
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();
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
@ -65,6 +65,12 @@ abstract class AbstractVoter implements VoterInterface
|
|||||||
// abstain vote by default in case none of the attributes are supported
|
// abstain vote by default in case none of the attributes are supported
|
||||||
$vote = self::ACCESS_ABSTAIN;
|
$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) {
|
foreach ($attributes as $attribute) {
|
||||||
if (!$this->supportsAttribute($attribute)) {
|
if (!$this->supportsAttribute($attribute)) {
|
||||||
continue;
|
continue;
|
||||||
@ -73,9 +79,16 @@ abstract class AbstractVoter implements VoterInterface
|
|||||||
// as soon as at least one attribute is supported, default is to deny access
|
// as soon as at least one attribute is supported, default is to deny access
|
||||||
$vote = self::ACCESS_DENIED;
|
$vote = self::ACCESS_DENIED;
|
||||||
|
|
||||||
if ($this->isGranted($attribute, $object, $token->getUser())) {
|
if ($isNewOverwritten) {
|
||||||
// grant access as soon as at least one voter returns a positive response
|
if ($this->voteOnAttribute($attribute, $object, $token)) {
|
||||||
return self::ACCESS_GRANTED;
|
// 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 class AbstractVoter implements VoterInterface
|
|||||||
* @param object $object
|
* @param object $object
|
||||||
* @param UserInterface|string $user
|
* @param UserInterface|string $user
|
||||||
*
|
*
|
||||||
|
* @deprecated This method will be removed in 3.0 - override voteOnAttribute instead.
|
||||||
|
*
|
||||||
* @return bool
|
* @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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace Symfony\Component\Security\Tests\Core\Authentication\Voter;
|
namespace Symfony\Component\Security\Tests\Core\Authentication\Voter;
|
||||||
|
|
||||||
|
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||||
use Symfony\Component\Security\Core\Authorization\Voter\AbstractVoter;
|
use Symfony\Component\Security\Core\Authorization\Voter\AbstractVoter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,6 +47,17 @@ class AbstractVoterTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertEquals($expectedVote, $this->voter->vote($this->token, $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()
|
public function getData()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
@ -75,6 +87,26 @@ class VoterFixture extends AbstractVoter
|
|||||||
return array('foo', 'bar', 'baz');
|
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)
|
protected function isGranted($attribute, $object, $user = null)
|
||||||
{
|
{
|
||||||
return $attribute === 'foo';
|
return $attribute === 'foo';
|
||||||
|
Reference in New Issue
Block a user