‪TYPO3CMS  10.4
FrontendUserAuthenticationTest.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use Doctrine\DBAL\Statement;
21 use Prophecy\Argument;
22 use Psr\Log\NullLogger;
35 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
36 
42 class ‪FrontendUserAuthenticationTest extends UnitTestCase
43 {
44  private const ‪NOT_CHECKED_INDICATOR = '--not-checked--';
45 
49  protected ‪$resetSingletonInstances = true;
50 
57  {
58  $uniqueSessionId = ‪StringUtility::getUniqueId('test');
59  $_COOKIE['fe_typo_user'] = $uniqueSessionId;
60 
61  // This setup fakes the "getAuthInfoArray() db call
62  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
63  $connectionPoolProphecy = $this->prophesize(ConnectionPool::class);
64  $connectionPoolProphecy->getQueryBuilderForTable('fe_users')->willReturn($queryBuilderProphecy->reveal());
65  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphecy->reveal());
66  $expressionBuilderProphecy = $this->prophesize(ExpressionBuilder::class);
67  $queryBuilderProphecy->expr()->willReturn($expressionBuilderProphecy->reveal());
68  $compositeExpressionProphecy = $this->prophesize(CompositeExpression::class);
69  $expressionBuilderProphecy->andX(Argument::cetera())->willReturn($compositeExpressionProphecy->reveal());
70  $expressionBuilderProphecy->in(Argument::cetera())->willReturn('');
71 
72  // Main session backend setup
73  $sessionBackendProphecy = $this->prophesize(SessionBackendInterface::class);
74  $sessionRecord = [
75  'ses_id' => $uniqueSessionId . ‪self::NOT_CHECKED_INDICATOR,
76  'ses_data' => serialize(['foo' => 'bar']),
77  'ses_anonymous' => true,
78  'ses_iplock' => '[DISABLED]',
79  ];
80  $sessionBackendProphecy->get($uniqueSessionId)->shouldBeCalled()->willReturn($sessionRecord);
81  $sessionManagerProphecy = $this->prophesize(SessionManager::class);
82  GeneralUtility::setSingletonInstance(SessionManager::class, $sessionManagerProphecy->reveal());
83  $sessionManagerProphecy->getSessionBackend('FE')->willReturn($sessionBackendProphecy->reveal());
84 
85  $subject = new ‪FrontendUserAuthentication();
86  $subject->setLogger(new NullLogger());
87  $subject->gc_probability = -1;
88  $subject->start();
89 
90  self::assertArrayNotHasKey('uid', $subject->user);
91  self::assertEquals('bar', $subject->getSessionData('foo'));
92  self::assertEquals($uniqueSessionId, $subject->id);
93  }
94 
99  {
100  // This setup fakes the "getAuthInfoArray() db call
101  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
102  $connectionPoolProphecy = $this->prophesize(ConnectionPool::class);
103  $connectionPoolProphecy->getQueryBuilderForTable('fe_users')->willReturn($queryBuilderProphecy->reveal());
104  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphecy->reveal());
105  $expressionBuilderProphecy = $this->prophesize(ExpressionBuilder::class);
106  $queryBuilderProphecy->expr()->willReturn($expressionBuilderProphecy->reveal());
107  $compositeExpressionProphecy = $this->prophesize(CompositeExpression::class);
108  $expressionBuilderProphecy->andX(Argument::cetera())->willReturn($compositeExpressionProphecy->reveal());
109  $expressionBuilderProphecy->in(Argument::cetera())->willReturn('');
110 
111  // Main session backend setup
112  $sessionBackendProphecy = $this->prophesize(SessionBackendInterface::class);
113  $sessionManagerProphecy = $this->prophesize(SessionManager::class);
114  GeneralUtility::setSingletonInstance(SessionManager::class, $sessionManagerProphecy->reveal());
115  $sessionManagerProphecy->getSessionBackend('FE')->willReturn($sessionBackendProphecy->reveal());
116  // @todo Session handling is not used/evaluated at all in this test
117 
118  // Verify new session id is generated
119  $randomProphecy = $this->prophesize(Random::class);
120  $randomProphecy->generateRandomHexString(32)->shouldBeCalled()->willReturn('newSessionId');
121  GeneralUtility::addInstance(Random::class, $randomProphecy->reveal());
122 
123  // set() and update() shouldn't be called since no session cookie is set
124  $sessionBackendProphecy->set(Argument::cetera())->shouldNotBeCalled();
125  $sessionBackendProphecy->update(Argument::cetera())->shouldNotBeCalled();
126 
127  $subject = new ‪FrontendUserAuthentication();
128  $subject->setLogger(new NullLogger());
129  $subject->gc_probability = -1;
130  $subject->start();
131  $subject->storeSessionData();
132  }
133 
140  public function ‪canSetAndUnsetSessionKey()
141  {
142  $uniqueSessionId = ‪StringUtility::getUniqueId('test');
143  $_COOKIE['fe_typo_user'] = $uniqueSessionId;
144 
145  // This setup fakes the "getAuthInfoArray() db call
146  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
147  $connectionPoolProphecy = $this->prophesize(ConnectionPool::class);
148  $connectionPoolProphecy->getQueryBuilderForTable('fe_users')->willReturn($queryBuilderProphecy->reveal());
149  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphecy->reveal());
150  $expressionBuilderProphecy = $this->prophesize(ExpressionBuilder::class);
151  $queryBuilderProphecy->expr()->willReturn($expressionBuilderProphecy->reveal());
152  $compositeExpressionProphecy = $this->prophesize(CompositeExpression::class);
153  $expressionBuilderProphecy->andX(Argument::cetera())->willReturn($compositeExpressionProphecy->reveal());
154  $expressionBuilderProphecy->in(Argument::cetera())->willReturn('');
155 
156  // Main session backend setup
157  $sessionBackendProphecy = $this->prophesize(SessionBackendInterface::class);
158  $sessionRecord = [
159  'ses_id' => $uniqueSessionId . ‪self::NOT_CHECKED_INDICATOR,
160  'ses_data' => serialize(['foo' => 'bar']),
161  'ses_anonymous' => true,
162  'ses_iplock' => '[DISABLED]',
163  ];
164  $sessionBackendProphecy->get($uniqueSessionId)->shouldBeCalled()->willReturn($sessionRecord);
165  $sessionManagerProphecy = $this->prophesize(SessionManager::class);
166  GeneralUtility::setSingletonInstance(SessionManager::class, $sessionManagerProphecy->reveal());
167  $sessionManagerProphecy->getSessionBackend('FE')->willReturn($sessionBackendProphecy->reveal());
168 
169  // set() and update() shouldn't be called since no session cookie is set
170  $sessionBackendProphecy->set(Argument::cetera())->shouldNotBeCalled();
171  $sessionBackendProphecy->update(Argument::cetera())->shouldNotBeCalled();
172  // remove() should be called with given session id
173  $sessionBackendProphecy->remove($uniqueSessionId)->shouldBeCalled();
174 
175  $subject = new FrontendUserAuthentication();
176  $subject->setLogger(new NullLogger());
177  $subject->gc_probability = -1;
178  $subject->start();
179  $subject->setSessionData('foo', 'bar');
180  $subject->removeSessionData();
181  self::assertNull($subject->getSessionData('someKey'));
182  }
183 
189  public function ‪canSetSessionDataForAnonymousUser()
190  {
191  $uniqueSessionId = ‪StringUtility::getUniqueId('test');
192  $_COOKIE['fe_typo_user'] = $uniqueSessionId;
193  ‪$GLOBALS['TYPO3_CONF_VARS']['FE']['lockIP'] = 0;
194  $currentTime = ‪$GLOBALS['EXEC_TIME'];
195 
196  // This setup fakes the "getAuthInfoArray() db call
197  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
198  $connectionPoolProphecy = $this->prophesize(ConnectionPool::class);
199  $connectionPoolProphecy->getQueryBuilderForTable('fe_users')->willReturn($queryBuilderProphecy->reveal());
200  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphecy->reveal());
201  $expressionBuilderProphecy = $this->prophesize(ExpressionBuilder::class);
202  $queryBuilderProphecy->expr()->willReturn($expressionBuilderProphecy->reveal());
203  $compositeExpressionProphecy = $this->prophesize(CompositeExpression::class);
204  $expressionBuilderProphecy->andX(Argument::cetera())->willReturn($compositeExpressionProphecy->reveal());
205  $expressionBuilderProphecy->in(Argument::cetera())->willReturn('');
206 
207  // Main session backend setup
208  $sessionBackendProphecy = $this->prophesize(SessionBackendInterface::class);
209  $sessionBackendProphecy->get($uniqueSessionId)->shouldBeCalled()->willThrow(new SessionNotFoundException('testing', 1486676313));
210  $sessionManagerProphecy = $this->prophesize(SessionManager::class);
211  GeneralUtility::setSingletonInstance(SessionManager::class, $sessionManagerProphecy->reveal());
212  $sessionManagerProphecy->getSessionBackend('FE')->willReturn($sessionBackendProphecy->reveal());
213 
214  // Verify new session id is generated
215  $randomProphecy = $this->prophesize(Random::class);
216  $randomProphecy->generateRandomHexString(32)->shouldBeCalled()->willReturn('newSessionId');
217  GeneralUtility::addInstance(Random::class, $randomProphecy->reveal());
218 
219  // set() and update() shouldn't be called since no session cookie is set
220  $sessionBackendProphecy->update(Argument::cetera())->shouldNotBeCalled();
221  $sessionBackendProphecy->get('newSessionId')->shouldBeCalled()->willThrow(new SessionNotFoundException('testing', 1486676314));
222 
223  // new session should be written
224  $sessionBackendProphecy->set(
225  'newSessionId',
226  [
227  'ses_id' => 'newSessionId',
228  'ses_iplock' => '[DISABLED]',
229  'ses_userid' => 0,
230  'ses_tstamp' => $currentTime,
231  'ses_data' => serialize(['foo' => 'bar']),
232  'ses_permanent' => 0,
233  'ses_anonymous' => 1 // sic!
234  ]
235  )->shouldBeCalled();
236 
237  $subject = new FrontendUserAuthentication();
238  $subject->setLogger(new NullLogger());
239  $subject->gc_probability = -1;
240  $subject->start();
241  self::assertEmpty($subject->getSessionData($uniqueSessionId));
242  self::assertEmpty($subject->user);
243  $subject->setSessionData('foo', 'bar');
244  self::assertNotNull($subject->getSessionData('foo'));
245 
246  // Suppress "headers already sent" errors - phpunit does that internally already
247  $prev = error_reporting(0);
248  $subject->storeSessionData();
249  error_reporting($prev);
250  }
251 
258  {
259  $uniqueSessionId = ‪StringUtility::getUniqueId('test');
260  $_COOKIE['fe_typo_user'] = $uniqueSessionId;
261  $currentTime = ‪$GLOBALS['EXEC_TIME'];
262 
263  // This setup fakes the "getAuthInfoArray() db call
264  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
265  $connectionPoolProphecy = $this->prophesize(ConnectionPool::class);
266  $connectionPoolProphecy->getQueryBuilderForTable('fe_users')->willReturn($queryBuilderProphecy->reveal());
267  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphecy->reveal());
268  $expressionBuilderProphecy = $this->prophesize(ExpressionBuilder::class);
269  $queryBuilderProphecy->expr()->willReturn($expressionBuilderProphecy->reveal());
270  $compositeExpressionProphecy = $this->prophesize(CompositeExpression::class);
271  $expressionBuilderProphecy->andX(Argument::cetera())->willReturn($compositeExpressionProphecy->reveal());
272  $expressionBuilderProphecy->in(Argument::cetera())->willReturn('');
273 
274  // Main session backend setup
275  $sessionBackendProphecy = $this->prophesize(SessionBackendInterface::class);
276  $sessionManagerProphecy = $this->prophesize(SessionManager::class);
277  GeneralUtility::setSingletonInstance(SessionManager::class, $sessionManagerProphecy->reveal());
278  $sessionManagerProphecy->getSessionBackend('FE')->willReturn($sessionBackendProphecy->reveal());
279 
280  // a valid session is returned
281  $sessionBackendProphecy->get($uniqueSessionId)->shouldBeCalled()->willReturn(
282  [
283  'ses_id' => $uniqueSessionId . self::NOT_CHECKED_INDICATOR,
284  'ses_userid' => 1,
285  'ses_iplock' => '[DISABLED]',
286  'ses_tstamp' => $currentTime,
287  'ses_data' => serialize(['foo' => 'bar']),
288  'ses_permanent' => 0,
289  'ses_anonymous' => 0 // sic!
290  ]
291  );
292 
293  // Mock call to fe_users table and let it return a valid user row
294  $connectionPoolFeUserProphecy = $this->prophesize(ConnectionPool::class);
295  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolFeUserProphecy->reveal());
296  $queryBuilderFeUserProphecy = $this->prophesize(QueryBuilder::class);
297  $queryBuilderFeUserProphecyRevelation = $queryBuilderFeUserProphecy->reveal();
298  $connectionPoolFeUserProphecy->getQueryBuilderForTable('fe_users')->willReturn($queryBuilderFeUserProphecyRevelation);
299  $queryBuilderFeUserProphecy->select('*')->willReturn($queryBuilderFeUserProphecyRevelation);
300  $queryBuilderFeUserProphecy->setRestrictions(Argument::cetera())->shouldBeCalled();
301  $queryBuilderFeUserProphecy->from('fe_users')->shouldBeCalled()->willReturn($queryBuilderFeUserProphecyRevelation);
302  $expressionBuilderFeUserProphecy = $this->prophesize(ExpressionBuilder::class);
303  $queryBuilderFeUserProphecy->expr()->willReturn($expressionBuilderFeUserProphecy->reveal());
304  $queryBuilderFeUserProphecy->createNamedParameter(Argument::cetera())->willReturnArgument(0);
305  $expressionBuilderFeUserProphecy->eq(Argument::cetera())->willReturn('1=1');
306  $queryBuilderFeUserProphecy->where(Argument::cetera())->shouldBeCalled()->willReturn($queryBuilderFeUserProphecyRevelation);
307  $statementFeUserProphecy = $this->prophesize(Statement::class);
308  $queryBuilderFeUserProphecy->execute()->shouldBeCalled()->willReturn($statementFeUserProphecy->reveal());
309  $statementFeUserProphecy->fetch()->willReturn(
310  [
311  'uid' => 1,
312  'username' => 'existingUserName',
313  'password' => 'abc',
314  'deleted' => 0,
315  'disabled' => 0
316  ]
317  );
318 
319  $subject = new FrontendUserAuthentication();
320  $subject->setLogger(new NullLogger());
321  $subject->gc_probability = -1;
322  $subject->start();
323 
324  self::assertNotNull($subject->user);
325  self::assertEquals('existingUserName', $subject->user['username']);
326  }
327 
332  {
333  ‪$GLOBALS['BE_USER'] = [];
334  // This setup fakes the "getAuthInfoArray() db call
335  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
336  $connectionPoolProphecy = $this->prophesize(ConnectionPool::class);
337  $connectionPoolProphecy->getQueryBuilderForTable('fe_users')->willReturn($queryBuilderProphecy->reveal());
338  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphecy->reveal());
339  $expressionBuilderProphecy = $this->prophesize(ExpressionBuilder::class);
340  $queryBuilderProphecy->expr()->willReturn($expressionBuilderProphecy->reveal());
341  $compositeExpressionProphecy = $this->prophesize(CompositeExpression::class);
342  $expressionBuilderProphecy->andX(Argument::cetera())->willReturn($compositeExpressionProphecy->reveal());
343  $expressionBuilderProphecy->in(Argument::cetera())->willReturn('');
344 
345  // Main session backend setup
346  $sessionBackendProphecy = $this->prophesize(SessionBackendInterface::class);
347  $sessionManagerProphecy = $this->prophesize(SessionManager::class);
348  GeneralUtility::setSingletonInstance(SessionManager::class, $sessionManagerProphecy->reveal());
349  $sessionManagerProphecy->getSessionBackend('FE')->willReturn($sessionBackendProphecy->reveal());
350 
351  // no session exists, yet
352  $sessionBackendProphecy->get('newSessionId')->willThrow(new SessionNotFoundException('testing', 1486676358));
353  $sessionBackendProphecy->remove('newSessionId')->shouldBeCalled();
354 
355  // Verify new session id is generated
356  $randomProphecy = $this->prophesize(Random::class);
357  $randomProphecy->generateRandomHexString(32)->shouldBeCalled()->willReturn('newSessionId');
358  GeneralUtility::addInstance(Random::class, $randomProphecy->reveal());
359 
360  // Mock the login data and auth services here since fully prophesize this is a lot of hassle
361  $subject = $this->getAccessibleMock(
362  FrontendUserAuthentication::class,
363  [
364  'getLoginFormData',
365  'getAuthServices',
366  'createUserSession',
367  'getCookie',
368  ]
369  );
370  $subject->setLogger(new NullLogger());
371  $subject->gc_probability = -1;
372 
373  // Mock a login attempt
374  $subject->method('getLoginFormData')->willReturn([
375  'status' => 'login',
376  'uname' => 'existingUserName',
377  'uident' => 'abc'
378  ]);
379 
380  $authServiceMock = $this->getMockBuilder(AuthenticationService::class)->getMock();
381  $authServiceMock->method('getUser')->willReturn([
382  'uid' => 1,
383  'username' => 'existingUserName'
384  ]);
385  // Auth services can return status codes: 0 (failed/abort), 100 (not responsible, continue), 200 (ok)
386  $authServiceMock->method('authUser')->willReturn(200);
387  // We need to wrap the array to something thats is \Traversable, in PHP 7.1 we can use traversable pseudo type instead
388  $subject->method('getAuthServices')->willReturn(new \ArrayIterator([$authServiceMock]));
389 
390  $subject->method('createUserSession')->willReturn([
391  'ses_id' => 'newSessionId'
392  ]);
393 
394  $subject->method('getCookie')->willReturn(null);
395 
396  $subject->start();
397  self::assertFalse($subject->loginFailure);
398  self::assertEquals('existingUserName', $subject->user['username']);
399  }
400 
407  {
408  self::markTestSkipped('Test is flaky, convert to a functional test');
409  // Mock SessionBackend
410  $sessionBackend = $this->getMockBuilder(SessionBackendInterface::class)->getMock();
411 
412  $oldSessionRecord = [
413  'ses_id' => 'oldSessionId',
414  'ses_data' => serialize(['foo' => 'bar']),
415  'ses_anonymous' => 1,
416  'ses_iplock' => 0,
417  ];
418 
419  // Return old, non authenticated session
420  $sessionBackend->method('get')->willReturn($oldSessionRecord);
421 
422  $expectedSessionRecord = array_merge(
423  $oldSessionRecord,
424  [
425  //ses_id is overwritten by the session backend
426  'ses_anonymous' => 0
427  ]
428  );
429 
430  $expectedUserId = 1;
431 
432  $sessionBackend->expects(self::once())->method('set')->with(
433  'newSessionId',
434  self::equalTo($expectedSessionRecord)
435  )->willReturnArgument(1);
436 
437  $this->subject->method('getSessionBackend')->willReturn($sessionBackend);
438  // Load old sessions
439  $this->subject->method('getCookie')->willReturn('oldSessionId');
440  $this->subject->method('createSessionId')->willReturn('newSessionId');
441 
442  // Mock a login attempt
443  $this->subject->method('getLoginFormData')->willReturn([
444  'status' => 'login',
445  'uname' => 'existingUserName',
446  'uident' => 'abc'
447  ]);
448 
449  $authServiceMock = $this->getMockBuilder(AuthenticationService::class)->getMock();
450  $authServiceMock->method('getUser')->willReturn([
451  'uid' => 1,
452  'username' => 'existingUserName'
453  ]);
454 
455  $authServiceMock->method('authUser')->willReturn(true); // Auth services can return true or 200
456 
457  // We need to wrap the array to something thats is \Traversable, in PHP 7.1 we can use traversable pseudo type instead
458  $this->subject->method('getAuthServices')->willReturn(new \ArrayIterator([$authServiceMock]));
459 
460  // Should call regenerateSessionId
461  // New session should be stored with with old values
462  $this->subject->start();
463 
464  self::assertEquals('newSessionId', $this->subject->id);
465  self::assertEquals($expectedUserId, $this->subject->user['uid']);
466  $this->subject->setSessionData('foobar', 'baz');
467  self::assertArraySubset(['foo' => 'bar'], $this->subject->_get('sessionData'));
468  self::assertTrue($this->subject->sesData_change);
469  }
470 
476  public function ‪canRemoveSessionData()
477  {
478  self::markTestSkipped('Test is flaky, convert to a functional test');
479  // Mock SessionBackend
480  $sessionBackend = $this->getMockBuilder(SessionBackendInterface::class)->getMock();
481  $sessionBackend->method('get')->willReturn(
482  [
483  'ses_id' => 'existingId',
484  'ses_userid' => 1, // fe_user with uid 0 assumed in database, see fixtures.xml
485  'ses_data' => serialize(['foo' => 'bar']),
486  'ses_iplock' => 0,
487  'ses_tstamp' => time() + 100 // Return a time in future to make avoid mocking $GLOBALS['EXEC_TIME']
488  ]
489  );
490  $this->subject->method('getSessionBackend')->willReturn($sessionBackend);
491  $this->subject->method('getCookie')->willReturn('existingId');
492 
493  $this->subject->start();
494 
495  $this->subject->removeSessionData();
496  self::assertEmpty($this->subject->getSessionData('foo'));
497  $this->subject->storeSessionData();
498  self::assertEmpty($this->subject->getSessionData('foo'));
499  }
500 
507  {
508  self::markTestSkipped('Test is flaky, convert to a functional test');
509  $sessionBackend = $this->getMockBuilder(SessionBackendInterface::class)->getMock();
510  // Mock SessionBackend
511  $this->subject->method('getSessionBackend')->willReturn($sessionBackend);
512 
513  $this->subject->method('createSessionId')->willReturn('newSessionId');
514 
515  $expectedSessionRecord = [
516  'ses_anonymous' => 1,
517  'ses_data' => serialize(['foo' => 'bar'])
518  ];
519 
520  $sessionBackend->expects(self::at(0))->method('get')->willThrowException(new SessionNotFoundException('testing', 1486045419));
521  $sessionBackend->expects(self::at(1))->method('get')->willThrowException(new SessionNotFoundException('testing', 1486045420));
522  $sessionBackend->expects(self::at(2))->method('get')->willReturn(
523  [
524  'ses_id' => 'newSessionId',
525  'ses_anonymous' => 1
526  ]
527  );
528 
529  $sessionBackend->expects(self::once())
530  ->method('set')
531  ->with('newSessionId', new \PHPUnit_Framework_Constraint_ArraySubset($expectedSessionRecord))
532  ->willReturn([
533  'ses_id' => 'newSessionId',
534  'ses_anonymous' => 1,
535  'ses_data' => serialize(['foo' => 'bar']),
536  ]);
537 
538  // Can set and store session data
539  $this->subject->start();
540  self::assertEmpty($this->subject->_get('sessionData'));
541  self::assertEmpty($this->subject->user);
542  $this->subject->setSessionData('foo', 'bar');
543  self::assertNotNull($this->subject->getSessionData('foo'));
544  $this->subject->storeSessionData();
545 
546  // Should delete session after setting to null
547  $this->subject->setSessionData('foo', null);
548  self::assertNull($this->subject->getSessionData('foo'));
549  $sessionBackend->expects(self::once())->method('remove')->with('newSessionId');
550  $sessionBackend->expects(self::never())->method('update');
551 
552  $this->subject->storeSessionData();
553  }
554 
560  {
561  self::markTestSkipped('Test is flaky, convert to a functional test');
562  $sessionBackend = $this->getMockBuilder(SessionBackendInterface::class)->getMock();
563  $this->subject->method('getSessionBackend')->willReturn($sessionBackend);
564  $this->subject->method('createSessionId')->willReturn('newSessionId');
565 
566  $sessionBackend->method('get')->willReturn(
567  [
568  'ses_id' => 'existingId',
569  'ses_userid' => 1,
570  'ses_data' => serialize(['foo' => 'bar']),
571  'ses_iplock' => 0,
572  'ses_tstamp' => time() + 100 // Return a time in future to make avoid mocking $GLOBALS['EXEC_TIME']
573  ]
574  );
575  $this->subject->method('getSessionBackend')->willReturn($sessionBackend);
576  $this->subject->method('getCookie')->willReturn('existingId');
577 
578  $this->subject->method('getRawUserByUid')->willReturn([
579  'uid' => 1,
580  ]);
581 
582  // fix logout data
583  // Mock a logout attempt
584  $this->subject->method('getLoginFormData')->willReturn([
585  'status' => 'logout',
586 
587  ]);
588 
589  $sessionBackend->expects(self::once())->method('set')->with('newSessionId', self::anything())->willReturnArgument(1);
590  $sessionBackend->expects(self::once())->method('remove')->with('existingId');
591 
592  // start
593  $this->subject->start();
594  // asset that session data is there
595  self::assertNotEmpty($this->subject->user);
596  self::assertEquals(1, (int)$this->subject->user['ses_anonymous']);
597  self::assertEquals(['foo' => 'bar'], $this->subject->_get('sessionData'));
598 
599  self::assertEquals('newSessionId', $this->subject->id);
600  }
601 }
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder
Definition: ExpressionBuilder.php:35
‪TYPO3\CMS\Frontend\Tests\Unit\Authentication\FrontendUserAuthenticationTest\canSetAndUnsetSessionKey
‪canSetAndUnsetSessionKey()
Definition: FrontendUserAuthenticationTest.php:139
‪TYPO3\CMS\Frontend\Tests\Unit\Authentication\FrontendUserAuthenticationTest\sessionDataShouldBePreservedOnLogout
‪sessionDataShouldBePreservedOnLogout()
Definition: FrontendUserAuthenticationTest.php:558
‪TYPO3\CMS\Frontend\Tests\Unit\Authentication
Definition: FrontendUserAuthenticationTest.php:18
‪TYPO3\CMS\Frontend\Tests\Unit\Authentication\FrontendUserAuthenticationTest\NOT_CHECKED_INDICATOR
‪const NOT_CHECKED_INDICATOR
Definition: FrontendUserAuthenticationTest.php:44
‪TYPO3\CMS\Core\Session\SessionManager
Definition: SessionManager.php:39
‪TYPO3\CMS\Frontend\Tests\Unit\Authentication\FrontendUserAuthenticationTest\destroysAnonymousSessionIfDataIsNull
‪destroysAnonymousSessionIfDataIsNull()
Definition: FrontendUserAuthenticationTest.php:505
‪TYPO3\CMS\Frontend\Tests\Unit\Authentication\FrontendUserAuthenticationTest\storeSessionDataOnAnonymousUserWithNoData
‪storeSessionDataOnAnonymousUserWithNoData()
Definition: FrontendUserAuthenticationTest.php:97
‪TYPO3\CMS\Frontend\Tests\Unit\Authentication\FrontendUserAuthenticationTest\canRemoveSessionData
‪canRemoveSessionData()
Definition: FrontendUserAuthenticationTest.php:475
‪TYPO3\CMS\Core\Database\Query\QueryBuilder
Definition: QueryBuilder.php:52
‪TYPO3\CMS\Core\Database\Query\Expression\CompositeExpression
Definition: CompositeExpression.php:25
‪TYPO3\CMS\Core\Session\Backend\SessionBackendInterface
Definition: SessionBackendInterface.php:28
‪TYPO3\CMS\Frontend\Tests\Unit\Authentication\FrontendUserAuthenticationTest\canPreserveSessionDataWhenAuthenticating
‪canPreserveSessionDataWhenAuthenticating()
Definition: FrontendUserAuthenticationTest.php:405
‪TYPO3\CMS\Frontend\Tests\Unit\Authentication\FrontendUserAuthenticationTest\userFieldIsNotSetForAnonymousSessions
‪userFieldIsNotSetForAnonymousSessions()
Definition: FrontendUserAuthenticationTest.php:55
‪TYPO3\CMS\Core\Authentication\AuthenticationService
Definition: AuthenticationService.php:33
‪TYPO3\CMS\Core\Utility\StringUtility\getUniqueId
‪static string getUniqueId($prefix='')
Definition: StringUtility.php:92
‪TYPO3\CMS\Frontend\Tests\Unit\Authentication\FrontendUserAuthenticationTest\canSetSessionDataForAnonymousUser
‪canSetSessionDataForAnonymousUser()
Definition: FrontendUserAuthenticationTest.php:188
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Frontend\Tests\Unit\Authentication\FrontendUserAuthenticationTest\canLogUserInWithoutAnonymousSession
‪canLogUserInWithoutAnonymousSession()
Definition: FrontendUserAuthenticationTest.php:330
‪TYPO3\CMS\Core\Crypto\Random
Definition: Random.php:24
‪TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication
Definition: FrontendUserAuthentication.php:30
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Core\Utility\StringUtility
Definition: StringUtility.php:22
‪TYPO3\CMS\Frontend\Tests\Unit\Authentication\FrontendUserAuthenticationTest\$resetSingletonInstances
‪bool $resetSingletonInstances
Definition: FrontendUserAuthenticationTest.php:48
‪TYPO3\CMS\Core\Session\Backend\Exception\SessionNotFoundException
Definition: SessionNotFoundException.php:24
‪TYPO3\CMS\Frontend\Tests\Unit\Authentication\FrontendUserAuthenticationTest
Definition: FrontendUserAuthenticationTest.php:43
‪TYPO3\CMS\Frontend\Tests\Unit\Authentication\FrontendUserAuthenticationTest\canLoadExistingAuthenticatedSession
‪canLoadExistingAuthenticatedSession()
Definition: FrontendUserAuthenticationTest.php:256