Skip to content

Commit 876257b

Browse files
jwmickeyjaviereguiluz
authored andcommitted
implemented community suggestions
- removed role_heirarchy from switch user voter to simplify - removed double-spaces between sentences. - added versionadded - added header
1 parent e6c569b commit 876257b

File tree

1 file changed

+11
-122
lines changed

1 file changed

+11
-122
lines changed

security/impersonating_user.rst

Lines changed: 11 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -187,30 +187,28 @@ also adjust the query parameter name via the ``parameter`` setting:
187187
),
188188
));
189189
190+
Limiting User Switching
191+
-----------------------
192+
190193
If you need more control over user switching, but don't require the complexity
191-
of a full ACL implementation, you can use a security voter. For example, you
194+
of a full ACL implementation, you can use a security voter. For example, you
192195
may want to allow employees to be able to impersonate a user with the
193196
``ROLE_CUSTOMER`` role without giving them the ability to impersonate a more
194197
elevated user such as an administrator.
195198

196-
First, create the voter class::
199+
.. versionadded:: 4.1
200+
The target user was added as the voter subject parameter in Symfony 4.1.
201+
202+
Create the voter class::
197203

198204
namespace App\Security\Voter;
199205

200206
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
201207
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
202-
use Symfony\Component\Security\Core\Role\RoleHierarchy;
203208
use Symfony\Component\Security\Core\User\UserInterface;
204209

205210
class SwitchToCustomerVoter extends Voter
206211
{
207-
private $roleHierarchy;
208-
209-
public function __construct(RoleHierarchy $roleHierarchy)
210-
{
211-
$this->roleHierarchy = $roleHierarchy;
212-
}
213-
214212
protected function supports($attribute, $subject)
215213
{
216214
return in_array($attribute, ['ROLE_ALLOWED_TO_SWITCH'])
@@ -235,8 +233,7 @@ First, create the voter class::
235233

236234
private function hasSwitchToCustomerRole(TokenInterface $token)
237235
{
238-
$roles = $this->roleHierarchy->getReachableRoles($token->getRoles());
239-
foreach ($roles as $role) {
236+
foreach ($token->getRoles() as $role) {
240237
if ($role->getRole() === 'ROLE_SWITCH_TO_CUSTOMER') {
241238
return true;
242239
}
@@ -246,116 +243,8 @@ First, create the voter class::
246243
}
247244
}
248245

249-
.. caution::
250-
251-
Notice that when checking for the ``ROLE_CUSTOMER`` role on the target user, only the roles
252-
explicitly assigned to the user are checked rather than checking all reachable roles from
253-
the role hierarchy. The reason for this is to avoid accidentally granting access to an
254-
elevated user that may have inherited the role via the hierarchy. This logic is specific
255-
to the example, but keep this in mind when writing your own voter.
256-
257-
Next, add the roles to the security configuration:
258-
259-
.. configuration-block::
260-
261-
.. code-block:: yaml
262-
263-
# config/packages/security.yaml
264-
security:
265-
# ...
266-
267-
role_hierarchy:
268-
ROLE_CUSTOMER: [ROLE_USER]
269-
ROLE_EMPLOYEE: [ROLE_USER, ROLE_SWITCH_TO_CUSTOMER]
270-
ROLE_SUPER_ADMIN: [ROLE_EMPLOYEE, ROLE_ALLOWED_TO_SWITCH]
271-
272-
.. code-block:: xml
273-
274-
<!-- config/packages/security.xml -->
275-
<?xml version="1.0" encoding="UTF-8"?>
276-
<srv:container xmlns="http://symfony.com/schema/dic/security"
277-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
278-
xmlns:srv="http://symfony.com/schema/dic/services"
279-
xsi:schemaLocation="http://symfony.com/schema/dic/services
280-
http://symfony.com/schema/dic/services/services-1.0.xsd">
281-
<config>
282-
<!-- ... -->
283-
284-
<role id="ROLE_CUSTOMER">ROLE_USER</role>
285-
<role id="ROLE_EMPLOYEE">ROLE_USER, ROLE_SWITCH_TO_CUSTOMER</role>
286-
<role id="ROLE_SUPER_ADMIN">ROLE_EMPLOYEE, ROLE_ALLOWED_TO_SWITCH</role>
287-
</config>
288-
</srv:container>
289-
290-
.. code-block:: php
291-
292-
// config/packages/security.php
293-
$container->loadFromExtension('security', array(
294-
// ...
295-
296-
'role_hierarchy' => array(
297-
'ROLE_CUSTOMER' => 'ROLE_USER',
298-
'ROLE_EMPLOYEE' => 'ROLE_USER, ROLE_SWITCH_TO_CUSTOMER',
299-
'ROLE_SUPER_ADMIN' => array(
300-
'ROLE_EMPLOYEE',
301-
'ROLE_ALLOWED_TO_SWITCH',
302-
),
303-
),
304-
));
305-
306-
Thanks to autowiring, we only need to configure the role hierarchy argument when registering
307-
the voter as a service:
308-
309-
.. configuration-block::
310-
311-
.. code-block:: yaml
312-
313-
// config/services.yaml
314-
services:
315-
# ...
316-
317-
App\Security\Voter\SwitchToCustomerVoter:
318-
arguments:
319-
$roleHierarchy: "@security.role_hierarchy"
320-
321-
.. code-block:: xml
322-
323-
<!-- config/services.xml -->
324-
<?xml version="1.0" encoding="UTF-8"?>
325-
<container xmlns="http://symfony.com/schema/dic/services"
326-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
327-
xsi:schemaLocation="http://symfony.com/schema/dic/services
328-
http://symfony.com/schema/dic/services/services-1.0.xsd">
329-
330-
<services>
331-
<!-- ... -->
332-
<service id="App\Security\Voter\SwitchToCustomerVoter">
333-
<argument key="$roleHierarchy">"@security.role_hierarchy"</argument>
334-
</service>
335-
</services>
336-
</container>
337-
338-
.. code-block:: php
339-
340-
// config/services.php
341-
use App\Security\Voter\SwitchToCustomerVoter;
342-
use Symfony\Component\DependencyInjection\Definition;
343-
use Symfony\Component\DependencyInjection\Reference;
344-
345-
// Same as before
346-
$definition = new Definition();
347-
348-
$definition
349-
->setAutowired(true)
350-
->setAutoconfigured(true)
351-
->setPublic(false)
352-
;
353-
354-
$this->registerClasses($definition, 'App\\', '../src/*', '../src/{Entity,Migrations,Tests}');
355-
356-
// Explicitly configure the service
357-
$container->getDefinition(SwitchToCustomerVoter::class)
358-
->setArgument('$roleHierarchy', new Reference('security.role_hierarchy'));
246+
Thanks to service autoconfiguration and autowiring, this new voter is automatically
247+
registered as a service and tagged as a security voter.
359248

360249
Now a user who has the ``ROLE_SWITCH_TO_CUSTOMER`` role can switch to a user who explicitly has the
361250
``ROLE_CUSTOMER`` role, but not other users.

0 commit comments

Comments
 (0)