diff --git a/app/config/eccube/packages/framework.yaml b/app/config/eccube/packages/framework.yaml index 585d4322d42..6145711bcc8 100644 --- a/app/config/eccube/packages/framework.yaml +++ b/app/config/eccube/packages/framework.yaml @@ -8,10 +8,9 @@ framework: trusted_hosts: ~ # https://symfony.com/doc/current/reference/configuration/framework.html#handler-id session: - handler_id: session.handler.native_file + handler_id: 'Eccube\Session\Storage\Handler\SameSiteNoneCompatSessionHandler' save_path: '%kernel.project_dir%/var/sessions/%kernel.environment%' name: '%env(ECCUBE_COOKIE_NAME)%' - cookie_path: '%env(ECCUBE_COOKIE_PATH)%' cookie_lifetime: '%env(ECCUBE_COOKIE_LIFETIME)%' gc_maxlifetime: '%env(ECCUBE_GC_MAXLIFETIME)%' cookie_httponly: true diff --git a/app/config/eccube/services.yaml b/app/config/eccube/services.yaml index 9d6a5e34c83..1cb1730ce3f 100644 --- a/app/config/eccube/services.yaml +++ b/app/config/eccube/services.yaml @@ -171,3 +171,10 @@ services: # Symfony\Bridge\Twig\Extension\RoutingExtensionの後に登録するため, # autoconfigureはfalseにし, CompilerPassで追加する. autoconfigure: false + + native_file_session_handler: + class: Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler + + Eccube\Session\Storage\Handler\SameSiteNoneCompatSessionHandler: + arguments: + - '@native_file_session_handler' diff --git a/composer.json b/composer.json index b0614e13f26..4d459c9728c 100644 --- a/composer.json +++ b/composer.json @@ -50,6 +50,7 @@ "sensio/generator-bundle": "^3.1", "setasign/fpdi": "^2.2", "setasign/fpdi-tcpdf": "^2.2", + "skorp/detect-incompatible-samesite-useragents": "^1.0", "suncat/mobile-detect-bundle": "^1.1", "swiftmailer/swiftmailer": "^6.1", "symfony/asset": "^3.4", diff --git a/composer.lock b/composer.lock index 2d78c5aeeeb..b959620205b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "1c7efc44402b4eb643446b45fbc2d105", + "content-hash": "9f90fb1a2efd3a3160e24841a6a19488", "packages": [ { "name": "composer/ca-bundle", @@ -1686,6 +1686,7 @@ "monolog", "productivity" ], + "abandoned": true, "time": "2019-10-24T07:13:31+00:00" }, { @@ -3347,6 +3348,7 @@ } ], "description": "This bundle generates code for you", + "abandoned": "symfony/maker-bundle", "time": "2017-12-07T15:36:41+00:00" }, { @@ -3447,8 +3449,53 @@ "fpdi", "pdf" ], + "abandoned": true, "time": "2019-01-30T14:39:33+00:00" }, + { + "name": "skorp/detect-incompatible-samesite-useragents", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/skorp/detect-incompatible-samesite-useragents.git", + "reference": "4299c61f8c4edac2b63fd8629408d0bfc5ad76d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/skorp/detect-incompatible-samesite-useragents/zipball/4299c61f8c4edac2b63fd8629408d0bfc5ad76d9", + "reference": "4299c61f8c4edac2b63fd8629408d0bfc5ad76d9", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Skorp\\Dissua\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kadir Özdemir" + } + ], + "description": "Determine if UserAgent is incompatible with SameSite=None", + "keywords": [ + "cookies", + "safari", + "samesite", + "samesite cookie" + ], + "time": "2020-01-29T21:12:37+00:00" + }, { "name": "suncat/mobile-detect-bundle", "version": "v1.1.1", @@ -7569,6 +7616,7 @@ "code", "zf" ], + "abandoned": "laminas/laminas-code", "time": "2019-10-05T23:18:22+00:00" }, { @@ -7623,6 +7671,7 @@ "events", "zf2" ], + "abandoned": "laminas/laminas-eventmanager", "time": "2018-04-25T15:33:34+00:00" } ], @@ -8000,12 +8049,12 @@ "version": "1.7.1", "source": { "type": "git", - "url": "https://github.com/facebook/php-webdriver.git", + "url": "https://github.com/php-webdriver/php-webdriver-archive.git", "reference": "e43de70f3c7166169d0f14a374505392734160e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/e43de70f3c7166169d0f14a374505392734160e5", + "url": "https://api.github.com/repos/php-webdriver/php-webdriver-archive/zipball/e43de70f3c7166169d0f14a374505392734160e5", "reference": "e43de70f3c7166169d0f14a374505392734160e5", "shasum": "" }, @@ -8053,6 +8102,7 @@ "selenium", "webdriver" ], + "abandoned": "php-webdriver/webdriver", "time": "2019-06-13T08:02:18+00:00" }, { diff --git a/src/Eccube/Session/Storage/Handler/SameSiteNoneCompatSessionHandler.php b/src/Eccube/Session/Storage/Handler/SameSiteNoneCompatSessionHandler.php new file mode 100644 index 00000000000..f3eaffa8996 --- /dev/null +++ b/src/Eccube/Session/Storage/Handler/SameSiteNoneCompatSessionHandler.php @@ -0,0 +1,213 @@ +handler = $handler; + + ini_set('session.cookie_secure', $this->getCookieSecure()); + ini_set('session.cookie_samesite', $this->getCookieSameSite()); + ini_set('session.cookie_path', $this->getCookiePath()); + } + + /** + * {@inheritdoc} + */ + public function open($savePath, $sessionName) + { + $this->sessionName = $sessionName; + // see https://github.com/symfony/symfony/blob/2adc85d49cbe14e346068fa7e9c2e1f08ab31de6/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/AbstractSessionHandler.php#L35-L37 + if (!headers_sent() && !ini_get('session.cache_limiter') && '0' !== ini_get('session.cache_limiter')) { + header(sprintf('Cache-Control: max-age=%d, private, must-revalidate', 60 * (int) ini_get('session.cache_expire'))); + } + + return $this->handler->open($savePath, $sessionName); + } + + /** + * {@inheritdoc} + */ + protected function doRead($sessionId) + { + return $this->handler->read($sessionId); + } + + /** + * {@inheritdoc} + */ + public function updateTimestamp($sessionId, $data) + { + return $this->write($sessionId, $data); + } + + /** + * {@inheritdoc} + */ + protected function doWrite($sessionId, $data) + { + return $this->handler->write($sessionId, $data); + } + + /** + * {@inheritdoc} + * @see https://github.com/symfony/symfony/blob/2adc85d49cbe14e346068fa7e9c2e1f08ab31de6/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/AbstractSessionHandler.php#L126-L167 + */ + public function destroy($sessionId) + { + if (\PHP_VERSION_ID < 70000) { + $this->prefetchData = null; + } + if (!headers_sent() && filter_var(ini_get('session.use_cookies'), FILTER_VALIDATE_BOOLEAN)) { + if (!$this->sessionName) { + throw new \LogicException(sprintf('Session name cannot be empty, did you forget to call "parent::open()" in "%s"?.', \get_class($this))); + } + $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; + + if (11 !== strpos($h, $sessionCookieWithId, 11)) { + $otherCookies[] = $h; + } + } else { + $otherCookies[] = $h; + } + } + if ($sessionCookieFound) { + header_remove('Set-Cookie'); + foreach ($otherCookies as $h) { + header($h, false); + } + } else { + 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 { + setcookie($this->sessionName, '', + [ + 'expires' => 0, + 'path' => $this->getCookiePath(), + 'domain' => ini_get('session.cookie_domain'), + 'secure' => filter_var(ini_get('session.cookie_secure'), FILTER_VALIDATE_BOOLEAN), + 'httponly' => filter_var(ini_get('session.cookie_httponly'), FILTER_VALIDATE_BOOLEAN), + 'samesite' => $this->getCookieSameSite(), + ] + ); + } + } + } + + return $this->newSessionId === $sessionId || $this->doDestroy($sessionId); + } + + /** + * {@inheritdoc} + */ + protected function doDestroy($sessionId) + { + $this->doDestroy = false; + + return $this->handler->destroy($sessionId); + } + + /** + * {@inheritdoc} + */ + public function close() + { + return $this->handler->close(); + } + + /** + * @return bool + */ + public function gc($maxlifetime) + { + return $this->handler->gc($maxlifetime); + } + + /** + * @return string + */ + public function getCookieSameSite() + { + if ($this->shouldSendSameSiteNone() && \PHP_VERSION_ID >= 70300 && $this->getCookieSecure()) { + return Cookie::SAMESITE_NONE; + } + + return ''; + } + + /** + * @return string + */ + public function getCookiePath() + { + $cookiePath = env('ECCUBE_COOKIE_PATH', '/'); + if ($this->shouldSendSameSiteNone() && \PHP_VERSION_ID < 70300 && $this->getCookieSecure()) { + return $cookiePath.'; SameSite='.Cookie::SAMESITE_NONE; + } + + return $cookiePath; + } + + /** + * @return string + */ + public function getCookieSecure() + { + $request = Request::createFromGlobals(); + return $request->isSecure() ? '1' : '0'; + } + + /** + * @return bool + */ + private function shouldSendSameSiteNone() + { + $userAgent = array_key_exists('HTTP_USER_AGENT', $_SERVER) ? $_SERVER['HTTP_USER_AGENT'] : null; + return SameSite::handle($userAgent); + } +} diff --git a/tests/Eccube/Tests/Session/Storage/Handler/SameSiteNoneCompatSessionHandlerTest.php b/tests/Eccube/Tests/Session/Storage/Handler/SameSiteNoneCompatSessionHandlerTest.php new file mode 100644 index 00000000000..bbbb5e76c5b --- /dev/null +++ b/tests/Eccube/Tests/Session/Storage/Handler/SameSiteNoneCompatSessionHandlerTest.php @@ -0,0 +1,115 @@ + ['file', '/dev/null', 'w'], + 2 => ['file', '/dev/null', 'w'], + ]; + if (!self::$server = @proc_open('exec php -S localhost:8053', $spec, $pipes, self::FIXTURES_DIR)) { + self::markTestSkipped('PHP server unable to start.'); + } + sleep(1); + } + + public static function tearDownAfterClass() + { + if (self::$server) { + proc_terminate(self::$server); + proc_close(self::$server); + } + } + + /** + * @dataProvider provideSession + */ + public function testSecureSession($fixture, $user_agent, $shouldSendSameSiteNone) + { + $context = [ + 'http' => [ + 'header' => "Cookie: sid=123abc\r\nX-Forwarded-proto: https", + 'user_agent' => $user_agent + ] + ]; + $context = stream_context_create($context); + $result = file_get_contents(sprintf('http://localhost:8053/%s.php', $fixture), false, $context); + + if ($shouldSendSameSiteNone) { + if (PHP_VERSION_ID < 70300) { + // PHP7.3未満は互換用 cookie + $this->assertStringEqualsFile(sprintf(self::FIXTURES_DIR.'/%s.samesite-compat.expected', $fixture), $result); + } else { + $this->assertStringEqualsFile(sprintf(self::FIXTURES_DIR.'/%s.samesite.expected', $fixture), $result); + } + } else { + $this->assertStringEqualsFile(sprintf(self::FIXTURES_DIR.'/%s.secure.expected', $fixture), $result); + } + } + + /** + * Secure 属性が付与されない場合は, SameSite 属性も付与されない(ブラウザのデフォルト値) + * @dataProvider provideSession + */ + public function testNonSecureSession($fixture, $user_agent, $shouldSendSameSiteNone) + { + $context = [ + 'http' => [ + 'header' => "Cookie: sid=123abc\r\n", + 'user_agent' => $user_agent + ] + ]; + $context = stream_context_create($context); + $result = file_get_contents(sprintf('http://localhost:8053/%s.php', $fixture), false, $context); + + $this->assertStringEqualsFile(sprintf(self::FIXTURES_DIR.'/%s.expected', $fixture), $result); + } + + /** + * @see https://github.com/skorp/detect-incompatible-samesite-useragents/blob/master/tests/UserAgents.php + */ + public function provideSession() + { + $userAgents = [ + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130' => true, + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.3945.130' => false, + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3945.130' => false, + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1.1 Safari/605.1.15' => false, + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Safari/605.1.15' => true, + 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 EdgiOS/44.8.0 Mobile/15E148 Safari/605.1.15' => false, + 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_1_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.1 Mobile/15E148 Safari/604.1' => true, + 'Mozilla/5.0 (Linux; U; Android 4.1.2; en-us; SM-T210R Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 UCBrowser/2.3.2.300' => false, + 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3) AppleWebKit/534.31 (KHTML, like Gecko) Chrome/17.0.558.0 Safari/534.31 UCBrowser/3.0.0.357' => false, + ]; + + foreach (glob(self::FIXTURES_DIR.'/*.php') as $file) { + $name = pathinfo($file, PATHINFO_FILENAME); + if ($name == 'common') continue; + if ($name == 'storage') { + // TODO Mock が動作しないためスキップ + continue; + } + if ($name == 'regenerate') { + // XXX PHP7.4.5, 7.3.17 のバグでエラーになるためスキップ + // see https://github.com/symfony/symfony/pull/36485#issuecomment-615928699 + if (PHP_VERSION_ID === 70405) continue; + if (PHP_VERSION_ID === 70317) continue; + } + foreach ($userAgents as $user_agent => $shouldSendSameSiteNone) { + yield [$name, $user_agent, $shouldSendSameSiteNone]; + } + } + } +} diff --git a/tests/Fixtures/session/common.php b/tests/Fixtures/session/common.php new file mode 100644 index 00000000000..a9d196779da --- /dev/null +++ b/tests/Fixtures/session/common.php @@ -0,0 +1,181 @@ +overload(); +} + +Request::setTrustedProxies(['127.0.0.1', '::1', 'REMOTE_ADDR'], Request::HEADER_X_FORWARDED_ALL ^ Request::HEADER_X_FORWARDED_HOST); +Request::setTrustedHosts(['127.0.0.1', '::1']); +Request::createFromGlobals(); + +error_reporting(-1); +ini_set('html_errors', 0); +ini_set('display_errors', 1); +ini_set('session.gc_probability', 0); +ini_set('session.serialize_handler', 'php'); +ini_set('session.cookie_lifetime', 0); +ini_set('session.cookie_domain', ''); +ini_set('session.cookie_secure', ''); +ini_set('session.cookie_httponly', ''); +ini_set('session.use_cookies', 1); +ini_set('session.use_only_cookies', 1); +ini_set('session.cache_expire', 180); +ini_set('session.cookie_path', '/'); +ini_set('session.cookie_domain', ''); +ini_set('session.cookie_secure', 1); +ini_set('session.cookie_httponly', 1); +ini_set('session.use_strict_mode', 1); +ini_set('session.lazy_write', 1); +ini_set('session.name', 'sid'); +ini_set('session.save_path', __DIR__); +ini_set('session.cache_limiter', ''); + +header_remove('X-Powered-By'); +header('Content-Type: text/plain; charset=utf-8'); + +register_shutdown_function(function () { + echo "\n"; + session_write_close(); + print_r(headers_list()); + echo "shutdown\n"; +}); +ob_start(); + +class MockSessionHandler extends \SessionHandler +{ + private $data; + + public function __construct($data = null) + { + $this->data = $data; + } + + public function getData() + { + return $this->data; + } + + public function open($path, $name) + { + return parent::open($path, $name); + } +} +class TestSessionHandler extends SameSiteNoneCompatSessionHandler +{ + private $handler; + private $data; + + public function __construct(\SessionHandlerInterface $handler) + { + parent::__construct($handler); + $this->data = $handler->getData(); + } + + public function open($path, $name) + { + echo __FUNCTION__, "\n"; + + return parent::open($path, $name); + } + + public function validateId($sessionId) + { + echo __FUNCTION__, "\n"; + + return parent::validateId($sessionId); + } + + /** + * {@inheritdoc} + */ + public function read($sessionId) + { + echo __FUNCTION__, "\n"; + + return parent::read($sessionId); + } + + /** + * {@inheritdoc} + */ + public function updateTimestamp($sessionId, $data) + { + echo __FUNCTION__, "\n"; + + return true; + } + + /** + * {@inheritdoc} + */ + public function write($sessionId, $data) + { + echo __FUNCTION__, "\n"; + + return parent::write($sessionId, $data); + } + + /** + * {@inheritdoc} + */ + public function destroy($sessionId) + { + echo __FUNCTION__, "\n"; + + return parent::destroy($sessionId); + } + + public function close() + { + echo __FUNCTION__, "\n"; + + return true; + } + + public function gc($maxLifetime) + { + echo __FUNCTION__, "\n"; + + return true; + } + + protected function doRead($sessionId) + { + echo __FUNCTION__.': ', $this->data, "\n"; + + return $this->data; + } + + protected function doWrite($sessionId, $data) + { + echo __FUNCTION__.': ', $data, "\n"; + + return true; + } + + protected function doDestroy($sessionId) + { + echo __FUNCTION__, "\n"; + + return true; + } +} diff --git a/tests/Fixtures/session/empty_destroys.expected b/tests/Fixtures/session/empty_destroys.expected new file mode 100644 index 00000000000..c01fffbce23 --- /dev/null +++ b/tests/Fixtures/session/empty_destroys.expected @@ -0,0 +1,17 @@ +open +validateId +read +doRead: abc|i:123; +read + +write +destroy +doDestroy +close +Array +( + [0] => Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=10800, private, must-revalidate + [2] => Set-Cookie: sid=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; HttpOnly +) +shutdown diff --git a/tests/Fixtures/session/empty_destroys.php b/tests/Fixtures/session/empty_destroys.php new file mode 100644 index 00000000000..beee69fa811 --- /dev/null +++ b/tests/Fixtures/session/empty_destroys.php @@ -0,0 +1,8 @@ + Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=10800, private, must-revalidate + [2] => Set-Cookie: sid=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; SameSite=none; secure; HttpOnly +) +shutdown diff --git a/tests/Fixtures/session/empty_destroys.samesite.expected b/tests/Fixtures/session/empty_destroys.samesite.expected new file mode 100644 index 00000000000..6cbe3fbf38f --- /dev/null +++ b/tests/Fixtures/session/empty_destroys.samesite.expected @@ -0,0 +1,17 @@ +open +validateId +read +doRead: abc|i:123; +read + +write +destroy +doDestroy +close +Array +( + [0] => Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=10800, private, must-revalidate + [2] => Set-Cookie: sid=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly; SameSite=none +) +shutdown diff --git a/tests/Fixtures/session/empty_destroys.secure.expected b/tests/Fixtures/session/empty_destroys.secure.expected new file mode 100644 index 00000000000..82037147407 --- /dev/null +++ b/tests/Fixtures/session/empty_destroys.secure.expected @@ -0,0 +1,17 @@ +open +validateId +read +doRead: abc|i:123; +read + +write +destroy +doDestroy +close +Array +( + [0] => Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=10800, 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/tests/Fixtures/session/read_only.expected b/tests/Fixtures/session/read_only.expected new file mode 100644 index 00000000000..587adaf158b --- /dev/null +++ b/tests/Fixtures/session/read_only.expected @@ -0,0 +1,14 @@ +open +validateId +read +doRead: abc|i:123; +read +123 +updateTimestamp +close +Array +( + [0] => Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=10800, private, must-revalidate +) +shutdown diff --git a/tests/Fixtures/session/read_only.php b/tests/Fixtures/session/read_only.php new file mode 100644 index 00000000000..ceb00478d60 --- /dev/null +++ b/tests/Fixtures/session/read_only.php @@ -0,0 +1,8 @@ + Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=10800, private, must-revalidate +) +shutdown diff --git a/tests/Fixtures/session/read_only.samesite.expected b/tests/Fixtures/session/read_only.samesite.expected new file mode 100644 index 00000000000..587adaf158b --- /dev/null +++ b/tests/Fixtures/session/read_only.samesite.expected @@ -0,0 +1,14 @@ +open +validateId +read +doRead: abc|i:123; +read +123 +updateTimestamp +close +Array +( + [0] => Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=10800, private, must-revalidate +) +shutdown diff --git a/tests/Fixtures/session/read_only.secure.expected b/tests/Fixtures/session/read_only.secure.expected new file mode 100644 index 00000000000..587adaf158b --- /dev/null +++ b/tests/Fixtures/session/read_only.secure.expected @@ -0,0 +1,14 @@ +open +validateId +read +doRead: abc|i:123; +read +123 +updateTimestamp +close +Array +( + [0] => Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=10800, private, must-revalidate +) +shutdown diff --git a/tests/Fixtures/session/regenerate.expected b/tests/Fixtures/session/regenerate.expected new file mode 100644 index 00000000000..d462a571c37 --- /dev/null +++ b/tests/Fixtures/session/regenerate.expected @@ -0,0 +1,24 @@ +open +validateId +read +doRead: abc|i:123; +read +destroy +doDestroy +close +open +validateId +read +doRead: abc|i:123; +read + +write +doWrite: abc|i:123; +close +Array +( + [0] => Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=10800, private, must-revalidate + [2] => Set-Cookie: sid=random_session_id; path=/; HttpOnly +) +shutdown diff --git a/tests/Fixtures/session/regenerate.php b/tests/Fixtures/session/regenerate.php new file mode 100644 index 00000000000..115f011cc62 --- /dev/null +++ b/tests/Fixtures/session/regenerate.php @@ -0,0 +1,10 @@ + Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=10800, private, must-revalidate + [2] => Set-Cookie: sid=random_session_id; path=/; SameSite=none; secure; HttpOnly +) +shutdown diff --git a/tests/Fixtures/session/regenerate.samesite.expected b/tests/Fixtures/session/regenerate.samesite.expected new file mode 100644 index 00000000000..8f5e59a2fb4 --- /dev/null +++ b/tests/Fixtures/session/regenerate.samesite.expected @@ -0,0 +1,24 @@ +open +validateId +read +doRead: abc|i:123; +read +destroy +doDestroy +close +open +validateId +read +doRead: abc|i:123; +read + +write +doWrite: abc|i:123; +close +Array +( + [0] => Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=10800, private, must-revalidate + [2] => Set-Cookie: sid=random_session_id; path=/; secure; HttpOnly; SameSite=none +) +shutdown diff --git a/tests/Fixtures/session/regenerate.secure.expected b/tests/Fixtures/session/regenerate.secure.expected new file mode 100644 index 00000000000..baa5f2f6f5c --- /dev/null +++ b/tests/Fixtures/session/regenerate.secure.expected @@ -0,0 +1,24 @@ +open +validateId +read +doRead: abc|i:123; +read +destroy +doDestroy +close +open +validateId +read +doRead: abc|i:123; +read + +write +doWrite: abc|i:123; +close +Array +( + [0] => Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=10800, private, must-revalidate + [2] => Set-Cookie: sid=random_session_id; path=/; secure; HttpOnly +) +shutdown diff --git a/tests/Fixtures/session/ruleset.xml b/tests/Fixtures/session/ruleset.xml new file mode 100644 index 00000000000..7e219bf1b0d --- /dev/null +++ b/tests/Fixtures/session/ruleset.xml @@ -0,0 +1,36 @@ + + + A sample coding standard + + + + + + + + + + + + + + + + + + + + + + + Line longer than the max of %s; has %s chars + + + Line longer than %s chars; has %s chars + + + + + 0 + + diff --git a/tests/Fixtures/session/storage.expected b/tests/Fixtures/session/storage.expected new file mode 100644 index 00000000000..4533a10a1f7 --- /dev/null +++ b/tests/Fixtures/session/storage.expected @@ -0,0 +1,20 @@ +open +validateId +read +doRead: +read +Array +( + [0] => bar +) +$_SESSION is not empty +write +destroy +close +$_SESSION is not empty +Array +( + [0] => Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=0, private, must-revalidate +) +shutdown diff --git a/tests/Fixtures/session/storage.php b/tests/Fixtures/session/storage.php new file mode 100644 index 00000000000..adb04bb0fc2 --- /dev/null +++ b/tests/Fixtures/session/storage.php @@ -0,0 +1,24 @@ +setSaveHandler(new TestSessionHandler(new MockSessionHandler())); +$flash = new FlashBag(); +$storage->registerBag($flash); +$storage->start(); + +$flash->add('foo', 'bar'); + +print_r($flash->get('foo')); +echo empty($_SESSION) ? '$_SESSION is empty' : '$_SESSION is not empty'; +echo "\n"; + +$storage->save(); + +echo empty($_SESSION) ? '$_SESSION is empty' : '$_SESSION is not empty'; + +ob_start(function ($buffer) { return str_replace(session_id(), 'random_session_id', $buffer); }); diff --git a/tests/Fixtures/session/storage.samesite-compat.expected b/tests/Fixtures/session/storage.samesite-compat.expected new file mode 100644 index 00000000000..4533a10a1f7 --- /dev/null +++ b/tests/Fixtures/session/storage.samesite-compat.expected @@ -0,0 +1,20 @@ +open +validateId +read +doRead: +read +Array +( + [0] => bar +) +$_SESSION is not empty +write +destroy +close +$_SESSION is not empty +Array +( + [0] => Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=0, private, must-revalidate +) +shutdown diff --git a/tests/Fixtures/session/storage.samesite.expected b/tests/Fixtures/session/storage.samesite.expected new file mode 100644 index 00000000000..4533a10a1f7 --- /dev/null +++ b/tests/Fixtures/session/storage.samesite.expected @@ -0,0 +1,20 @@ +open +validateId +read +doRead: +read +Array +( + [0] => bar +) +$_SESSION is not empty +write +destroy +close +$_SESSION is not empty +Array +( + [0] => Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=0, private, must-revalidate +) +shutdown diff --git a/tests/Fixtures/session/storage.secure.expected b/tests/Fixtures/session/storage.secure.expected new file mode 100644 index 00000000000..4533a10a1f7 --- /dev/null +++ b/tests/Fixtures/session/storage.secure.expected @@ -0,0 +1,20 @@ +open +validateId +read +doRead: +read +Array +( + [0] => bar +) +$_SESSION is not empty +write +destroy +close +$_SESSION is not empty +Array +( + [0] => Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=0, private, must-revalidate +) +shutdown diff --git a/tests/Fixtures/session/with_cookie.expected b/tests/Fixtures/session/with_cookie.expected new file mode 100644 index 00000000000..33da0a5be6e --- /dev/null +++ b/tests/Fixtures/session/with_cookie.expected @@ -0,0 +1,15 @@ +open +validateId +read +doRead: abc|i:123; +read + +updateTimestamp +close +Array +( + [0] => Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=10800, private, must-revalidate + [2] => Set-Cookie: abc=def +) +shutdown diff --git a/tests/Fixtures/session/with_cookie.php b/tests/Fixtures/session/with_cookie.php new file mode 100644 index 00000000000..14cda048f00 --- /dev/null +++ b/tests/Fixtures/session/with_cookie.php @@ -0,0 +1,8 @@ + Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=10800, private, must-revalidate + [2] => Set-Cookie: abc=def +) +shutdown diff --git a/tests/Fixtures/session/with_cookie.samesite.expected b/tests/Fixtures/session/with_cookie.samesite.expected new file mode 100644 index 00000000000..33da0a5be6e --- /dev/null +++ b/tests/Fixtures/session/with_cookie.samesite.expected @@ -0,0 +1,15 @@ +open +validateId +read +doRead: abc|i:123; +read + +updateTimestamp +close +Array +( + [0] => Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=10800, private, must-revalidate + [2] => Set-Cookie: abc=def +) +shutdown diff --git a/tests/Fixtures/session/with_cookie.secure.expected b/tests/Fixtures/session/with_cookie.secure.expected new file mode 100644 index 00000000000..33da0a5be6e --- /dev/null +++ b/tests/Fixtures/session/with_cookie.secure.expected @@ -0,0 +1,15 @@ +open +validateId +read +doRead: abc|i:123; +read + +updateTimestamp +close +Array +( + [0] => Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=10800, private, must-revalidate + [2] => Set-Cookie: abc=def +) +shutdown diff --git a/tests/Fixtures/session/with_cookie_and_session.expected b/tests/Fixtures/session/with_cookie_and_session.expected new file mode 100644 index 00000000000..5de2d9e3904 --- /dev/null +++ b/tests/Fixtures/session/with_cookie_and_session.expected @@ -0,0 +1,24 @@ +open +validateId +read +doRead: abc|i:123; +read +updateTimestamp +close +open +validateId +read +doRead: abc|i:123; +read + +write +destroy +doDestroy +close +Array +( + [0] => Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=10800, private, must-revalidate + [2] => Set-Cookie: abc=def +) +shutdown diff --git a/tests/Fixtures/session/with_cookie_and_session.php b/tests/Fixtures/session/with_cookie_and_session.php new file mode 100644 index 00000000000..b4cbc4fad65 --- /dev/null +++ b/tests/Fixtures/session/with_cookie_and_session.php @@ -0,0 +1,13 @@ + Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=10800, private, must-revalidate + [2] => Set-Cookie: abc=def +) +shutdown diff --git a/tests/Fixtures/session/with_cookie_and_session.samesite.expected b/tests/Fixtures/session/with_cookie_and_session.samesite.expected new file mode 100644 index 00000000000..5de2d9e3904 --- /dev/null +++ b/tests/Fixtures/session/with_cookie_and_session.samesite.expected @@ -0,0 +1,24 @@ +open +validateId +read +doRead: abc|i:123; +read +updateTimestamp +close +open +validateId +read +doRead: abc|i:123; +read + +write +destroy +doDestroy +close +Array +( + [0] => Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=10800, private, must-revalidate + [2] => Set-Cookie: abc=def +) +shutdown diff --git a/tests/Fixtures/session/with_cookie_and_session.secure.expected b/tests/Fixtures/session/with_cookie_and_session.secure.expected new file mode 100644 index 00000000000..5de2d9e3904 --- /dev/null +++ b/tests/Fixtures/session/with_cookie_and_session.secure.expected @@ -0,0 +1,24 @@ +open +validateId +read +doRead: abc|i:123; +read +updateTimestamp +close +open +validateId +read +doRead: abc|i:123; +read + +write +destroy +doDestroy +close +Array +( + [0] => Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=10800, private, must-revalidate + [2] => Set-Cookie: abc=def +) +shutdown