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

Conversation

jvasseur
Copy link
Contributor

Q A
Branch? master
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? yes
Tests pass? yes
License MIT

Use an IteratorArgument for injecting voters into the AccessDecisionManager.

@@ -81,7 +88,7 @@ public function getStrategy()
}

/**
* @return array
* @return iterable
Copy link
Member

Choose a reason for hiding this comment

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

technically, this is a BC break if the calling code passes it to a function requiring an array

Copy link
Contributor Author

@jvasseur jvasseur Jan 27, 2017

Choose a reason for hiding this comment

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

True, but this class is marked as internal, so the BC break should be ok.

Copy link
Member

Choose a reason for hiding this comment

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

iterable|VoterInterface[] for helping IDE?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Would IDEs support the iterable<VoterInterface> syntax from PSR-5 ?

@stof
Copy link
Member

stof commented Jan 27, 2017

What is the benefit of this change ?

@jvasseur
Copy link
Contributor Author

The benefits are :

  • prevent instancing all the voters when not needed.
  • remove the need for the setVoters method to allow voters to depend on the AccessDecisionManager.

*/
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.

@nicolas-grekas
Copy link
Member

👍

@nicolas-grekas nicolas-grekas added this to the 3.3 milestone Jan 29, 2017
@@ -45,7 +46,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(array_values($voters)));
$adm = $container->getDefinition('security.access.decision_manager');
Copy link
Member

Choose a reason for hiding this comment

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

Won't this change break the DebugAccessDecisionManager?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I updated it to grab the voters properties from the AccessDecisionManager in the same way it is doing it for the strategy : https://github.com/symfony/symfony/pull/21437/files#diff-76aa9de2473eccdc05075961beaed023R42

Copy link
Member

Choose a reason for hiding this comment

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

But now the debug.security.access.decision_manager service will not be aware of the available voters, will it (see #18566 for more context)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The voters will be injected into the security.access.decision_manager service that will then be injected into the debug.security.access.decision_manager service that will grab the voters so everything should be fine.

Copy link
Member

Choose a reason for hiding this comment

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

But then these lines will never be executed: https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Security/Core/Authorization/TraceableAccessDecisionManager.php#L62-L70 So getVoters() would always return an empty list.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It tried different solutions to fix this problems but either they break BC in a worse way or introduce a risk that the voters list shown in the profiler is different than the one used by the access decision manager.

Or maybe someone else has solution to fix this problem.
Maybe this would be ok keeping it like this, the only thing broken would be getting an empty voter list in the profiler when using such an implementation.

Copy link
Member

Choose a reason for hiding this comment

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

IIRC we explicitly have this handling because there were issue otherwise when you were, for example, using the JMSSecurityExtraBundle which ships with its own RememberingAccessDecisionManager.

Copy link
Member

Choose a reason for hiding this comment

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

What's the conclusion here?

Copy link
Member

Choose a reason for hiding this comment

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

Did someone test the changes from this PR in a real project to ensure that the profiler still works as expected?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My opinion here would be to keep it like this and accept that you lose the list of voters in the profiler in some cases (you already lose the configured strategy in those cases).

The alternatives are IMO not worth it. One of them would be to pass the list of voters to the DebugAccessDecisionManager independently, but that would introduce the possibility that the list shown in the profiler is not the same as the one used by the AccessDecisionManager (if someone modify it in another compile pass). And the other possibilities I could think of would either have worst BC breaks or introduce possible differences in behavior between prod and dev environments.

* @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 $voters An iterator of VoterInterface instances
Copy link
Member

Choose a reason for hiding this comment

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

That's a BC break, we should accept iterable|VoterInterface[]

Copy link
Contributor Author

Choose a reason for hiding this comment

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

iterable is equivalent to array|\Traversable so we still accept arrays as before.

Copy link
Member

Choose a reason for hiding this comment

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

iterable|VoterInterface[] would still allow IDEs to provide type hints

@nicolas-grekas
Copy link
Member

I did not look at the exact logic: in AccessDecisionManager::decideUnanimous, would it be possible to swap the two foreach, ie iterate over voters, then over attributes inside? That may prevent instantiating some voters if eg a grant is denied early.

@jvasseur jvasseur force-pushed the voter-iterator branch 2 times, most recently from 5a25337 to 58797f3 Compare January 31, 2017 22:20
Copy link
Member

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

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

👍

@jvasseur jvasseur force-pushed the voter-iterator branch 5 times, most recently from 926a51c to a4b574e Compare March 1, 2017 15:15
@nicolas-grekas
Copy link
Member

@jvasseur can you please rebase? there are failures related to this PR isn't it?

@jvasseur
Copy link
Contributor Author

jvasseur commented Mar 1, 2017

Rebased and fix the test failure that was related to the changes in this PR.

Copy link
Member

@chalasr chalasr left a comment

Choose a reason for hiding this comment

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

changelog/upgrade files should mention this

@fabpot
Copy link
Member

fabpot commented Mar 22, 2017

👍

@fabpot
Copy link
Member

fabpot commented Mar 22, 2017

A quick rebase to ensure that tests are all-right would be good as well.

@jvasseur
Copy link
Contributor Author

@fabpot rebased on current master.

Remaining test failures are unrelated to this PR.

@xabbuh
Copy link
Member

xabbuh commented Mar 23, 2017

So did someone try this PR in a real project and made sure that this will not break the security profiler?

@jvasseur
Copy link
Contributor Author

I did try it on a real project and everything was working. But since I made some changes to the PR since then I will try to do it again when I have some free time.

@chalasr
Copy link
Member

chalasr commented Mar 23, 2017

CHANGELOG/UPGRADE-* still need an update.

@nicolas-grekas
Copy link
Member

ping @jvasseur

@jvasseur
Copy link
Contributor Author

jvasseur commented Apr 4, 2017

Note added to CHANGELOG/UPGRADE.

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

Copy link
Member

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

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

👍

@fabpot
Copy link
Member

fabpot commented Apr 4, 2017

Thank you @jvasseur.

@fabpot fabpot merged commit 4ec80b1 into symfony:master Apr 4, 2017
fabpot added a commit that referenced this pull request Apr 4, 2017
This PR was merged into the 3.3-dev branch.

Discussion
----------

[Security] Use IteratorArgument for voters

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | yes
| Tests pass?   | yes
| License       | MIT

Use an IteratorArgument for injecting voters into the AccessDecisionManager.

Commits
-------

4ec80b1 Use IteratorArgument for voters
@jvasseur jvasseur deleted the voter-iterator branch April 4, 2017 21:00
@fabpot fabpot mentioned this pull request May 1, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants