Skip to content

Commit 64dd750

Browse files
committed
Merge branch '5.4' into 6.0
* 5.4: Don't rely on session service in tests [Mime] Fix encoding filenames in multipart/form-data Properly warn about deprecation of IS_AUTHENTICATED_ANONYMOUSLY [Lock] Create tables in transaction only if supported by driver [Validator] Improve French translation [HttpFoundation] Take php session.cookie settings into account [Translations] Add missing translations for Galician (gl) [ErrorHandler] fix on patching return types on Windows [DependencyInjection] fix linting callable classes alias `cache.app.taggable` to `cache.app` if using `cache.adapter.redis_tag_aware` restore the overriden locale on tearDown - avoid interfering with any configured value [Serializer] Improve UidNormalizer denormalize error message [DependencyInjection] Cast tag value to string
2 parents c1e8c4a + 77b2fe7 commit 64dd750

File tree

2 files changed

+118
-6
lines changed

2 files changed

+118
-6
lines changed

EventListener/AbstractSessionListener.php

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,12 @@ public function onKernelResponse(ResponseEvent $event)
135135
*/
136136
$sessionName = $session->getName();
137137
$sessionId = $session->getId();
138-
$sessionCookiePath = $this->sessionOptions['cookie_path'] ?? '/';
139-
$sessionCookieDomain = $this->sessionOptions['cookie_domain'] ?? null;
140-
$sessionCookieSecure = $this->sessionOptions['cookie_secure'] ?? false;
141-
$sessionCookieHttpOnly = $this->sessionOptions['cookie_httponly'] ?? true;
142-
$sessionCookieSameSite = $this->sessionOptions['cookie_samesite'] ?? Cookie::SAMESITE_LAX;
138+
$sessionOptions = $this->getSessionOptions($this->sessionOptions);
139+
$sessionCookiePath = $sessionOptions['cookie_path'] ?? '/';
140+
$sessionCookieDomain = $sessionOptions['cookie_domain'] ?? null;
141+
$sessionCookieSecure = $sessionOptions['cookie_secure'] ?? false;
142+
$sessionCookieHttpOnly = $sessionOptions['cookie_httponly'] ?? true;
143+
$sessionCookieSameSite = $sessionOptions['cookie_samesite'] ?? Cookie::SAMESITE_LAX;
143144

144145
SessionUtils::popSessionCookie($sessionName, $sessionId);
145146

@@ -157,7 +158,7 @@ public function onKernelResponse(ResponseEvent $event)
157158
);
158159
} elseif ($sessionId !== $requestSessionCookieId) {
159160
$expire = 0;
160-
$lifetime = $this->sessionOptions['cookie_lifetime'] ?? null;
161+
$lifetime = $sessionOptions['cookie_lifetime'] ?? null;
161162
if ($lifetime) {
162163
$expire = time() + $lifetime;
163164
}
@@ -265,4 +266,23 @@ public function reset(): void
265266
* Gets the session object.
266267
*/
267268
abstract protected function getSession(): ?SessionInterface;
269+
270+
private function getSessionOptions(array $sessionOptions): array
271+
{
272+
$mergedSessionOptions = [];
273+
274+
foreach (session_get_cookie_params() as $key => $value) {
275+
$mergedSessionOptions['cookie_'.$key] = $value;
276+
}
277+
278+
foreach ($sessionOptions as $key => $value) {
279+
// do the same logic as in the NativeSessionStorage
280+
if ('cookie_secure' === $key && 'auto' === $value) {
281+
continue;
282+
}
283+
$mergedSessionOptions[$key] = $value;
284+
}
285+
286+
return $mergedSessionOptions;
287+
}
268288
}

Tests/EventListener/SessionListenerTest.php

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use PHPUnit\Framework\TestCase;
1515
use Psr\Log\LoggerInterface;
1616
use Symfony\Component\DependencyInjection\Container;
17+
use Symfony\Component\HttpFoundation\Cookie;
1718
use Symfony\Component\HttpFoundation\Request;
1819
use Symfony\Component\HttpFoundation\RequestStack;
1920
use Symfony\Component\HttpFoundation\Response;
@@ -31,6 +32,97 @@
3132

3233
class SessionListenerTest extends TestCase
3334
{
35+
/**
36+
* @dataProvider provideSessionOptions
37+
* @runInSeparateProcess
38+
*/
39+
public function testSessionCookieOptions(array $phpSessionOptions, array $sessionOptions, array $expectedSessionOptions)
40+
{
41+
$session = $this->createMock(Session::class);
42+
$session->method('getUsageIndex')->will($this->onConsecutiveCalls(0, 1));
43+
$session->method('getId')->willReturn('123456');
44+
$session->method('getName')->willReturn('PHPSESSID');
45+
$session->method('save');
46+
$session->method('isStarted')->willReturn(true);
47+
48+
if (isset($phpSessionOptions['samesite'])) {
49+
ini_set('session.cookie_samesite', $phpSessionOptions['samesite']);
50+
}
51+
session_set_cookie_params(0, $phpSessionOptions['path'] ?? null, $phpSessionOptions['domain'] ?? null, $phpSessionOptions['secure'] ?? null, $phpSessionOptions['httponly'] ?? null);
52+
53+
$listener = new SessionListener(new Container(), false, $sessionOptions);
54+
$kernel = $this->createMock(HttpKernelInterface::class);
55+
56+
$request = new Request();
57+
$listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));
58+
59+
$request->setSession($session);
60+
$response = new Response();
61+
$listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));
62+
63+
$cookies = $response->headers->getCookies();
64+
$this->assertSame('PHPSESSID', $cookies[0]->getName());
65+
$this->assertSame('123456', $cookies[0]->getValue());
66+
$this->assertSame($expectedSessionOptions['cookie_path'], $cookies[0]->getPath());
67+
$this->assertSame($expectedSessionOptions['cookie_domain'], $cookies[0]->getDomain());
68+
$this->assertSame($expectedSessionOptions['cookie_secure'], $cookies[0]->isSecure());
69+
$this->assertSame($expectedSessionOptions['cookie_httponly'], $cookies[0]->isHttpOnly());
70+
$this->assertSame($expectedSessionOptions['cookie_samesite'], $cookies[0]->getSameSite());
71+
}
72+
73+
public function provideSessionOptions(): \Generator
74+
{
75+
if (\PHP_VERSION_ID > 70300) {
76+
yield 'set_samesite_by_php' => [
77+
'phpSessionOptions' => ['samesite' => Cookie::SAMESITE_STRICT],
78+
'sessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_secure' => true, 'cookie_httponly' => true],
79+
'expectedSessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_secure' => true, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_STRICT],
80+
];
81+
}
82+
83+
yield 'set_cookie_path_by_php' => [
84+
'phpSessionOptions' => ['path' => '/prod/'],
85+
'sessionOptions' => ['cookie_domain' => '', 'cookie_secure' => true, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],
86+
'expectedSessionOptions' => ['cookie_path' => '/prod/', 'cookie_domain' => '', 'cookie_secure' => true, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],
87+
];
88+
89+
yield 'set_cookie_secure_by_php' => [
90+
'phpSessionOptions' => ['secure' => true],
91+
'sessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],
92+
'expectedSessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_secure' => true, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],
93+
];
94+
95+
yield 'set_cookiesecure_auto_by_symfony_false_by_php' => [
96+
'phpSessionOptions' => ['secure' => false],
97+
'sessionOptions' => ['cookie_path' => '/test/', 'cookie_httponly' => 'auto', 'cookie_secure' => 'auto', 'cookie_samesite' => Cookie::SAMESITE_LAX],
98+
'expectedSessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_secure' => false, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],
99+
];
100+
101+
yield 'set_cookiesecure_auto_by_symfony_true_by_php' => [
102+
'phpSessionOptions' => ['secure' => true],
103+
'sessionOptions' => ['cookie_path' => '/test/', 'cookie_httponly' => 'auto', 'cookie_secure' => 'auto', 'cookie_samesite' => Cookie::SAMESITE_LAX],
104+
'expectedSessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_secure' => true, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],
105+
];
106+
107+
yield 'set_cookie_httponly_by_php' => [
108+
'phpSessionOptions' => ['httponly' => true],
109+
'sessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_secure' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],
110+
'expectedSessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_secure' => true, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],
111+
];
112+
113+
yield 'set_cookie_domain_by_php' => [
114+
'phpSessionOptions' => ['domain' => 'test.symfony'],
115+
'sessionOptions' => ['cookie_path' => '/test/', 'cookie_httponly' => true, 'cookie_secure' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],
116+
'expectedSessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => 'test.symfony', 'cookie_secure' => true, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],
117+
];
118+
119+
yield 'set_samesite_by_symfony' => [
120+
'phpSessionOptions' => ['samesite' => Cookie::SAMESITE_STRICT],
121+
'sessionOptions' => ['cookie_path' => '/test/', 'cookie_httponly' => true, 'cookie_secure' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],
122+
'expectedSessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_secure' => true, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],
123+
];
124+
}
125+
34126
public function testOnlyTriggeredOnMainRequest()
35127
{
36128
$listener = $this->getMockForAbstractClass(AbstractSessionListener::class);

0 commit comments

Comments
 (0)