Skip to content

Commit d657834

Browse files
committed
Merge branch '2.3' into 2.7
* 2.3: [Security][bugfix] "Remember me" cookie cleared on logout with custom "secure"/"httponly" config options [1] [ci] Use current PHP_BINARY when running ./phpunit Fixed typos [UPGRADE-3.0] fix bullet indentation [Security] InMemoryUserProvider now concerns whether user's password is changed when refreshing
2 parents 2c46204 + 9becf27 commit d657834

File tree

10 files changed

+139
-44
lines changed

10 files changed

+139
-44
lines changed

UPGRADE-3.0.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -299,17 +299,18 @@ UPGRADE FROM 2.x to 3.0
299299
```php
300300
echo $form->getErrors(true, false);
301301
```
302-
* The `Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList` class has been removed in
303-
favor of `Symfony\Component\Form\ChoiceList\ArrayChoiceList`.
304302

305-
* The `Symfony\Component\Form\Extension\Core\ChoiceList\LazyChoiceList` class has been removed in
306-
favor of `Symfony\Component\Form\ChoiceList\LazyChoiceList`.
303+
* The `Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList` class has been removed in
304+
favor of `Symfony\Component\Form\ChoiceList\ArrayChoiceList`.
307305

308-
* The `Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList` class has been removed in
309-
favor of `Symfony\Component\Form\ChoiceList\ArrayChoiceList`.
306+
* The `Symfony\Component\Form\Extension\Core\ChoiceList\LazyChoiceList` class has been removed in
307+
favor of `Symfony\Component\Form\ChoiceList\LazyChoiceList`.
310308

311-
* The `Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList` class has been removed in
312-
favor of `Symfony\Component\Form\ChoiceList\ArrayChoiceList`.
309+
* The `Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList` class has been removed in
310+
favor of `Symfony\Component\Form\ChoiceList\ArrayChoiceList`.
311+
312+
* The `Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList` class has been removed in
313+
favor of `Symfony\Component\Form\ChoiceList\ArrayChoiceList`.
313314

314315
### FrameworkBundle
315316

phpunit

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,26 @@ use Symfony\Component\Process\ProcessUtils;
66
error_reporting(-1);
77
require __DIR__.'/src/Symfony/Component/Process/ProcessUtils.php';
88

9-
$PHPUNIT_VERSION = '4.8';
9+
// PHPUnit 4.8 does not support PHP 7, while 5.0 requires PHP 5.6+
10+
$PHPUNIT_VERSION = PHP_VERSION_ID >= 70000 ? '5.0' : '4.8';
1011
$PHPUNIT_DIR = __DIR__.'/.phpunit';
12+
$PHP = defined('PHP_BINARY') ? PHP_BINARY : 'php';
13+
14+
if (!file_exists($COMPOSER = __DIR__.'/composer.phar')) {
15+
$COMPOSER = rtrim('\\' === DIRECTORY_SEPARATOR ? `where.exe composer.phar` : (`which composer.phar` ?: `which composer`));
16+
if (!file_exists($COMPOSER)) {
17+
stream_copy_to_stream(
18+
fopen('https://getcomposer.org/composer.phar', 'rb'),
19+
fopen($COMPOSER = __DIR__.'/composer.phar', 'wb')
20+
);
21+
}
22+
}
1123

12-
// PHPUnit 4.8 does not support PHP 7, while 5.0 requires PHP 5.6+
13-
if (PHP_VERSION_ID >= 70000) {
14-
$PHPUNIT_VERSION = '5.0';
24+
$PHP = ProcessUtils::escapeArgument($PHP);
25+
$COMPOSER = $PHP.' '.ProcessUtils::escapeArgument($COMPOSER);
26+
27+
if (!(isset($argv[1]) && 'install' === $argv[1]) && !file_exists(__DIR__.'/vendor')) {
28+
passthru("$COMPOSER update --no-progress --ansi");
1529
}
1630

1731
if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit")) {
@@ -30,8 +44,8 @@ if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit")) {
3044
$zip->extractTo(getcwd());
3145
$zip->close();
3246
chdir("phpunit-$PHPUNIT_VERSION");
33-
passthru("composer remove --no-update symfony/yaml");
34-
passthru("composer install --prefer-source --no-progress --ansi");
47+
passthru("$COMPOSER remove --no-update symfony/yaml");
48+
passthru("$COMPOSER install --prefer-source --no-progress --ansi");
3549
chdir($oldPwd);
3650
}
3751

@@ -42,7 +56,7 @@ if (isset($argv[1]) && 'symfony' === $argv[1]) {
4256
array_shift($cmd);
4357
}
4458

45-
$cmd[0] = "php $PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit --colors=always";
59+
$cmd[0] = sprintf('%s %s --colors=always', $PHP, ProcessUtils::escapeArgument("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit"));
4660
$cmd = str_replace('%', '%%', implode(' ', $cmd)).' %1$s';
4761

4862
$phpIniMatrix = isset($_SERVER['PHP_INI_MATRIX']) ? explode(' ', $_SERVER['PHP_INI_MATRIX']) : array();
@@ -52,7 +66,7 @@ if ($phpIniMatrix) {
5266
exit(1);
5367
}
5468

55-
$phpDir = dirname(`where.exe php`);
69+
$phpDir = ProcessUtils::escapeArgument(dirname(`where.exe php`));
5670

5771
$newCmd = 'cmd /v:on /d /c "(SET X=0';
5872
foreach ($phpIniMatrix as $iniFile) {

src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionHandler.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,9 @@ public function write($sessionId, $data)
160160
$mergeStmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
161161
$mergeStmt->bindValue(':time', time(), \PDO::PARAM_INT);
162162

163-
//Oracle has a bug that will intermitently happen if you
164-
//have only 1 bind on a CLOB field for 2 different statements
165-
//(INSERT and UPDATE in this case)
163+
// Oracle has a bug that will intermittently happen if you
164+
// have only 1 bind on a CLOB field for 2 different statements
165+
// (INSERT and UPDATE in this case)
166166
if ('oracle' == $this->con->getDatabasePlatform()->getName()) {
167167
$mergeStmt->bindParam(':data2', $encoded, \PDO::PARAM_STR);
168168
}

src/Symfony/Bundle/FrameworkBundle/Translation/PhpExtractor.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ protected function normalizeToken($token)
9090
/**
9191
* Seeks to a non-whitespace token.
9292
*/
93-
private function seekToNextReleventToken(\Iterator $tokenIterator)
93+
private function seekToNextRelevantToken(\Iterator $tokenIterator)
9494
{
9595
for (; $tokenIterator->valid(); $tokenIterator->next()) {
9696
$t = $tokenIterator->current();
@@ -153,7 +153,7 @@ protected function parseTokens($tokens, MessageCatalogue $catalog)
153153
$tokenIterator->seek($key);
154154

155155
foreach ($sequence as $item) {
156-
$this->seekToNextReleventToken($tokenIterator);
156+
$this->seekToNextRelevantToken($tokenIterator);
157157

158158
if ($this->normalizeToken($tokenIterator->current()) == $item) {
159159
$tokenIterator->next();

src/Symfony/Component/Security/Core/Tests/User/InMemoryUserProviderTest.php

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,39 @@ class InMemoryUserProviderTest extends \PHPUnit_Framework_TestCase
1818
{
1919
public function testConstructor()
2020
{
21-
$provider = new InMemoryUserProvider(array(
21+
$provider = $this->createProvider();
22+
23+
$user = $provider->loadUserByUsername('fabien');
24+
$this->assertEquals('foo', $user->getPassword());
25+
$this->assertEquals(array('ROLE_USER'), $user->getRoles());
26+
$this->assertFalse($user->isEnabled());
27+
}
28+
29+
public function testRefresh()
30+
{
31+
$user = new User('fabien', 'bar');
32+
33+
$provider = $this->createProvider();
34+
35+
$refreshedUser = $provider->refreshUser($user);
36+
$this->assertEquals('foo', $refreshedUser->getPassword());
37+
$this->assertEquals(array('ROLE_USER'), $refreshedUser->getRoles());
38+
$this->assertFalse($refreshedUser->isEnabled());
39+
$this->assertFalse($refreshedUser->isCredentialsNonExpired());
40+
}
41+
42+
/**
43+
* @return InMemoryUserProvider
44+
*/
45+
protected function createProvider()
46+
{
47+
return new InMemoryUserProvider(array(
2248
'fabien' => array(
2349
'password' => 'foo',
2450
'enabled' => false,
2551
'roles' => array('ROLE_USER'),
2652
),
2753
));
28-
29-
$user = $provider->loadUserByUsername('fabien');
30-
$this->assertEquals('foo', $user->getPassword());
31-
$this->assertEquals(array('ROLE_USER'), $user->getRoles());
32-
$this->assertFalse($user->isEnabled());
3354
}
3455

3556
public function testCreateUser()

src/Symfony/Component/Security/Core/User/InMemoryUserProvider.php

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,9 @@ public function createUser(UserInterface $user)
6767
*/
6868
public function loadUserByUsername($username)
6969
{
70-
if (!isset($this->users[strtolower($username)])) {
71-
$ex = new UsernameNotFoundException(sprintf('Username "%s" does not exist.', $username));
72-
$ex->setUsername($username);
73-
74-
throw $ex;
75-
}
70+
$user = $this->getUser($username);
7671

77-
$user = $this->users[strtolower($username)];
78-
79-
return new User($user->getUsername(), $user->getPassword(), $user->getRoles(), $user->isEnabled(), $user->isAccountNonExpired(),
80-
$user->isCredentialsNonExpired(), $user->isAccountNonLocked());
72+
return new User($user->getUsername(), $user->getPassword(), $user->getRoles(), $user->isEnabled(), $user->isAccountNonExpired(), $user->isCredentialsNonExpired(), $user->isAccountNonLocked());
8173
}
8274

8375
/**
@@ -89,7 +81,9 @@ public function refreshUser(UserInterface $user)
8981
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user)));
9082
}
9183

92-
return $this->loadUserByUsername($user->getUsername());
84+
$storedUser = $this->getUser($user->getUsername());
85+
86+
return new User($storedUser->getUsername(), $storedUser->getPassword(), $storedUser->getRoles(), $storedUser->isEnabled(), $storedUser->isAccountNonExpired(), $storedUser->isCredentialsNonExpired() && $storedUser->getPassword() === $user->getPassword(), $storedUser->isAccountNonLocked());
9387
}
9488

9589
/**
@@ -99,4 +93,25 @@ public function supportsClass($class)
9993
{
10094
return $class === 'Symfony\Component\Security\Core\User\User';
10195
}
96+
97+
/**
98+
* Returns the user by given username.
99+
*
100+
* @param string $username The username.
101+
*
102+
* @return User
103+
*
104+
* @throws UsernameNotFoundException If user whose given username does not exist.
105+
*/
106+
private function getUser($username)
107+
{
108+
if (!isset($this->users[strtolower($username)])) {
109+
$ex = new UsernameNotFoundException(sprintf('Username "%s" does not exist.', $username));
110+
$ex->setUsername($username);
111+
112+
throw $ex;
113+
}
114+
115+
return $this->users[strtolower($username)];
116+
}
102117
}

src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ protected function cancelCookie(Request $request)
293293
$this->logger->debug('Clearing remember-me cookie.', array('name' => $this->options['name']));
294294
}
295295

296-
$request->attributes->set(self::COOKIE_ATTR_NAME, new Cookie($this->options['name'], null, 1, $this->options['path'], $this->options['domain']));
296+
$request->attributes->set(self::COOKIE_ATTR_NAME, new Cookie($this->options['name'], null, 1, $this->options['path'], $this->options['domain'], $this->options['secure'], $this->options['httponly']));
297297
}
298298

299299
/**

src/Symfony/Component/Security/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,16 +82,35 @@ public function testAutoLogin()
8282
$this->assertSame('fookey', $returnedToken->getProviderKey());
8383
}
8484

85-
public function testLogout()
85+
/**
86+
* @dataProvider provideOptionsForLogout
87+
*/
88+
public function testLogout(array $options)
8689
{
87-
$service = $this->getService(null, array('name' => 'foo', 'path' => null, 'domain' => null));
90+
$service = $this->getService(null, $options);
8891
$request = new Request();
8992
$response = new Response();
9093
$token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
9194

9295
$service->logout($request, $response, $token);
9396

94-
$this->assertTrue($request->attributes->get(RememberMeServicesInterface::COOKIE_ATTR_NAME)->isCleared());
97+
$cookie = $request->attributes->get(RememberMeServicesInterface::COOKIE_ATTR_NAME);
98+
99+
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Cookie', $cookie);
100+
$this->assertTrue($cookie->isCleared());
101+
$this->assertSame($options['name'], $cookie->getName());
102+
$this->assertSame($options['path'], $cookie->getPath());
103+
$this->assertSame($options['domain'], $cookie->getDomain());
104+
$this->assertSame($options['secure'], $cookie->isSecure());
105+
$this->assertSame($options['httponly'], $cookie->isHttpOnly());
106+
}
107+
108+
public function provideOptionsForLogout()
109+
{
110+
return array(
111+
array(array('name' => 'foo', 'path' => '/', 'domain' => null, 'secure' => false, 'httponly' => true)),
112+
array(array('name' => 'foo', 'path' => '/bar', 'domain' => 'baz.com', 'secure' => true, 'httponly' => false)),
113+
);
95114
}
96115

97116
public function testLoginFail()
@@ -267,6 +286,13 @@ protected function getService($userProvider = null, $options = array(), $logger
267286
$userProvider = $this->getProvider();
268287
}
269288

289+
if (!isset($options['secure'])) {
290+
$options['secure'] = false;
291+
}
292+
if (!isset($options['httponly'])) {
293+
$options['httponly'] = true;
294+
}
295+
270296
return $this->getMockForAbstractClass('Symfony\Component\Security\Http\RememberMe\AbstractRememberMeServices', array(
271297
array($userProvider), 'fookey', 'fookey', $options, $logger,
272298
));

src/Symfony/Component/Security/Http/Tests/RememberMe/PersistentTokenBasedRememberMeServicesTest.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ public function testAutoLogin()
180180

181181
public function testLogout()
182182
{
183-
$service = $this->getService(null, array('name' => 'foo', 'path' => '/foo', 'domain' => 'foodomain.foo'));
183+
$service = $this->getService(null, array('name' => 'foo', 'path' => '/foo', 'domain' => 'foodomain.foo', 'secure' => true, 'httponly' => false));
184184
$request = new Request();
185185
$request->cookies->set('foo', $this->encodeCookie(array('fooseries', 'foovalue')));
186186
$response = new Response();
@@ -201,6 +201,8 @@ public function testLogout()
201201
$this->assertTrue($cookie->isCleared());
202202
$this->assertEquals('/foo', $cookie->getPath());
203203
$this->assertEquals('foodomain.foo', $cookie->getDomain());
204+
$this->assertTrue($cookie->isSecure());
205+
$this->assertFalse($cookie->isHttpOnly());
204206
}
205207

206208
public function testLogoutSimplyIgnoresNonSetRequestCookie()
@@ -311,6 +313,13 @@ protected function getService($userProvider = null, $options = array(), $logger
311313
$userProvider = $this->getProvider();
312314
}
313315

316+
if (!isset($options['secure'])) {
317+
$options['secure'] = false;
318+
}
319+
if (!isset($options['httponly'])) {
320+
$options['httponly'] = true;
321+
}
322+
314323
return new PersistentTokenBasedRememberMeServices(array($userProvider), 'fookey', 'fookey', $options, $logger, new SecureRandom(sys_get_temp_dir().'/_sf2.seed'));
315324
}
316325

src/Symfony/Component/Security/Http/Tests/RememberMe/TokenBasedRememberMeServicesTest.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ public function provideUsernamesForAutoLogin()
153153

154154
public function testLogout()
155155
{
156-
$service = $this->getService(null, array('name' => 'foo', 'path' => null, 'domain' => null));
156+
$service = $this->getService(null, array('name' => 'foo', 'path' => null, 'domain' => null, 'secure' => true, 'httponly' => false));
157157
$request = new Request();
158158
$response = new Response();
159159
$token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
@@ -164,6 +164,8 @@ public function testLogout()
164164
$this->assertTrue($cookie->isCleared());
165165
$this->assertEquals('/', $cookie->getPath());
166166
$this->assertNull($cookie->getDomain());
167+
$this->assertTrue($cookie->isSecure());
168+
$this->assertFalse($cookie->isHttpOnly());
167169
}
168170

169171
public function testLoginFail()
@@ -264,6 +266,13 @@ protected function getService($userProvider = null, $options = array(), $logger
264266
$userProvider = $this->getProvider();
265267
}
266268

269+
if (!isset($options['secure'])) {
270+
$options['secure'] = false;
271+
}
272+
if (!isset($options['httponly'])) {
273+
$options['httponly'] = true;
274+
}
275+
267276
$service = new TokenBasedRememberMeServices(array($userProvider), 'fookey', 'fookey', $options, $logger);
268277

269278
return $service;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy