Skip to content

[Security] Use IteratorArgument for voters #21437

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

Merged
merged 1 commit into from
Apr 4, 2017
Merged
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
2 changes: 2 additions & 0 deletions UPGRADE-3.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,8 @@ Security
* The `LogoutUrlGenerator::registerListener()` method will expect a 6th `$context = null` argument in 4.0.
Define the argument when overriding this method.

* The `AccessDecisionManager::setVoters()` has been deprecated. Pass the voters to the constructor instead.
Copy link
Member

Choose a reason for hiding this comment

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

corresponding entry missing from UPGRADE-4.0.md (the ... has been removed. ...)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed


SecurityBundle
--------------

Expand Down
2 changes: 2 additions & 0 deletions UPGRADE-4.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,8 @@ Security

* The `LogoutUrlGenerator::registerListener()` method expects a 6th `$context = null` argument.

* The `AccessDecisionManager::setVoters()` has been removed. Pass the voters to the constructor instead.

SecurityBundle
--------------

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace Symfony\Bundle\SecurityBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait;
Expand Down Expand Up @@ -39,7 +40,7 @@ public function process(ContainerBuilder $container)
throw new LogicException('No security voters found. You need to tag at least one with "security.voter"');
}

$adm = $container->getDefinition($container->hasDefinition('debug.security.access.decision_manager') ? 'debug.security.access.decision_manager' : 'security.access.decision_manager');
$adm->addMethodCall('setVoters', array($voters));
$adm = $container->getDefinition('security.access.decision_manager');
$adm->replaceArgument(0, new IteratorArgument($voters));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ public function testThatSecurityVotersAreProcessedInPriorityOrder()
$compilerPass = new AddSecurityVotersPass();
$compilerPass->process($container);

$calls = $container->getDefinition('security.access.decision_manager')->getMethodCalls();
$refs = $calls[0][1][0];
$argument = $container->getDefinition('security.access.decision_manager')->getArgument(0);
$refs = $argument->getValues();
$this->assertEquals(new Reference('highest_prio_service'), $refs[0]);
$this->assertEquals(new Reference('lowest_prio_service'), $refs[1]);
$this->assertCount(4, $refs);
Expand Down
5 changes: 5 additions & 0 deletions src/Symfony/Component/Security/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
CHANGELOG
=========

3.3.0
-----

* deprecated `setVoters()` of the `AccessDecisionManager` class in favor of passing the voters to the constructor.

3.2.0
-----

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,14 @@ class AccessDecisionManager implements AccessDecisionManagerInterface
private $allowIfEqualGrantedDeniedDecisions;

/**
* Constructor.
*
* @param VoterInterface[] $voters An array 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
* @param iterable|VoterInterface[] $voters 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
*
* @throws \InvalidArgumentException
*/
public function __construct(array $voters = array(), $strategy = self::STRATEGY_AFFIRMATIVE, $allowIfAllAbstainDecisions = false, $allowIfEqualGrantedDeniedDecisions = true)
public function __construct($voters = array(), $strategy = self::STRATEGY_AFFIRMATIVE, $allowIfAllAbstainDecisions = false, $allowIfEqualGrantedDeniedDecisions = true)
{
$strategyMethod = 'decide'.ucfirst($strategy);
if (!is_callable(array($this, $strategyMethod))) {
Expand All @@ -58,9 +56,13 @@ public function __construct(array $voters = array(), $strategy = self::STRATEGY_
* Configures the voters.
*
* @param VoterInterface[] $voters An array of VoterInterface instances
*
* @deprecated since version 3.3, to be removed in 4.0. Pass the voters to the constructor instead.
*/
public function setVoters(array $voters)
{
@trigger_error(sprintf('The %s() method is deprecated since version 3.3 and will be removed in 4.0. Pass the voters to the constructor instead.', __METHOD__), E_USER_DEPRECATED);
Copy link
Member

Choose a reason for hiding this comment

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

Do we gain anything by deprecating this method? Does it hurt to keep it?

Copy link
Contributor Author

@jvasseur jvasseur Jan 29, 2017

Choose a reason for hiding this comment

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

Changing the type of the $voters argument from array to iterable would be a BC break so this would mean having a different argument type for the constructor parameter and this method.


$this->voters = $voters;
}

Expand Down Expand Up @@ -162,8 +164,8 @@ private function decideConsensus(TokenInterface $token, array $attributes, $obje
private function decideUnanimous(TokenInterface $token, array $attributes, $object = null)
{
$grant = 0;
foreach ($attributes as $attribute) {
foreach ($this->voters as $voter) {
foreach ($this->voters as $voter) {
foreach ($attributes as $attribute) {
$result = $voter->vote($token, $object, array($attribute));

switch ($result) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,13 @@ public function __construct(AccessDecisionManagerInterface $manager)
$this->manager = $manager;

if ($this->manager instanceof AccessDecisionManager) {
// The strategy is stored in a private property of the decorated service
// The strategy and voters are stored in a private properties of the decorated service
$reflection = new \ReflectionProperty(AccessDecisionManager::class, 'strategy');
$reflection->setAccessible(true);
$this->strategy = $reflection->getValue($manager);
$reflection = new \ReflectionProperty(AccessDecisionManager::class, 'voters');
$reflection->setAccessible(true);
$this->voters = $reflection->getValue($manager);
}
}

Expand All @@ -58,9 +61,13 @@ public function decide(TokenInterface $token, array $attributes, $object = null)

/**
* {@inheritdoc}
*
* @deprecated since version 3.3, to be removed in 4.0. Pass voters to the decorated AccessDecisionManager instead.
*/
public function setVoters(array $voters)
{
@trigger_error(sprintf('The %s() method is deprecated since version 3.3 and will be removed in 4.0. Pass voters to the decorated AccessDecisionManager instead.', __METHOD__), E_USER_DEPRECATED);

if (!method_exists($this->manager, 'setVoters')) {
return;
}
Expand All @@ -81,7 +88,7 @@ public function getStrategy()
}

/**
* @return array
* @return iterable|VoterInterface[]
*/
public function getVoters()
{
Expand Down