Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Fix the supports() method argument type of the security voter #37325

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 0 commits into from
Closed

Fix the supports() method argument type of the security voter #37325

wants to merge 0 commits into from

Conversation

francoispluchino
Copy link
Contributor

Q A
Branch? 5.0 and 5.1
Bug fix? yes
New feature? no
Deprecations? no
Tickets ~
License MIT
Doc PR ~

Since adding types to method arguments in the version 5.0 (and therefore also 5.1), there is a type mismatch on the first argument of the supports() method of the abstract class Symfony\Component\Security\Core\Authorization\Voter\Voter.

Indeed, the supports() method had in previous versions (4.x), the phpdoc indicating that the argument $attribute must be a string, but this one is not compatible with the isGranted() method of the interface Symfony\Component\Security\Core\AuthorizationAuthorizationCheckerInterface whose the $attribute argument is of type mixed.

The problem arises when you have voters extending the abstract class Voter positioned before a vote with an attribute of a type other than string.

Apart from Voters created by third parties, there is the voter ExpressionVoter which waits in attribute, an instance of the class Symfony\Component\ExpressionLanguage\Expression (you can see the doc for an example). Just add a voter extending the abstract class Voter with a higher priority than the voter ExpressionVoter to get the error:

Argument 1 passed to FooVoter::supports() must be of the type string, object given

To avoid removing the type of the $attribute argument from the method Symfony\Component\Security\Core\Authorization\Voter\Voter::supports(string $attribute, $subject), which can break the backward compatibility, you just have to test in the vote() method if the attribute is not a string and continue before calling the supports() method.

@GrahamCampbell
Copy link
Contributor

* @param array $attributes An array of attributes associated with the method being invoked

Should this doc be changed to string[] in Symfony 6?

@francoispluchino
Copy link
Contributor Author

francoispluchino commented Jun 18, 2020

As I said, if we force typing on a string[], we will break the backward compatibility of some voters including the voter Symfony\Component\Security\Core\Authorization\Voter\ExpressionVoter that wait for an instance of the class Symfony\Component\ExpressionLanguage\Expression.

Only the helper Voter has this problem, because it is the only voter who expects a string to validate its use in the supports method. Either the supports method returns false if $attribute is not a string, either you must do the verification just before calling the supports method.

@derrabus
Copy link
Member

This change should be covered by a test. Also, your change might break some (probably rare) scenarios that would work right now:

  • $attribute could be a stringable object.
  • A voter could have removed the string type declaration from the supports() method signature.

@francoispluchino
Copy link
Contributor Author

@derrabus

Of course, I'm going to add a test :-)

$attribute could be a stringable object.

Indeed, we can very well have a stringable object, however, as has never been indicated in the documentation or the phpdoc, some voters are therefore not stringable.

A voter could have removed the string type declaration from the supports() method signature.

It was my first intention, however, we will break the Backward Compatibility if some voters override the supports() method.. It is for this reason that I preferred to opt for a 'pre-test' of verification of the attribute.

@derrabus
Copy link
Member

Indeed, we can very well have a stringable object, however, as has never been indicated in the documentation or the phpdoc, some voters are therefore not stringable.

All voters that extend the abstract Voter class are. You are breaking that case: https://3v4l.org/2N1Hp

we will break the Backward Compatibility if some voters override the supports() method.

I'm not suggesting to change the supports() method. This is the case you might break: https://3v4l.org/MrcDq

@francoispluchino
Copy link
Contributor Author

Not all tests are passed in php 7.3, but these are tests for the Cache component. There was no error in the previous commit of this PR, so maybe just restart the tests for php 7.3 will remove the error Error: Call to undefined method Doctrine\DBAL\Driver\PDOSqlite\Driver::getName() (problem with a dependency version of Doctrine DBAL?).

@francoispluchino
Copy link
Contributor Author

francoispluchino commented Jun 18, 2020

@derrabus We do indeed agree on the 2 points. However, send a non-stringable attribute to a voter extending the abstract class `Voter', and you will get the error:

Argument 1 passed to FooVoter::supports() must be of the type string, object given

Given that the AccessDecisionManager and the AuthorizationChecker classes accept attributes of any type (mixed), the problem with the attributes not stringable (see the test in this PR).

@GrahamCampbell
Copy link
Contributor

As I said, if we force typing on a string[], we will break the backward compatibility

I know, This is why I said v6.

@derrabus
Copy link
Member

However, send a non-stringable attribute to a voter extending the abstract class `Voter', and you will get the error:

Not necessarily, please see the second 3v4l link I posted.

@francoispluchino
Copy link
Contributor Author

Why limit arbitrarily the type to an array of strings? It is only the aid class to build the Voter that has become blocking.

In addition, if we just change the phpdoc to string[] for the $attributes argument of Symfony\Component\Security\Core\Authorization\Voter\VoterInterface::vote(), we will also need to change the phpdoc for Symfony/Component/Security/Core/Authorization/AuthorizationCheckerInterface::isGranted() and Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface::decide().

The principle of the supports() method is precisely to validate if the subject and attributes are supported by the voter.

@francoispluchino
Copy link
Contributor Author

Not necessarily, please see the second 3v4l link I posted.

Remove my modification in the class Voter and run the test of this PR, and you get the error.

@derrabus
Copy link
Member

Not necessarily, please see the second 3v4l link I posted.

Remove my modification in the class Voter and run the test of this PR, and you get the error.

Again, please see the second 3v4l link I posted above. It shows you a voter that passes.

@francoispluchino
Copy link
Contributor Author

Sorry, but I will repeat myself :-), but the test passes with my modification, but without my modification you get:

1) Symfony\Component\Security\Core\Tests\Authorization\Voter\VoterTest::testVote with data set #9 (array(stdClass Object ()), 0, stdClass Object (), 'AC
CESS_ABSTAIN if attributes ...trings')
TypeError: Argument 1 passed to Symfony\Component\Security\Core\Tests\Authorization\Voter\VoterTest_Voter::supports() must be of the type string, object
 given, called in E:\Git\php\symfony\symfony\src\Symfony\Component\Security\Core\Authorization\Voter\Voter.php on line 33

E:\Git\php\symfony\symfony\src\Symfony\Component\Security\Core\Tests\Authorization\Voter\VoterTest.php:70
E:\Git\php\symfony\symfony\src\Symfony\Component\Security\Core\Authorization\Voter\Voter.php:33
E:\Git\php\symfony\symfony\src\Symfony\Component\Security\Core\Tests\Authorization\Voter\VoterTest.php:59

@derrabus
Copy link
Member

All right, I give up. 🤷🏻‍♂️

@ro0NL
Copy link
Contributor

ro0NL commented Jun 18, 2020

@francoispluchino try a testcase with a custom voter that removes the string type here;

protected function supports(string $attribute, $object): bool

we could simply remove the string types in core:

abstract protected function supports(string $attribute, $subject);
/**
* Perform a single access check operation on a given attribute, subject and token.
* It is safe to assume that $attribute and $subject already passed the "supports()" method check.
*
* @param mixed $subject
*
* @return bool
*/
abstract protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token);
as this contradicts with the actual type of $attributes (array, not string[]).

@francoispluchino
Copy link
Contributor Author

Yes, I had misunderstood the meaning of your answer, I am in the process of making the modification for this case.

@francoispluchino
Copy link
Contributor Author

@ro0NL If we delete the type string, we break the voters implementing the method supports(string $attribute, $subject) :

PHP Fatal error:  Declaration of Symfony\Component\Security\Core\Tests\Authorization\Voter\VoterTest_Voter::supports(string $attribute, $object): bool m
ust be compatible with Symfony\Component\Security\Core\Authorization\Voter\Voter::supports($attribute, $subject) in E:\Git\php\symfony\symfony\src\Symfo
ny\Component\Security\Core\Tests\Authorization\Voter\VoterTest.php on line 72

@ro0NL
Copy link
Contributor

ro0NL commented Jun 18, 2020

Ah true. We could reflect e.g. $attributeMustBeString, or just catch the type error.

@francoispluchino
Copy link
Contributor Author

I just added the test concerning the use case of attributes with a type object but stringable (in rapport with this comment).

@francoispluchino
Copy link
Contributor Author

@derrabus

Not necessarily, please see the second 3v4l link I posted.

As I point out to @ro0NL, your example can break compatibility with Voters implementing the new signature (see this comment).

However, thank you for your example concerning the fact that a stringable object can no longer be validated by a Voter when it was the case before my PR. I just add this use case.

@ro0NL
Copy link
Contributor

ro0NL commented Jun 18, 2020

There's still the second case: https://3v4l.org/MrcDq, where attributes are just objects (non stringable), or maybe someone uses ints. array $attributes implies mixed $attribute. It can be anything, depending on the voter removing the typehint yes/no.

@francoispluchino
Copy link
Contributor Author

@ro0NL Yes, but in this case, the Voter cannot extend the abstract class Voter, and so, the problem does not exist. Precisely the error arrives when you want to validate an attribute with object type which is not stringable, and that a Voter extend the abstract class Voter. When this Voter tries to check out if the attribute is supported or not, the error occurs just before because the object cannot be converted to a string with the auto convertion by the type of the $attribute argument in the supports() method.

@ro0NL
Copy link
Contributor

ro0NL commented Jun 18, 2020

Im not sure i follow now 😕

https://3v4l.org/MrcDq bool(true)
with your patch https://3v4l.org/1Ef7n bool(false)

@francoispluchino
Copy link
Contributor Author

I don't think it is advisable to remove the typing from the method Voter::supports() and to update the phpdoc to indicate that the $attribute argument is now of type mixed. As indicated, we risk breaking compatibility with the classes being the new signature of Voter::supports(). It is a helper class, it should keep for the majority cases, namely the use of a string for the attribute. Personally, I have no preference as to whether or not to keep strong typing on the method Voter::supports(), but I would like to know the opinion of each as well as the Core team, if possible.

@francoispluchino
Copy link
Contributor Author

francoispluchino commented Jun 18, 2020

Im not sure i follow now 😕

https://3v4l.org/MrcDq bool(true)
with your patch https://3v4l.org/1Ef7n bool(false)

You remove the type of the $attribute argument on the supports method. See my previous comment.

Note: However, your example is still valid, but if we remove the type in the abstract class, an error is thrown if the Voter use the new signature. It is for this reason that I chose to do a test before calling the method supports().

@derrabus
Copy link
Member

derrabus commented Jun 18, 2020

if we remove the type in the abstract class

We cannot do this and nobody suggested to do this.

Yet, the type can be removed by userland code when implementing the voter. That is a valid thing to do in php and that is all that my second example shows. And since the type declaration wasn't there in Symfony 2/3/4, there are probably quite a few voter implementations out there that do not have the type declaration.

Expecting an object (or anything but a string) at this point might not be an execution path that was intended, but it's one that currently works and that will be broken by the change you're suggesting. But I don't really know how to deal with it. It might even be okay to break it.

@francoispluchino
Copy link
Contributor Author

Yes, I was looking for a solution when we delete the type. However, I don't see how to check whether the typing is present or not on the instantiated class.

@francoispluchino
Copy link
Contributor Author

The problem arises when we want to call the method isGranted() with an attribute which is an instance of a non-stringable object, and it passes in all voters including voters extending the abstract class Voter.

@derrabus
Copy link
Member

However, I don't see how to check whether the typing is present or not on the instantiated class.

You you catch and parse the TypeError though. But we probably want to avoid that kind of dark magic if we can. 😎

@francoispluchino
Copy link
Contributor Author

It's not a problem to add the méthode __toString() on the class that is used for the attribute argument when it is own code, but it's a problem with third-party libraries. Givent that the method isGranted() accepts attributes with a type mixed, we cannot just say that it is enough to break compatibility for the Symfony 5.x, alas.

You you catch and parse the TypeError though. But we probably want to avoid that kind of dark magic if we can. 😎

Totally agree with you, but I don't see any other more elegant solution.

@francoispluchino
Copy link
Contributor Author

I just modified the PR to use a try/catch for the TypeError, and added tests for the attributes of type object stringable and integer (so that removes the type of the $attribute argument in the final class).

@wouterj
Copy link
Member

wouterj commented Jun 18, 2020

Apart from ExpressionVoter, are there other bundles/projects using non-string attributes? I recently had a (private) talk about ExpressionVoter and I'm convinced it's not necessarily correct, so we can/should change it. If there are no good use-cases for non-string attributes, I think it's good to consider deprecating non-string attributes.

@jvasseur
Copy link
Contributor

@wouterj how would you implement the ExpressionVoter without allowing non-string attributes ?

I'm all in favor of restricting what we can use as attributes but I'm not sure it's a reasonable move.

Another thing to take into account is that PHP will probably add support for enums at some points and people will want to use enums as attributes.

@wouterj
Copy link
Member

wouterj commented Jun 18, 2020

Let's not take PHP enums into consideration. First of all, it'll take a while before it will be added (it's already discussed for many years). Secondly, as everyone is now migrating to strict typed code bases, they will need to provide compatibility with current day strict typing for enums (e.g. an enum of strings should be able to be passed to a string type check).

About ExpressionVoter: I don't think it should be a voter. The only use-case is in access_control. In other cases, it's much better to just write plain PHP logic instead of using the expression language. Anyways, let's not hijack this ticket with proposed changes in something else - I'll create a PR once I have some time to work on it.

@derrabus
Copy link
Member

Another thing to take into account is that PHP will probably add support for enums at some points and people will want to use enums as attributes.

That's a change we can hardly anticipate right now, can we? There are however libraries like myclabs/php-enum that emulate enums in php. They should work already because the enum instances are stringable.

@francoispluchino
Copy link
Contributor Author

@wouterj. I aggree with you, but for the moment, it is necessary to fix the bug, and depreciate or not for version 5.2 and prohibit the use of a non-string attribute in version 6.0, if we decide to take this direction.

Personally I have a use case which led me to do it like voting ExpressionVoter when I used a string attribute before.

Example 1:

In my case, I use several voters including one which allows to validate permissions according to the subject. This subject can very well be a string (name of the class), an instance of a class, or an instance of a FieldVote class containing the name of the field and the instance or name of the class. In any case, we do have an authorization attribute and a subject.

In attribute, I used a permission name in the same style as the RoleVoter, namely, the role name in uppercase prefixed with ROLE_. This scenario is "natural" because the name of the role has always been formed with the ROLE_ prefix. However, for my PermissionVoter, I must indicate the name of the permission as an attribute. This gave for theupdate and edit permissions:

// Check the authorization on the object
$authorizationChecker->isGranted('perm_update', $entity);
$authorizationChecker->isGranted('perm_update', PostInterface::class);

// Check the authorization on the field of object
$authorizationChecker->isGranted('perm_edit', new FieldVote($entity, 'title'));
$authorizationChecker->isGranted('perm_edit', new FieldVote(PostInterface::class, 'title'));

As you can see, it is not "natural" for a user to have to do magic by prefixing the name of the permission with: permission_, perm_, permission:, perm:, PERMISSION_, PERM_, PERMISSION:, PERM:, permission/, permission@, etc... or any other symbol to separate.

Of course, I could use an array of the style ['permission', 'update'] or any other style, but you see the problem, it's easy to make a mistake. Also, using simply the permission name as an attribute can behave unexpectedly with other Voters.

Using the example below is much more meaningful and logical, while being certain of the expected behavior:

// Check the authorization on the object
$authorizationChecker->isGranted(new PermissionVote('update'), $entity);
$authorizationChecker->isGranted(new PermissionVote('update'), PostInterface::class);

// Check the authorization on the field of object
$authorizationChecker->isGranted(new PermissionVote('edit'), new FieldVote($entity, 'title'));
$authorizationChecker->isGranted(new PermissionVote('edit'), new FieldVote(PostInterface::class, 'title'));

You can see the old version of the component using the prefix perm_ as attribute in this bundle (the new version is not yet open source).

The fact of define the permission in the attribute and leaving the subject to the $subject attribute that we want to validate, goes according to the logic initially planned by the Security component. However, we could have put an attribute of type string like for example permission and created a configurable object to include the name of the permission and the subject. But you find that it becomes an unintuitive hack by doing in this way, while not making it easier to use.

Of course, it is possible to make the class PermissionVote stringable, which I just did to avoid the error with the current version of Symfony, but this is a workaround compared to the current documentation of the method AuthorizationChecker::isGranted().

Example 2:

There is also another reason to use something other than an attribute string. This time, it's with a component validating Oauth2 scopes. The Voter waits in attribute for an instance of the class ScopeVoter which can be configurable, and no subject, because subject, is always the authenticated user.

The class ScopeVote can have a string or a list of string in its constructor which are the required Oauth2 scopes. It also has an option to validate if at least one scope is in the list or if all scopes are required for the subject tested.

You will therefore understand that there is still a possibility of unexpected behavior if we put in attribute, only the name of the scope without prefix like scope_, and it would also not be logical to put the "configuration" of the check with the subject tested in the $subject argument, that would be contrary to the original logic.

// Check if the current user is authorized to read a Post with a his Oauth2 scopes
$authorizationChecker->isGranted(new ScopeVote(['post', 'post.readonly'], false));
// Check if the current user is authorized to manage a Post with a his Oauth2 scopes
$authorizationChecker->isGranted(new ScopeVote('post'));

Note:

  • post scope is to manage the Post entity (read, create, update, delete, etc)
  • post.readonly scope is to read only Post
  • The second argument of the ScopeVote class is to check if all the scopes listed are required, by default, this value is true

Another problem if we use a string instead of an instance of an object, it is likely easier that another Voter can validate the attribute and the subject when it was not intended for him. With an object, we can be certain that we reach the correct Voter which checks if the instance of the attribute is compatible, while making the code more readable and understandable. And as I said, put a permission string in attribute (or scope string in attribute), and in subject, an instance for the configuration and the subject does not correspond to the initial logic of the component. And using an array for the attribute will make the code more difficult to understand, in contrast to the class.

For example, it is more complicated to have:

$authorizationChecker->isGranted('permission', new PermissionVote('edit', new FieldVote(PostInterface::class, 'title')));
$authorizationChecker->isGranted('scope', new ScopeVote('post'));

that:

$authorizationChecker->isGranted(new PermissionVote('edit'), new FieldVote(PostInterface::class, 'title'));
$authorizationChecker->isGranted(new ScopeVote('post'));

Regarding strict typing, I agree with you, and it is also for this reason that I used classes as an attribute, knowing that the documentation of Symfony authorized it. Of course, we can very well decide to deprecate the use of non-string attribute, but I think it would be more appropriate to allow at least stringable objects.

This comment is very long, and I hope I have been understandable enough with my English and the wish to be as brief as possible, but it is ultimately quite difficult :-).

@wouterj
Copy link
Member

wouterj commented Jun 18, 2020

@wouterj. I aggree with you, but for the moment, it is necessary to fix the bug, and depreciate or not for version 5.2 and prohibit the use of a non-string attribute in version 6.0, if we decide to take this direction.

Yes, agreed. But I think the bug can be fixed a bit more "hacky" if we know we can clean it up in 6.0 :)

Thanks for your interesting insights! I need some time to process all the information - I'll follow-up with an RFC issue. Let's finish this bug report - as I agree that a bug has been introduced.

continue;
}
} catch (\TypeError $e) {
if (preg_match((sprintf('/Argument 1 passed to ([\w\\\]+)::supports\(\) must be of the type string, (\w+) given/')), $e->getMessage())) {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if (preg_match((sprintf('/Argument 1 passed to ([\w\\\]+)::supports\(\) must be of the type string, (\w+) given/')), $e->getMessage())) {
if (0 === strpos($e->getMessage(), 'Argument 1 passed to') && false !== strpos($e->getMessage(), '::supports() must be of the type string')) {

Strpos seems to be about 50% quicker: https://3v4l.org/47iXF

This method is potentially called quite a lot (for every voter in access_control and all isGranted calls), so it's performance critical, so I think it's worth considering.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed, this is to be considered. Your test is less strict but it is probably sufficient, but above all faster. I make the modification.

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 is done.

Copy link
Member

Choose a reason for hiding this comment

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

@wouterj Please keep in mind that the error message format changes with php 8. The error message does not begin with Argument anymore, but with the method name, IIRC.

Copy link
Member

@wouterj wouterj Jun 18, 2020

Choose a reason for hiding this comment

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

Travis agrees:

TypeError: Symfony\Component\Security\Core\Tests\Authorization\Voter\VoterTest_Voter::supports(): Argument #1 ($attribute) must be of type string, stdClass given, called in /home/travis/build/symfony/symfony/src/Symfony/Component/Security/Core/Authorization/Voter/Voter.php on line 34

So it probably should do something like:

if (\PHP_VERSION_ID < 80000) {
    if (0 === strpos($e->getMessage(), 'Argument 1 passed to') && false !== strpos($e->getMessage(), '::supports() must be of the type string')) {
        continue;
    }
} else if (false !== strpos($e->getMessage(), 'supports(): Argument #1')) {
    continue;
}

throw $e;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@wouterj Thank you, I didn't have PHP 8 on hand right now. I take your code.

Copy link
Member

Choose a reason for hiding this comment

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

I think almost nobody has. Fortunately, the Symfony test suite runs on PHP 8. You can find its results in the "Travis" link below. The relevant failure is https://travis-ci.org/github/symfony/symfony/jobs/699831814#L4276 (you can ignore the other failures, lots of things are work-in-progress for PHP 8/external dependency support).

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 is done.

Copy link
Member

@wouterj wouterj left a comment

Choose a reason for hiding this comment

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

Thanks for your very quick responses! Looks good to me now (looks like all test failures are unrelated)

@fabpot fabpot changed the base branch from master to 5.0 June 25, 2020 09:01
@fabpot
Copy link
Member

fabpot commented Jun 25, 2020

Thank you @francoispluchino.

@fabpot fabpot closed this Jun 25, 2020
fabpot added a commit that referenced this pull request Jun 25, 2020
…ter (francoispluchino)

This PR was submitted for the master branch but it was merged into the 5.0 branch instead.

Discussion
----------

Fix the supports() method argument type of the security voter

| Q             | A
| ------------- | ---
| Branch?       | 5.0 and 5.1
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | ~
| License       | MIT
| Doc PR        | ~

Since adding types to method arguments in the version 5.0 (and therefore also 5.1), there is a type mismatch on the first argument of the `supports()` method of the abstract class `Symfony\Component\Security\Core\Authorization\Voter\Voter`.

Indeed, the `supports()` method had in previous versions (4.x), the phpdoc indicating that the argument `$attribute` must be a `string`, but this one is not compatible with the `isGranted()` method of the interface `Symfony\Component\Security\Core\AuthorizationAuthorizationCheckerInterface` whose the `$attribute` argument is of type `mixed`.

The problem arises when you have voters extending the abstract class `Voter` positioned before a vote with an attribute of a type other than `string`.

Apart from Voters created by third parties, there is the voter `ExpressionVoter` which waits in attribute, an instance of the class `Symfony\Component\ExpressionLanguage\Expression` (you can see the [doc](https://symfony.com/doc/current/security/expressions.html) for an example). Just add a voter extending the abstract class `Voter` with a higher priority than the voter `ExpressionVoter` to get the error:

```
Argument 1 passed to FooVoter::supports() must be of the type string, object given
```

To avoid removing the type of the `$attribute` argument from the method `Symfony\Component\Security\Core\Authorization\Voter\Voter::supports(string $attribute, $subject)`, which can break the backward compatibility, you just have to test in the `vote()` method if the attribute is not a `string` and continue before calling the `supports()` method.

Commits
-------

b8192ee Fix the 'supports' method argument type of the security voter
This was referenced Jul 24, 2020
@Warxcell
Copy link
Contributor

Warxcell commented Feb 2, 2023

This is very confusing, and still NOT fixed in Symfony 6.0 - the type there is STILL string, but isGranted still accepts mixed

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.

10 participants