Skip to content

Commit 89bb895

Browse files
committed
Merge branch '2.7' into 2.8
* 2.7: Fixed pathinfo calculation for requests starting with a question mark. [Security] simplify the SwitchUserListenerTest
2 parents 8371dea + 2240ecf commit 89bb895

File tree

4 files changed

+122
-150
lines changed

4 files changed

+122
-150
lines changed

src/Symfony/Component/HttpFoundation/Request.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1753,6 +1753,9 @@ protected function prepareBaseUrl()
17531753

17541754
// Does the baseUrl have anything in common with the request_uri?
17551755
$requestUri = $this->getRequestUri();
1756+
if ($requestUri !== '' && $requestUri[0] !== '/') {
1757+
$requestUri = '/'.$requestUri;
1758+
}
17561759

17571760
if ($baseUrl && false !== $prefix = $this->getUrlencodedPrefix($requestUri, $baseUrl)) {
17581761
// full $baseUrl matches
@@ -1825,9 +1828,12 @@ protected function preparePathInfo()
18251828
}
18261829

18271830
// Remove the query string from REQUEST_URI
1828-
if ($pos = strpos($requestUri, '?')) {
1831+
if (false !== $pos = strpos($requestUri, '?')) {
18291832
$requestUri = substr($requestUri, 0, $pos);
18301833
}
1834+
if ($requestUri !== '' && $requestUri[0] !== '/') {
1835+
$requestUri = '/'.$requestUri;
1836+
}
18311837

18321838
$pathInfo = substr($requestUri, strlen($baseUrl));
18331839
if (null !== $baseUrl && (false === $pathInfo || '' === $pathInfo)) {

src/Symfony/Component/HttpFoundation/Tests/RequestTest.php

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1264,6 +1264,12 @@ public function testGetPathInfo()
12641264
$request->initialize(array(), array(), array(), array(), array(), $server);
12651265

12661266
$this->assertEquals('/path%20test/info', $request->getPathInfo());
1267+
1268+
$server = array();
1269+
$server['REQUEST_URI'] = '?a=b';
1270+
$request->initialize(array(), array(), array(), array(), array(), $server);
1271+
1272+
$this->assertEquals('/', $request->getPathInfo());
12671273
}
12681274

12691275
public function testGetPreferredLanguage()
@@ -2041,6 +2047,61 @@ public function methodCacheableProvider()
20412047
array('CONNECT', false),
20422048
);
20432049
}
2050+
2051+
public function nonstandardRequestsData()
2052+
{
2053+
return array(
2054+
array('', '', '/', 'http://host:8080/', ''),
2055+
array('/', '', '/', 'http://host:8080/', ''),
2056+
2057+
array('hello/app.php/x', '', '/x', 'http://host:8080/hello/app.php/x', '/hello', '/hello/app.php'),
2058+
array('/hello/app.php/x', '', '/x', 'http://host:8080/hello/app.php/x', '/hello', '/hello/app.php'),
2059+
2060+
array('', 'a=b', '/', 'http://host:8080/?a=b'),
2061+
array('?a=b', 'a=b', '/', 'http://host:8080/?a=b'),
2062+
array('/?a=b', 'a=b', '/', 'http://host:8080/?a=b'),
2063+
2064+
array('x', 'a=b', '/x', 'http://host:8080/x?a=b'),
2065+
array('x?a=b', 'a=b', '/x', 'http://host:8080/x?a=b'),
2066+
array('/x?a=b', 'a=b', '/x', 'http://host:8080/x?a=b'),
2067+
2068+
array('hello/x', '', '/x', 'http://host:8080/hello/x', '/hello'),
2069+
array('/hello/x', '', '/x', 'http://host:8080/hello/x', '/hello'),
2070+
2071+
array('hello/app.php/x', 'a=b', '/x', 'http://host:8080/hello/app.php/x?a=b', '/hello', '/hello/app.php'),
2072+
array('hello/app.php/x?a=b', 'a=b', '/x', 'http://host:8080/hello/app.php/x?a=b', '/hello', '/hello/app.php'),
2073+
array('/hello/app.php/x?a=b', 'a=b', '/x', 'http://host:8080/hello/app.php/x?a=b', '/hello', '/hello/app.php'),
2074+
);
2075+
}
2076+
2077+
/**
2078+
* @dataProvider nonstandardRequestsData
2079+
*/
2080+
public function testNonstandardRequests($requestUri, $queryString, $expectedPathInfo, $expectedUri, $expectedBasePath = '', $expectedBaseUrl = null)
2081+
{
2082+
if (null === $expectedBaseUrl) {
2083+
$expectedBaseUrl = $expectedBasePath;
2084+
}
2085+
2086+
$server = array(
2087+
'HTTP_HOST' => 'host:8080',
2088+
'SERVER_PORT' => '8080',
2089+
'QUERY_STRING' => $queryString,
2090+
'PHP_SELF' => '/hello/app.php',
2091+
'SCRIPT_FILENAME' => '/some/path/app.php',
2092+
'REQUEST_URI' => $requestUri,
2093+
);
2094+
2095+
$request = new Request(array(), array(), array(), array(), array(), $server);
2096+
2097+
$this->assertEquals($expectedPathInfo, $request->getPathInfo());
2098+
$this->assertEquals($expectedUri, $request->getUri());
2099+
$this->assertEquals($queryString, $request->getQueryString());
2100+
$this->assertEquals(8080, $request->getPort());
2101+
$this->assertEquals('host:8080', $request->getHttpHost());
2102+
$this->assertEquals($expectedBaseUrl, $request->getBaseUrl());
2103+
$this->assertEquals($expectedBasePath, $request->getBasePath());
2104+
}
20442105
}
20452106

20462107
class RequestContentProxy extends Request

src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php

Lines changed: 53 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@
1212
namespace Symfony\Component\Security\Http\Tests\Firewall;
1313

1414
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\HttpFoundation\Request;
16+
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
17+
use Symfony\Component\HttpKernel\HttpKernelInterface;
18+
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
19+
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
20+
use Symfony\Component\Security\Core\Role\SwitchUserRole;
21+
use Symfony\Component\Security\Core\User\User;
1522
use Symfony\Component\Security\Http\Event\SwitchUserEvent;
1623
use Symfony\Component\Security\Http\Firewall\SwitchUserListener;
1724
use Symfony\Component\Security\Http\SecurityEvents;
@@ -32,14 +39,12 @@ class SwitchUserListenerTest extends TestCase
3239

3340
protected function setUp()
3441
{
35-
$this->tokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface')->getMock();
42+
$this->tokenStorage = new TokenStorage();
3643
$this->userProvider = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserProviderInterface')->getMock();
3744
$this->userChecker = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserCheckerInterface')->getMock();
3845
$this->accessDecisionManager = $this->getMockBuilder('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface')->getMock();
39-
$this->request = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')->getMock();
40-
$this->request->query = $this->getMockBuilder('Symfony\Component\HttpFoundation\ParameterBag')->getMock();
41-
$this->request->server = $this->getMockBuilder('Symfony\Component\HttpFoundation\ServerBag')->getMock();
42-
$this->event = $this->getEvent($this->request);
46+
$this->request = new Request();
47+
$this->event = new GetResponseEvent($this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(), $this->request, HttpKernelInterface::MASTER_REQUEST);
4348
}
4449

4550
/**
@@ -53,54 +58,42 @@ public function testProviderKeyIsRequired()
5358

5459
public function testEventIsIgnoredIfUsernameIsNotPassedWithTheRequest()
5560
{
56-
$this->request->expects($this->any())->method('get')->with('_switch_user')->will($this->returnValue(null));
57-
58-
$this->event->expects($this->never())->method('setResponse');
59-
$this->tokenStorage->expects($this->never())->method('setToken');
60-
6161
$listener = new SwitchUserListener($this->tokenStorage, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager);
6262
$listener->handle($this->event);
63+
64+
$this->assertNull($this->event->getResponse());
65+
$this->assertNull($this->tokenStorage->getToken());
6366
}
6467

6568
/**
6669
* @expectedException \Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException
6770
*/
6871
public function testExitUserThrowsAuthenticationExceptionIfOriginalTokenCannotBeFound()
6972
{
70-
$token = $this->getToken(array($this->getMockBuilder('Symfony\Component\Security\Core\Role\RoleInterface')->getMock()));
73+
$token = new UsernamePasswordToken('username', '', 'key', array('ROLE_FOO'));
7174

72-
$this->tokenStorage->expects($this->any())->method('getToken')->will($this->returnValue($token));
73-
$this->request->expects($this->any())->method('get')->with('_switch_user')->will($this->returnValue('_exit'));
75+
$this->tokenStorage->setToken($token);
76+
$this->request->query->set('_switch_user', '_exit');
7477

7578
$listener = new SwitchUserListener($this->tokenStorage, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager);
7679
$listener->handle($this->event);
7780
}
7881

7982
public function testExitUserUpdatesToken()
8083
{
81-
$originalToken = $this->getToken();
82-
$role = $this->getMockBuilder('Symfony\Component\Security\Core\Role\SwitchUserRole')
83-
->disableOriginalConstructor()
84-
->getMock();
85-
$role->expects($this->any())->method('getSource')->will($this->returnValue($originalToken));
86-
87-
$this->tokenStorage->expects($this->any())
88-
->method('getToken')
89-
->will($this->returnValue($this->getToken(array($role))));
90-
91-
$this->request->expects($this->any())->method('get')->with('_switch_user')->will($this->returnValue('_exit'));
92-
$this->request->expects($this->any())->method('getUri')->will($this->returnValue('/'));
93-
$this->request->query->expects($this->once())->method('remove', '_switch_user');
94-
$this->request->query->expects($this->any())->method('all')->will($this->returnValue(array()));
95-
$this->request->server->expects($this->once())->method('set')->with('QUERY_STRING', '');
96-
97-
$this->tokenStorage->expects($this->once())
98-
->method('setToken')->with($originalToken);
99-
$this->event->expects($this->once())
100-
->method('setResponse')->with($this->isInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse'));
84+
$originalToken = new UsernamePasswordToken('username', '', 'key', array());
85+
$this->tokenStorage->setToken(new UsernamePasswordToken('username', '', 'key', array(new SwitchUserRole('ROLE_PREVIOUS', $originalToken))));
86+
87+
$this->request->query->set('_switch_user', '_exit');
10188

10289
$listener = new SwitchUserListener($this->tokenStorage, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager);
10390
$listener->handle($this->event);
91+
92+
$this->assertSame(array(), $this->request->query->all());
93+
$this->assertSame('', $this->request->server->get('QUERY_STRING'));
94+
$this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $this->event->getResponse());
95+
$this->assertSame($this->request->getUri(), $this->event->getResponse()->getTargetUrl());
96+
$this->assertSame($originalToken, $this->tokenStorage->getToken());
10497
}
10598

10699
public function testExitUserDispatchesEventWithRefreshedUser()
@@ -113,38 +106,9 @@ public function testExitUserDispatchesEventWithRefreshedUser()
113106
->method('refreshUser')
114107
->with($originalUser)
115108
->willReturn($refreshedUser);
116-
$originalToken = $this->getToken();
117-
$originalToken
118-
->expects($this->any())
119-
->method('getUser')
120-
->willReturn($originalUser);
121-
$role = $this
122-
->getMockBuilder('Symfony\Component\Security\Core\Role\SwitchUserRole')
123-
->disableOriginalConstructor()
124-
->getMock();
125-
$role->expects($this->any())->method('getSource')->willReturn($originalToken);
126-
$this
127-
->tokenStorage
128-
->expects($this->any())
129-
->method('getToken')
130-
->willReturn($this->getToken(array($role)));
131-
$this
132-
->request
133-
->expects($this->any())
134-
->method('get')
135-
->with('_switch_user')
136-
->willReturn('_exit');
137-
$this
138-
->request
139-
->expects($this->any())
140-
->method('getUri')
141-
->willReturn('/');
142-
$this
143-
->request
144-
->query
145-
->expects($this->any())
146-
->method('all')
147-
->will($this->returnValue(array()));
109+
$originalToken = new UsernamePasswordToken($originalUser, '', 'key');
110+
$this->tokenStorage->setToken(new UsernamePasswordToken('username', '', 'key', array(new SwitchUserRole('ROLE_PREVIOUS', $originalToken))));
111+
$this->request->query->set('_switch_user', '_exit');
148112

149113
$dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock();
150114
$dispatcher
@@ -166,41 +130,9 @@ public function testExitUserDoesNotDispatchEventWithStringUser()
166130
->userProvider
167131
->expects($this->never())
168132
->method('refreshUser');
169-
$originalToken = $this->getToken();
170-
$originalToken
171-
->expects($this->any())
172-
->method('getUser')
173-
->willReturn($originalUser);
174-
$role = $this
175-
->getMockBuilder('Symfony\Component\Security\Core\Role\SwitchUserRole')
176-
->disableOriginalConstructor()
177-
->getMock();
178-
$role
179-
->expects($this->any())
180-
->method('getSource')
181-
->willReturn($originalToken);
182-
$this
183-
->tokenStorage
184-
->expects($this->any())
185-
->method('getToken')
186-
->willReturn($this->getToken(array($role)));
187-
$this
188-
->request
189-
->expects($this->any())
190-
->method('get')
191-
->with('_switch_user')
192-
->willReturn('_exit');
193-
$this
194-
->request
195-
->query
196-
->expects($this->any())
197-
->method('all')
198-
->will($this->returnValue(array()));
199-
$this
200-
->request
201-
->expects($this->any())
202-
->method('getUri')
203-
->willReturn('/');
133+
$originalToken = new UsernamePasswordToken($originalUser, '', 'key');
134+
$this->tokenStorage->setToken(new UsernamePasswordToken('username', '', 'key', array(new SwitchUserRole('ROLE_PREVIOUS', $originalToken))));
135+
$this->request->query->set('_switch_user', '_exit');
204136

205137
$dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock();
206138
$dispatcher
@@ -217,10 +149,10 @@ public function testExitUserDoesNotDispatchEventWithStringUser()
217149
*/
218150
public function testSwitchUserIsDisallowed()
219151
{
220-
$token = $this->getToken(array($this->getMockBuilder('Symfony\Component\Security\Core\Role\RoleInterface')->getMock()));
152+
$token = new UsernamePasswordToken('username', '', 'key', array('ROLE_FOO'));
221153

222-
$this->tokenStorage->expects($this->any())->method('getToken')->will($this->returnValue($token));
223-
$this->request->expects($this->any())->method('get')->with('_switch_user')->will($this->returnValue('kuba'));
154+
$this->tokenStorage->setToken($token);
155+
$this->request->query->set('_switch_user', 'kuba');
224156

225157
$this->accessDecisionManager->expects($this->once())
226158
->method('decide')->with($token, array('ROLE_ALLOWED_TO_SWITCH'))
@@ -232,17 +164,11 @@ public function testSwitchUserIsDisallowed()
232164

233165
public function testSwitchUser()
234166
{
235-
$token = $this->getToken(array($this->getMockBuilder('Symfony\Component\Security\Core\Role\RoleInterface')->getMock()));
236-
$user = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserInterface')->getMock();
237-
$user->expects($this->any())->method('getRoles')->will($this->returnValue(array()));
167+
$token = new UsernamePasswordToken('username', '', 'key', array('ROLE_FOO'));
168+
$user = new User('username', 'password', array());
238169

239-
$this->tokenStorage->expects($this->any())->method('getToken')->will($this->returnValue($token));
240-
$this->request->expects($this->any())->method('get')->with('_switch_user')->will($this->returnValue('kuba'));
241-
$this->request->query->expects($this->once())->method('remove', '_switch_user');
242-
$this->request->query->expects($this->any())->method('all')->will($this->returnValue(array()));
243-
244-
$this->request->expects($this->any())->method('getUri')->will($this->returnValue('/'));
245-
$this->request->server->expects($this->once())->method('set')->with('QUERY_STRING', '');
170+
$this->tokenStorage->setToken($token);
171+
$this->request->query->set('_switch_user', 'kuba');
246172

247173
$this->accessDecisionManager->expects($this->once())
248174
->method('decide')->with($token, array('ROLE_ALLOWED_TO_SWITCH'))
@@ -253,25 +179,26 @@ public function testSwitchUser()
253179
->will($this->returnValue($user));
254180
$this->userChecker->expects($this->once())
255181
->method('checkPostAuth')->with($user);
256-
$this->tokenStorage->expects($this->once())
257-
->method('setToken')->with($this->isInstanceOf('Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken'));
258182

259183
$listener = new SwitchUserListener($this->tokenStorage, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager);
260184
$listener->handle($this->event);
185+
186+
$this->assertSame(array(), $this->request->query->all());
187+
$this->assertSame('', $this->request->server->get('QUERY_STRING'));
188+
$this->assertInstanceOf('Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken', $this->tokenStorage->getToken());
261189
}
262190

263191
public function testSwitchUserKeepsOtherQueryStringParameters()
264192
{
265-
$token = $this->getToken(array($this->getMockBuilder('Symfony\Component\Security\Core\Role\RoleInterface')->getMock()));
266-
$user = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserInterface')->getMock();
267-
$user->expects($this->any())->method('getRoles')->will($this->returnValue(array()));
193+
$token = new UsernamePasswordToken('username', '', 'key', array('ROLE_FOO'));
194+
$user = new User('username', 'password', array());
268195

269-
$this->tokenStorage->expects($this->any())->method('getToken')->will($this->returnValue($token));
270-
$this->request->expects($this->any())->method('get')->with('_switch_user')->will($this->returnValue('kuba'));
271-
$this->request->query->expects($this->once())->method('remove', '_switch_user');
272-
$this->request->query->expects($this->any())->method('all')->will($this->returnValue(array('page' => 3, 'section' => 2)));
273-
$this->request->expects($this->any())->method('getUri')->will($this->returnValue('/'));
274-
$this->request->server->expects($this->once())->method('set')->with('QUERY_STRING', 'page=3&section=2');
196+
$this->tokenStorage->setToken($token);
197+
$this->request->query->replace(array(
198+
'_switch_user' => 'kuba',
199+
'page' => 3,
200+
'section' => 2,
201+
));
275202

276203
$this->accessDecisionManager->expects($this->once())
277204
->method('decide')->with($token, array('ROLE_ALLOWED_TO_SWITCH'))
@@ -282,33 +209,11 @@ public function testSwitchUserKeepsOtherQueryStringParameters()
282209
->will($this->returnValue($user));
283210
$this->userChecker->expects($this->once())
284211
->method('checkPostAuth')->with($user);
285-
$this->tokenStorage->expects($this->once())
286-
->method('setToken')->with($this->isInstanceOf('Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken'));
287212

288213
$listener = new SwitchUserListener($this->tokenStorage, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager);
289214
$listener->handle($this->event);
290-
}
291-
292-
private function getEvent($request)
293-
{
294-
$event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseEvent')
295-
->disableOriginalConstructor()
296-
->getMock();
297-
298-
$event->expects($this->any())
299-
->method('getRequest')
300-
->will($this->returnValue($request));
301-
302-
return $event;
303-
}
304-
305-
private function getToken(array $roles = array())
306-
{
307-
$token = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock();
308-
$token->expects($this->any())
309-
->method('getRoles')
310-
->will($this->returnValue($roles));
311215

312-
return $token;
216+
$this->assertSame('page=3&section=2', $this->request->server->get('QUERY_STRING'));
217+
$this->assertInstanceOf('Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken', $this->tokenStorage->getToken());
313218
}
314219
}

0 commit comments

Comments
 (0)