Description
Symfony version(s) affected: 5.1
Description
With the new Security system (5.1+) enabled
We have some a specific use case in our app I couldn't find how to handle: Voter can not handle anymore authorization of anonymous/unconnected users.
Our use case in details:
- some objects in our application can be seen by everybody (including anonymous Users) or only some specific Users
- so those objects each have
isGranted(?User $user)
method - to handle that, a Voter is used, it will fetch token from Security and call object's
isGranted
with the User it eventually found, ornull
if there is no connected User, we are getting a InsufficientAuthenticationException
: "Full authentication is required to access this resource"
The exception is raised by Symfony\Component\Security\Core\Authorization\AuthorizationChecker:isGranted()
. It throws exception when there is no token. In the legacy system, an AnonymousToken
was present.
How to reproduce
- set
security.enable_authenticator_manager: true
- implement a Voter which allows anonymous Users
- configure any controller action with corresponding security attribute
- try to access it while unlogged
Possible Solution
Right now, I couldn't think of any work around in userland, as it happens in the authorization layer, outside of the authentication Guard we can configure.
Twig is working around it with a try... catch
- which is also creating an inconsistency, btw (#30609) - but it prevents Voters from being able to decide if an anonymous User can be granted or not (cf. line 55 of Symfony\Component\Security\Core\Authorization\AuthorizationChecker:isGranted()
- if there is no token, even if no exception is sent, all authorization checks are bypassed).
I have the impression a bypass over authentication/authorization separation - maybe something like AuthenticationVoter
? Of Voter::supportsAnonymous
?
AuthorizationManager
could then call these voters even if no token is present.
Edit: I found an ugly workaround, adding an AnonymousAuthenticator
called on every request, to re-add an AnonymousToken
through an AnoymousPassport
(internal class). It feels a little bit hacky to do that user-side, but it allows to keep BC:
https://gist.github.com/romaricdrigon/63f1d83ba7c516e6c6205b384c18376f
Additional context
RFC related to the same topic: #30609