[Security] remove support for defining voters that don't implement the VoterInterface interface.
This commit is contained in:
parent
8483564b71
commit
f527790080
@ -455,6 +455,8 @@ Security
|
||||
* The `AccessDecisionManager::setVoters()` method has been removed. Pass the
|
||||
voters to the constructor instead.
|
||||
|
||||
* Support for defining voters that don't implement the `VoterInterface` has been removed.
|
||||
|
||||
SecurityBundle
|
||||
--------------
|
||||
|
||||
|
@ -8,6 +8,7 @@ CHANGELOG
|
||||
* made `FirewallMap::$container` and `::$map` private
|
||||
* made the first `UserPasswordEncoderCommand::_construct()` argument mandatory
|
||||
* `UserPasswordEncoderCommand` does not extend `ContainerAwareCommand` anymore
|
||||
* removed support for voters that don't implement the `VoterInterface`
|
||||
|
||||
3.4.0
|
||||
-----
|
||||
|
@ -38,19 +38,14 @@ class AddSecurityVotersPass implements CompilerPassInterface
|
||||
|
||||
$voters = $this->findAndSortTaggedServices('security.voter', $container);
|
||||
if (!$voters) {
|
||||
throw new LogicException('No security voters found. You need to tag at least one with "security.voter"');
|
||||
throw new LogicException('No security voters found. You need to tag at least one with "security.voter".');
|
||||
}
|
||||
|
||||
foreach ($voters as $voter) {
|
||||
$class = $container->getDefinition((string) $voter)->getClass();
|
||||
|
||||
if (!is_a($class, VoterInterface::class, true)) {
|
||||
@trigger_error(sprintf('Using a security.voter tag on a class without implementing the %1$s is deprecated as of 3.4 and will be removed in 4.0. Implement the %1$s instead.', VoterInterface::class), E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
if (!method_exists($class, 'vote')) {
|
||||
// in case the vote method is completely missing, to prevent exceptions when voting
|
||||
throw new LogicException(sprintf('%s should implement the %s interface when used as voter.', $class, VoterInterface::class));
|
||||
throw new LogicException(sprintf('%s must implement the %s when used as a voter.', $class, VoterInterface::class));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,16 +14,15 @@ namespace Symfony\Bundle\SecurityBundle\Tests\DependencyInjection\Compiler;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Compiler\AddSecurityVotersPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\LogicException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\Security\Core\Authorization\AccessDecisionManager;
|
||||
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
|
||||
use Symfony\Component\Security\Core\Tests\Authorization\Stub\VoterWithoutInterface;
|
||||
|
||||
class AddSecurityVotersPassTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\LogicException
|
||||
* @expectedExceptionMessage No security voters found. You need to tag at least one with "security.voter".
|
||||
*/
|
||||
public function testNoVoters()
|
||||
{
|
||||
@ -71,8 +70,8 @@ class AddSecurityVotersPassTest extends TestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
* @expectedDeprecation Using a security.voter tag on a class without implementing the Symfony\Component\Security\Core\Authorization\Voter\VoterInterface is deprecated as of 3.4 and will be removed in 4.0. Implement the Symfony\Component\Security\Core\Authorization\Voter\VoterInterface instead.
|
||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\LogicException
|
||||
* @expectedExceptionMessage stdClass must implement the Symfony\Component\Security\Core\Authorization\Voter\VoterInterface when used as a voter.
|
||||
*/
|
||||
public function testVoterMissingInterface()
|
||||
{
|
||||
@ -82,40 +81,7 @@ class AddSecurityVotersPassTest extends TestCase
|
||||
->addArgument(array())
|
||||
;
|
||||
$container
|
||||
->register('without_interface', VoterWithoutInterface::class)
|
||||
->addTag('security.voter')
|
||||
;
|
||||
$compilerPass = new AddSecurityVotersPass();
|
||||
$compilerPass->process($container);
|
||||
|
||||
$argument = $container->getDefinition('security.access.decision_manager')->getArgument(0);
|
||||
$refs = $argument->getValues();
|
||||
$this->assertEquals(new Reference('without_interface'), $refs[0]);
|
||||
$this->assertCount(1, $refs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
public function testVoterMissingInterfaceAndMethod()
|
||||
{
|
||||
$exception = LogicException::class;
|
||||
$message = 'stdClass should implement the Symfony\Component\Security\Core\Authorization\Voter\VoterInterface interface when used as voter.';
|
||||
|
||||
if (method_exists($this, 'expectException')) {
|
||||
$this->expectException($exception);
|
||||
$this->expectExceptionMessage($message);
|
||||
} else {
|
||||
$this->setExpectedException($exception, $message);
|
||||
}
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container
|
||||
->register('security.access.decision_manager', AccessDecisionManager::class)
|
||||
->addArgument(array())
|
||||
;
|
||||
$container
|
||||
->register('without_method', 'stdClass')
|
||||
->register('without_interface', 'stdClass')
|
||||
->addTag('security.voter')
|
||||
;
|
||||
$compilerPass = new AddSecurityVotersPass();
|
||||
|
@ -8,7 +8,8 @@ CHANGELOG
|
||||
You should implement this method yourself in your concrete authenticator.
|
||||
* removed the `AccessDecisionManager::setVoters()` method
|
||||
* removed the `RoleInterface`
|
||||
* added a sixth `string $context` argument to`LogoutUrlGenerator::registerListener()`
|
||||
* removed support for voters that don't implement the `VoterInterface`
|
||||
* added a sixth `string $context` argument to `LogoutUrlGenerator::registerListener()`
|
||||
|
||||
3.4.0
|
||||
-----
|
||||
|
@ -13,7 +13,6 @@ namespace Symfony\Component\Security\Core\Authorization;
|
||||
|
||||
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Exception\LogicException;
|
||||
|
||||
/**
|
||||
* AccessDecisionManager is the base class for all access decision managers
|
||||
@ -33,7 +32,7 @@ class AccessDecisionManager implements AccessDecisionManagerInterface
|
||||
private $allowIfEqualGrantedDeniedDecisions;
|
||||
|
||||
/**
|
||||
* @param iterable|VoterInterface[] $voters An iterator of VoterInterface instances
|
||||
* @param iterable|VoterInterface[] $voters An array or an iterator of VoterInterface instances
|
||||
* @param string $strategy The vote strategy
|
||||
* @param bool $allowIfAllAbstainDecisions Whether to grant access if all voters abstained or not
|
||||
* @param bool $allowIfEqualGrantedDeniedDecisions Whether to grant access if result are equals
|
||||
@ -71,7 +70,7 @@ class AccessDecisionManager implements AccessDecisionManagerInterface
|
||||
{
|
||||
$deny = 0;
|
||||
foreach ($this->voters as $voter) {
|
||||
$result = $this->vote($voter, $token, $object, $attributes);
|
||||
$result = $voter->vote($token, $object, $attributes);
|
||||
switch ($result) {
|
||||
case VoterInterface::ACCESS_GRANTED:
|
||||
return true;
|
||||
@ -112,7 +111,7 @@ class AccessDecisionManager implements AccessDecisionManagerInterface
|
||||
$grant = 0;
|
||||
$deny = 0;
|
||||
foreach ($this->voters as $voter) {
|
||||
$result = $this->vote($voter, $token, $object, $attributes);
|
||||
$result = $voter->vote($token, $object, $attributes);
|
||||
|
||||
switch ($result) {
|
||||
case VoterInterface::ACCESS_GRANTED:
|
||||
@ -153,7 +152,7 @@ class AccessDecisionManager implements AccessDecisionManagerInterface
|
||||
$grant = 0;
|
||||
foreach ($this->voters as $voter) {
|
||||
foreach ($attributes as $attribute) {
|
||||
$result = $this->vote($voter, $token, $object, array($attribute));
|
||||
$result = $voter->vote($token, $object, array($attribute));
|
||||
|
||||
switch ($result) {
|
||||
case VoterInterface::ACCESS_GRANTED:
|
||||
@ -177,27 +176,4 @@ class AccessDecisionManager implements AccessDecisionManagerInterface
|
||||
|
||||
return $this->allowIfAllAbstainDecisions;
|
||||
}
|
||||
|
||||
/**
|
||||
* TokenInterface vote proxy method.
|
||||
*
|
||||
* Acts as a BC layer when the VoterInterface is not implemented on the voter.
|
||||
*
|
||||
* @deprecated as of 3.4 and will be removed in 4.0. Call the voter directly as the instance will always be a VoterInterface
|
||||
*/
|
||||
private function vote($voter, TokenInterface $token, $subject, $attributes)
|
||||
{
|
||||
if ($voter instanceof VoterInterface) {
|
||||
return $voter->vote($token, $subject, $attributes);
|
||||
}
|
||||
|
||||
if (method_exists($voter, 'vote')) {
|
||||
@trigger_error(sprintf('Calling vote() on an voter without %1$s is deprecated as of 3.4 and will be removed in 4.0. Implement the %1$s on your voter.', VoterInterface::class), E_USER_DEPRECATED);
|
||||
|
||||
// making the assumption that the signature matches
|
||||
return $voter->vote($token, $subject, $attributes);
|
||||
}
|
||||
|
||||
throw new LogicException(sprintf('%s should implement the %s interface when used as voter.', get_class($voter), VoterInterface::class));
|
||||
}
|
||||
}
|
||||
|
@ -12,11 +12,8 @@
|
||||
namespace Symfony\Component\Security\Core\Tests\Authorization;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Authorization\AccessDecisionManager;
|
||||
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
|
||||
use Symfony\Component\Security\Core\Exception\LogicException;
|
||||
use Symfony\Component\Security\Core\Tests\Authorization\Stub\VoterWithoutInterface;
|
||||
|
||||
class AccessDecisionManagerTest extends TestCase
|
||||
{
|
||||
@ -141,34 +138,4 @@ class AccessDecisionManagerTest extends TestCase
|
||||
|
||||
return $voter;
|
||||
}
|
||||
|
||||
public function testVotingWrongTypeNoVoteMethod()
|
||||
{
|
||||
$exception = LogicException::class;
|
||||
$message = sprintf('stdClass should implement the %s interface when used as voter.', VoterInterface::class);
|
||||
|
||||
if (method_exists($this, 'expectException')) {
|
||||
$this->expectException($exception);
|
||||
$this->expectExceptionMessage($message);
|
||||
} else {
|
||||
$this->setExpectedException($exception, $message);
|
||||
}
|
||||
|
||||
$adm = new AccessDecisionManager(array(new \stdClass()));
|
||||
$token = $this->getMockBuilder(TokenInterface::class)->getMock();
|
||||
|
||||
$adm->decide($token, array('TEST'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
* @expectedDeprecation Calling vote() on an voter without Symfony\Component\Security\Core\Authorization\Voter\VoterInterface is deprecated as of 3.4 and will be removed in 4.0. Implement the Symfony\Component\Security\Core\Authorization\Voter\VoterInterface on your voter.
|
||||
*/
|
||||
public function testVotingWrongTypeWithVote()
|
||||
{
|
||||
$adm = new AccessDecisionManager(array(new VoterWithoutInterface()));
|
||||
$token = $this->getMockBuilder(TokenInterface::class)->getMock();
|
||||
|
||||
$adm->decide($token, array('TEST'));
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* 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\Stub;
|
||||
|
||||
/**
|
||||
* @author Iltar van der Berg <kjarli@gmail.com>
|
||||
*/
|
||||
class VoterWithoutInterface
|
||||
{
|
||||
public function vote()
|
||||
{
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user