Description
- A) When logged in, change the value returned by isEnabled() (whatever property it looks at in your User class) to 0 / false in the database and refresh page, it will log you out completely and take you back to the login page, change picked up in https://github.com/symfony/symfony/blob/2.7/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php#L279-L281 (your user entity implements
AdvancedUserInterface
) - B) When logged in, change the username or password behind the scenes and refresh page, In this case it will not log you out completely and it will not take you back to the login page. It will set you Authenticated to No in the profiler and as soon as you hit a page that requires a role, it will reload your roles and profiler will say "Authenticated: Yes" - no difference to an end user as they will always have the standard user role. If the subsequent request does not require a role, you will stay logged in while "Authenticated" will state "No" in the profiler.
- Some in-depth incosistencies there - it seems that the whole user re-loading and checking if the user has changed has no real effects except in case A when roles are required via security.yml or is_granted - both cases will be picked up in this block https://github.com/symfony/symfony/blob/2.7/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php#L244-L287 and xdebug will hit both in https://github.com/symfony/symfony/blob/2.7/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php#L111-L113
- Significant difference happens somewhere down the request pipeline causes case A to completely log out and redirect back to the login url after https://github.com/symfony/symfony/blob/2.7/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php#L111-L113
- Best way forward would be to create automated tests for this behaviour so it can be tested what happens when there are changes to the user between "requests" in both cases? The behaviour should be consistent. Great long term benefits for the core security aspect of symfony.
- There is a test that checks if authenticated is getting changed when the user changes https://github.com/symfony/symfony/blob/2.7/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php#L185-L196 - however the isAuthenticated returning false doesn't really do "much" as it will only cause a "reload" of roles if there is a call to isGranted (be it via annotation, template or direct on auth checker), in turn this means that reloading the user for checking if it has changed does not have any tangible benefits and only adds one hit to database/storage per request. Best would be to extend tests combined with tests that check for
IS_AUTHENTICATED_*
to check for cases A & B above - and check if the user is grantedIS_AUTHENTICATED_FULLY
in both cases, case A loses it, case B keeps it. I have not come across any tests that would mock the http context and allow to test between "mocked" requests, any samples?
Extra info for case A: the behaviour as described only happen if on the page there is a call in the template to is_granted, has the annotation @Security is_granted or requires a role via access_control in security.yml, or call isGranted in controller; something else I've spotted is that @Security has_role annotation will not log out the user but that is not the concern of this ticket (this observation might help though).
A call to is_granted helpers takes us to https://github.com/symfony/symfony/blob/2.7/src/Symfony/Component/Security/Core/Authorization/AuthorizationChecker.php#L68 which in turn ends up in https://github.com/symfony/symfony/blob/2.7/src/Symfony/Component/Security/Core/Authorization/AccessDecisionManager.php#L64
Symfony is great so just trying to keep its security great, too!
References:
#13870
symfony/symfony-docs#5419