N°7398 - be able to add custom data in session files generated by SessionHandler

This commit is contained in:
odain
2025-03-12 11:25:51 +01:00
parent f44468b7a1
commit a4a05a2579
7 changed files with 204 additions and 44 deletions

View File

@@ -1233,6 +1233,14 @@ class Config
'source_of_value' => '', 'source_of_value' => '',
'show_in_conf_sample' => false, 'show_in_conf_sample' => false,
], ],
'sessions_tracking.session_handler_extension' => [
'type' => 'string',
'description' => 'to store more data in itop session files, set your own iSessionHandlerExtension implementation class in this variable',
'default' => '',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'sessions_tracking.gc_threshold' => [ 'sessions_tracking.gc_threshold' => [
'type' => 'integer', 'type' => 'integer',
'description' => 'fallback in case cron is not active: probability in percent that session files are cleanup during any itop request (100 means always)', 'description' => 'fallback in case cron is not active: probability in percent that session files are cleanup during any itop request (100 means always)',

View File

@@ -525,6 +525,7 @@ return array(
'Combodo\\iTop\\Service\\TemporaryObjects\\TemporaryObjectsEvents' => $baseDir . '/sources/Service/TemporaryObjects/TemporaryObjectsEvents.php', 'Combodo\\iTop\\Service\\TemporaryObjects\\TemporaryObjectsEvents' => $baseDir . '/sources/Service/TemporaryObjects/TemporaryObjectsEvents.php',
'Combodo\\iTop\\SessionTracker\\SessionGC' => $baseDir . '/sources/SessionTracker/SessionGC.php', 'Combodo\\iTop\\SessionTracker\\SessionGC' => $baseDir . '/sources/SessionTracker/SessionGC.php',
'Combodo\\iTop\\SessionTracker\\SessionHandler' => $baseDir . '/sources/SessionTracker/SessionHandler.php', 'Combodo\\iTop\\SessionTracker\\SessionHandler' => $baseDir . '/sources/SessionTracker/SessionHandler.php',
'Combodo\\iTop\\SessionTracker\\iSessionHandlerExtension' => $baseDir . '/sources/SessionTracker/iSessionHandlerExtension.php',
'CompileCSSService' => $baseDir . '/application/compilecssservice.class.inc.php', 'CompileCSSService' => $baseDir . '/application/compilecssservice.class.inc.php',
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'Config' => $baseDir . '/core/config.class.inc.php', 'Config' => $baseDir . '/core/config.class.inc.php',
@@ -1560,6 +1561,7 @@ return array(
'Sabberworm\\CSS\\Value\\URL' => $vendorDir . '/sabberworm/php-css-parser/src/Value/URL.php', 'Sabberworm\\CSS\\Value\\URL' => $vendorDir . '/sabberworm/php-css-parser/src/Value/URL.php',
'Sabberworm\\CSS\\Value\\Value' => $vendorDir . '/sabberworm/php-css-parser/src/Value/Value.php', 'Sabberworm\\CSS\\Value\\Value' => $vendorDir . '/sabberworm/php-css-parser/src/Value/Value.php',
'Sabberworm\\CSS\\Value\\ValueList' => $vendorDir . '/sabberworm/php-css-parser/src/Value/ValueList.php', 'Sabberworm\\CSS\\Value\\ValueList' => $vendorDir . '/sabberworm/php-css-parser/src/Value/ValueList.php',
'SanitizeTrait' => $baseDir . '/core/restservices.class.inc.php',
'ScalarExpression' => $baseDir . '/core/oql/expression.class.inc.php', 'ScalarExpression' => $baseDir . '/core/oql/expression.class.inc.php',
'ScalarOqlExpression' => $baseDir . '/core/oql/oqlquery.class.inc.php', 'ScalarOqlExpression' => $baseDir . '/core/oql/oqlquery.class.inc.php',
'ScssPhp\\ScssPhp\\Base\\Range' => $vendorDir . '/scssphp/scssphp/src/Base/Range.php', 'ScssPhp\\ScssPhp\\Base\\Range' => $vendorDir . '/scssphp/scssphp/src/Base/Range.php',
@@ -3201,6 +3203,7 @@ return array(
'iPreferencesExtension' => $baseDir . '/application/applicationextension.inc.php', 'iPreferencesExtension' => $baseDir . '/application/applicationextension.inc.php',
'iProcess' => $baseDir . '/core/backgroundprocess.inc.php', 'iProcess' => $baseDir . '/core/backgroundprocess.inc.php',
'iQueryModifier' => $baseDir . '/core/querymodifier.class.inc.php', 'iQueryModifier' => $baseDir . '/core/querymodifier.class.inc.php',
'iRestInputSanitizer' => $baseDir . '/application/applicationextension.inc.php',
'iRestServiceProvider' => $baseDir . '/application/applicationextension.inc.php', 'iRestServiceProvider' => $baseDir . '/application/applicationextension.inc.php',
'iScheduledProcess' => $baseDir . '/core/backgroundprocess.inc.php', 'iScheduledProcess' => $baseDir . '/core/backgroundprocess.inc.php',
'iSelfRegister' => $baseDir . '/core/userrights.class.inc.php', 'iSelfRegister' => $baseDir . '/core/userrights.class.inc.php',

View File

@@ -915,6 +915,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Combodo\\iTop\\Service\\TemporaryObjects\\TemporaryObjectsEvents' => __DIR__ . '/../..' . '/sources/Service/TemporaryObjects/TemporaryObjectsEvents.php', 'Combodo\\iTop\\Service\\TemporaryObjects\\TemporaryObjectsEvents' => __DIR__ . '/../..' . '/sources/Service/TemporaryObjects/TemporaryObjectsEvents.php',
'Combodo\\iTop\\SessionTracker\\SessionGC' => __DIR__ . '/../..' . '/sources/SessionTracker/SessionGC.php', 'Combodo\\iTop\\SessionTracker\\SessionGC' => __DIR__ . '/../..' . '/sources/SessionTracker/SessionGC.php',
'Combodo\\iTop\\SessionTracker\\SessionHandler' => __DIR__ . '/../..' . '/sources/SessionTracker/SessionHandler.php', 'Combodo\\iTop\\SessionTracker\\SessionHandler' => __DIR__ . '/../..' . '/sources/SessionTracker/SessionHandler.php',
'Combodo\\iTop\\SessionTracker\\iSessionHandlerExtension' => __DIR__ . '/../..' . '/sources/SessionTracker/iSessionHandlerExtension.php',
'CompileCSSService' => __DIR__ . '/../..' . '/application/compilecssservice.class.inc.php', 'CompileCSSService' => __DIR__ . '/../..' . '/application/compilecssservice.class.inc.php',
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'Config' => __DIR__ . '/../..' . '/core/config.class.inc.php', 'Config' => __DIR__ . '/../..' . '/core/config.class.inc.php',
@@ -1950,6 +1951,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Sabberworm\\CSS\\Value\\URL' => __DIR__ . '/..' . '/sabberworm/php-css-parser/src/Value/URL.php', 'Sabberworm\\CSS\\Value\\URL' => __DIR__ . '/..' . '/sabberworm/php-css-parser/src/Value/URL.php',
'Sabberworm\\CSS\\Value\\Value' => __DIR__ . '/..' . '/sabberworm/php-css-parser/src/Value/Value.php', 'Sabberworm\\CSS\\Value\\Value' => __DIR__ . '/..' . '/sabberworm/php-css-parser/src/Value/Value.php',
'Sabberworm\\CSS\\Value\\ValueList' => __DIR__ . '/..' . '/sabberworm/php-css-parser/src/Value/ValueList.php', 'Sabberworm\\CSS\\Value\\ValueList' => __DIR__ . '/..' . '/sabberworm/php-css-parser/src/Value/ValueList.php',
'SanitizeTrait' => __DIR__ . '/../..' . '/core/restservices.class.inc.php',
'ScalarExpression' => __DIR__ . '/../..' . '/core/oql/expression.class.inc.php', 'ScalarExpression' => __DIR__ . '/../..' . '/core/oql/expression.class.inc.php',
'ScalarOqlExpression' => __DIR__ . '/../..' . '/core/oql/oqlquery.class.inc.php', 'ScalarOqlExpression' => __DIR__ . '/../..' . '/core/oql/oqlquery.class.inc.php',
'ScssPhp\\ScssPhp\\Base\\Range' => __DIR__ . '/..' . '/scssphp/scssphp/src/Base/Range.php', 'ScssPhp\\ScssPhp\\Base\\Range' => __DIR__ . '/..' . '/scssphp/scssphp/src/Base/Range.php',
@@ -3591,6 +3593,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'iPreferencesExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php', 'iPreferencesExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
'iProcess' => __DIR__ . '/../..' . '/core/backgroundprocess.inc.php', 'iProcess' => __DIR__ . '/../..' . '/core/backgroundprocess.inc.php',
'iQueryModifier' => __DIR__ . '/../..' . '/core/querymodifier.class.inc.php', 'iQueryModifier' => __DIR__ . '/../..' . '/core/querymodifier.class.inc.php',
'iRestInputSanitizer' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
'iRestServiceProvider' => __DIR__ . '/../..' . '/application/applicationextension.inc.php', 'iRestServiceProvider' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
'iScheduledProcess' => __DIR__ . '/../..' . '/core/backgroundprocess.inc.php', 'iScheduledProcess' => __DIR__ . '/../..' . '/core/backgroundprocess.inc.php',
'iSelfRegister' => __DIR__ . '/../..' . '/core/userrights.class.inc.php', 'iSelfRegister' => __DIR__ . '/../..' . '/core/userrights.class.inc.php',

View File

@@ -139,23 +139,60 @@ class SessionHandler extends \SessionHandler
// - Data corruption (not a json / not an array / no previous creation_time key) // - Data corruption (not a json / not an array / no previous creation_time key)
$iCreationTime = time(); $iCreationTime = time();
$aJson=[];
if (! is_null($sPreviousFileVersionContent)) { if (! is_null($sPreviousFileVersionContent)) {
$aJson = json_decode($sPreviousFileVersionContent, true); $aJson = json_decode($sPreviousFileVersionContent, true);
if (is_array($aJson) && array_key_exists('creation_time', $aJson)) { if (is_array($aJson)){
$iCreationTime = $aJson['creation_time']; if (array_key_exists('creation_time', $aJson)) {
$iCreationTime = $aJson['creation_time'];
}
} else {
IssueLog::Warning(__METHOD__ . ': not a json due (session file corruption?)', null, [ 'sPreviousFileVersionContent' => $sPreviousFileVersionContent ]);
$aJson=[];
} }
} }
$aData = [
'login_mode' => Session::Get('login_mode'),
'user_id' => $sUserId,
'creation_time' => $iCreationTime,
'context' => implode('|', ContextTag::GetStack())
];
$oiSessionHandlerExtension = $this->GetSessionHandlerExtension();
if (! is_null($oiSessionHandlerExtension)){
$oiSessionHandlerExtension->CompleteSessionData($aJson, $aData);
}
return json_encode ( return json_encode (
[ $aData
'login_mode' => Session::Get('login_mode'),
'user_id' => $sUserId,
'creation_time' => $iCreationTime,
'context' => implode('|', ContextTag::GetStack())
]
); );
} catch(Exception $e) { } catch(Exception $e) {
IssueLog::Error(__METHOD__, null, [ 'error' => $e->getMessage() ]);
}
return null;
}
private function GetSessionHandlerExtension() : ?iSessionHandlerExtension
{
$sSessionHandlerExtensionClass = utils::GetConfig()->Get('sessions_tracking.session_handler_extension');
if (strlen($sSessionHandlerExtensionClass) !=0){
try{
if (! class_exists($sSessionHandlerExtensionClass)){
throw new \Exception("Cannot find class");
}
/** @var iSessionHandlerExtension $oSessionHandlerExtension */
$oSessionHandlerExtension = new $sSessionHandlerExtensionClass;
if ($oSessionHandlerExtension instanceof iSessionHandlerExtension){
return $oSessionHandlerExtension;
}
throw new \Exception("Not an instance of iSessionHandlerExtension");
} catch(\Exception $e) {
IssueLog::Error(__METHOD__ . ': cannot instanciate iSessionHandlerExtension', null, ['sessions_tracking.session_handler_extension' => $sSessionHandlerExtensionClass]);
}
} }
return null; return null;

View File

@@ -0,0 +1,16 @@
<?php
namespace Combodo\iTop\SessionTracker;
interface iSessionHandlerExtension {
public function __construct();
/**
* Called by SessionHandler to change data stored in iTop session files
* @param array $aJson: previous data stored in session file
* @param array $aData: usual session data see @SessionHandler
*
* @return void
*/
public function CompleteSessionData(array $aJson, array &$aData) : void;
}

View File

@@ -3,19 +3,21 @@
namespace Combodo\iTop\Test\UnitTest\SessionTracker; namespace Combodo\iTop\Test\UnitTest\SessionTracker;
use Combodo\iTop\Application\Helper\Session; use Combodo\iTop\Application\Helper\Session;
use Combodo\iTop\SessionTracker\iSessionHandlerExtension;
use Combodo\iTop\SessionTracker\SessionHandler; use Combodo\iTop\SessionTracker\SessionHandler;
use Combodo\iTop\Test\UnitTest\ItopDataTestCase; use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
use ContextTag; use ContextTag;
class SessionHandlerTest extends ItopDataTestCase class SessionHandlerTest extends ItopDataTestCase
{ {
private $aFiles ; private $aFiles;
private $oTag ; private $oTag;
protected function setUp(): void protected function setUp(): void
{ {
parent::setUp(); parent::setUp();
$this->aFiles=[]; $this->RequireOnceUnitTestFile('./iSessionHandlerExtensionExamples.php');
$this->aFiles = [];
$this->oTag = new ContextTag(ContextTag::TAG_REST); $this->oTag = new ContextTag(ContextTag::TAG_REST);
} }
@@ -24,47 +26,53 @@ class SessionHandlerTest extends ItopDataTestCase
parent::tearDown(); parent::tearDown();
$this->oTag = null; $this->oTag = null;
foreach ($this->aFiles as $sFile){ foreach ($this->aFiles as $sFile) {
if (is_file($sFile)){ if (is_file($sFile)) {
@unlink($sFile); @unlink($sFile);
} }
} }
} }
private function CreateUserAndLogIn() : ? string { private function CreateUserAndLogIn(): ?string
{
$_SESSION = []; $_SESSION = [];
$oUser = $this->CreateContactlessUser("admin" . uniqid(), 1, "1234@Abcdefg"); $oUser = $this->CreateContactlessUser("admin".uniqid(), 1, "1234@Abcdefg");
\UserRights::Login($oUser->Get('login')); \UserRights::Login($oUser->Get('login'));
return $oUser->GetKey(); return $oUser->GetKey();
} }
private function GenerateSessionContent(SessionHandler $oSessionHandler, ?string $sPreviousFileVersionContent) : ?string { private function GenerateSessionContent(SessionHandler $oSessionHandler, ?string $sPreviousFileVersionContent): ?string
{
return $this->InvokeNonPublicMethod(SessionHandler::class, "generate_session_content", $oSessionHandler, $aArgs = [$sPreviousFileVersionContent]); return $this->InvokeNonPublicMethod(SessionHandler::class, "generate_session_content", $oSessionHandler, $aArgs = [$sPreviousFileVersionContent]);
} }
/* /*
* @covers SessionHandler::generate_session_content * @covers SessionHandler::generate_session_content
*/ */
public function testGenerateSessionContentNoUserLoggedIn(){ public function testGenerateSessionContentNoUserLoggedIn()
{
$oSessionHandler = new SessionHandler(); $oSessionHandler = new SessionHandler();
$sContent = $this->GenerateSessionContent($oSessionHandler, null); $sContent = $this->GenerateSessionContent($oSessionHandler, null);
$this->assertNull($sContent, "Session content should be null when there is no user logged in"); $this->assertNull($sContent, "Session content should be null when there is no user logged in");
} }
public function GenerateSessionContentCorruptedPreviousFileContentProvider() { public function GenerateSessionContentCorruptedPreviousFileContentProvider()
{
return [ return [
'not a json' => [ "not a json" ], 'not a json' => ["not a json"],
'not an array' => [ json_encode("not an array") ], 'not an array' => [json_encode("not an array")],
'array without creation_time key' => [ json_encode([]) ], 'array without creation_time key' => [json_encode([])],
]; ];
} }
/** /**
* @covers SessionHandler::generate_session_content * @covers SessionHandler::generate_session_content
* @dataProvider GenerateSessionContentCorruptedPreviousFileContentProvider * @dataProvider GenerateSessionContentCorruptedPreviousFileContentProvider
*/ */
public function testGenerateSessionContent_SessionFileRepairment(?string $sFileContent){ public function testGenerateSessionContent_SessionFileRepairment(?string $sFileContent)
{
$sUserId = $this->CreateUserAndLogIn(); $sUserId = $this->CreateUserAndLogIn();
$oSessionHandler = new SessionHandler(); $oSessionHandler = new SessionHandler();
@@ -84,7 +92,8 @@ class SessionHandlerTest extends ItopDataTestCase
/* /*
* @covers SessionHandler::generate_session_content * @covers SessionHandler::generate_session_content
*/ */
public function testGenerateSessionContent(){ public function testGenerateSessionContent()
{
$sUserId = $this->CreateUserAndLogIn(); $sUserId = $this->CreateUserAndLogIn();
$oSessionHandler = new SessionHandler(); $oSessionHandler = new SessionHandler();
@@ -105,33 +114,36 @@ class SessionHandlerTest extends ItopDataTestCase
// Switch context + change user id via impersonation // Switch context + change user id via impersonation
// check it is still tracked in session files // check it is still tracked in session files
$oOtherUser = $this->CreateContactlessUser("admin" . uniqid(), 1, "1234@Abcdefg"); $oOtherUser = $this->CreateContactlessUser("admin".uniqid(), 1, "1234@Abcdefg");
$this->assertTrue(\UserRights::Impersonate($oOtherUser->Get('login')), "Failed to execute impersonate on: ".$oOtherUser->Get('login')); $this->assertTrue(\UserRights::Impersonate($oOtherUser->Get('login')), "Failed to execute impersonate on: ".$oOtherUser->Get('login'));
$oTag2 = new ContextTag(ContextTag::TAG_SYNCHRO); $oTag2 = new ContextTag(ContextTag::TAG_SYNCHRO);
$sNewContent = $this->GenerateSessionContent($oSessionHandler, $sFirstContent); $sNewContent = $this->GenerateSessionContent($oSessionHandler, $sFirstContent);
$this->assertNotNull($sNewContent, 'Should not return null'); $this->assertNotNull($sNewContent, 'Should not return null');
$aJson = json_decode($sNewContent, true); $aJson = json_decode($sNewContent, true);
$this->assertNotEquals(false, $aJson, 'Should return a valid json string, found: '.$sNewContent); $this->assertNotEquals(false, $aJson, 'Should return a valid json string, found: '.$sNewContent);
$this->assertEquals(ContextTag::TAG_REST . '|' . ContextTag::TAG_SYNCHRO, $aJson['context'] ?? '', "After impersonation, should report the new context tags in [context]: $sNewContent"); $this->assertEquals(ContextTag::TAG_REST.'|'.ContextTag::TAG_SYNCHRO, $aJson['context'] ?? '', "After impersonation, should report the new context tags in [context]: $sNewContent");
$this->assertEquals($iFirstSessionCreationTime, $aJson['creation_time'] ?? '', "After impersonation, should still report the the session start timestamp in [creation_time]: $sNewContent"); $this->assertEquals($iFirstSessionCreationTime, $aJson['creation_time'] ?? '', "After impersonation, should still report the the session start timestamp in [creation_time]: $sNewContent");
$this->assertEquals('foo_login_mode', $aJson['login_mode'] ?? '', "After impersonation, should still report the login mode in [login_mode]: $sNewContent"); $this->assertEquals('foo_login_mode', $aJson['login_mode'] ?? '', "After impersonation, should still report the login mode in [login_mode]: $sNewContent");
$this->assertEquals($oOtherUser->GetKey(), $aJson['user_id'] ?? '', "Should report the impersonate user in [user_id]: $sNewContent"); $this->assertEquals($oOtherUser->GetKey(), $aJson['user_id'] ?? '', "Should report the impersonate user in [user_id]: $sNewContent");
} }
private function touchSessionFile(SessionHandler $oSessionHandler, $session_id) : ?string { private function touchSessionFile(SessionHandler $oSessionHandler, $session_id): ?string
{
$sRes = $this->InvokeNonPublicMethod(SessionHandler::class, "touch_session_file", $oSessionHandler, $aArgs = [$session_id]); $sRes = $this->InvokeNonPublicMethod(SessionHandler::class, "touch_session_file", $oSessionHandler, $aArgs = [$session_id]);
if (!is_null($sRes) && is_file($sRes)) { if (!is_null($sRes) && is_file($sRes)) {
// Record the file for cleanup on tearDown // Record the file for cleanup on tearDown
$this->aFiles[] = $sRes; $this->aFiles[] = $sRes;
} }
clearstatcache(); clearstatcache();
return $sRes; return $sRes;
} }
/* /*
* @covers SessionHandler::touch_session_file * @covers SessionHandler::touch_session_file
*/ */
public function testTouchSessionFile_NoUserLoggedIn(){ public function testTouchSessionFile_NoUserLoggedIn()
{
$oSessionHandler = new SessionHandler(); $oSessionHandler = new SessionHandler();
$session_id = uniqid(); $session_id = uniqid();
$sFile = $this->touchSessionFile($oSessionHandler, $session_id); $sFile = $this->touchSessionFile($oSessionHandler, $session_id);
@@ -143,7 +155,8 @@ class SessionHandlerTest extends ItopDataTestCase
/* /*
* @covers SessionHandler::touch_session_file * @covers SessionHandler::touch_session_file
*/ */
public function testTouchSessionFile_UserLoggedIn(){ public function testTouchSessionFile_UserLoggedIn()
{
$sUserId = $this->CreateUserAndLogIn(); $sUserId = $this->CreateUserAndLogIn();
Session::Set('login_mode', 'foo_login_mode'); Session::Set('login_mode', 'foo_login_mode');
@@ -174,7 +187,8 @@ class SessionHandlerTest extends ItopDataTestCase
/** /**
* @covers SessionHandler::touch_session_file * @covers SessionHandler::touch_session_file
*/ */
public function testTouchSessionFileWithEmptySessionId() { public function testTouchSessionFileWithEmptySessionId()
{
$this->CreateUserAndLogIn(); $this->CreateUserAndLogIn();
Session::Set('login_mode', 'toto'); Session::Set('login_mode', 'toto');
@@ -183,32 +197,36 @@ class SessionHandlerTest extends ItopDataTestCase
$this->assertNull($this->touchSessionFile($oSessionHandler, false), 'Should return null when session id (boolean) false'); $this->assertNull($this->touchSessionFile($oSessionHandler, false), 'Should return null when session id (boolean) false');
} }
private function GetFilePath(SessionHandler $oSessionHandler, $session_id) : string { private function GetFilePath(SessionHandler $oSessionHandler, $session_id): string
{
$sFile = $this->InvokeNonPublicMethod(SessionHandler::class, "get_file_path", $oSessionHandler, $aArgs = [$session_id]); $sFile = $this->InvokeNonPublicMethod(SessionHandler::class, "get_file_path", $oSessionHandler, $aArgs = [$session_id]);
// Record file for cleanup on tearDown // Record file for cleanup on tearDown
$this->aFiles[] = $sFile; $this->aFiles[] = $sFile;
return $sFile; return $sFile;
} }
public function GgcWithTimeLimitProvider(){ public function GgcWithTimeLimitProvider()
{
return [ return [
'no cleanup time limit' => [ 'no cleanup time limit' => [
'iTimeLimit' => -1, 'iTimeLimit' => -1,
'iExpectedProcessed' => 2 'iExpectedProcessed' => 2,
], ],
'cleanup time limit in the pass => first file removed only' => [ 'cleanup time limit in the pass => first file removed only' => [
'iTimeLimit' => time() - 1, 'iTimeLimit' => time() - 1,
'iExpectedProcessed' => 1 'iExpectedProcessed' => 1,
], ],
]; ];
} }
/** /**
* @covers SessionHandler::gc_with_time_limit * @covers SessionHandler::gc_with_time_limit
* @covers SessionHandler::list_session_files * @covers SessionHandler::list_session_files
* @dataProvider GgcWithTimeLimitProvider * @dataProvider GgcWithTimeLimitProvider
*/ */
public function testGgcWithTimeLimit($iTimeLimit, $iExpectedProcessed) { public function testGgcWithTimeLimit($iTimeLimit, $iExpectedProcessed)
{
$oSessionHandler = new SessionHandler(); $oSessionHandler = new SessionHandler();
//remove all first //remove all first
$oSessionHandler->gc_with_time_limit(-1); $oSessionHandler->gc_with_time_limit(-1);
@@ -218,11 +236,11 @@ class SessionHandlerTest extends ItopDataTestCase
$iNbExpiredFiles = 2; $iNbExpiredFiles = 2;
$iNbFiles = 5; $iNbFiles = 5;
$iExpiredTimeStamp = time() - $max_lifetime - 1; $iExpiredTimeStamp = time() - $max_lifetime - 1;
for($i=0; $i<$iNbFiles; $i++) { for ($i = 0; $i < $iNbFiles; $i++) {
$sFile = $this->GetFilePath($oSessionHandler, uniqid()); $sFile = $this->GetFilePath($oSessionHandler, uniqid());
file_put_contents($sFile, "fakedata"); file_put_contents($sFile, "fakedata");
if ($iNbExpiredFiles > 0){ if ($iNbExpiredFiles > 0) {
$iNbExpiredFiles--; $iNbExpiredFiles--;
touch($sFile, $iExpiredTimeStamp); touch($sFile, $iExpiredTimeStamp);
} }
@@ -230,7 +248,7 @@ class SessionHandlerTest extends ItopDataTestCase
$aFoundSessionFiles = $oSessionHandler->list_session_files(); $aFoundSessionFiles = $oSessionHandler->list_session_files();
$this->assertEquals($iNbFiles, sizeof($aFoundSessionFiles), 'list_session_files should reports all files'); $this->assertEquals($iNbFiles, sizeof($aFoundSessionFiles), 'list_session_files should reports all files');
foreach ($aFoundSessionFiles as $sFile){ foreach ($aFoundSessionFiles as $sFile) {
$this->assertTrue(is_file($sFile), 'list_session_files should return a valid file paths, found: '.$sFile); $this->assertTrue(is_file($sFile), 'list_session_files should return a valid file paths, found: '.$sFile);
} }
@@ -238,4 +256,64 @@ class SessionHandlerTest extends ItopDataTestCase
$this->assertEquals($iExpectedProcessed, $iProcessed, 'gc_with_time_limit should report the count of expired files'); $this->assertEquals($iExpectedProcessed, $iProcessed, 'gc_with_time_limit should report the count of expired files');
$this->assertEquals($iNbFiles - $iExpectedProcessed, sizeof($oSessionHandler->list_session_files()), 'gc_with_time_limit should actually remove all processed files'); $this->assertEquals($iNbFiles - $iExpectedProcessed, sizeof($oSessionHandler->list_session_files()), 'gc_with_time_limit should actually remove all processed files');
} }
}
public function testGetSessionHandlerExtension_NoExtension()
{
\utils::GetConfig()->Set('sessions_tracking.session_handler_extension', '');
$oSessionHandler = new SessionHandler();
$oSessionHandlerExtension = $this->InvokeNonPublicMethod(SessionHandler::class, "GetSessionHandlerExtension", $oSessionHandler);
$this->assertNull($oSessionHandlerExtension, "by default no extension");
}
public function testGetSessionHandlerExtension_InvalidClassExtension()
{
\utils::GetConfig()->Set('sessions_tracking.session_handler_extension', 'dddf');
$oSessionHandler = new SessionHandler();
$oSessionHandlerExtension = $this->InvokeNonPublicMethod(SessionHandler::class, "GetSessionHandlerExtension", $oSessionHandler);
$this->assertNull($oSessionHandlerExtension);
}
public function testGetSessionHandlerExtension_InvalidExtension()
{
\utils::GetConfig()->Set('sessions_tracking.session_handler_extension', Session::class);
$oSessionHandler = new SessionHandler();
$oSessionHandlerExtension = $this->InvokeNonPublicMethod(SessionHandler::class, "GetSessionHandlerExtension", $oSessionHandler);
$this->assertNull($oSessionHandlerExtension);
}
public function testGetSessionHandlerExtension_OK()
{
\utils::GetConfig()->Set('sessions_tracking.session_handler_extension', 'Combodo\iTop\Test\UnitTest\SessionTracker\BasicSessionHandlerExtension');
$oSessionHandler = new SessionHandler();
$oSessionHandlerExtension = $this->InvokeNonPublicMethod(SessionHandler::class, "GetSessionHandlerExtension", $oSessionHandler);
$this->assertNotNull($oSessionHandlerExtension, "by default no extension");
$this->assertTrue($oSessionHandlerExtension instanceof iSessionHandlerExtension);
$this->assertInstanceOf(BasicSessionHandlerExtension::class, $oSessionHandlerExtension);
}
public function testGenerateSessionContent_WithAdditionalDataProvidedBySessionHandlerExtension()
{
\utils::GetConfig()->Set('sessions_tracking.session_handler_extension', 'Combodo\iTop\Test\UnitTest\SessionTracker\BasicSessionHandlerExtension');
$sUserId = $this->CreateUserAndLogIn();
$oSessionHandler = new SessionHandler();
Session::Set('login_mode', 'foo_login_mode');
//first time
$sFirstContent = $this->GenerateSessionContent($oSessionHandler, null);
$this->assertNotNull($sFirstContent, 'Should not return null');
$aJson = json_decode($sFirstContent, true);
$this->assertNotEquals(false, $aJson, 'Should return a valid json string, found: '.$sFirstContent);
$this->assertEquals($sUserId, $aJson['user_id'] ?? '', "Should report the login of the logged in user in [user_id]: $sFirstContent");
$this->assertEquals(ContextTag::TAG_REST, $aJson['context'] ?? '', "Should report the context tag(s) in [context]: $sFirstContent");
$this->assertIsInt($aJson['creation_time'] ?? '', "Should report the session start timestamp in [creation_time]: $sFirstContent");
$this->assertEquals('foo_login_mode', $aJson['login_mode'] ?? '', "Should report the current login mode in [login_mode]: $sFirstContent");
$this->assertEquals('gabuzomeu', $aJson['shadok'] ?? '', "Should report the current login mode in [shadok]: $sFirstContent");
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace Combodo\iTop\Test\UnitTest\SessionTracker;
use Combodo\iTop\SessionTracker\iSessionHandlerExtension;
class BasicSessionHandlerExtension implements iSessionHandlerExtension {
public function __construct(){
}
public function CompleteSessionData(array $aJson, array &$aData): void
{
$aData['shadok']='gabuzomeu';
}
}