-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
SwitchUserRole gets lost while reloading user #3085
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
Comments
Could you write a bit more about the context and setup, so I can try to recreate the bug (and try to fix it)? |
Given user entity: <?php
use FOS\UserBundle\Entity\User as BaseUser;
use Symfony\Component\Security\Core\User\EquatableInterface;
use Symfony\Component\Security\Core\User\UserInterface;
class MyUser extends BaseUser implements EquatableInterface, UserInterface {
public function isEqualTo(UserInterface $user) {
return false;
}
} User A is granted role |
@craue if the method always return false, the token will never be considered as authenticated (as the user is considered as having changed since last login) and so will require logging in again before accessing a restricted area |
@stof: I know. ;) That just serves as an example. Even though, the |
The actual use case is this: User A switches into B, who then performs actions to gain a new role, which requires the user to be reloaded. But he still needs to be able to switch back to A at a later time. Or am I just missing something here? |
@schmittjoh: Do you have any idea on how to solve this maybe? |
@schmittjoh ping |
Any news on the subject ? |
@craue What does your code look like for gaining a new role? I don't think this is a bug btw, but rather a missing feature? |
I had the same issue and it has to do with the way you serialize your user. I actually wrote a blog about it recently: http://12wiki.blogspot.nl/2012/09/symfony-2-and-case-of-missing.html |
@asm89: Let's just say that the new role is added in the DB directly. Now the user entity needs to be reloaded to gain the new role. But when doing this, the SwitchUserRole gets lost. @TheDevilOnLine: I tried your approach of modifying serialization of the user entity, but it doesn't solve the issue. |
@craue If you send me your user entity class, I'll take a look ;-) |
I found out what's wrong in my code. It's indeed about serialization. Thank you for the hint, @TheDevilOnLine. What pointed me to the solution is https://github.com/FriendsOfSymfony/FOSUserBundle/blob/6d1fe1bad7621e618a379aebc45b36e080e7eca8/Model/User.php#L152, although the comment itself seems to be outdated by the time I had some additional checks in the |
Maybe I was a bit too excited. 😒 SwitchUserRole still gets lost when adding if ($this->getRoles() != $user->getRoles()) {
return false;
} to |
Just an idea, but would it be a better approach to not save this special role in the user roles (which will be overwritten when reloading the user), but in a different session variable instead? Alternatively, this role has to be preserved while the user is reloaded. Any other ideas? /cc @schmittjoh |
I'm currently merging my system from Symfony 2.0 to Symfony 2.1(.6). Just wanted to confirm that under some conditions (which need to be found) ROLE_PREVIOUS_ADMIN is not saved into the impersionated user. |
Turns out I overlooked to use After implementing the EquatablerInterface, user impersionation now works. |
I could solve it by serializing the username (thanks @TheDevilOnLine!) But the documentation states that:
This should be corrected right? @craue do you really need to compare roles? According to EquatableInterface:
|
@frosas public function refreshUser(UserInterface $user)
{
$class = get_class($user);
if (!$this->supportsClass($class)) {
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', $class));
}
return $this->loadUserByUsername($user->getUsername());
} This is recently changed to: public function refreshUser(UserInterface $user)
{
$class = get_class($user);
if (!$this->supportsClass($class)) {
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', $class));
}
return $this->find($user->getId());
} |
@TheDevilOnLine where did you get this implementation from? All I've seen use |
@frosas I can relate to it being like that for the In-Memory users, as these don't have an id but do have a username! |
@TheDevilOnLine oh, you are right, sorry. But still |
Okay, after some digging I've found this:
So I would properly document how a user has to be serialized and compared both in documentation and code. What do you think? |
@frosas: Thank you for the hint about With some further testing, I eventually just removed the methods I can neither tell if I had it this way already nor if it worked as this issue is quite old now. But I can finally consider it as solved from my POV. |
I have to come back to this (again). The issue is still not solved. In my project, I can either
but not both. I've chosen to have the former working. |
👍 |
Just solved in few steps, thanks to previous comments:
|
The solution provided by @lucabartoli solution works 100%. If you're using email instead of username, your
and replace |
+1 for @lucabartoli |
@lucabartoli You, sir, are the man. I've spent countless hours trying to figure out this problem. I wish I would have stumbled on this thread sooner. |
Upon further inspection, I determined what my problem was. All of my User properties are private. Additionally, I'm implementing the AdvancedUserInterface, which requires the isEnabled() method that returns the property 'isActive'. Since this property is private in my User document, the expression below was evaluating to true because $this->user->isEnabled() was returning 'null', while $user->isEnabled() returned 'true'.
Because of this, the AbstractToken object determined the user changed on every request, which resulted in the need for the current token instance to be re-authenticated. My custom AuthenticationProvider would then authenticate the token, replacing the roles with new ones, eliminating the ROLE_PREVIOUS_ADMIN.
Simply adding 'isActive' to my Serializable methods in my User document resolved my issue.
Either serializing the 'isActive' property OR implementing @lucabartoli's solution worked for me. |
…le. (pawaclawczyk) This PR was squashed before being merged into the 2.3 branch (closes #8997). Discussion ---------- [Security] Fixed problem with losing ROLE_PREVIOUS_ADMIN role. <table> <tr> <td><b>Q</b></td> <td><b>A</b></td> </tr> <tr> <td>Bug fix?</td> <td>yes</td> </tr> <tr> <td>New feature</td> <td>no</td> </tr> <tr> <td>BC breaks?</td> <td>no</td> </tr> <tr> <td>Deprecations?</td> <td>no</td> </tr> <tr> <td>Tests pass?</td> <td>yes</td> </tr> <tr> <td>Fixed tickets</td> <td>#3085, #8974</td> </tr> <tr> <td>License</td> <td>MIT</td> </tr> <tr> <td>Doc PR</td> <td>n/a</td> </tr> </table> Problem occurs while user is impersonated. Authentication process generates new token and doeas not preserve role ```ROLE_PREVIOUS_ADMIN```. Ex. when parameter ```security.always_authenticate_before_granting``` is enabled. Commits ------- a7baa3b [Security] Fixed problem with losing ROLE_PREVIOUS_ADMIN role.
When, after switching to another user, the user is reloaded, the
SwitchUserRole
gets lost and it's not possible to switch back to the originating user.The text was updated successfully, but these errors were encountered: