[Security] remove support for defining voters that don't implement the VoterInterface interface.

This commit is contained in:
Hugo Hamon 2017-06-29 00:18:27 +02:00
parent 8483564b71
commit f527790080
8 changed files with 15 additions and 129 deletions

View File

@ -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
--------------

View File

@ -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
-----

View File

@ -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));
}
}

View File

@ -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();

View File

@ -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
-----

View File

@ -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));
}
}

View File

@ -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'));
}
}

View File

@ -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()
{
}
}