Skip to content

Removing the session migration on SimplePreAuthenticationListener #27427

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

Conversation

weaverryan
Copy link
Member

Q A
Branch? 2.8 (because 2.7 is now EOL)
Bug fix? yes
New feature? no
BC breaks? no
Deprecations? no->
Tests pass? yes
Fixed tickets Part of #27395
License MIT
Doc PR n/a

This partially reverts the session migration patches applied recently. Here are the details:

  1. Contao has a legacy security system. In this system they have a SimplePreAuthenticator that creates aContaoToken on every request:

https://github.com/contao/core-bundle/blob/504d8ed7c14a8e135def5722e47ffa1dc7c4d6ed/src/Security/ContaoAuthenticator.php#L88

  1. When that token (ContaoToken) is instantiated, it actually does a legacy, cookie-based authentication where a cookie is set by using the session id as a hash.

  2. But, then, because the ContaoAuthenticator returns the ContaoToken, the session is migrated, which effectively invalidates the cookie set by their legacy auth system (because the hash for the cookie uses the session id).

This is a legacy system that does some crazy stuff (their WIP newer version apparently already makes a lot of nice changes), but the point is that the patch causes side effects. We decided to migrate the session in SimplePreAuthenticationListener just to be extra safe: this authentication mechanism is not meant to be used with session-based authentication.

The downside of this revert is that, it makes session fixation a possibility with SimplePreAuthenticationListener. But, I believe this would only be possible if someone creates a "SimplePreAuthenticator" in order to make a traditional, session-based authentication system - e.g. a login form.

This authentication mechanism should not be used for session-based
authentication. Migrating the session caused some regressions in legacy
authentication systems.
@fabpot
Copy link
Member

fabpot commented May 31, 2018

At least, I would add a comment about the session fixation issue when used incorrectly.

@fabpot
Copy link
Member

fabpot commented May 31, 2018

Don't we need to do the same in AbstractPreAuthenticatedListener then?

@weaverryan
Copy link
Member Author

After some thought, there is a generic issue/incompatibility across all security listeners. Here it is:

If you create an auth mechanism that you expect will be used by a browser, then your auth mechanism must be smart enough to not re-authenticate the user when they are already authenticated

This is at the root of any bugs that were caused by the new behavior change. Here's a real-world example of the bad behavior. Suppose you have a Guard authenticator that authenticates entirely by IP address (i.e. look up the User in the database by their IP) & this is an app meant to be used by browsers. If the authenticator performs this authenticate on every request, then the session will be migrated on every request. But, this SHOULD happen. If we did not do this, that auth mechanism is susceptible to session fixation. The fix is to check if the user is already authenticated (via the session) in the authenticator and skip authentication in those cases.

So, I actually now think this is an annoying documentation issue: we must make sure that auth mechanisms intended for browser use do not re-auth on every request. I'm going to create a docs PR right now.

@weaverryan
Copy link
Member Author

See symfony/symfony-docs#9860 for the 2.8 version with Guard.

I believe that we should not merge this PR - that it's entirely a documentation issue.

@fabpot
Copy link
Member

fabpot commented May 31, 2018

Closing then

@fabpot fabpot closed this May 31, 2018
@aschempp
Copy link
Contributor

I think there is a generic misinterpretation. As the HTTP protocol is entirely stateless, a user is always authenticated on every request. In the Symfony firewall this can be any listener, the ContextListener (the one loading a token from session) is just another listener that attempts authentication.

The fix is to check if the user is already authenticated (via the session) in the authenticator and skip authentication in those cases.

Just because a session does exist, does not mean the user is authenticated through it. There can be plenty of other sources. For example if using Shibboleth as SSO solution, the $_SERVER variables can contain your authentication information (e.g. using an Apache module). The user must be authenticated from there on ever request otherwise the user will continue to be authenticated after logging out of the SSO application.

To me, a stateless firewall cannot not handle session migration. This can only be done reliably if the firewall listener is stateful.

@aschempp
Copy link
Contributor

aschempp commented May 31, 2018

oh well, just ignore my comment, I didn't see #27395 (comment) 🙈

weaverryan added a commit to symfony/symfony-docs that referenced this pull request Jun 11, 2018
…averryan)

This PR was squashed before being merged into the 2.8 branch (closes #9860).

Discussion
----------

Avoiding authentication on every request with Guard

Hi guys!

See symfony/symfony#27395 and symfony/symfony#27427

When we're happy with this, I can merge and handle the changes on 3.4, because it will be almost entirely different (with `supports()`, autowiring & the `Security` class - booya for progress!)

Commits
-------

d2f062a Avoiding authentication on every request with Guard
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.

5 participants