Skip to content

Commit 0296974

Browse files
author
Amrouche Hamza
committed
[TwigBridge] Create impersonation_exit_path() and *_url() functions
1 parent 4a602ca commit 0296974

File tree

5 files changed

+135
-1
lines changed

5 files changed

+135
-1
lines changed

src/Symfony/Bridge/Twig/Extension/SecurityExtension.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,25 @@
1414
use Symfony\Component\Security\Acl\Voter\FieldVote;
1515
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
1616
use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException;
17+
use Symfony\Component\Security\Http\Logout\ImpersonateUrlGenerator;
1718
use Twig\Extension\AbstractExtension;
1819
use Twig\TwigFunction;
1920

2021
/**
2122
* SecurityExtension exposes security context features.
2223
*
2324
* @author Fabien Potencier <fabien@symfony.com>
25+
* @author Amrouche Hamza <hamza.simperfit@gmail.com>
2426
*/
2527
class SecurityExtension extends AbstractExtension
2628
{
2729
private $securityChecker;
30+
private $impersonateUrlGenerator;
2831

29-
public function __construct(AuthorizationCheckerInterface $securityChecker = null)
32+
public function __construct(AuthorizationCheckerInterface $securityChecker = null, ImpersonateUrlGenerator $impersonateUrlGenerator)
3033
{
3134
$this->securityChecker = $securityChecker;
35+
$this->impersonateUrlGenerator = $impersonateUrlGenerator;
3236
}
3337

3438
public function isGranted($role, $object = null, $field = null)
@@ -48,13 +52,25 @@ public function isGranted($role, $object = null, $field = null)
4852
}
4953
}
5054

55+
public function getImpersonateExitPath()
56+
{
57+
return $this->impersonateUrlGenerator->getImpersonateExitPath();
58+
}
59+
60+
public function getImpersonateExitUrl()
61+
{
62+
return $this->impersonateUrlGenerator->getImpersonateExitUrl();
63+
}
64+
5165
/**
5266
* {@inheritdoc}
5367
*/
5468
public function getFunctions()
5569
{
5670
return array(
5771
new TwigFunction('is_granted', array($this, 'isGranted')),
72+
new TwigFunction('impersonation_exit_path', array($this, 'getImpersonateExitPath')),
73+
new TwigFunction('impersonation_exit_url', array($this, 'getImpersonateExitUrl')),
5874
);
5975
}
6076

src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ public function load(array $configs, ContainerBuilder $container)
8383
$container->removeDefinition('security.access.expression_voter');
8484
}
8585

86+
if (!class_exists('Symfony\Component\HttpFoundation\RequestStack') || !class_exists('Symfony\Component\Routing\Generator\UrlGeneratorInterface')) {
87+
$container->removeDefinition('security.impersonate_url_generator');
88+
}
89+
8690
// set some global scalars
8791
$container->setParameter('security.access.denied_url', $config['access_denied_url']);
8892
$container->setParameter('security.authentication.manager.erase_credentials', $config['erase_credentials']);

src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,12 @@
157157
<argument /> <!-- switch_user -->
158158
</service>
159159

160+
<service id="security.impersonate_url_generator" class="Symfony\Component\Security\Http\Logout\ImpersonateUrlGenerator">
161+
<argument type="service" id="request_stack" />
162+
<argument type="service" id="router" />
163+
<argument type="service" id="security.token_storage" on-invalid="null" />
164+
</service>
165+
160166
<service id="security.logout_url_generator" class="Symfony\Component\Security\Http\Logout\LogoutUrlGenerator">
161167
<argument type="service" id="request_stack" on-invalid="null" />
162168
<argument type="service" id="router" on-invalid="null" />

src/Symfony/Bundle/SecurityBundle/Resources/config/templating_twig.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
<service id="twig.extension.security" class="Symfony\Bridge\Twig\Extension\SecurityExtension">
1616
<tag name="twig.extension" />
1717
<argument type="service" id="security.authorization_checker" on-invalid="ignore" />
18+
<argument type="service" id="sec" on-invalid="ignore" />
19+
1820
</service>
1921
</services>
2022
</container>
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Security\Http\Logout;
13+
14+
use Symfony\Component\HttpFoundation\RequestStack;
15+
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
16+
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
17+
use Symfony\Component\Security\Core\Role\SwitchUserRole;
18+
use Symfony\Component\Security\Http\Firewall\SwitchUserListener;
19+
use Symfony\Component\Security\Http\FirewallMapInterface;
20+
use Symfony\Bundle\SecurityBundle\Security\FirewallMap;
21+
22+
/**
23+
* Provides generator functions for the impersonate url exit.
24+
*
25+
* @author Amrouche Hamza <hamza.simperfit@gmail.com>
26+
*/
27+
class ImpersonateUrlGenerator
28+
{
29+
private $requestStack;
30+
private $router;
31+
private $tokenStorage;
32+
private $firewallMap;
33+
34+
public function __construct(RequestStack $requestStack, UrlGeneratorInterface $router, TokenStorageInterface $tokenStorage = null, FirewallMapInterface $firewallMap)
35+
{
36+
$this->requestStack = $requestStack;
37+
$this->router = $router;
38+
$this->tokenStorage = $tokenStorage;
39+
$this->firewallMap = $firewallMap;
40+
}
41+
42+
public function getImpersonateExitPath(): string
43+
{
44+
return $this->generateImpersonateExitUrl(UrlGeneratorInterface::ABSOLUTE_PATH);
45+
}
46+
47+
public function getImpersonateExitUrl(): string
48+
{
49+
return $this->generateImpersonateExitUrl(UrlGeneratorInterface::ABSOLUTE_URL);
50+
}
51+
52+
private function generateImpersonateExitUrl($referenceType): string
53+
{
54+
$request = $this->requestStack->getCurrentRequest();
55+
$parameters = $request->query;
56+
$exitPath = null;
57+
if ($this->firewallMap instanceof FirewallMap) {
58+
$firewallConfig = $this->firewallMap->getFirewallConfig($request);
59+
60+
// generate exit impersonation path from current request
61+
if ($this->isImpersonatedUser() && null !== $switchUserConfig = $firewallConfig->getSwitchUser()) {
62+
$exitPath = $request->getRequestUri();
63+
$exitPath .= null === $request->getQueryString() ? '?' : '&';
64+
$exitPath .= sprintf('%s=%s', urlencode($switchUserConfig['parameter']), SwitchUserListener::EXIT_VALUE);
65+
}
66+
}
67+
if (null === $exitPath) {
68+
throw new \LogicException('Unable to generate the impersonate exit URL without a path.');
69+
}
70+
71+
if ('/' === $exitPath[0]) {
72+
if (!$this->requestStack) {
73+
throw new \LogicException('Unable to generate the impersonate exit URL without a RequestStack.');
74+
}
75+
76+
$url = UrlGeneratorInterface::ABSOLUTE_URL === $referenceType ? $request->getUriForPath($exitPath) : $request->getBaseUrl().$exitPath;
77+
78+
if (!empty($parameters)) {
79+
$url .= '?'.http_build_query($parameters);
80+
}
81+
} else {
82+
if (!$this->router) {
83+
throw new \LogicException('Unable to generate the impersonate exit URL without a Router.');
84+
}
85+
86+
$url = $this->router->generate($exitPath, array(), $referenceType);
87+
}
88+
89+
return $url;
90+
}
91+
92+
private function isImpersonatedUser(): bool
93+
{
94+
if (null === $token = $this->tokenStorage->getToken()) {
95+
return false;
96+
}
97+
98+
$assignedRoles = $token->getRoles();
99+
100+
foreach ($assignedRoles as $role) {
101+
if ($role instanceof SwitchUserRole) {
102+
return true;
103+
}
104+
}
105+
}
106+
}

0 commit comments

Comments
 (0)