Merge "Avoid master queries in Title::getLinksFrom()"
[lhc/web/wiklou.git] / tests / phpunit / includes / session / CookieSessionProviderTest.php
1 <?php
2
3 namespace MediaWiki\Session;
4
5 use MediaWikiTestCase;
6 use User;
7 use Psr\Log\LogLevel;
8
9 /**
10 * @group Session
11 * @group Database
12 * @covers MediaWiki\Session\CookieSessionProvider
13 */
14 class CookieSessionProviderTest extends MediaWikiTestCase {
15
16 private function getConfig() {
17 global $wgCookieExpiration;
18 return new \HashConfig( [
19 'CookiePrefix' => 'CookiePrefix',
20 'CookiePath' => 'CookiePath',
21 'CookieDomain' => 'CookieDomain',
22 'CookieSecure' => true,
23 'CookieHttpOnly' => true,
24 'SessionName' => false,
25 'ExtendedLoginCookies' => [ 'UserID', 'Token' ],
26 'ExtendedLoginCookieExpiration' => $wgCookieExpiration * 2,
27 ] );
28 }
29
30 public function testConstructor() {
31 try {
32 new CookieSessionProvider();
33 $this->fail( 'Expected exception not thrown' );
34 } catch ( \InvalidArgumentException $ex ) {
35 $this->assertSame(
36 'MediaWiki\\Session\\CookieSessionProvider::__construct: priority must be specified',
37 $ex->getMessage()
38 );
39 }
40
41 try {
42 new CookieSessionProvider( [ 'priority' => 'foo' ] );
43 $this->fail( 'Expected exception not thrown' );
44 } catch ( \InvalidArgumentException $ex ) {
45 $this->assertSame(
46 'MediaWiki\\Session\\CookieSessionProvider::__construct: Invalid priority',
47 $ex->getMessage()
48 );
49 }
50 try {
51 new CookieSessionProvider( [ 'priority' => SessionInfo::MIN_PRIORITY - 1 ] );
52 $this->fail( 'Expected exception not thrown' );
53 } catch ( \InvalidArgumentException $ex ) {
54 $this->assertSame(
55 'MediaWiki\\Session\\CookieSessionProvider::__construct: Invalid priority',
56 $ex->getMessage()
57 );
58 }
59 try {
60 new CookieSessionProvider( [ 'priority' => SessionInfo::MAX_PRIORITY + 1 ] );
61 $this->fail( 'Expected exception not thrown' );
62 } catch ( \InvalidArgumentException $ex ) {
63 $this->assertSame(
64 'MediaWiki\\Session\\CookieSessionProvider::__construct: Invalid priority',
65 $ex->getMessage()
66 );
67 }
68
69 try {
70 new CookieSessionProvider( [ 'priority' => 1, 'cookieOptions' => null ] );
71 $this->fail( 'Expected exception not thrown' );
72 } catch ( \InvalidArgumentException $ex ) {
73 $this->assertSame(
74 'MediaWiki\\Session\\CookieSessionProvider::__construct: cookieOptions must be an array',
75 $ex->getMessage()
76 );
77 }
78
79 $config = $this->getConfig();
80 $p = \TestingAccessWrapper::newFromObject(
81 new CookieSessionProvider( [ 'priority' => 1 ] )
82 );
83 $p->setLogger( new \TestLogger() );
84 $p->setConfig( $config );
85 $this->assertEquals( 1, $p->priority );
86 $this->assertEquals( [
87 'callUserSetCookiesHook' => false,
88 'sessionName' => 'CookiePrefix_session',
89 ], $p->params );
90 $this->assertEquals( [
91 'prefix' => 'CookiePrefix',
92 'path' => 'CookiePath',
93 'domain' => 'CookieDomain',
94 'secure' => true,
95 'httpOnly' => true,
96 ], $p->cookieOptions );
97
98 $config->set( 'SessionName', 'SessionName' );
99 $p = \TestingAccessWrapper::newFromObject(
100 new CookieSessionProvider( [ 'priority' => 3 ] )
101 );
102 $p->setLogger( new \TestLogger() );
103 $p->setConfig( $config );
104 $this->assertEquals( 3, $p->priority );
105 $this->assertEquals( [
106 'callUserSetCookiesHook' => false,
107 'sessionName' => 'SessionName',
108 ], $p->params );
109 $this->assertEquals( [
110 'prefix' => 'CookiePrefix',
111 'path' => 'CookiePath',
112 'domain' => 'CookieDomain',
113 'secure' => true,
114 'httpOnly' => true,
115 ], $p->cookieOptions );
116
117 $p = \TestingAccessWrapper::newFromObject( new CookieSessionProvider( [
118 'priority' => 10,
119 'callUserSetCookiesHook' => true,
120 'cookieOptions' => [
121 'prefix' => 'XPrefix',
122 'path' => 'XPath',
123 'domain' => 'XDomain',
124 'secure' => 'XSecure',
125 'httpOnly' => 'XHttpOnly',
126 ],
127 'sessionName' => 'XSession',
128 ] ) );
129 $p->setLogger( new \TestLogger() );
130 $p->setConfig( $config );
131 $this->assertEquals( 10, $p->priority );
132 $this->assertEquals( [
133 'callUserSetCookiesHook' => true,
134 'sessionName' => 'XSession',
135 ], $p->params );
136 $this->assertEquals( [
137 'prefix' => 'XPrefix',
138 'path' => 'XPath',
139 'domain' => 'XDomain',
140 'secure' => 'XSecure',
141 'httpOnly' => 'XHttpOnly',
142 ], $p->cookieOptions );
143 }
144
145 public function testBasics() {
146 $provider = new CookieSessionProvider( [ 'priority' => 10 ] );
147
148 $this->assertTrue( $provider->persistsSessionID() );
149 $this->assertTrue( $provider->canChangeUser() );
150
151 $msg = $provider->whyNoSession();
152 $this->assertInstanceOf( 'Message', $msg );
153 $this->assertSame( 'sessionprovider-nocookies', $msg->getKey() );
154 }
155
156 public function testProvideSessionInfo() {
157 $params = [
158 'priority' => 20,
159 'sessionName' => 'session',
160 'cookieOptions' => [ 'prefix' => 'x' ],
161 ];
162 $provider = new CookieSessionProvider( $params );
163 $logger = new \TestLogger( true );
164 $provider->setLogger( $logger );
165 $provider->setConfig( $this->getConfig() );
166 $provider->setManager( new SessionManager() );
167
168 $user = User::newFromName( 'UTSysop' );
169 $id = $user->getId();
170 $name = $user->getName();
171 $token = $user->getToken( true );
172
173 $sessionId = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
174
175 // No data
176 $request = new \FauxRequest();
177 $info = $provider->provideSessionInfo( $request );
178 $this->assertNull( $info );
179 $this->assertSame( [], $logger->getBuffer() );
180 $logger->clearBuffer();
181
182 // Session key only
183 $request = new \FauxRequest();
184 $request->setCookies( [
185 'session' => $sessionId,
186 ], '' );
187 $info = $provider->provideSessionInfo( $request );
188 $this->assertNotNull( $info );
189 $this->assertSame( $params['priority'], $info->getPriority() );
190 $this->assertSame( $sessionId, $info->getId() );
191 $this->assertNotNull( $info->getUserInfo() );
192 $this->assertSame( 0, $info->getUserInfo()->getId() );
193 $this->assertNull( $info->getUserInfo()->getName() );
194 $this->assertFalse( $info->forceHTTPS() );
195 $this->assertSame( [
196 [
197 LogLevel::DEBUG,
198 'Session "{session}" requested without UserID cookie',
199 ],
200 ], $logger->getBuffer() );
201 $logger->clearBuffer();
202
203 // User, no session key
204 $request = new \FauxRequest();
205 $request->setCookies( [
206 'xUserID' => $id,
207 'xToken' => $token,
208 ], '' );
209 $info = $provider->provideSessionInfo( $request );
210 $this->assertNotNull( $info );
211 $this->assertSame( $params['priority'], $info->getPriority() );
212 $this->assertNotSame( $sessionId, $info->getId() );
213 $this->assertNotNull( $info->getUserInfo() );
214 $this->assertSame( $id, $info->getUserInfo()->getId() );
215 $this->assertSame( $name, $info->getUserInfo()->getName() );
216 $this->assertFalse( $info->forceHTTPS() );
217 $this->assertSame( [], $logger->getBuffer() );
218 $logger->clearBuffer();
219
220 // User and session key
221 $request = new \FauxRequest();
222 $request->setCookies( [
223 'session' => $sessionId,
224 'xUserID' => $id,
225 'xToken' => $token,
226 ], '' );
227 $info = $provider->provideSessionInfo( $request );
228 $this->assertNotNull( $info );
229 $this->assertSame( $params['priority'], $info->getPriority() );
230 $this->assertSame( $sessionId, $info->getId() );
231 $this->assertNotNull( $info->getUserInfo() );
232 $this->assertSame( $id, $info->getUserInfo()->getId() );
233 $this->assertSame( $name, $info->getUserInfo()->getName() );
234 $this->assertFalse( $info->forceHTTPS() );
235 $this->assertSame( [], $logger->getBuffer() );
236 $logger->clearBuffer();
237
238 // User with bad token
239 $request = new \FauxRequest();
240 $request->setCookies( [
241 'session' => $sessionId,
242 'xUserID' => $id,
243 'xToken' => 'BADTOKEN',
244 ], '' );
245 $info = $provider->provideSessionInfo( $request );
246 $this->assertNull( $info );
247 $this->assertSame( [
248 [
249 LogLevel::WARNING,
250 'Session "{session}" requested with invalid Token cookie.'
251 ],
252 ], $logger->getBuffer() );
253 $logger->clearBuffer();
254
255 // User id with no token
256 $request = new \FauxRequest();
257 $request->setCookies( [
258 'session' => $sessionId,
259 'xUserID' => $id,
260 ], '' );
261 $info = $provider->provideSessionInfo( $request );
262 $this->assertNotNull( $info );
263 $this->assertSame( $params['priority'], $info->getPriority() );
264 $this->assertSame( $sessionId, $info->getId() );
265 $this->assertNotNull( $info->getUserInfo() );
266 $this->assertFalse( $info->getUserInfo()->isVerified() );
267 $this->assertSame( $id, $info->getUserInfo()->getId() );
268 $this->assertSame( $name, $info->getUserInfo()->getName() );
269 $this->assertFalse( $info->forceHTTPS() );
270 $this->assertSame( [], $logger->getBuffer() );
271 $logger->clearBuffer();
272
273 $request = new \FauxRequest();
274 $request->setCookies( [
275 'xUserID' => $id,
276 ], '' );
277 $info = $provider->provideSessionInfo( $request );
278 $this->assertNull( $info );
279 $this->assertSame( [], $logger->getBuffer() );
280 $logger->clearBuffer();
281
282 // User and session key, with forceHTTPS flag
283 $request = new \FauxRequest();
284 $request->setCookies( [
285 'session' => $sessionId,
286 'xUserID' => $id,
287 'xToken' => $token,
288 'forceHTTPS' => true,
289 ], '' );
290 $info = $provider->provideSessionInfo( $request );
291 $this->assertNotNull( $info );
292 $this->assertSame( $params['priority'], $info->getPriority() );
293 $this->assertSame( $sessionId, $info->getId() );
294 $this->assertNotNull( $info->getUserInfo() );
295 $this->assertSame( $id, $info->getUserInfo()->getId() );
296 $this->assertSame( $name, $info->getUserInfo()->getName() );
297 $this->assertTrue( $info->forceHTTPS() );
298 $this->assertSame( [], $logger->getBuffer() );
299 $logger->clearBuffer();
300
301 // Invalid user id
302 $request = new \FauxRequest();
303 $request->setCookies( [
304 'session' => $sessionId,
305 'xUserID' => '-1',
306 ], '' );
307 $info = $provider->provideSessionInfo( $request );
308 $this->assertNull( $info );
309 $this->assertSame( [], $logger->getBuffer() );
310 $logger->clearBuffer();
311
312 // User id with matching name
313 $request = new \FauxRequest();
314 $request->setCookies( [
315 'session' => $sessionId,
316 'xUserID' => $id,
317 'xUserName' => $name,
318 ], '' );
319 $info = $provider->provideSessionInfo( $request );
320 $this->assertNotNull( $info );
321 $this->assertSame( $params['priority'], $info->getPriority() );
322 $this->assertSame( $sessionId, $info->getId() );
323 $this->assertNotNull( $info->getUserInfo() );
324 $this->assertFalse( $info->getUserInfo()->isVerified() );
325 $this->assertSame( $id, $info->getUserInfo()->getId() );
326 $this->assertSame( $name, $info->getUserInfo()->getName() );
327 $this->assertFalse( $info->forceHTTPS() );
328 $this->assertSame( [], $logger->getBuffer() );
329 $logger->clearBuffer();
330
331 // User id with wrong name
332 $request = new \FauxRequest();
333 $request->setCookies( [
334 'session' => $sessionId,
335 'xUserID' => $id,
336 'xUserName' => 'Wrong',
337 ], '' );
338 $info = $provider->provideSessionInfo( $request );
339 $this->assertNull( $info );
340 $this->assertSame( [
341 [
342 LogLevel::WARNING,
343 'Session "{session}" requested with mismatched UserID and UserName cookies.',
344 ],
345 ], $logger->getBuffer() );
346 $logger->clearBuffer();
347 }
348
349 public function testGetVaryCookies() {
350 $provider = new CookieSessionProvider( [
351 'priority' => 1,
352 'sessionName' => 'MySessionName',
353 'cookieOptions' => [ 'prefix' => 'MyCookiePrefix' ],
354 ] );
355 $this->assertArrayEquals( [
356 'MyCookiePrefixToken',
357 'MyCookiePrefixLoggedOut',
358 'MySessionName',
359 'forceHTTPS',
360 ], $provider->getVaryCookies() );
361 }
362
363 public function testSuggestLoginUsername() {
364 $provider = new CookieSessionProvider( [
365 'priority' => 1,
366 'sessionName' => 'MySessionName',
367 'cookieOptions' => [ 'prefix' => 'x' ],
368 ] );
369
370 $request = new \FauxRequest();
371 $this->assertEquals( null, $provider->suggestLoginUsername( $request ) );
372
373 $request->setCookies( [
374 'xUserName' => 'Example',
375 ], '' );
376 $this->assertEquals( 'Example', $provider->suggestLoginUsername( $request ) );
377 }
378
379 public function testPersistSession() {
380 $this->setMwGlobals( [ 'wgCookieExpiration' => 100 ] );
381
382 $provider = new CookieSessionProvider( [
383 'priority' => 1,
384 'sessionName' => 'MySessionName',
385 'callUserSetCookiesHook' => false,
386 'cookieOptions' => [ 'prefix' => 'x' ],
387 ] );
388 $config = $this->getConfig();
389 $provider->setLogger( new \TestLogger() );
390 $provider->setConfig( $config );
391 $provider->setManager( SessionManager::singleton() );
392
393 $sessionId = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
394 $store = new TestBagOStuff();
395 $user = User::newFromName( 'UTSysop' );
396 $anon = new User;
397
398 $backend = new SessionBackend(
399 new SessionId( $sessionId ),
400 new SessionInfo( SessionInfo::MIN_PRIORITY, [
401 'provider' => $provider,
402 'id' => $sessionId,
403 'persisted' => true,
404 'idIsSafe' => true,
405 ] ),
406 $store,
407 new \Psr\Log\NullLogger(),
408 10
409 );
410 \TestingAccessWrapper::newFromObject( $backend )->usePhpSessionHandling = false;
411
412 $mock = $this->getMock( 'stdClass', [ 'onUserSetCookies' ] );
413 $mock->expects( $this->never() )->method( 'onUserSetCookies' );
414 $this->mergeMwGlobalArrayValue( 'wgHooks', [ 'UserSetCookies' => [ $mock ] ] );
415
416 // Anonymous user
417 $backend->setUser( $anon );
418 $backend->setRememberUser( true );
419 $backend->setForceHTTPS( false );
420 $request = new \FauxRequest();
421 $provider->persistSession( $backend, $request );
422 $this->assertSame( $sessionId, $request->response()->getCookie( 'MySessionName' ) );
423 $this->assertSame( '', $request->response()->getCookie( 'xUserID' ) );
424 $this->assertSame( null, $request->response()->getCookie( 'xUserName' ) );
425 $this->assertSame( '', $request->response()->getCookie( 'xToken' ) );
426 $this->assertSame( '', $request->response()->getCookie( 'forceHTTPS' ) );
427 $this->assertSame( [], $backend->getData() );
428
429 // Logged-in user, no remember
430 $backend->setUser( $user );
431 $backend->setRememberUser( false );
432 $backend->setForceHTTPS( false );
433 $request = new \FauxRequest();
434 $provider->persistSession( $backend, $request );
435 $this->assertSame( $sessionId, $request->response()->getCookie( 'MySessionName' ) );
436 $this->assertSame( (string)$user->getId(), $request->response()->getCookie( 'xUserID' ) );
437 $this->assertSame( $user->getName(), $request->response()->getCookie( 'xUserName' ) );
438 $this->assertSame( '', $request->response()->getCookie( 'xToken' ) );
439 $this->assertSame( '', $request->response()->getCookie( 'forceHTTPS' ) );
440 $this->assertSame( [], $backend->getData() );
441
442 // Logged-in user, remember
443 $backend->setUser( $user );
444 $backend->setRememberUser( true );
445 $backend->setForceHTTPS( true );
446 $request = new \FauxRequest();
447 $time = time();
448 $provider->persistSession( $backend, $request );
449 $this->assertSame( $sessionId, $request->response()->getCookie( 'MySessionName' ) );
450 $this->assertSame( (string)$user->getId(), $request->response()->getCookie( 'xUserID' ) );
451 $this->assertSame( $user->getName(), $request->response()->getCookie( 'xUserName' ) );
452 $this->assertSame( $user->getToken(), $request->response()->getCookie( 'xToken' ) );
453 $this->assertSame( 'true', $request->response()->getCookie( 'forceHTTPS' ) );
454 $this->assertSame( [], $backend->getData() );
455 }
456
457 /**
458 * @dataProvider provideCookieData
459 * @param bool $secure
460 * @param bool $remember
461 */
462 public function testCookieData( $secure, $remember ) {
463 $this->setMwGlobals( [
464 'wgCookieExpiration' => 100,
465 'wgSecureLogin' => false,
466 ] );
467
468 $provider = new CookieSessionProvider( [
469 'priority' => 1,
470 'sessionName' => 'MySessionName',
471 'callUserSetCookiesHook' => false,
472 'cookieOptions' => [ 'prefix' => 'x' ],
473 ] );
474 $config = $this->getConfig();
475 $config->set( 'CookieSecure', $secure );
476 $provider->setLogger( new \TestLogger() );
477 $provider->setConfig( $config );
478 $provider->setManager( SessionManager::singleton() );
479
480 $sessionId = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
481 $user = User::newFromName( 'UTSysop' );
482 $this->assertFalse( $user->requiresHTTPS(), 'sanity check' );
483
484 $backend = new SessionBackend(
485 new SessionId( $sessionId ),
486 new SessionInfo( SessionInfo::MIN_PRIORITY, [
487 'provider' => $provider,
488 'id' => $sessionId,
489 'persisted' => true,
490 'idIsSafe' => true,
491 ] ),
492 new TestBagOStuff(),
493 new \Psr\Log\NullLogger(),
494 10
495 );
496 \TestingAccessWrapper::newFromObject( $backend )->usePhpSessionHandling = false;
497 $backend->setUser( $user );
498 $backend->setRememberUser( $remember );
499 $backend->setForceHTTPS( $secure );
500 $request = new \FauxRequest();
501 $time = time();
502 $provider->persistSession( $backend, $request );
503
504 $defaults = [
505 'expire' => (int)100,
506 'path' => $config->get( 'CookiePath' ),
507 'domain' => $config->get( 'CookieDomain' ),
508 'secure' => $secure,
509 'httpOnly' => $config->get( 'CookieHttpOnly' ),
510 'raw' => false,
511 ];
512 $extendedExpiry = $config->get( 'ExtendedLoginCookieExpiration' );
513 $extendedExpiry = (int)( $extendedExpiry === null ? 0 : $extendedExpiry );
514 $this->assertEquals( [ 'UserID', 'Token' ], $config->get( 'ExtendedLoginCookies' ),
515 'sanity check' );
516 $expect = [
517 'MySessionName' => [
518 'value' => (string)$sessionId,
519 'expire' => 0,
520 ] + $defaults,
521 'xUserID' => [
522 'value' => (string)$user->getId(),
523 'expire' => $extendedExpiry,
524 ] + $defaults,
525 'xUserName' => [
526 'value' => $user->getName(),
527 ] + $defaults,
528 'xToken' => [
529 'value' => $remember ? $user->getToken() : '',
530 'expire' => $remember ? $extendedExpiry : -31536000,
531 ] + $defaults,
532 'forceHTTPS' => [
533 'value' => $secure ? 'true' : '',
534 'secure' => false,
535 'expire' => $secure ? $remember ? $defaults['expire'] : 0 : -31536000,
536 ] + $defaults,
537 ];
538 foreach ( $expect as $key => $value ) {
539 $actual = $request->response()->getCookieData( $key );
540 if ( $actual && $actual['expire'] > 0 ) {
541 // Round expiry so we don't randomly fail if the seconds ticked during the test.
542 $actual['expire'] = round( $actual['expire'] - $time, -2 );
543 }
544 $this->assertEquals( $value, $actual, "Cookie $key" );
545 }
546 }
547
548 public static function provideCookieData() {
549 return [
550 [ false, false ],
551 [ false, true ],
552 [ true, false ],
553 [ true, true ],
554 ];
555 }
556
557 protected function getSentRequest() {
558 $sentResponse = $this->getMock( 'FauxResponse', [ 'headersSent', 'setCookie', 'header' ] );
559 $sentResponse->expects( $this->any() )->method( 'headersSent' )
560 ->will( $this->returnValue( true ) );
561 $sentResponse->expects( $this->never() )->method( 'setCookie' );
562 $sentResponse->expects( $this->never() )->method( 'header' );
563
564 $sentRequest = $this->getMock( 'FauxRequest', [ 'response' ] );
565 $sentRequest->expects( $this->any() )->method( 'response' )
566 ->will( $this->returnValue( $sentResponse ) );
567 return $sentRequest;
568 }
569
570 public function testPersistSessionWithHook() {
571 $provider = new CookieSessionProvider( [
572 'priority' => 1,
573 'sessionName' => 'MySessionName',
574 'callUserSetCookiesHook' => true,
575 'cookieOptions' => [ 'prefix' => 'x' ],
576 ] );
577 $provider->setLogger( new \Psr\Log\NullLogger() );
578 $provider->setConfig( $this->getConfig() );
579 $provider->setManager( SessionManager::singleton() );
580
581 $sessionId = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
582 $store = new TestBagOStuff();
583 $user = User::newFromName( 'UTSysop' );
584 $anon = new User;
585
586 $backend = new SessionBackend(
587 new SessionId( $sessionId ),
588 new SessionInfo( SessionInfo::MIN_PRIORITY, [
589 'provider' => $provider,
590 'id' => $sessionId,
591 'persisted' => true,
592 'idIsSafe' => true,
593 ] ),
594 $store,
595 new \Psr\Log\NullLogger(),
596 10
597 );
598 \TestingAccessWrapper::newFromObject( $backend )->usePhpSessionHandling = false;
599
600 // Anonymous user
601 $mock = $this->getMock( 'stdClass', [ 'onUserSetCookies' ] );
602 $mock->expects( $this->never() )->method( 'onUserSetCookies' );
603 $this->mergeMwGlobalArrayValue( 'wgHooks', [ 'UserSetCookies' => [ $mock ] ] );
604 $backend->setUser( $anon );
605 $backend->setRememberUser( true );
606 $backend->setForceHTTPS( false );
607 $request = new \FauxRequest();
608 $provider->persistSession( $backend, $request );
609 $this->assertSame( $sessionId, $request->response()->getCookie( 'MySessionName' ) );
610 $this->assertSame( '', $request->response()->getCookie( 'xUserID' ) );
611 $this->assertSame( null, $request->response()->getCookie( 'xUserName' ) );
612 $this->assertSame( '', $request->response()->getCookie( 'xToken' ) );
613 $this->assertSame( '', $request->response()->getCookie( 'forceHTTPS' ) );
614 $this->assertSame( [], $backend->getData() );
615
616 $provider->persistSession( $backend, $this->getSentRequest() );
617
618 // Logged-in user, no remember
619 $mock = $this->getMock( __CLASS__, [ 'onUserSetCookies' ] );
620 $mock->expects( $this->once() )->method( 'onUserSetCookies' )
621 ->will( $this->returnCallback( function ( $u, &$sessionData, &$cookies ) use ( $user ) {
622 $this->assertSame( $user, $u );
623 $this->assertEquals( [
624 'wsUserID' => $user->getId(),
625 'wsUserName' => $user->getName(),
626 'wsToken' => $user->getToken(),
627 ], $sessionData );
628 $this->assertEquals( [
629 'UserID' => $user->getId(),
630 'UserName' => $user->getName(),
631 'Token' => false,
632 ], $cookies );
633
634 $sessionData['foo'] = 'foo!';
635 $cookies['bar'] = 'bar!';
636 return true;
637 } ) );
638 $this->mergeMwGlobalArrayValue( 'wgHooks', [ 'UserSetCookies' => [ $mock ] ] );
639 $backend->setUser( $user );
640 $backend->setRememberUser( false );
641 $backend->setForceHTTPS( false );
642 $backend->setLoggedOutTimestamp( $loggedOut = time() );
643 $request = new \FauxRequest();
644 $provider->persistSession( $backend, $request );
645 $this->assertSame( $sessionId, $request->response()->getCookie( 'MySessionName' ) );
646 $this->assertSame( (string)$user->getId(), $request->response()->getCookie( 'xUserID' ) );
647 $this->assertSame( $user->getName(), $request->response()->getCookie( 'xUserName' ) );
648 $this->assertSame( '', $request->response()->getCookie( 'xToken' ) );
649 $this->assertSame( '', $request->response()->getCookie( 'forceHTTPS' ) );
650 $this->assertSame( 'bar!', $request->response()->getCookie( 'xbar' ) );
651 $this->assertSame( (string)$loggedOut, $request->response()->getCookie( 'xLoggedOut' ) );
652 $this->assertEquals( [
653 'wsUserID' => $user->getId(),
654 'wsUserName' => $user->getName(),
655 'wsToken' => $user->getToken(),
656 'foo' => 'foo!',
657 ], $backend->getData() );
658
659 $provider->persistSession( $backend, $this->getSentRequest() );
660
661 // Logged-in user, remember
662 $mock = $this->getMock( __CLASS__, [ 'onUserSetCookies' ] );
663 $mock->expects( $this->once() )->method( 'onUserSetCookies' )
664 ->will( $this->returnCallback( function ( $u, &$sessionData, &$cookies ) use ( $user ) {
665 $this->assertSame( $user, $u );
666 $this->assertEquals( [
667 'wsUserID' => $user->getId(),
668 'wsUserName' => $user->getName(),
669 'wsToken' => $user->getToken(),
670 ], $sessionData );
671 $this->assertEquals( [
672 'UserID' => $user->getId(),
673 'UserName' => $user->getName(),
674 'Token' => $user->getToken(),
675 ], $cookies );
676
677 $sessionData['foo'] = 'foo 2!';
678 $cookies['bar'] = 'bar 2!';
679 return true;
680 } ) );
681 $this->mergeMwGlobalArrayValue( 'wgHooks', [ 'UserSetCookies' => [ $mock ] ] );
682 $backend->setUser( $user );
683 $backend->setRememberUser( true );
684 $backend->setForceHTTPS( true );
685 $backend->setLoggedOutTimestamp( 0 );
686 $request = new \FauxRequest();
687 $provider->persistSession( $backend, $request );
688 $this->assertSame( $sessionId, $request->response()->getCookie( 'MySessionName' ) );
689 $this->assertSame( (string)$user->getId(), $request->response()->getCookie( 'xUserID' ) );
690 $this->assertSame( $user->getName(), $request->response()->getCookie( 'xUserName' ) );
691 $this->assertSame( $user->getToken(), $request->response()->getCookie( 'xToken' ) );
692 $this->assertSame( 'true', $request->response()->getCookie( 'forceHTTPS' ) );
693 $this->assertSame( 'bar 2!', $request->response()->getCookie( 'xbar' ) );
694 $this->assertSame( null, $request->response()->getCookie( 'xLoggedOut' ) );
695 $this->assertEquals( [
696 'wsUserID' => $user->getId(),
697 'wsUserName' => $user->getName(),
698 'wsToken' => $user->getToken(),
699 'foo' => 'foo 2!',
700 ], $backend->getData() );
701
702 $provider->persistSession( $backend, $this->getSentRequest() );
703 }
704
705 public function testUnpersistSession() {
706 $provider = new CookieSessionProvider( [
707 'priority' => 1,
708 'sessionName' => 'MySessionName',
709 'cookieOptions' => [ 'prefix' => 'x' ],
710 ] );
711 $provider->setLogger( new \Psr\Log\NullLogger() );
712 $provider->setConfig( $this->getConfig() );
713 $provider->setManager( SessionManager::singleton() );
714
715 $request = new \FauxRequest();
716 $provider->unpersistSession( $request );
717 $this->assertSame( '', $request->response()->getCookie( 'MySessionName' ) );
718 $this->assertSame( '', $request->response()->getCookie( 'xUserID' ) );
719 $this->assertSame( null, $request->response()->getCookie( 'xUserName' ) );
720 $this->assertSame( '', $request->response()->getCookie( 'xToken' ) );
721 $this->assertSame( '', $request->response()->getCookie( 'forceHTTPS' ) );
722
723 $provider->unpersistSession( $this->getSentRequest() );
724 }
725
726 public function testSetLoggedOutCookie() {
727 $provider = \TestingAccessWrapper::newFromObject( new CookieSessionProvider( [
728 'priority' => 1,
729 'sessionName' => 'MySessionName',
730 'cookieOptions' => [ 'prefix' => 'x' ],
731 ] ) );
732 $provider->setLogger( new \Psr\Log\NullLogger() );
733 $provider->setConfig( $this->getConfig() );
734 $provider->setManager( SessionManager::singleton() );
735
736 $t1 = time();
737 $t2 = time() - 86400 * 2;
738
739 // Set it
740 $request = new \FauxRequest();
741 $provider->setLoggedOutCookie( $t1, $request );
742 $this->assertSame( (string)$t1, $request->response()->getCookie( 'xLoggedOut' ) );
743
744 // Too old
745 $request = new \FauxRequest();
746 $provider->setLoggedOutCookie( $t2, $request );
747 $this->assertSame( null, $request->response()->getCookie( 'xLoggedOut' ) );
748
749 // Don't reset if it's already set
750 $request = new \FauxRequest();
751 $request->setCookies( [
752 'xLoggedOut' => $t1,
753 ], '' );
754 $provider->setLoggedOutCookie( $t1, $request );
755 $this->assertSame( null, $request->response()->getCookie( 'xLoggedOut' ) );
756 }
757
758 /**
759 * To be mocked for hooks, since PHPUnit can't otherwise mock methods that
760 * take references.
761 */
762 public function onUserSetCookies( $user, &$sessionData, &$cookies ) {
763 }
764
765 }