Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Impersonation (Login as Someone Else)

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

Have you ever had a bug you couldn't reproduce? Nope, me either. Of course we have! The worst is when a user reports a bug in their account... which would be really easy to verify and debug... if only we could log and see what they're seeing.

Look, we've got too much work to do to debug this the hard way. We need to be able switch to that user's account: we need to impersonate them.

Activating switch_user

Setting up impersonation is super easy. In security.yml, under your firewall, add a new key called switch_user set to ~ to activate the system:

... lines 1 - 2
security:
... lines 4 - 14
firewalls:
... lines 16 - 20
main:
... lines 22 - 28
switch_user: ~
... lines 30 - 40

Back to the User Provider

Now, on any URL, you can add ?_switch_user= and then the username of whoever you want to log in as. In our case, we want to login as weaverryan+5@gmail.com. Why is that the email address in our case? This actually goes back to your user provider.

We're using the built-in entity user provider, and we told it that we want to identify by the email. Before now, this setting was meaningless. If we changed that to some other field, then we would actually identify ourselves by that up in the URL.

Not Everyone Can Impersonate!

Hit enter to try switching users. OMG - access denied!

That makes sense - we can't just let anybody do this impersonation trick. Internally, this feature checks for a very specific role called ROLE_ALLOWED_TO_SWITCH. But, we don't have that.

Hey, no problem! Let's give this role to ROLE_ADMIN under role_hierarchy:

... lines 1 - 2
security:
... lines 4 - 6
role_hierarchy:
ROLE_ADMIN: [ROLE_MANAGE_GENUS, ROLE_ALLOWED_TO_SWITCH]
... lines 9 - 40

Cool! Try it out. It works! I mean, it doesn't work! Hmm, but it's not that security error anymore - it just can't find the user: weaverryan 5@gmail.com You know what? This is the because of the + sign in the email addresses - which represents a space in URLs. Change that to the url-encoded plus sign: %2B.

Boom! Now we're surfing as weaverryan+5@gmail.com. Pretty awesome. Once you're done, go back by adding ?_switch_user=_exit to any URL. That's it! We're back as our original user.

Switching users... yea, it's my favorite.

Leave a comment!

9
Login or Register to join the conversation
Benoit L. Avatar
Benoit L. Avatar Benoit L. | posted 3 years ago

Hi,I have on problem with impersonating, eg as an admin I have a page listing the users, with link to log in as, that's good, I login as the users, but I have the possibility to navigate back to previous page, then I can see all the users ! but when I click on a link that only admin has access to, I get the forbidden message. The admin is not dev, so has no clue to solve the issue, what can I do about that?

Reply

Hey Benoit L.!

I think I've gotten this question before... a LONG time ago... and basically the answer is: you can't avoid this... (good news!) you shouldn't try! The behavior you're seeing has nothing to do with Symfony: it's simply how the "Back" button in browsers work. So, to avoid this, what you would *really* be trying to do is disable the back button. And that (I believe) is not something that's really possible. I think the only solution would be to add some JavaScript to the admin page that, on "page load", sends an AJAX request to see if the user is still logged in. And if they are not, redirect elsewhere.

So, the good news is that this is not a Symfony-specific thing - it's just "how the Internet works". Another solution could be to open a new tab when you log in as the other user. Then, that tab would have no history and you couldn't click to go back.

Cheers!

Reply
Benoit L. Avatar

Hi Good to know that it has nothing to do with Symfony ! thanks

Reply
Default user avatar
Default user avatar Daniel Hauck | posted 5 years ago | edited

Hey Ryan,

awesome Tutorial!

For example in Jira I also have the option to log in as different users, There I have the "switch back" option.

I tried to implement the same here and found, that I got one extra role available, if I switch the user, which is the 'ROLE_PREVIOUS_ADMIN' role.

Is it the right way, to determine, if I impersonated someone?

Here is the code I used, to check in the twig template:


                {% if is_granted('ROLE_PREVIOUS_ADMIN') %}
                <li>&lt;a class="btn btn-danger" href="{{
                    path(app.request.attributes.get('_route'),
                    app.request.attributes.get('_route_params'))
                    }}?_switch_user=_exit">
                        STOP IMPERSONTATION
                    </a>
                </li>
                {% endif %}

And maybe, there is a shortcut, to get the current path out of twig ;)

thanks for the awesome tutorial!

Reply

Hey Daniel,

Yes, the ROLE_PREVIOUS_ADMIN is the Symfony way to do it! What about shortcut - I don't know any shorter than that. But probably you can create special route which always will redirect back based on HTTP referer: $request->headers->get('referer').

Cheers!

Reply
Nizar Avatar

Hello Victor
I associated acl with masks (MASK EDIT, MASK VIEW, ....) to an entity according to a role for example: ROLE_SUPER_ADMIN.
I would like to retrieve them to modify them using a form which contains permissions ie masks like (MASK_VIEW, ..)
Thanks for your help

Reply

Hey Nizar

Have you consider using the voter's system? https://symfony.com/doc/cur...
or you can check our video about it: https://knpuniversity.com/s...

Reply

But what happens when, for instance, you have ROLE_ADMIN and ROLE_SUPER_ADMIN both with the ROLE_ALLOWED_TO_SWITCH. How can you prevent an ADMIN impersonating a SUPER ADMIN?

Reply

Hey Piter,

Well, do not give an ADMIN the ROLE_ALLOWED_TO_SWITCH role? probably the simplest one :) But yeah, good question. I have never tried to do this, but looks like it's possible to do by overriding the default SwitchUserListener, see this answer in StackOverflow: https://stackoverflow.com/a... . With this way you have a full control with any crazy custom logic.

Cheers!

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=5.5.9",
        "symfony/symfony": "3.1.*", // v3.1.4
        "doctrine/orm": "^2.5", // v2.7.2
        "doctrine/doctrine-bundle": "^1.6", // 1.6.4
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.0
        "symfony/swiftmailer-bundle": "^2.3", // v2.3.11
        "symfony/monolog-bundle": "^2.8", // 2.11.1
        "symfony/polyfill-apcu": "^1.0", // v1.2.0
        "sensio/distribution-bundle": "^5.0", // v5.0.22
        "sensio/framework-extra-bundle": "^3.0.2", // v3.0.16
        "incenteev/composer-parameter-handler": "^2.0", // v2.1.2
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "knplabs/knp-markdown-bundle": "^1.4", // 1.4.2
        "doctrine/doctrine-migrations-bundle": "^1.1" // 1.1.1
    },
    "require-dev": {
        "sensio/generator-bundle": "^3.0", // v3.0.7
        "symfony/phpunit-bridge": "^3.0", // v3.1.3
        "nelmio/alice": "^2.1", // 2.1.4
        "doctrine/doctrine-fixtures-bundle": "^2.3" // 2.3.0
    }
}
userVoice