ILIAS  trunk Revision v13.0_alpha-52-g21c366bbdd4
ilSessionTest.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22use PHPUnit\Framework\TestCase;
23
24class ilSessionTest extends TestCase
25{
26 private ?Container $dic_backup = null;
27
28 protected function setUp(): void
29 {
30 global $DIC;
31
32 $this->dic_backup = $DIC;
33
34 if (!isset($DIC)) {
35 $DIC = new Container();
36 }
37
38 $this->setGlobalVariable(
39 'ilDB',
40 $this->createMock(ilDBInterface::class)
41 );
42
44 }
45
46 protected function tearDown(): void
47 {
48 global $DIC;
49
51
53 }
54
59 protected function setGlobalVariable(string $name, $value): void
60 {
61 global $DIC;
62
63 $GLOBALS[$name] = $value;
64
65 unset($DIC[$name]);
66 $DIC[$name] = static function (Container $c) use ($name) {
67 return $GLOBALS[$name];
68 };
69 }
70
71 public function testBasicSessionBehaviour(): void
72 {
73 global $DIC;
74
75 $this->setGlobalVariable(
76 'ilClientIniFile',
77 $this->getMockBuilder(ilIniFile::class)->disableOriginalConstructor()->getMock()
78 );
79
81 $settings = $this->getMockBuilder(ilSetting::class)->getMock();
83 ->expects($this->once())
84 ->method('get')
85 ->willReturnCallback(
86 function ($arg) {
87 if ($arg === 'session_statistics') {
88 return '0';
89 }
90
91 throw new RuntimeException($arg);
92 }
93 );
94 $this->setGlobalVariable(
95 'ilSetting',
97 );
98
100 $ilDB = $DIC['ilDB'];
101 $ilDB
102 ->expects($this->atLeastOnce())
103 ->method('update')
104 ->with('usr_session')
105 ->willReturn(1);
106
107 $consecutive_quote = [
108 '123456',
109 '123456',
110 '123456',
111 'e10adc3949ba59abbe56e057f20f883e',
112 '123456',
113 'e10adc3949ba59abbe56e057f20f883e',
114 'e10adc3949ba59abbe56e057f20f883e',
115 '123456',
116 '123456',
117 '123456',
118 time() - 100,
119 'e10adc3949ba59abbe56e057f20f883e',
120 17,
121 'e10adc3949ba59abbe56e057f20f883e'
122 ];
123 $ilDB
124 ->expects($this->exactly(count($consecutive_quote)))
125 ->method('quote')
126 ->with(
127 $this->callback(function ($value) use (&$consecutive_quote) {
128 if (count($consecutive_quote) === 4) {
129 $this->assertGreaterThan(array_shift($consecutive_quote), $value);
130 } else {
131 $this->assertSame(array_shift($consecutive_quote), $value);
132 }
133 return true;
134 })
135 )->willReturnOnConsecutiveCalls(
136 '123456',
137 '123456',
138 '123456',
139 'e10adc3949ba59abbe56e057f20f883e',
140 'e10adc3949ba59abbe56e057f20f883e',
141 '123456',
142 'e10adc3949ba59abbe56e057f20f883e',
143 'e10adc3949ba59abbe56e057f20f883e',
144 '123456',
145 '123456',
146 '123456',
147 (string) time(),
148 'e10adc3949ba59abbe56e057f20f883e',
149 '17',
150 'e10adc3949ba59abbe56e057f20f883e'
151 );
152 $ilDB
153 ->expects($this->exactly(6))
154 ->method('numRows')
155 ->willReturn(1, 1, 1, 0, 1, 0);
156
157 $consecutive_select = [
158 'SELECT 1 FROM usr_session WHERE session_id = 123456',
159 'SELECT 1 FROM usr_session WHERE session_id = 123456',
160 'SELECT data FROM usr_session WHERE session_id = 123456',
161 'SELECT * FROM usr_session WHERE session_id = e10adc3949ba59abbe56e057f20f883e',
162 'SELECT * FROM usr_session WHERE session_id = e10adc3949ba59abbe56e057f20f883e',
163 'SELECT 1 FROM usr_session WHERE session_id = 123456',
164 'SELECT data FROM usr_session WHERE session_id = e10adc3949ba59abbe56e057f20f883e',
165 'SELECT 1 FROM usr_session WHERE session_id = 123456',
166 'SELECT session_id, expires FROM usr_session WHERE expires < 123456',
167 'SELECT 1 FROM usr_session WHERE session_id = ',
168 'SELECT 1 FROM usr_session WHERE session_id = 17'
169 ];
170 $ilDB
171 ->expects($this->exactly(count($consecutive_select)))
172 ->method('query')
173 ->with(
174 $this->callback(function ($value) use (&$consecutive_select) {
175 if (count($consecutive_select) === 2) {
176 $this->assertStringStartsWith(array_shift($consecutive_select), $value);
177 } else {
178 $this->assertSame(array_shift($consecutive_select), $value);
179 }
180 return true;
181 })
182 )->willReturnOnConsecutiveCalls(
183 $this->createMock(ilDBStatement::class),
184 $this->createMock(ilDBStatement::class),
185 $this->createMock(ilDBStatement::class),
186 $this->createMock(ilDBStatement::class),
187 $this->createMock(ilDBStatement::class),
188 $this->createMock(ilDBStatement::class),
189 $this->createMock(ilDBStatement::class),
190 $this->createMock(ilDBStatement::class),
191 $this->createMock(ilDBStatement::class),
192 $this->createMock(ilDBStatement::class),
193 $this->createMock(ilDBStatement::class)
194 );
195 $ilDB
196 ->expects($this->exactly(4))
197 ->method('fetchAssoc')->willReturn(
198 ['data' => 'Testdata'],
199 [],
200 ['data' => 'Testdata'],
201 []
202 );
203 $ilDB
204 ->expects($this->once())
205 ->method('fetchObject')->willReturn(
206 (object) [
207 'data' => 'Testdata'
208 ]
209 );
210
211 $consecutive_delete = [
212 'DELETE FROM usr_sess_istorage WHERE session_id = 123456',
213 'DELETE FROM usr_session WHERE session_id = e10adc3949ba59abbe56e057f20f883e',
214 'DELETE FROM usr_session WHERE user_id = e10adc3949ba59abbe56e057f20f883e'
215 ];
216 $ilDB
217 ->expects($this->exactly(count($consecutive_delete)))
218 ->method('manipulate')->with(
219 $this->callback(function ($value) use (&$consecutive_delete) {
220 $this->assertSame(array_shift($consecutive_delete), $value);
221 return true;
222 })
223 )->willReturnOnConsecutiveCalls(
224 1,
225 1,
226 1
227 );
228
229 $cron_manager = $this->createMock(\ILIAS\Cron\Job\JobManager::class);
230 $cron_manager
231 ->expects($this->atLeastOnce())
232 ->method('isJobActive')
233 ->with($this->isString())
234 ->willReturn(true);
235 $this->setGlobalVariable(
236 'cron.manager',
237 $cron_manager
238 );
239
240 $result = '';
241 ilSession::writeData('123456', 'Testdata');
242 if (ilSession::exists('123456')) {
243 $result .= 'exists-';
244 }
245 if (ilSession::getData('123456') === 'Testdata') {
246 $result .= 'write-get-';
247 }
248 $duplicate = ilSession::duplicate('123456');
249 if (ilSession::getData($duplicate) === 'Testdata') {
250 $result .= 'duplicate-';
251 }
252 ilSession::destroy('123456');
253 if (!ilSession::exists('123456')) {
254 $result .= 'destroy-';
255 }
257 if (ilSession::exists($duplicate)) {
258 $result .= 'destroyExp-';
259 }
260
262 if (!ilSession::exists($duplicate)) {
263 $result .= 'destroyByUser-';
264 }
265
266 $this->assertEquals('exists-write-get-duplicate-destroy-destroyExp-destroyByUser-', $result);
267 }
268
269 public function testPasswordAssisstanceSession(): void
270 {
271 $actual = '';
272 $usr_id = 4711;
273
274 try {
275 $sqlite = new PDO('sqlite::memory:');
276 $create_table = <<<SQL
277create table usr_pwassist
278(
279 pwassist_id char(180) default '' not null primary key,
280 expires int default 0 not null,
281 ctime int default 0 not null,
282 user_id int default 0 not null,
283 constraint c1_idx
284 unique (user_id)
285);
286SQL;
287
288 $sqlite->query($create_table);
289 } catch (Exception $e) {
290 $this->markTestIncomplete(
291 'Cannot test the password assistance session storage because of missing sqlite: ' . $e->getMessage()
292 );
293 }
294
295 $db = $this->createMock(ilDBInterface::class);
296 $db->method('quote')->willReturnCallback(static function ($value, ?string $type = null) use ($sqlite): string {
297 if ($value === null) {
298 return 'NULL';
299 }
300
301 $pdo_type = PDO::PARAM_STR;
302 switch ($type) {
306 if ($value === '') {
307 return 'NULL';
308 }
309 if ($value === 'NOW()') {
310 return $value;
311 }
312 $value = (string) $value;
313 break;
315 return (string) (int) $value;
317 $pdo_type = PDO::PARAM_INT;
318 $value = (string) $value;
319 break;
321 default:
322 $value = (string) $value;
323 $pdo_type = PDO::PARAM_STR;
324 break;
325 }
326
327 return $sqlite->quote((string) $value, $pdo_type);
328 });
329 $db->method('query')->willReturnCallback(static function (string $query) use ($sqlite): ilDBStatement {
330 return new ilPDOStatement($sqlite->query($query));
331 });
332 $db->method('manipulate')->willReturnCallback(static function (string $query) use ($sqlite): int {
333 return (int) $sqlite->exec($query);
334 });
335 $db->method('manipulateF')->willReturnCallback(static function (...$args) use ($db): int {
336 $query = $args[0];
337
338 $quoted_values = [];
339 foreach ($args[1] as $k => $t) {
340 $quoted_values[] = $db->quote($args[2][$k], $t);
341 }
342 $query = vsprintf($query, $quoted_values);
343
344 return $db->manipulate($query);
345 });
346 $db->method('fetchAssoc')->willReturnCallback(static function (ilDBStatement $statement): ?array {
347 $res = $statement->fetch(PDO::FETCH_ASSOC);
348 if ($res === null || $res === false) {
349 $statement->closeCursor();
350
351 return null;
352 }
353
354 return $res;
355 });
356
357 $pwa_repository = new \ILIAS\Init\PasswordAssitance\Repository\PasswordAssistanceDbRepository(
358 $db,
359 (new \ILIAS\Data\Factory())->clock()->system()
360 );
361
362 $hash = new \ILIAS\Init\PasswordAssitance\ValueObject\PasswordAssistanceHash(
363 'ae869e66007cc9812f1752f7a3a59f07d3e28bed8361827d0a05563e5c2f4b11'
364 );
365 $session = $pwa_repository->createSession(
366 $hash,
367 (new \ILIAS\Data\Factory())->objId($usr_id)
368 );
369
370 $result = $pwa_repository->getSessionByUsrId($session->usrId());
371 if ($result->value()->hash()->value() === $session->hash()->value()) {
372 $actual .= 'find-';
373 }
374
375 $result = $pwa_repository->getSessionByHash($session->hash());
376 if ($result->value()->usrId()->toInt() === $usr_id) {
377 $actual .= 'read-';
378 }
379
380 $pwa_repository->deleteSession($session);
381 $result = $pwa_repository->getSessionByHash($session->hash());
382 if ($result->isError()) {
383 $actual .= 'destroy-';
384 }
385
386 $this->assertEquals('find-read-destroy-', $actual);
387
388 $sqlite = null;
389 }
390
392 {
393 $client_ini = $this->getMockBuilder(ilIniFile::class)->disableOriginalConstructor()->getMock();
394 $client_ini
395 ->expects($this->once())
396 ->method('readVariable')
397 ->with('session', 'expire')
398 ->willReturn('1800');
399 $this->setGlobalVariable('ilClientIniFile', $client_ini);
400
401 $ilDB = $GLOBALS['DIC']['ilDB'];
402
403 $before = time();
404 $ilDB
405 ->expects($this->once())
406 ->method('update')
407 ->with(
408 'usr_session',
409 $this->callback(static function (array $values) use ($before): bool {
410 if (array_key_exists('data', $values) || array_key_exists('user_id', $values)) {
411 return false;
412 }
413
414 $expires = $values['expires'][1] ?? null;
415 $ctime = $values['ctime'][1] ?? null;
416
417 return $values['expires'][0] === ilDBConstants::T_INTEGER
418 && $values['ctime'][0] === ilDBConstants::T_INTEGER
419 && is_int($expires)
420 && $expires >= $before + 1800
421 && $expires <= time() + 1800
422 && is_int($ctime)
423 && $ctime >= $before
424 && $ctime <= time();
425 }),
426 ['session_id' => [ilDBConstants::T_TEXT, 'known-session-id']]
427 )
428 ->willReturn(1);
429
430 self::assertTrue(ilSession::updateTimestamp('known-session-id'));
431 }
432
434 {
435 $ilDB = $GLOBALS['DIC']['ilDB'];
436 $ilDB->expects($this->never())->method('update');
437
438 self::assertTrue(ilSession::updateTimestamp(''));
439 }
440
442 {
443 $ilDB = $GLOBALS['DIC']['ilDB'];
444 $ilDB->expects($this->never())->method('update');
445
447 try {
448 self::assertTrue(ilSession::updateTimestamp('wac-session-id'));
449 } finally {
451 }
452 }
453
455 {
456 $client_ini = $this->getMockBuilder(ilIniFile::class)->disableOriginalConstructor()->getMock();
457 $client_ini
458 ->expects($this->once())
459 ->method('readVariable')
460 ->with('session', 'expire')
461 ->willReturn('1800');
462 $this->setGlobalVariable('ilClientIniFile', $client_ini);
463
464 $ilDB = $GLOBALS['DIC']['ilDB'];
465 $ilDB->expects($this->once())->method('update')->willReturn(1);
466 $ilDB->expects($this->never())->method('manipulate');
467
469
470 self::assertTrue($handler->updateTimestamp('known-session-id', 'unchanged-payload'));
471 }
472
474 {
476
477 $client_ini = $this->createStub(ilIniFile::class);
478 $client_ini->method('readVariable')->willReturnCallback(
479 static function (string $group, string $key): string {
480 if ($group === 'session' && $key === 'expire') {
481 return '1800';
482 }
483
484 return '';
485 }
486 );
487 $this->setGlobalVariable('ilClientIniFile', $client_ini);
488
489 $cron_manager = $this->createMock(\ILIAS\Cron\Job\JobManager::class);
490 $cron_manager
491 ->expects($this->once())
492 ->method('isJobActive')
493 ->with('auth_destroy_expired_sessions')
494 ->willReturn(true);
495 $this->setGlobalVariable('cron.manager', $cron_manager);
496
497 $ilDB = $GLOBALS['DIC']['ilDB'];
498 $ilDB->expects($this->once())->method('update')->willReturn(0);
499 $ilDB->method('quote')->willReturnCallback(
500 static fn(mixed $value, ?string $type = null): string => '[' . (string) $value . ']'
501 );
502 $ilDB->expects($this->once())->method('query')->willReturn($this->createStub(ilDBStatement::class));
503 $ilDB->expects($this->once())->method('numRows')->willReturn(0);
504 $ilDB
505 ->expects($this->once())
506 ->method('manipulate')
507 ->with($this->callback(static function (string $sql): bool {
508 return str_contains($sql, 'INSERT INTO usr_session')
509 && str_contains($sql, '[expired-session-id]')
510 && str_contains($sql, '[expired-flag-payload]');
511 }))
512 ->willReturn(1);
513
514 $working_directory = getcwd();
515 if (is_string($working_directory) && !defined('IL_INITIAL_WD')) {
516 define('IL_INITIAL_WD', $working_directory);
517 }
518
519 try {
521
522 self::assertTrue($handler->updateTimestamp('expired-session-id', 'expired-flag-payload'));
523 } finally {
524 if (is_string($working_directory)) {
525 chdir($working_directory);
526 }
527 }
528 }
529}
$settings
Definition: index.php:44
Customizing of pimple-DIC for ILIAS.
Definition: Container.php:38
Class ilPDOStatement is a Wrapper Class for PDOStatement.
testPasswordAssisstanceSession()
testHandlerKeepsExistingSessionOnTimestampUpdate()
testUpdateTimestampTouchesExpiryWithoutRewritingPayload()
testHandlerStoresPayloadWhenTimestampUpdateMatchesNoRow()
setGlobalVariable(string $name, $value)
Container $dic_backup
testUpdateTimestampSkipsEmptySessionId()
testUpdateTimestampSkipsWebAccessWithoutSession()
static updateTimestamp(string $session_id)
Move the idle deadline of an existing session without rewriting its payload.
static destroyByUserId(int $a_user_id)
Destroy session.
static destroyExpiredSessions()
Destroy expired sessions.
static duplicate(string $a_session_id)
Duplicate session.
static getData(string $a_session_id)
Get session data from table.
static destroy($a_session_id, ?int $a_closing_context=null, $a_expired_at=null)
Destroy session.
static exists(string $a_session_id)
static enableWebAccessWithoutSession(bool $enable_web_access_without_session)
Interface ilDBStatement.
fetch(int $fetch_mode=ilDBConstants::FETCHMODE_ASSOC)
Interface Observer \BackgroundTasks Contains several chained tasks and infos about them.
$handler
Definition: oai.php:31
foreach($_POST as $key=> $value) $res
global $DIC
Definition: shib_login.php:26
$GLOBALS["DIC"]
Definition: wac.php:66