From 9bb194098f6df090f4174096c1e9a86a903f9b87 Mon Sep 17 00:00:00 2001 From: Jules Pietri Date: Wed, 5 Feb 2020 19:53:27 +0100 Subject: [PATCH 1/5] [DoctrineBridge] Fixed submitting ids with query limit or offset --- .../Form/ChoiceList/ORMQueryBuilderLoader.php | 2 +- .../Tests/Form/Type/EntityTypeTest.php | 27 ++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php index 875b08dae9..9c1f779e5f 100644 --- a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php +++ b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php @@ -62,7 +62,7 @@ class ORMQueryBuilderLoader implements EntityLoaderInterface $metadata = $this->queryBuilder->getEntityManager()->getClassMetadata(current($this->queryBuilder->getRootEntities())); foreach ($this->getEntities() as $entity) { - if (\in_array(current($metadata->getIdentifierValues($entity)), $values, true)) { + if (\in_array((string) current($metadata->getIdentifierValues($entity)), $values, true)) { $choices[] = $entity; } } diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php index bc12de5d42..7bb57d707d 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php @@ -956,7 +956,32 @@ class EntityTypeTest extends BaseTypeTest $this->assertNull($field->getData()); } - public function testDisallowChoicesThatAreNotIncludedQueryBuilderSingleIdentifierWithLimit() + public function testSingleIdentifierWithLimit() + { + $entity1 = new SingleIntIdEntity(1, 'Foo'); + $entity2 = new SingleIntIdEntity(2, 'Bar'); + $entity3 = new SingleIntIdEntity(3, 'Baz'); + + $this->persist([$entity1, $entity2, $entity3]); + + $repository = $this->em->getRepository(self::SINGLE_IDENT_CLASS); + + $field = $this->factory->createNamed('name', static::TESTED_TYPE, null, [ + 'em' => 'default', + 'class' => self::SINGLE_IDENT_CLASS, + 'query_builder' => $repository->createQueryBuilder('e') + ->where('e.id IN (1, 2, 3)') + ->setMaxResults(1), + 'choice_label' => 'name', + ]); + + $field->submit('1'); + + $this->assertTrue($field->isSynchronized()); + $this->assertSame($entity1, $field->getData()); + } + + public function testDisallowChoicesThatAreNotIncludedByQueryBuilderSingleIdentifierWithLimit() { $entity1 = new SingleIntIdEntity(1, 'Foo'); $entity2 = new SingleIntIdEntity(2, 'Bar'); From f46e6cb8a086d0c44502cf35e699a1aa0044b11c Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 4 Sep 2018 10:27:39 +0200 Subject: [PATCH 2/5] [HttpFoundation][FrameworkBundle] fix support for samesite in session cookies --- .../DependencyInjection/Configuration.php | 2 + .../FrameworkExtension.php | 2 +- .../DependencyInjection/ConfigurationTest.php | 1 + .../HttpFoundation/Session/SessionUtils.php | 59 +++++++++++++++++++ .../Handler/AbstractSessionHandler.php | 48 +++++++-------- .../Session/Storage/NativeSessionStorage.php | 42 +++++++++++-- .../Storage/Handler/Fixtures/storage.expected | 3 +- .../Fixtures/with_cookie_and_session.expected | 1 + .../Handler/Fixtures/with_samesite.expected | 16 +++++ .../Handler/Fixtures/with_samesite.php | 13 ++++ .../with_samesite_and_migration.expected | 23 ++++++++ .../Fixtures/with_samesite_and_migration.php | 15 +++++ .../Storage/NativeSessionStorageTest.php | 8 ++- 13 files changed, 195 insertions(+), 38 deletions(-) create mode 100644 src/Symfony/Component/HttpFoundation/Session/SessionUtils.php create mode 100644 src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/with_samesite.expected create mode 100644 src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/with_samesite.php create mode 100644 src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/with_samesite_and_migration.expected create mode 100644 src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/with_samesite_and_migration.php diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 00316daf55..67ddeb2f8b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -20,6 +20,7 @@ use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\Form\Form; +use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\Lock\Lock; use Symfony\Component\Lock\Store\SemaphoreStore; use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface; @@ -490,6 +491,7 @@ class Configuration implements ConfigurationInterface ->scalarNode('cookie_domain')->end() ->booleanNode('cookie_secure')->end() ->booleanNode('cookie_httponly')->defaultTrue()->end() + ->enumNode('cookie_samesite')->values([null, Cookie::SAMESITE_LAX, Cookie::SAMESITE_STRICT])->defaultNull()->end() ->booleanNode('use_cookies')->end() ->scalarNode('gc_divisor')->end() ->scalarNode('gc_probability')->defaultValue(1)->end() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 3e28e52ad3..1762112a49 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -867,7 +867,7 @@ class FrameworkExtension extends Extension // session storage $container->setAlias('session.storage', $config['storage_id'])->setPrivate(true); $options = ['cache_limiter' => '0']; - foreach (['name', 'cookie_lifetime', 'cookie_path', 'cookie_domain', 'cookie_secure', 'cookie_httponly', 'use_cookies', 'gc_maxlifetime', 'gc_probability', 'gc_divisor', 'use_strict_mode'] as $key) { + foreach (['name', 'cookie_lifetime', 'cookie_path', 'cookie_domain', 'cookie_secure', 'cookie_httponly', 'cookie_samesite', 'use_cookies', 'gc_maxlifetime', 'gc_probability', 'gc_divisor'] as $key) { if (isset($config[$key])) { $options[$key] = $config[$key]; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index e66c9ebfc6..dbfd38f34d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -436,6 +436,7 @@ class ConfigurationTest extends TestCase 'storage_id' => 'session.storage.native', 'handler_id' => 'session.handler.native_file', 'cookie_httponly' => true, + 'cookie_samesite' => null, 'gc_probability' => 1, 'save_path' => '%kernel.cache_dir%/sessions', 'metadata_update_threshold' => '0', diff --git a/src/Symfony/Component/HttpFoundation/Session/SessionUtils.php b/src/Symfony/Component/HttpFoundation/Session/SessionUtils.php new file mode 100644 index 0000000000..04a25f7165 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Session/SessionUtils.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Session; + +/** + * Session utility functions. + * + * @author Nicolas Grekas + * @author RĂ©mon van de Kamp + * + * @internal + */ +final class SessionUtils +{ + /** + * Find the session header amongst the headers that are to be sent, remove it, and return + * it so the caller can process it further. + */ + public static function popSessionCookie($sessionName, $sessionId) + { + $sessionCookie = null; + $sessionCookiePrefix = sprintf(' %s=', urlencode($sessionName)); + $sessionCookieWithId = sprintf('%s%s;', $sessionCookiePrefix, urlencode($sessionId)); + $otherCookies = []; + foreach (headers_list() as $h) { + if (0 !== stripos($h, 'Set-Cookie:')) { + continue; + } + if (11 === strpos($h, $sessionCookiePrefix, 11)) { + $sessionCookie = $h; + + if (11 !== strpos($h, $sessionCookieWithId, 11)) { + $otherCookies[] = $h; + } + } else { + $otherCookies[] = $h; + } + } + if (null === $sessionCookie) { + return null; + } + + header_remove('Set-Cookie'); + foreach ($otherCookies as $h) { + header($h, false); + } + + return $sessionCookie; + } +} diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/AbstractSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/AbstractSessionHandler.php index 84ba0ebba3..ec59d895ce 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/AbstractSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/AbstractSessionHandler.php @@ -11,6 +11,8 @@ namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; +use Symfony\Component\HttpFoundation\Session\SessionUtils; + /** * This abstract session handler provides a generic implementation * of the PHP 7.0 SessionUpdateTimestampHandlerInterface, @@ -27,7 +29,7 @@ abstract class AbstractSessionHandler implements \SessionHandlerInterface, \Sess private $igbinaryEmptyData; /** - * {@inheritdoc} + * @return bool */ public function open($savePath, $sessionName) { @@ -62,7 +64,7 @@ abstract class AbstractSessionHandler implements \SessionHandlerInterface, \Sess abstract protected function doDestroy($sessionId); /** - * {@inheritdoc} + * @return bool */ public function validateId($sessionId) { @@ -73,7 +75,7 @@ abstract class AbstractSessionHandler implements \SessionHandlerInterface, \Sess } /** - * {@inheritdoc} + * @return string */ public function read($sessionId) { @@ -99,7 +101,7 @@ abstract class AbstractSessionHandler implements \SessionHandlerInterface, \Sess } /** - * {@inheritdoc} + * @return bool */ public function write($sessionId, $data) { @@ -124,7 +126,7 @@ abstract class AbstractSessionHandler implements \SessionHandlerInterface, \Sess } /** - * {@inheritdoc} + * @return bool */ public function destroy($sessionId) { @@ -135,32 +137,24 @@ abstract class AbstractSessionHandler implements \SessionHandlerInterface, \Sess if (!$this->sessionName) { throw new \LogicException(sprintf('Session name cannot be empty, did you forget to call "parent::open()" in "%s"?.', static::class)); } - $sessionCookie = sprintf(' %s=', urlencode($this->sessionName)); - $sessionCookieWithId = sprintf('%s%s;', $sessionCookie, urlencode($sessionId)); - $sessionCookieFound = false; - $otherCookies = []; - foreach (headers_list() as $h) { - if (0 !== stripos($h, 'Set-Cookie:')) { - continue; - } - if (11 === strpos($h, $sessionCookie, 11)) { - $sessionCookieFound = true; + $cookie = SessionUtils::popSessionCookie($this->sessionName, $sessionId); - if (11 !== strpos($h, $sessionCookieWithId, 11)) { - $otherCookies[] = $h; - } + /* + * We send an invalidation Set-Cookie header (zero lifetime) + * when either the session was started or a cookie with + * the session name was sent by the client (in which case + * we know it's invalid as a valid session cookie would've + * started the session). + */ + if (null === $cookie || isset($_COOKIE[$this->sessionName])) { + if (\PHP_VERSION_ID < 70300) { + setcookie($this->sessionName, '', 0, ini_get('session.cookie_path'), ini_get('session.cookie_domain'), filter_var(ini_get('session.cookie_secure'), FILTER_VALIDATE_BOOLEAN), filter_var(ini_get('session.cookie_httponly'), FILTER_VALIDATE_BOOLEAN)); } else { - $otherCookies[] = $h; + $params = session_get_cookie_params(); + unset($params['lifetime']); + setcookie($this->sessionName, '', $params); } } - if ($sessionCookieFound) { - header_remove('Set-Cookie'); - foreach ($otherCookies as $h) { - header($h, false); - } - } else { - setcookie($this->sessionName, '', 0, ini_get('session.cookie_path'), ini_get('session.cookie_domain'), filter_var(ini_get('session.cookie_secure'), FILTER_VALIDATE_BOOLEAN), filter_var(ini_get('session.cookie_httponly'), FILTER_VALIDATE_BOOLEAN)); - } } return $this->newSessionId === $sessionId || $this->doDestroy($sessionId); diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php index cbf7cadc7e..7502897a44 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php @@ -12,6 +12,7 @@ namespace Symfony\Component\HttpFoundation\Session\Storage; use Symfony\Component\HttpFoundation\Session\SessionBagInterface; +use Symfony\Component\HttpFoundation\Session\SessionUtils; use Symfony\Component\HttpFoundation\Session\Storage\Handler\StrictSessionHandler; use Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy; use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy; @@ -48,6 +49,11 @@ class NativeSessionStorage implements SessionStorageInterface */ protected $metadataBag; + /** + * @var string|null + */ + private $emulateSameSite; + /** * Depending on how you want the storage driver to behave you probably * want to override this constructor entirely. @@ -67,6 +73,7 @@ class NativeSessionStorage implements SessionStorageInterface * cookie_lifetime, "0" * cookie_path, "/" * cookie_secure, "" + * cookie_samesite, null * entropy_file, "" * entropy_length, "0" * gc_divisor, "100" @@ -94,9 +101,7 @@ class NativeSessionStorage implements SessionStorageInterface * trans_sid_hosts, $_SERVER['HTTP_HOST'] * trans_sid_tags, "a=href,area=href,frame=src,form=" * - * @param array $options Session configuration options - * @param \SessionHandlerInterface|null $handler - * @param MetadataBag $metaBag MetadataBag + * @param AbstractProxy|\SessionHandlerInterface|null $handler */ public function __construct(array $options = [], $handler = null, MetadataBag $metaBag = null) { @@ -150,6 +155,13 @@ class NativeSessionStorage implements SessionStorageInterface throw new \RuntimeException('Failed to start the session'); } + if (null !== $this->emulateSameSite) { + $originalCookie = SessionUtils::popSessionCookie(session_name(), session_id()); + if (null !== $originalCookie) { + header(sprintf('%s; SameSite=%s', $originalCookie, $this->emulateSameSite), false); + } + } + $this->loadSession(); return true; @@ -215,6 +227,13 @@ class NativeSessionStorage implements SessionStorageInterface // @see https://bugs.php.net/70013 $this->loadSession(); + if (null !== $this->emulateSameSite) { + $originalCookie = SessionUtils::popSessionCookie(session_name(), session_id()); + if (null !== $originalCookie) { + header(sprintf('%s; SameSite=%s', $originalCookie, $this->emulateSameSite), false); + } + } + return $isRegenerated; } @@ -223,6 +242,7 @@ class NativeSessionStorage implements SessionStorageInterface */ public function save() { + // Store a copy so we can restore the bags in case the session was not left empty $session = $_SESSION; foreach ($this->bags as $bag) { @@ -248,7 +268,11 @@ class NativeSessionStorage implements SessionStorageInterface session_write_close(); } finally { restore_error_handler(); - $_SESSION = $session; + + // Restore only if not empty + if ($_SESSION) { + $_SESSION = $session; + } } $this->closed = true; @@ -347,7 +371,7 @@ class NativeSessionStorage implements SessionStorageInterface $validOptions = array_flip([ 'cache_expire', 'cache_limiter', 'cookie_domain', 'cookie_httponly', - 'cookie_lifetime', 'cookie_path', 'cookie_secure', + 'cookie_lifetime', 'cookie_path', 'cookie_secure', 'cookie_samesite', 'entropy_file', 'entropy_length', 'gc_divisor', 'gc_maxlifetime', 'gc_probability', 'hash_bits_per_character', 'hash_function', 'lazy_write', 'name', 'referer_check', @@ -360,6 +384,12 @@ class NativeSessionStorage implements SessionStorageInterface foreach ($options as $key => $value) { if (isset($validOptions[$key])) { + if ('cookie_samesite' === $key && \PHP_VERSION_ID < 70300) { + // PHP < 7.3 does not support same_site cookies. We will emulate it in + // the start() method instead. + $this->emulateSameSite = $value; + continue; + } ini_set('url_rewriter.tags' !== $key ? 'session.'.$key : $key, $value); } } @@ -381,7 +411,7 @@ class NativeSessionStorage implements SessionStorageInterface * @see https://php.net/sessionhandlerinterface * @see https://php.net/sessionhandler * - * @param \SessionHandlerInterface|null $saveHandler + * @param AbstractProxy|\SessionHandlerInterface|null $saveHandler * * @throws \InvalidArgumentException */ diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/storage.expected b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/storage.expected index 4533a10a1f..05a5d5d0b0 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/storage.expected +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/storage.expected @@ -11,10 +11,11 @@ $_SESSION is not empty write destroy close -$_SESSION is not empty +$_SESSION is empty Array ( [0] => Content-Type: text/plain; charset=utf-8 [1] => Cache-Control: max-age=0, private, must-revalidate + [2] => Set-Cookie: sid=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly ) shutdown diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/with_cookie_and_session.expected b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/with_cookie_and_session.expected index 5de2d9e390..63078228df 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/with_cookie_and_session.expected +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/with_cookie_and_session.expected @@ -20,5 +20,6 @@ Array [0] => Content-Type: text/plain; charset=utf-8 [1] => Cache-Control: max-age=10800, private, must-revalidate [2] => Set-Cookie: abc=def + [3] => Set-Cookie: sid=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly ) shutdown diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/with_samesite.expected b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/with_samesite.expected new file mode 100644 index 0000000000..d20fb88ec0 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/with_samesite.expected @@ -0,0 +1,16 @@ +open +validateId +read +doRead: +read + +write +doWrite: foo|s:3:"bar"; +close +Array +( + [0] => Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=0, private, must-revalidate + [2] => Set-Cookie: sid=random_session_id; path=/; secure; HttpOnly; SameSite=lax +) +shutdown diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/with_samesite.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/with_samesite.php new file mode 100644 index 0000000000..fc2c418289 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/with_samesite.php @@ -0,0 +1,13 @@ + 'lax']); +$storage->setSaveHandler(new TestSessionHandler()); +$storage->start(); + +$_SESSION = ['foo' => 'bar']; + +ob_start(function ($buffer) { return str_replace(session_id(), 'random_session_id', $buffer); }); diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/with_samesite_and_migration.expected b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/with_samesite_and_migration.expected new file mode 100644 index 0000000000..8b5fc08bd3 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/with_samesite_and_migration.expected @@ -0,0 +1,23 @@ +open +validateId +read +doRead: +read +destroy +close +open +validateId +read +doRead: +read + +write +doWrite: foo|s:3:"bar"; +close +Array +( + [0] => Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=0, private, must-revalidate + [2] => Set-Cookie: sid=random_session_id; path=/; secure; HttpOnly; SameSite=lax +) +shutdown diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/with_samesite_and_migration.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/with_samesite_and_migration.php new file mode 100644 index 0000000000..a28b6fedfc --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/with_samesite_and_migration.php @@ -0,0 +1,15 @@ + 'lax']); +$storage->setSaveHandler(new TestSessionHandler()); +$storage->start(); + +$_SESSION = ['foo' => 'bar']; + +$storage->regenerate(true); + +ob_start(function ($buffer) { return preg_replace('~_sf2_meta.*$~m', '', str_replace(session_id(), 'random_session_id', $buffer)); }); diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/NativeSessionStorageTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/NativeSessionStorageTest.php index 9ce8108dac..d2cf324525 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/NativeSessionStorageTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/NativeSessionStorageTest.php @@ -36,7 +36,7 @@ class NativeSessionStorageTest extends TestCase protected function setUp() { $this->iniSet('session.save_handler', 'files'); - $this->iniSet('session.save_path', $this->savePath = sys_get_temp_dir().'/sf2test'); + $this->iniSet('session.save_path', $this->savePath = sys_get_temp_dir().'/sftest'); if (!is_dir($this->savePath)) { mkdir($this->savePath); } @@ -167,6 +167,10 @@ class NativeSessionStorageTest extends TestCase 'cookie_httponly' => false, ]; + if (\PHP_VERSION_ID >= 70300) { + $options['cookie_samesite'] = 'lax'; + } + $this->getStorage($options); $temp = session_get_cookie_params(); $gco = []; @@ -175,8 +179,6 @@ class NativeSessionStorageTest extends TestCase $gco['cookie_'.$key] = $value; } - unset($gco['cookie_samesite']); - $this->assertEquals($options, $gco); } From 3604bb701885fb5330175c96b91522420a7e0496 Mon Sep 17 00:00:00 2001 From: Wim Molenberghs Date: Fri, 7 Feb 2020 07:50:31 +0100 Subject: [PATCH 3/5] Update UserPasswordEncoderCommand.php --- .../SecurityBundle/Command/UserPasswordEncoderCommand.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Command/UserPasswordEncoderCommand.php b/src/Symfony/Bundle/SecurityBundle/Command/UserPasswordEncoderCommand.php index a5537eca5d..3f33624432 100644 --- a/src/Symfony/Bundle/SecurityBundle/Command/UserPasswordEncoderCommand.php +++ b/src/Symfony/Bundle/SecurityBundle/Command/UserPasswordEncoderCommand.php @@ -87,16 +87,16 @@ generated to encode the password: Pass the full user class path as the second argument to encode passwords for your own entities: - php %command.full_name% --no-interaction [password] App\Entity\User + php %command.full_name% --no-interaction [password] 'App\Entity\User' Executing the command interactively allows you to generate a random salt for encoding the password: - php %command.full_name% [password] App\Entity\User + php %command.full_name% [password] 'App\Entity\User' In case your encoder doesn't require a salt, add the empty-salt option: - php %command.full_name% --empty-salt [password] App\Entity\User + php %command.full_name% --empty-salt [password] 'App\Entity\User' EOF ) From ef157d5b3f299206d0a76f1d2f63b684a14db02c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Ostroluck=C3=BD?= Date: Mon, 7 Oct 2019 22:32:49 +0200 Subject: [PATCH 4/5] [Console] Consider STDIN interactive --- src/Symfony/Component/Console/Application.php | 11 -------- .../Console/Tester/ApplicationTester.php | 9 +----- .../phpt/uses_stdin_as_interactive_input.phpt | 28 +++++++++++++++++++ 3 files changed, 29 insertions(+), 19 deletions(-) create mode 100644 src/Symfony/Component/Console/Tests/phpt/uses_stdin_as_interactive_input.phpt diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index 410900cc2b..acd3268788 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -36,7 +36,6 @@ use Symfony\Component\Console\Input\InputAwareInterface; use Symfony\Component\Console\Input\InputDefinition; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\Console\Input\StreamableInputInterface; use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -947,16 +946,6 @@ class Application implements ResetInterface if (true === $input->hasParameterOption(['--no-interaction', '-n'], true)) { $input->setInteractive(false); - } elseif (\function_exists('posix_isatty')) { - $inputStream = null; - - if ($input instanceof StreamableInputInterface) { - $inputStream = $input->getStream(); - } - - if (!@posix_isatty($inputStream) && false === getenv('SHELL_INTERACTIVE')) { - $input->setInteractive(false); - } } switch ($shellVerbosity = (int) getenv('SHELL_VERBOSITY')) { diff --git a/src/Symfony/Component/Console/Tester/ApplicationTester.php b/src/Symfony/Component/Console/Tester/ApplicationTester.php index ced56cff20..4f99da18d5 100644 --- a/src/Symfony/Component/Console/Tester/ApplicationTester.php +++ b/src/Symfony/Component/Console/Tester/ApplicationTester.php @@ -59,19 +59,12 @@ class ApplicationTester $this->input->setInteractive($options['interactive']); } - $shellInteractive = getenv('SHELL_INTERACTIVE'); - if ($this->inputs) { $this->input->setStream(self::createStream($this->inputs)); - putenv('SHELL_INTERACTIVE=1'); } $this->initOutput($options); - $this->statusCode = $this->application->run($this->input, $this->output); - - putenv($shellInteractive ? "SHELL_INTERACTIVE=$shellInteractive" : 'SHELL_INTERACTIVE'); - - return $this->statusCode; + return $this->statusCode = $this->application->run($this->input, $this->output); } } diff --git a/src/Symfony/Component/Console/Tests/phpt/uses_stdin_as_interactive_input.phpt b/src/Symfony/Component/Console/Tests/phpt/uses_stdin_as_interactive_input.phpt new file mode 100644 index 0000000000..db1bb4ce43 --- /dev/null +++ b/src/Symfony/Component/Console/Tests/phpt/uses_stdin_as_interactive_input.phpt @@ -0,0 +1,28 @@ +--STDIN-- +Hello World +--FILE-- +register('app') + ->setCode(function(InputInterface $input, OutputInterface $output) { + $output->writeln((new QuestionHelper())->ask($input, $output, new Question('Foo?'))); + }) + ->getApplication() + ->setDefaultCommand('app', true) + ->run() +; +--EXPECT-- +Foo?Hello World From abac71b0a44bfb11c60e21a3f50f0ca3c16021d2 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 7 Feb 2020 09:43:36 +0100 Subject: [PATCH 5/5] [FrameworkBundle] fix "samesite" in XSD --- .../DependencyInjection/Configuration.php | 2 +- .../Resources/config/schema/symfony-1.0.xsd | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 67ddeb2f8b..400c8a7920 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -491,7 +491,7 @@ class Configuration implements ConfigurationInterface ->scalarNode('cookie_domain')->end() ->booleanNode('cookie_secure')->end() ->booleanNode('cookie_httponly')->defaultTrue()->end() - ->enumNode('cookie_samesite')->values([null, Cookie::SAMESITE_LAX, Cookie::SAMESITE_STRICT])->defaultNull()->end() + ->enumNode('cookie_samesite')->values([null, Cookie::SAMESITE_LAX, Cookie::SAMESITE_STRICT, Cookie::SAMESITE_NONE])->defaultNull()->end() ->booleanNode('use_cookies')->end() ->scalarNode('gc_divisor')->end() ->scalarNode('gc_probability')->defaultValue(1)->end() diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 531f7dddb9..39011822e9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -113,6 +113,7 @@ + @@ -306,6 +307,15 @@ + + + + + + + + +