22

In an application built with Symfony2 we want superadmins to be able to impersonate other users. This is easily done by giving the superadmin user the ROLE_ALLOWED_TO_SWITCH role. The switching is implemented with a call to "somewhere?_switch_user=" as suggesed in the reference documentation.

The problem however, is to detect in a template if the current user is actually impersonated so as to print a link to "somewhere?_switch_user=_exit" on the page, thus enabling the impersonating user to return to her real user.

Mohammed H
  • 6,880
  • 16
  • 81
  • 127

5 Answers5

31

I haven't been using Symfony2 for a while so I'm not sure, but when you switch to another user you gain all roles assigned to that user and one extra role: ROLE_PREVIOUS_ADMIN. So I guess all you need to do is to use voter to check whether such a role is assigned to the current user using voter.

// Twig

{% if is_granted('ROLE_PREVIOUS_ADMIN') %}
    <a href="...?_switch_user=_exit">EXIT</a>
{% endif %}

// PHP

<?php if ($view['security']->isGranted('ROLE_PREVIOUS_ADMIN')): ?>
    <a href="...?_switch_user=_exit">EXIT</a>
<?php endif ?>
Crozin
  • 43,890
  • 13
  • 88
  • 135
  • 2
    Is there anyway to get the id of the impersonator? It would be useful for scenarios where the impersonator is making updates and we want the audit trail to recognize the original id of the impersonator. – anushr Oct 13 '11 at 12:08
  • @anushr: yes, use `?_switch_user=_exit` (it exists since [2.3](http://symfony.com/doc/2.3/cookbook/security/impersonating_user.html) at least). – A.L Dec 08 '15 at 16:45
18

An example of how to get more details about the impersonator:

use Symfony\Component\Security\Core\Role\SwitchUserRole;


$sec = $this->get('security.context');

if($sec->isGranted('ROLE_PREVIOUS_ADMIN')) {
  foreach($sec->getToken()->getRoles() as $role) {
    if ($role instanceof SwitchUserRole) {
      $admin_user = $role->getSource()->getUser();
    }
  }
}

You then have admin_user as the original user object. Remember to use the SwitchUserRole.

Sirhara
  • 381
  • 2
  • 8
  • 1
    Worth noting however, if you have foreign keys on your user, security will not have the hydrated items – Ascherer Feb 18 '13 at 22:23
3

An example of how to display impersonator in twig:

{% if is_granted('ROLE_PREVIOUS_ADMIN') %}
  {% for role in app.security.token.roles %}
    {% if role.role == 'ROLE_PREVIOUS_ADMIN' %}
      {{ role.source.user.username }}
    {% endif %}
  {% endfor %}
{% endif %}
WayFarer
  • 1,040
  • 11
  • 19
  • Do you know how to do this in Symfony3? The `app.security` variable has been deprecated and removed, and I'm looking for an alternative now that we're updating to the most recent version. – user5670895 Apr 22 '16 at 12:02
  • 1
    @FighterJet use `app.token_storage` instead of app.security – WayFarer Apr 22 '16 at 12:43
  • `app.token_storage` doesn't seem to be available, according to the [docs](http://symfony.com/doc/current/reference/twig_reference.html#app)... – user5670895 Apr 22 '16 at 13:26
  • "app.token_storage.token.roles" this is not working for me. I have to check same condition {% if role.role == 'ROLE_PREVIOUS_ADMIN' %} {{ role.source.user.username }} {% endif %} Please help me how to check "ROLE_PREVIOUS_ADMIN" ? – mobizen Sep 20 '17 at 10:13
  • @mobize As of Symfony 3.2 the `app` variable has a `getToken()` method so you can access the current token from twig via `app.token` (https://api.symfony.com/3.2/Symfony/Bridge/Twig/AppVariable.html#method_getToken). This is still true for the current master branch (4.2-DEV). – flu Oct 12 '18 at 15:22
0

If you need to test role from the previous admin user :

Working on Symfony 3.4

{% if is_granted('ROLE_PREVIOUS_ADMIN') %}
    {% for role in app.token.roles %}
        {% if role.role == 'ROLE_PREVIOUS_ADMIN' %}
            {% for role_from_previous in role.source.roles if role_from_previous.role == "ROLE_DELETE" %}
                {{ role.source.user.username }} has "ROLE_DELETE"
            {% endfor %}
        {% endif %}
    {% endfor %}
{% endif %}
K0rell
  • 71
  • 1
  • 9
0

To get the original user in the controller, you can use this code:

$token = $this->container->get('security.token_storage')->getToken();
if ($token instanceof \Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken) {
    $impersonatorUser = $token->getOriginalToken()->getUser();
}
qwertz
  • 1,894
  • 17
  • 13