8000 [Security] Allow AuthorizationChecker::isGrantedForUser to check for guest permissions by aschempp · Pull Request #61938 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

Conversation

@aschempp
Copy link
Contributor
@aschempp aschempp commented Oct 2, 2025
Q A
Branch? 7.4
Bug fix? no
New feature? yes
Deprecations? yes
Issues
License MIT

Unfortunately, the new User authorization checker added in #48142 (Symfony 7.3) does not allow to check for a guest (a token without a user). This PR should be seen as draft because the code is not backwards compatible. It feels wrong to add another isGrantedForGuest method – any idea about a BC way? The "usual" func_get_args wouldn't work here I think?

/cc @natewiebe13

@carsonbot

This comment has been minimized.

@aschempp aschempp marked this pull request as ready for review October 2, 2025 17:06
@aschempp aschempp requested a review from chalasr as a code owner October 2, 2025 17:06
@carsonbot carsonbot added this to the 7.4 milestone Oct 2, 2025
@carsonbot carsonbot changed the title Allow AuthorizationChecker::isGrantedForUser to check for guest permissions Allow AuthorizationChecker::isGrantedForUser to check for guest permissions Oct 2, 2025
@carsonbot carsonbot changed the title Allow AuthorizationChecker::isGrantedForUser to check for guest permissions [Security] Allow AuthorizationChecker::isGrantedForUser to check for guest permissions Oct 2, 2025
@nicolas-grekas
Copy link
Member
nicolas-grekas commented Oct 3, 2025

Indeed, I see no BC path to add the nullable type to the interface.
Maybe there's no need to change anything and you can pass a user with no roles instead?

@xabbuh
Copy link
Member
xabbuh commented Oct 3, 2025

We could introduce a class that decorates the existing one with a different signature and creates such an empty user when forwarding the call. Or maybe another helper in AbstractController doing this might also ease things?

@xabbuh
Copy link
Member
xabbuh commented Oct 3, 2025

Such a method could also be placed in the Security class in SecurityBundle.

@antonkomarev
Copy link

@aschempp there is one more possible option, to make Guest user a separate class, which implements Userinterface too. But it may require a lot of changes in legacy systems.

@chalasr
Copy link
Member
chalasr commented Oct 4, 2025

Given the purpose of this method and the fact that one aim of the now well-established authenticator system was to remove the concept of unauthenticated tokens (see e.g. #42050 and #42510), I don't think we should try to address this here, passing some kind of null user on the caller's side seems good enough.

@chalasr chalasr requested a review from wouterj October 4, 2025 11:58
@aschempp
Copy link
Contributor Author
aschempp commented Oct 8, 2025

passing some kind of null user on the caller's side seems good enough.

That would be perfectly fine with me. But shouldn't the security system then return such a null user in e.g. SecurityHelper::getUser() as well? Which certainly would be a BC break as well 😅

As an example of our current system (Contao CMS), we have permissions on objects that can be given to certain user groups, or to guests. Our voters then decides whether there is a user in the current system and which groups it belongs to, or if the object is allowed for guests. If there's a new NullUser concept, we'd need to adjust all voters to check for ->getUser() === null || $user instanceof NullUser which feels kinda wrong?

Btw. would you consider this a bug (to be fixed in 7.3 possibly) or a feature to check for guest users?

@aschempp
Copy link
Contributor Author
aschempp commented Oct 8, 2025

The most backward and forward compatible solution might be to create a new UserAndGuestAuthorizationCheckerInterface that accepts a null object. We could then deprecated the other interface …
Since most applications will probably use the core AuthorizationChecker, everyone could instantly use the new method instead of the deprecated old one.

Let me know if you like that idea, I can then update the PR (we can still decide on final naming later).

@aschempp aschempp changed the title [Security] Allow AuthorizationChecker::isGrantedForUser to check for guest permissions [WIP] [Security] Allow AuthorizationChecker::isGrantedForUser to check for guest permissions Oct 20, 2025
@aschempp aschempp changed the title [WIP] [Security] Allow AuthorizationChecker::isGrantedForUser to check for guest permissions [Security] Allow AuthorizationChecker::isGrantedForUser to check for guest permissions Oct 20, 2025
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.

how critical is it to have this in 7.4 vs 8.1?

@nicolas-grekas nicolas-grekas added the ❄️ Feature Freeze Important Pull Requests to finish before the next Symfony "feature freeze" label Oct 24, 2025
@aschempp
Copy link
Contributor Author

how critical is it to have this in 7.4 vs 8.1?

It would help me to have it in 7.4, but I can also make it work without. I don't see how waiting until 8.1 would solve any issue though, because we can't trigger a deprecation that we want to add an argument that isn't possible 😅


I think I found a neater solution. The implementation class (AuthorizationChecker) is allowed to widen the argument to null. So we could add a new interface for the same method like below: https://3v4l.org/XYqQb

interface UserAuthorizationCheckerInterface
{
    public function isGrantedForUser(UserInterface $user, mixed $attribute, mixed $subject = null, ?AccessDecision $accessDecision = null): bool;
}

interface UserGuestAuthorizationCheckerInterface
{
    public function isGrantedForUser(?UserInterface $user, mixed $attribute, mixed $subject = null, ?AccessDecision $accessDecision = null): bool;
}

class AuthorizationChecker implements UserAuthorizationCheckerInterface, UserGuestAuthorizationCheckerInterface
{
    final public function isGrantedForUser(?UserInterface $user, mixed $attribute, mixed $subject = null, ?AccessDecision $accessDecision = null): bool
    {
        // ...
    }
}

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.

don't forget adding autowiring aliases

*
* @author Nate Wiebe <nate@northern.co>
*
* @deprecated since Symfony 7.4, implement the UserGuestAuthorizationCheckerInterface instead.
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 have to deprecate? it might be better not to?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

you mean someone in Symfony 8.x might want to implement only checking for users but not for guests? I would think of the new interface as replacing the current one (because it allows both), but I'm fine with either way. Maybe we could also come up with something more generic than UserGuest... that would work as a better replacement in the future 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Autowiring alias added.

What do you think of OfflineAuthorizationCheckerInterface since we have an OfflineToken as well?

Copy link
Member

Choose a reason for hiding this comment

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

Dunno, others might have an opinion :) (please mind fabbot, it still has spotted a few things)

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.

This approach makes sense to me.

@aschempp
Copy link
Contributor Author

The failing 8.4 (high deps) test seems "normal", since the interface added in this PR is not available in the dependency when using 8.x-dev. Everything else seems fixed after a rebase. Let me know if someone has better ideas for the interface name, otherwise this is RTM for me 😊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature Security ❄️ Feature Freeze Important Pull Requests to finish before the next Symfony "feature freeze" Status: Reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

0