Replies: 4 comments 2 replies
-
Hi, Another way of accomplishing that behaviour would be to remove $dispatcher->removeListener(KernelEvents::RESPONSE, [$contextListener, 'onKernelResponse']) This would require the contextListener to be manually wired in with an explicit definition in Hope it helps! |
Beta Was this translation helpful? Give feedback.
-
Looking at Symfony 6.3.4's changelog and seeing #51350, I hoped it would fix this issue... but it does not. The nasty hack is still needed. :( |
Beta Was this translation helpful? Give feedback.
-
I have the same use case where an API should accept both session based authentication and stateless token based authentication. Maybe a marker interface like if ($token instanceof StatelessToken) {
return;
} |
Beta Was this translation helpful? Give feedback.
-
Hi @gnutix Thank you for raising this issue. I'm curious if you have any suggestions on how to bypass the Context Listener in Symfony 3.4. I've observed that the Perhaps we could invalidate the session and adjust the priority of our new listener to -1?
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hello there! :)
I'm currently migrating our Guard security classes to Symfony 5.4's new Authenticators and am having trouble finding a proper way to do what I need. There are 2 ways (currently, more coming) to authenticate a user in the application :
json_login
, which should produce a stateful authentication (re-usable across multiple requests using the session and a cookie)And there are the following routes patterns :
/api/sign-in/*
: must be public, used for the login form/api/*
: must be secured, but some are restricted to requests having an Device Token, some can be access if you have a stateful authentication (cookie), and some can use either of both authentications/*
(any other route of the application) : must be secured, only using stateful authentication (cookie)And finally, only one
main
firewall (without any specific options likestateless
,pattern
,context
or else).PS : In
/api
, there are both Symfony routes and "legacy" routes (using mostly Slim, others plain PHP, routed through aLegacyController
- kind of like this, but not exactly..). Prior to this Guard => Authentication migration, the "Device Token" authentication was done solely in the legacy code (completely outside of Symfony's Security system), which means Symfony had no idea the user was authenticated on those routes (through the Device Token). Now that there is an Authenticator for it, Symfony knows.So looking at the doc, I thought : OK, let's create two firewalls, one stateless for the devices with
pattern: ^/api
and the other one stateful with the json_login auth withoutpattern
, and share the authentication using thecontext
option. Except...So I can't use
context
andstateless
simultaneously, which means when a user has logged in using the login form and has a stateful authentication, when he loads any page that does AJAX calls to/api/{whatever}
(without providing a Device Token), he won't be considered logged in as this route will match the stateless firewall and his stateful authentication won't be recognized...I know of one "proper solution", which would be to add a new Authenticator to the stateless
/api
firewall that would use a JWT token (or something similar) to say "hey, I'm user X", that the frontend would have to provide everytime it calls an/api
route. But that's a lot of efforts, as the frontend completely relies on the user's session's just "being there"... Same for functional tests.Currently, I've found a hack to make the Device Token authenticator "stateless" (even though the firewall is stateful) using a
kernel.response
event listener with priority1
(just beforeSymfony\Component\Security\Http\Firewall\ContextListener
at0
) that sets$event->getRequest()->attributes->set('_security_firewall_run', 'hacked');
only when the user has been successfully authenticated using the Device Token Authenticator.This way,
ContextListener::onKernelResponse()
is skipped (because it checks_security_firewall_run
against the firewall name at the very beginning and returns early if they don't match), which effectively prevents persisting the token in the session altogether, making it "stateless".I'm not really proud of this hack though... But I'm kind of stuck between a "short term gain" (one line of code fixes my problem : one stateless authenticator in a stateful environment) VS "long term gain" (having a new authenticator and adapt the frontend, which is probably weeks of work for both a backend and frontend team, with a cleaner API in the end).
Would you folks have any other suggestions ? Cleaner ways to prevent Symfony from setting the
Set-Cookie
header, or other ways to configure the firewalls ? Why is stateless tokens (instead of stateless firewalls) not a standard option from the Security component (knowing it "works" - in our use case at most - with one line of code) ?Thanks for your insights.
gnutix
Beta Was this translation helpful? Give feedback.
All reactions