8000 feature #13342 [security] Fetching current stored context when not ex… · symfony/symfony@388ae55 · GitHub
[go: up one dir, main page]

Skip to content

Commit 388ae55

Browse files
committed
feature #13342 [security] Fetching current stored context when not explicitly specified (jaytaph)
This PR was squashed before being merged into the 2.7 branch (closes #13342). Discussion ---------- [security] Fetching current stored context when not explicitly specified | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #12160 | License | MIT | Doc PR | N/A This patch will use the current stored context found in a token (provided, there is one), if none has been specified. According to a quick scan of the code, this will be the only place where `getProviderKey()` is used outside a specific class (the authentication providers will check token type before calling `getProviderKey()`, but maybe it's be a good idea to implement a "providerKeyTokenInterface" or something. It's a nicer solution imho than the current `method_exists()` Commits ------- f6046ba [security] Fetching current stored context when not explicitly specified
2 parents e756135 + f6046ba commit 388ae55

File tree

6 files changed

+96
-15
lines changed

6 files changed

+96
-15
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
<services>
1313
<service id="templating.helper.logout_url" class="%templating.helper.logout_url.class%">
1414
<tag name="templating.helper" alias="logout_url" />
15-
<argument type="service" id="service_container" />
15+
<argument type="service" id="request_stack" />
1616
<argument type="service" id="router" />
17+
<argument type="service" id="security.token_storage" />
1718
</service>
1819

1920
<service id="templating.helper.security" class="%templating.helper.security.class%">

src/Symfony/Bundle/SecurityBundle/Templating/Helper/LogoutUrlHelper.php

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
use Symfony\Component\DependencyInjection\ContainerInterface;
1515
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderAdapter;
1616
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
17+
use Symfony\Component\HttpFoundation\RequestStack;
1718
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
19+
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
1820
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
1921
use Symfony\Component\Templating\Helper\Helper;
2022

@@ -25,20 +27,33 @@
2527
*/
2628
class LogoutUrlHelper extends Helper
2729
{
28-
private $container;
30+
private $requestStack;
2931
private $listeners = array();
3032
private $router;
33+
private $tokenStorage;
3134

3235
/**
3336
* Constructor.
3437
*
35-
* @param ContainerInterface $container A ContainerInterface instance
36-
* @param UrlGeneratorInterface $router A Router instance
38+
* @param ContainerInterface|RequestStack $requestStack A ContainerInterface instance or RequestStack
39+
* @param UrlGeneratorInterface $router The router service
40+
* @param TokenStorageInterface|null $tokenStorage The token storage service
41+
*
42+
* @deprecated Passing a ContainerInterface as a first argument is deprecated since 2.7 and will be removed in 3.0.
3743
*/
38-
public function __construct(ContainerInterface $container, UrlGeneratorInterface $router)
44+
public function __construct($requestStack, UrlGeneratorInterface $router, TokenStorageInterface $tokenStorage = null)
3945
{
40-
$this->container = $container;
46+
if ($requestStack instanceof ContainerInterface) {
47+
$this->requestStack = $requestStack->get('request_stack');
48+
trigger_error('The '.__CLASS__.' constructor will require a RequestStack instead of a ContainerInterface instance in 3.0.', E_USER_DEPRECATED);
49+
} elseif ($requestStack instanceof RequestStack) {
50+
6D47 $this->requestStack = $requestStack;
51+
} else {
52+
throw new \InvalidArgumentException(sprintf('%s takes either a RequestStack or a ContainerInterface object as its first argument.', __METHOD__));
53+
}
54+
4155
$this->router = $router;
56+
$this->tokenStorage = $tokenStorage;
4257
}
4358

4459
/**
@@ -64,7 +79,7 @@ public function registerListener($key, $logoutPath, $csrfTokenId, $csrfParameter
6479
/**
6580
* Generates the absolute logout path for the firewall.
6681
*
67-
* @param string $key The firewall key
82+
* @param string|null $key The firewall key or null to use the current firewall key
6883
*
6984
* @return string The logout path
7085
*/
@@ -76,7 +91,7 @@ public function getLogoutPath($key)
7691
/**
7792
* Generates the absolute logout URL for the firewall.
7893
*
79-
* @param string $key The firewall key
94+
* @param string|null $key The firewall key or null to use the current firewall key
8095
*
8196
* @return string The logout URL
8297
*/
@@ -88,15 +103,27 @@ public function getLogoutUrl($key)
88103
/**
89104
* Generates the logout URL for the firewall.
90105
*
91-
* @param string $key The firewall key
106+
* @param string|null $key The firewall key or null to use the current firewall key
92107
* @param bool|string $referenceType The type of reference (one of the constants in UrlGeneratorInterface)
93108
*
94109
* @return string The logout URL
95110
*
96-
* @throws \InvalidArgumentException if no LogoutListener is registered for the key
111+
* @throws \InvalidArgumentException if no LogoutListener is registered for the key or the key could not be found automatically.
97112
*/
98113
private function generateLogoutUrl($key, $referenceType)
99114
{
115+
// Fetch the current provider key from token, if possible
116+
if (null === $key && null !== $this->tokenStorage) {
117+
$token = $this->tokenStorage->getToken();
118+
if (null !== $token && method_exists($token, 'getProviderKey')) {
119+
$key = $token->getProviderKey();
120+
}
121+
}
122+
123+
if (null === $key) {
124+
throw new \InvalidArgumentException('Unable to find the current firewall LogoutListener, please provide the provider key manually.');
125+
}
126+
100127
if (!array_key_exists($key, $this->listeners)) {
101128
throw new \InvalidArgumentException(sprintf('No LogoutListener found for firewall key "%s".', $key));
102129
}
@@ -106,7 +133,7 @@ private function generateLogoutUrl($key, $referenceType)
106133
$parameters = null !== $csrfTokenManager ? array($csrfParameter => (string) $csrfTokenManager->getToken($csrfTokenId)) : array();
107134

108135
if ('/' === $logoutPath[0]) {
109-
$request = $this->container->get('request_stack')->getCurrentRequest();
136+
$request = $this->requestStack->getCurrentRequest();
110137

111138
$url = UrlGeneratorInterface::ABSOLUTE_URL === $referenceType ? $request->getUriForPath($logoutPath) : $request->getBasePath().$logoutPath;
112139

src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/views/Login/after_login.html.twig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,14 @@
33
{% block body %}
44
Hello {{ app.user.username }}!<br /><br />
55
You're browsing to path "{{ app.request.pathInfo }}".
6+
7+
<a href="{{ logout_path('default') }}">Log out</a>.
8+
<a href="{{ logout_url('default') }}">Log out</a>.
9+
10+
<a href="{{ logout_path('second_area') }}">Log out</a>.
11+
<a href="{{ logout_url('second_area') }}">Log out</a>.
12+
13+
<a href="{{ logout_path() }}">Log out</a>.
14+
<a href="{{ logout_url() }}">Log out</a>.
15+
616
{% endblock %}

src/Symfony/Bundle/SecurityBundle/Tests/Functional/FormLoginTest.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,40 @@ public function testFormLogin($config)
3636
$this->assertContains('You\'re browsing to path "/profile".', $text);
3737
}
3838

39+
/**
40+
* @dataProvider getConfigs
41+
*/
42+
public function testFormLogout($config)
43+
{
44+
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config));
45+
$client->insulate();
46+
47+
$form = $client->request('GET', '/login')->selectButton('login')->form();
48+
$form['_username'] = 'johannes';
49+
$form['_password'] = 'test';
50+
$client->submit($form);
51+
52+
$this->assertRedirect($client->getResponse(), '/profile');
53+
54+
$crawler = $client->followRedirect();
55+
$text = $crawler->text();
56+
57+
$this->assertContains('Hello johannes!', $text);
58+
$this->assertContains('You\'re browsing to path "/profile".', $text);
59+
60+
$logoutLinks = $crawler->selectLink('Log out')->links();
61+
$this->assertCount(6, $logoutLinks);
62+
$this->assertSame($logoutLinks[0]->getUri(), $logoutLinks[1]->getUri());
63+
$this->assertSame($logoutLinks[2]->getUri(), $logoutLinks[3]->getUri());
64+
$this->assertSame($logoutLinks[4]->getUri(), $logoutLinks[5]->getUri());
65+
66+
$this->assertNotSame($logoutLinks[0]->getUri(), $logoutLinks[2]->getUri());
67+
$this->assertNotSame($logoutLinks[1]->getUri(), $logoutLinks[3]->getUri());
68+
69+
$this->assertSame($logoutLinks[0]->getUri(), $logoutLinks[4]->getUri());
70+
$this->assertSame($logoutLinks[1]->getUri(), $logoutLinks[5]->getUri());
71+
}
72+
3973
/**
4074
* @dataProvider getConfigs
4175
*/

src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/config.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,17 @@ security:
2323
form_login:
2424
check_path: /login_check
2525
default_target_path: /profile
26+
logout: ~
2627
anonymous: ~
2728

29+
# This firewall is here just to check its the logout functionality
30+
second_area:
31+
http_basic: ~
32+
anonymous: ~
33+
logout:
34+
target: /second/target
35+
path: /second/logout
36+
2837
access_control:
2938
- { path: ^/unprotected_resource$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
3039
- { path: ^/secure-but-not-covered-by-access-control$, roles: IS_AUTHENTICATED_ANONYMOUSLY }

src/Symfony/Bundle/SecurityBundle/Twig/Extension/LogoutUrlExtension.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,23 +41,23 @@ public function getFunctions()
4141
/**
4242
* Generates the relative logout URL for the firewall.
4343
*
44-
* @param string $key The firewall key
44+
* @param string|null $key The firewall key or null to use the current firewall key
4545
*
4646
* @return string The relative logout URL
4747
*/
48-
public function getLogoutPath($key)
48+
public function getLogoutPath($key = null)
4949
{
5050
return $this->helper->getLogoutPath($key);
5151
}
5252

5353
/**
5454
* Generates the absolute logout URL for the firewall.
5555
*
56-
* @param string $key The firewall key
56+
* @param string|null $key The firewall key or null to use the current firewall key
5757
*
5858
* @return string The absolute logout URL
5959
*/
60-
public function getLogoutUrl($key)
60+
public function getLogoutUrl($key = null)
6161
{
6262
return $this->helper->getLogoutUrl($key);
6363
}

0 commit comments

Comments
 (0)
0