.. index::
single: Security; Impersonating User
How to Impersonate a User
=========================
Sometimes, it's useful to be able to switch from one user to another without
having to log out and log in again (for instance when you are debugging or trying
to understand a bug a user sees that you can't reproduce).
.. caution::
User impersonation is not compatible with
:doc:`pre authenticated firewalls `. The
reason is that impersonation requires the authentication state to be maintained
server-side, but pre-authenticated information (``SSL_CLIENT_S_DN_Email``,
``REMOTE_USER`` or other) is sent in each request.
Impersonating the user can be easily done by activating the ``switch_user``
firewall listener:
.. configuration-block::
.. code-block:: yaml
# app/config/security.yml
security:
# ...
firewalls:
main:
# ...
switch_user: true
.. code-block:: xml
.. code-block:: php
// app/config/security.php
$container->loadFromExtension('security', array(
// ...
'firewalls' => array(
'main'=> array(
// ...
'switch_user' => true,
),
),
));
To switch to another user, just add a query string with the ``_switch_user``
parameter and the username as the value to the current URL:
.. code-block:: text
http://example.com/somewhere?_switch_user=thomas
To switch back to the original user, use the special ``_exit`` username:
.. code-block:: text
http://example.com/somewhere?_switch_user=_exit
During impersonation, the user is provided with a special role called
``ROLE_PREVIOUS_ADMIN``. In a template, for instance, this role can be used
to show a link to exit impersonation:
.. configuration-block::
.. code-block:: html+twig
{% if is_granted('ROLE_PREVIOUS_ADMIN') %}
Exit impersonation
{% endif %}
.. code-block:: html+php
isGranted('ROLE_PREVIOUS_ADMIN')): ?>
Exit impersonation
In some cases you may need to get the object that represents the impersonator
user rather than the impersonated user. Use the following snippet to iterate
over the user's roles until you find one that a ``SwitchUserRole`` object::
use Symfony\Component\Security\Core\Role\SwitchUserRole;
$authorizationChecker = $this->get('security.authorization_checker');
$tokenStorage = $this->get('security.token_storage');
if ($authorizationChecker->isGranted('ROLE_PREVIOUS_ADMIN')) {
foreach ($tokenStorage->getToken()->getRoles() as $role) {
if ($role instanceof SwitchUserRole) {
$impersonatorUser = $role->getSource()->getUser();
break;
}
}
}
Of course, this feature needs to be made available to a small group of users.
By default, access is restricted to users having the ``ROLE_ALLOWED_TO_SWITCH``
role. The name of this role can be modified via the ``role`` setting. For
extra security, you can also change the query parameter name via the ``parameter``
setting:
.. configuration-block::
.. code-block:: yaml
# app/config/security.yml
security:
# ...
firewalls:
main:
# ...
switch_user: { role: ROLE_ADMIN, parameter: _want_to_be_this_user }
.. code-block:: xml
.. code-block:: php
// app/config/security.php
$container->loadFromExtension('security', array(
// ...
'firewalls' => array(
'main'=> array(
// ...
'switch_user' => array(
'role' => 'ROLE_ADMIN',
'parameter' => '_want_to_be_this_user',
),
),
),
));
Events
------
The firewall dispatches the ``security.switch_user`` event right after the impersonation
is completed. The :class:`Symfony\\Component\\Security\\Http\\Event\\SwitchUserEvent` is
passed to the listener, and you can use this to get the user that you are now impersonating.
The :doc:`/session/locale_sticky_session` article does not update the locale
when you impersonate a user. The following code sample will show how to change
the sticky locale:
.. configuration-block::
.. code-block:: yaml
# app/config/services.yml
services:
app.switch_user_listener:
class: AppBundle\EventListener\SwitchUserListener
tags:
- { name: kernel.event_listener, event: security.switch_user, method: onSwitchUser }
.. code-block:: xml
.. code-block:: php
// app/config/services.php
use AppBundle\EventListener\SwitchUserListener;
$container
->register('app.switch_user_listener', SwitchUserListener::class)
->addTag('kernel.event_listener', array(
'event' => 'security.switch_user',
'method' => 'onSwitchUser',
))
;
.. caution::
The listener implementation assumes your ``User`` entity has a ``getLocale()`` method::
// src/AppBundle/EventListener/SwitchUserListener.php
namespace AppBundle\EventListener;
use Symfony\Component\Security\Http\Event\SwitchUserEvent;
class SwitchUserListener
{
public function onSwitchUser(SwitchUserEvent $event)
{
$event->getRequest()->getSession()->set(
'_locale',
$event->getTargetUser()->getLocale()
);
}
}