Skip to content

Voters - different behavior on dev/test and production enviroment #39205

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
adeptofvoltron opened this issue Nov 27, 2020 · 6 comments
Closed
Labels
Bug Good first issue Ideal for your first contribution! (some Symfony experience may be required) Security Status: Reviewed

Comments

@adeptofvoltron
Copy link
Contributor

Symfony version(s) affected: tested on 5.0.10 (but from what I see in a code,

Description

Basically each voter in dev/test env is wrapped in \Symfony\Component\Security\Core\Authorization\Voter\TraceableVoter proxy. In that commit @nicolas-grekas added return type int. Because there is no "strict types" in file...all return results are type juggled to int.
In prod env, there is no such proxy so the result is not juggled into an int.

Voter Result is used in \Symfony\Component\Security\Core\Authorization\AccessDecisionManager where it is strictly compared.

How to reproduce

There are several possible solutions, and I would be happy to implement it. However, I do not know properly the "Symfony way" to contribute. So I am going to be more than happy by pointing to the correct solution:

  • Option nr . 1 Use strict types in TraceableVoter -> It will throw an error if someone's voter will return different type than boolean.
    disadventages: backward-incompatible, some projects may not handle such error + I did not see using strict_types in Symfony(surprised tbh).

  • Option nr . 2 Cast return from Voter in AccessDecisionManager into "int". I think it is an ugly version, but most likely to be correct here

  • Option nr. 3 remove return type declaration from vote method (after allis cause the problem). There is no such declaration in VoterInterface

  • Option nr. 4 - most elegant imho. Adding the return type declaration in VoterInterface. however in breaks backward compatibility so that solution can be introduced in 6.0 framework.

Additional context

@lyrixx
Copy link
Member

lyrixx commented Nov 28, 2020

All voters must return an int.
https://github.com/symfony/symfony/blob/5.x/src/Symfony/Component/Security/Core/Authorization/Voter/VoterInterface.php#L38

Why do you return something else?

IMHO nothing should be fixed here

@jvasseur
Copy link
Contributor

I think the problem is that if you make a mistake and return something that is castable ton an int (for example true instead of ACCESS_GRANTED) it will work in dev environment where it shouldn't, and the bug will only appear in production.

@wouterj
Copy link
Member

wouterj commented Nov 29, 2020

Thanks for all information in the issue description, that makes it very easy to trace the exact problem here.

I would propose the following solution:

  1. Remove the : int type juggling indicator in the 4.4 branch
  2. Deprecate not returning an int in 5.x. This can be done exactly like done in the Console component in 4.4:
    if (!\is_int($statusCode)) {
    @trigger_error(sprintf('Return value of "%s::execute()" should always be of the type int since Symfony 4.4, %s returned.', static::class, \gettype($statusCode)), \E_USER_DEPRECATED);
    }
  3. Add an exception in 6.0, like in the Console component:
    if (!\is_int($statusCode)) {
    throw new \TypeError(sprintf('Return value of "%s::execute()" must be of the type int, "%s" returned.', static::class, get_debug_type($statusCode)));
    }

Are you willing to create a PR for (1) and (2)?

There is no such declaration in VoterInterface

There is, in the PHPdoc:

* @return int either ACCESS_GRANTED, ACCESS_ABSTAIN, or ACCESS_DENIED
*/
public function vote(TokenInterface $token, $subject, array $attributes);
As types are very new in PHP (and Symfony is still migrating to PHP types), PHPdocs are just as important for the contract as PHP types.

@wouterj wouterj added Status: Reviewed Good first issue Ideal for your first contribution! (some Symfony experience may be required) and removed Status: Needs Review Status: Waiting feedback labels Nov 29, 2020
@adeptofvoltron
Copy link
Contributor Author

@wouterj thx for the response. I will do exactly the way you suggested. today in the late afternoon(CET time zone).

@adeptofvoltron
Copy link
Contributor Author

@jvasseur and @lyrixx that is correct. However, the dev environment should escalate errors, not hide them.

@jvasseur
Copy link
Contributor

@adeptofvoltron yes, but erroring in this case would be a BC break, that why we can only deprecate it for now.

@chalasr chalasr closed this as completed Nov 30, 2020
@derrabus derrabus reopened this Nov 30, 2020
fabpot added a commit that referenced this issue 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
Labels
Bug Good first issue Ideal for your first contribution! (some Symfony experience may be required) Security Status: Reviewed
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants