Skip to content

[Security] voters now are going to be obligated to return int values #39248

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

Closed
wants to merge 9 commits into from

Conversation

adeptofvoltron
Copy link
Contributor

@adeptofvoltron adeptofvoltron commented Nov 30, 2020

Q A
Branch? 5.x
Bug fix? yes
New feature? no
Deprecations? yes
Tickets Fix #39205
License MIT
Doc PR

Everything described with details in the related ticket

@carsonbot carsonbot changed the title [security] voters now are going to be obligated to return int values [Security] [security] voters now are going to be obligated to return int values Nov 30, 2020
@adeptofvoltron adeptofvoltron changed the title [Security] [security] voters now are going to be obligated to return int values [Security] voters now are going to be obligated to return int values Nov 30, 2020
@derrabus derrabus added this to the 5.x milestone Nov 30, 2020
@derrabus
Copy link
Member

derrabus commented Nov 30, 2020

We cannot introduce deprecations in 5.2 anymore. This PR should target 5.3.

Copy link
Member

@derrabus derrabus left a comment

Choose a reason for hiding this comment

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

  • The deprecation should be triggered in prod as well, so TraceableVoter is imho not the right place for this logic. I think we should move it to AccessDecisionManager instead.
  • in_array() does not perform a type-safe comparison by default! I don't think the current logic would catch the case drafted in the corresponding issue.
  • I would avoid in_array() altogether because it's inefficient.

@adeptofvoltron
Copy link
Contributor Author

@derrabus I was thinking of usage of is_int however it would not cover all possible scenarios. That why I used the in_array method. However, point taken about the strict comparison. Already repaired.

The fix is in TraceableVoter on purpose. please check the reason for the related issue. In the brief, I wanted to escalate error on dev environments.

PR should target 5.3....actually it is on branch 5.x shall I create a new Upgrade file??

@stof
Copy link
Member

stof commented Nov 30, 2020

PR should target 5.3....actually it is on branch 5.x shall I create a new Upgrade file??

yes, as that's the first PR adding a deprecation for 5.3...

@adeptofvoltron
Copy link
Contributor Author

@stof thank you. My first PR to Symfony so I am not totally familiar with that community approach. You helped me a lot.
@derrabus if you can now relate to the requested changes. Are they fullfilled?

@derrabus
Copy link
Member

derrabus commented Nov 30, 2020

The fix is in TraceableVoter on purpose. please check the reason for the related issue. In the brief, I wanted to escalate error on dev environments.

Understood. But this would still create different behavior on dev and prod. Right now, a voter can return false or 42 or "1" or null or new DateTime() and AccessDecisionManager would count that as abstain in prod. If we want to be more strict about the return value (and maybe even add the int return type to VoterInterface in 6.0), we should trigger the deprecation even if TraceableVoter is not available.

This is why I think AccessDecisionManager is in fact the better place.

@wouterj, can you join the discussion please? 😃

@wouterj
Copy link
Member

wouterj commented Nov 30, 2020

Hi! Thanks for your 2 PRs, one of them is already merged. Congrats on your first contributions! (and even though this one has some comments, it's really in a good state for a first contribution!)

I agree with @derrabus and I think the confusion here is on the goal of these changes. In my mind, it's not about escalating errors in dev when an incorrect value is returned (in which case it's the TraceableVoter that should do have this check), but it's about being able to simulate the : int return type (we cannot add it, as that would break backwards compatibility IIRC). In order to do that, we should add an \is_int() check in AccessDecisionManager.

In fact, your idea "showing somewhere that an incorrect value is returned by vote()" might be a great idea in just the dev environment (thus in TraceableVoter). But let's not do that in this PR (as it would also require some changes to the security profiler page I think).

@adeptofvoltron
Copy link
Contributor Author

You guys are here maintainers. so it is up to You. I must admit that You both are super patient.

However, adding that deprecation in AccessDecisionManager leads to a situation when in the dev environment you got no error at all (because TraceableVoter will cast the value to integer). And on the production environment, you will get deprecation + app will not work the way developer thought it will. It was my goal at the beginning.

But fine. I will make the changes you desire in 5 minutes.
Thank you @wouterj and @derrabus for help.

@wouterj
Copy link
Member

wouterj commented Nov 30, 2020

Wait, that's an important detail! Now that the : int return type is removed (the changes from 4.4 will be merged up to 5.1, 5.2 & 5.x), the TraceableVoter is no longer type casting it to an int, right?

@adeptofvoltron
Copy link
Contributor Author

@wouterj yes you right. I just was not sure when changes from 4.4 will be merged up. I do not know the SF workflow yet.

Comment on lines 86 to 89
@trigger_error(
sprintf('Return value of "%s::vote()" should always be of the type int since Symfony 5.0, %s returned.', \get_class($voter), \gettype($result)),
\E_USER_DEPRECATED
);
Copy link
Member

@derrabus derrabus Nov 30, 2020

Choose a reason for hiding this comment

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

Suggested change
@trigger_error(
sprintf('Return value of "%s::vote()" should always be of the type int since Symfony 5.0, %s returned.', \get_class($voter), \gettype($result)),
\E_USER_DEPRECATED
);
trigger_deprecation('symfony/security-core', '5.3', 'Returning a value of type "%s" in "%s::vote()" is deprecated, return an int instead.', get_debug_type($result), get_debug_type($voter));

Copy link
Contributor Author

Choose a reason for hiding this comment

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

now I am lost. 5.3 is supposed to be for PHP 8.0 only??

Copy link
Member

Choose a reason for hiding this comment

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

We have a Polyfill for get_debug_type(). You can safely use that method on PHP 7 as well.

Copy link
Contributor Author

@adeptofvoltron adeptofvoltron Nov 30, 2020

Choose a reason for hiding this comment

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

ah perfect. I allowed myself to write to you on slack. For faster communication

Copy link
Member

Choose a reason for hiding this comment

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

@derrabus
Copy link
Member

When triggering the deprecation, we might want to check if we have a TraceableVoter instance and report the decorated class instead of TraceableVoter.

@derrabus
Copy link
Member

I'm going to merge your change up now, @adeptofvoltron.

@derrabus
Copy link
Member

There you go. No more return type on 5.x. 😃

@@ -119,6 +122,9 @@ private function decideConsensus(TokenInterface $token, array $attributes, $obje
$deny = 0;
foreach ($this->voters as $voter) {
$result = $voter->vote($token, $object, $attributes);
if (false === \is_int($result)) {
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 about adding a elseif ($result !== VoterInterface::ACCESS_ABSTAIN) below?
It will assert the return value is a valid constant!

The deprecation message would be `return either VoterInterface::ACCESS_GRANTED, VoterInterface::ACCESS_DENIED or VoterInterface::ACCESS_ABSTAIN).

In Symfony 6.0 we will be able to type hint and replace the deprecation by an exception.

@adeptofvoltron
Copy link
Contributor Author

for a week or two, I will have to focus on another project...so I will finish that PR after that.
It is going to be easier for me if I reopen it after that. Do not worry guys I remember all the comments ;)

fabpot added a commit that referenced this pull request Dec 8, 2020
This PR was merged into the 5.3-dev branch.

Discussion
----------

[Security] Assert voter returns valid decision

| Q             | A
| ------------- | ---
| Branch?       | 5.x
| Bug fix?      | no
| New feature?  | no
| Deprecations? | yes
| Tickets       | Fix #39205
| License       | MIT
| Doc PR        |

Replace #39248

Commits
-------

ffdfb4f Assert voter returns valid decision
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.

Voters - different behavior on dev/test and production enviroment
7 participants