This commit is contained in:
jf-cbd
2026-03-06 17:41:42 +01:00
parent a02db83d0a
commit 69006c1e2f
8 changed files with 38 additions and 49 deletions

View File

@@ -102,32 +102,32 @@ if ($sTargetPage === false) {
// force login if needed
require_once(APPROOT.'/application/startup.inc.php');
$aModuleDelegatedExecutionPolicy = GetModuleDelegatedExecutionPolicy($sModule);
if (is_null($aModuleDelegatedExecutionPolicy) || !in_array($sPage, $aModuleDelegatedExecutionPolicy)) {
$bForceLoginWhenNoExecutionPolicy = MetaModel::GetConfig()->Get('security.force_login_when_no_delegated_authentication_endpoints_list');
if ($bForceLoginWhenNoExecutionPolicy) {
$aModuleDelegatedAuthenticationEndpoints = GetModuleDelegatedAuthenticationEndpoints($sModule);
if (is_null($aModuleDelegatedAuthenticationEndpoints) || !in_array($sPage, $aModuleDelegatedAuthenticationEndpoints)) {
$bForceLoginWhenNoDelegatedAuthenticationEndpoints = MetaModel::GetConfig()->Get('security.force_login_when_no_delegated_authentication_endpoints_list');
if ($bForceLoginWhenNoDelegatedAuthenticationEndpoints) {
LoginWebPage::DoLoginEx();
}
}
if (is_null($aModuleDelegatedExecutionPolicy) && !MetaModel::GetConfig()->Get('security.force_login_when_no_delegated_authentication_endpoints_list')) {
if (is_null($aModuleDelegatedAuthenticationEndpoints) && !MetaModel::GetConfig()->Get('security.force_login_when_no_delegated_authentication_endpoints_list')) {
// check if user is not logged in, if not log a warning in the log file as the page is executed without login, which is not recommended for security reason
if (is_null(UserRights::GetUserId())) {
IssueLog::Warning("The page '$sPage' is called be executed without login. In the future, this call will be blocked, and will likely cause unwanted behavior in the module '$sModule'.
Please define an execution policy for the module as described in https://www.itophub.io/wiki/page?id=latest:customization:new_extension#security.");
Please define a delegated authentication endpoints for the module as described in https://www.itophub.io/wiki/page?id=latest:customization:new_extension#security.");
}
}
if (is_array($aModuleDelegatedExecutionPolicy) && !in_array($sPage, $aModuleDelegatedExecutionPolicy)) {
// if module defined a delegated execution policy but not for the current page, we consider that the page is not allowed to be executed without login
if (is_array($aModuleDelegatedAuthenticationEndpoints) && !in_array($sPage, $aModuleDelegatedAuthenticationEndpoints)) {
// if module defined a delegated authentication endpoints but not for the current page, we consider that the page is not allowed to be executed without login
LoginWebPage::DoLoginEx();
}
require_once($sTargetPage);
function GetModuleDelegatedExecutionPolicy(string $sModuleName): ?array
function GetModuleDelegatedAuthenticationEndpoints(string $sModuleName): ?array
{
$sModuleFile = utils::GetAbsoluteModulePath($sModuleName).'/module.'.$sModuleName.'.php';
$oExtensionMap = new iTopExtensionsMap();
$aModuleParam = $oExtensionMap->GetModuleInfo($sModuleFile)[2];
return $aModuleParam['execution_policy'] ?? null;
return $aModuleParam['delegated_authentication_endpoints'] ?? null;
}

View File

@@ -18,30 +18,30 @@ class LoginWebPageTest extends ItopDataTestCase
{
parent::setUp();
$this->BackupConfiguration();
$sFolderPath = APPROOT.'env-production/extension-with-execution-policy';
$sFolderPath = APPROOT.'env-production/extension-with-delegated-authentication-endpoints-list';
if (file_exists($sFolderPath)) {
throw new Exception("Folder $sFolderPath already exists, please remove it before running the test");
}
mkdir($sFolderPath);
$this->RecurseCopy(__DIR__.'/extension-with-execution-policy', $sFolderPath);
$this->RecurseCopy(__DIR__.'/extension-with-delegated-authentication-endpoints-list', $sFolderPath);
$sFolderPath = APPROOT.'env-production/extension-without-execution-policy';
$sFolderPath = APPROOT.'env-production/extension-without-delegated-authentication-endpoints-list';
if (file_exists($sFolderPath)) {
throw new Exception("Folder $sFolderPath already exists, please remove it before running the test");
}
mkdir($sFolderPath);
$this->RecurseCopy(__DIR__.'/extension-without-execution-policy', $sFolderPath);
$this->RecurseCopy(__DIR__.'/extension-without-delegated-authentication-endpoints-list', $sFolderPath);
}
public function tearDown(): void
{
parent::tearDown();
$sFolderPath = APPROOT.'env-production/extension-with-execution-policy';
$sFolderPath = APPROOT.'env-production/extension-with-delegated-authentication-endpoints-list';
if (file_exists($sFolderPath)) {
$this->RecurseRmdir($sFolderPath);
} else {
throw new Exception("Folder $sFolderPath does not exist, it should have been created in setUp");
}
$sFolderPath = APPROOT.'env-production/extension-without-execution-policy';
$sFolderPath = APPROOT.'env-production/extension-without-delegated-authentication-endpoints-list';
if (file_exists($sFolderPath)) {
$this->RecurseRmdir($sFolderPath);
} else {
@@ -61,16 +61,16 @@ class LoginWebPageTest extends ItopDataTestCase
*
* @throws \Exception
*/
public function testInExecutionPolicyFile()
public function testInDelegatedAuthenticationEndpoints()
{
$sPageContent = $this->CallItopUri(
"pages/exec.php?exec_module=extension-with-execution-policy&exec_page=src/Controller/FileInExecutionPolicy.php",
"pages/exec.php?exec_module=extension-with-delegated-authentication-endpoints-list&exec_page=src/Controller/FileInDelegatedAuthenticationEndpointsList.php",
[],
[],
true
);
$this->assertStringNotContainsString('<title>iTop login</title>', $sPageContent, 'File listed in execution policy file (in the module), login should not be requested by exec, file handle its own policy');
$this->assertStringNotContainsString('<title>iTop login</title>', $sPageContent, 'File listed in delegated authentication endpoints list (in the module), login should not be requested by exec.');
}
public function testUserCanAccessAnyFile()
@@ -81,7 +81,7 @@ class LoginWebPageTest extends ItopDataTestCase
$this->GivenConfigFileAllowedLoginTypes(explode('|', 'form'));
$sPageContent = $this->CallItopUri(
"pages/exec.php?exec_module=extension-with-execution-policy&exec_page=src/Controller/FileNotInExecutionPolicy.php",
"pages/exec.php?exec_module=extension-with-delegated-authentication-endpoints-list&exec_page=src/Controller/FileNotInDelegatedAuthenticationEndpointsList.php",
[
'auth_user' => $sUserLogin,
'auth_pwd' => self::PASSWORD,
@@ -90,50 +90,50 @@ class LoginWebPageTest extends ItopDataTestCase
true
);
$this->assertStringContainsString('Yo', $sPageContent, 'Logged in user should access any file via exec.php even if the page isn\'t listed in execution policy');
$this->assertStringContainsString('Yo', $sPageContent, 'Logged in user should access any file via exec.php even if the page isn\'t listed in delegated authentication endpoints list');
}
public function testNoPolicyFileWithForceLoginConf()
public function testNotInDelegatedAuthenticationEndpointsListWithForceLoginConf()
{
MetaModel::GetConfig()->Set('security.force_login_when_no_delegated_authentication_endpoints_list', true);
$sPageContent = $this->CallItopUri(
"pages/exec.php?exec_module=extension-with-execution-policy&exec_page=src/Controller/FileNotInExecutionPolicy.php",
"pages/exec.php?exec_module=extension-with-delegated-authentication-endpoints-list&exec_page=src/Controller/FileNotInDelegatedAuthenticationEndpointsList.php",
);
$this->assertStringContainsString('<title>iTop login</title>', $sPageContent, 'if itop is configured to force login when no execution policy, then login should be required even if there is no policy file');
$this->assertStringContainsString('<title>iTop login</title>', $sPageContent, 'if itop is configured to force login when no there is no delegated authentication endpoints list, then login should be required.');
}
public function testNoPolicyFileWithDefaultConfiguration()
public function testNoDelegatedAuthenticationEndpointsListWithDefaultConfiguration()
{
$sPageContent = $this->CallItopUri(
"pages/exec.php?exec_module=extension-without-execution-policy&exec_page=src/Controller/File.php",
"pages/exec.php?exec_module=extension-without-delegated-authentication-endpoints-list&exec_page=src/Controller/File.php",
[],
[],
true
);
$this->assertStringContainsString('Yo', $sPageContent, 'by default (until N°9343) if no execution policy is defined, not logged in persons should access pages');
$this->assertStringContainsString('Yo', $sPageContent, 'by default (until N°9343) if no delegated authentication endpoints list is defined, not logged in persons should access pages');
}
public function testNotInExecutionPolicy()
public function testNotInDelegatedAuthenticationEndpointsList()
{
$sPageContent = $this->CallItopUri(
"pages/exec.php?exec_module=extension-with-execution-policy&exec_page=src/Controller/FileNotInExecutionPolicy.php",
"pages/exec.php?exec_module=extension-with-delegated-authentication-endpoints-list&exec_page=src/Controller/FileNotInDelegatedAuthenticationEndpointsList.php",
[],
[],
true
);
$this->assertStringContainsString('<title>iTop login</title>', $sPageContent, 'Since an execution policy is defined and file isn\'t listed in it, login should be required');
$this->assertStringContainsString('<title>iTop login</title>', $sPageContent, 'Since an delegated authentication endpoints list is defined and file isn\'t listed in it, login should be required');
}
/**
* @dataProvider InExecutionPolicyFileWithAdminRequiredProvider
* @dataProvider InDelegatedAuthenticationEndpointsWithAdminRequiredProvider
*
* @throws \Exception
*/
public function testInExecutionPolicyFileWithAdminRequired($iProfileId, $bShouldSeeForbiddenAdminPage)
public function testInDelegatedAuthenticationEndpointsWithAdminRequired($iProfileId, $bShouldSeeForbiddenAdminPage)
{
// generate random login
$sUserLogin = 'user-'.date('YmdHis');
@@ -141,7 +141,7 @@ class LoginWebPageTest extends ItopDataTestCase
$this->GivenConfigFileAllowedLoginTypes(explode('|', 'form'));
$sPageContent = $this->CallItopUri(
"pages/exec.php?exec_module=extension-with-execution-policy&exec_page=src/Controller/FileInExecutionPolicyAndAdminRequired.php",
"pages/exec.php?exec_module=extension-with-delegated-authentication-endpoints-list&exec_page=src/Controller/FileInDelegatedAuthenticationEndpointsListAndAdminRequired.php",
[
'auth_user' => $sUserLogin,
'auth_pwd' => self::PASSWORD,
@@ -150,12 +150,12 @@ class LoginWebPageTest extends ItopDataTestCase
true
);
$bShouldSeeForbiddenAdminPage ?
$this->assertStringNotContainsString('<title>Access restricted to people having administrator privileges</title>', $sPageContent, 'Should prevent non admin user to access this page') : // in execution policy file (in the module), login should not be required, file handle its own policy
$this->assertStringNotContainsString('<title>Access restricted to people having administrator privileges</title>', $sPageContent, 'Should prevent non admin user to access this page') : // in delegated authentication endpoints list (in the module), login should not be required
$this->assertStringContainsString('Yo !', $sPageContent, 'Should execute the file and see its content since user has admin profile');
}
public function InExecutionPolicyFileWithAdminRequiredProvider()
public function InDelegatedAuthenticationEndpointsWithAdminRequiredProvider()
{
return [
'Administrator profile' => [

View File

@@ -17,9 +17,9 @@ SetupWebPage::AddModule(
'installer' => 'TemplatesBaseInstaller',
// Security
'execution_policy' => [
'src/Controller/FileInExecutionPolicy.php',
'src/Controller/CheckAnythingButAdminRequired.php',
'delegated_authentication_endpoints' => [
'src/Controller/FileInDelegatedAuthenticationEndpointsList.php',
'src/Controller/FileInDelegatedAuthenticationEndpointsAndAdminRequiredList.php',
],
// Components