Compare commits

...

6 Commits

Author SHA1 Message Date
Eric Espie
9fe705c70d N°9950 - Error loading structural data on upgrade 2026-08-21 10:15:50 +02:00
Eric Espie
3987785690 N°9950 - Error loading structural data on upgrade 2026-08-21 10:12:31 +02:00
Eric Espié
b8f02f48bd Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-08-21 10:00:20 +02:00
Eric Espié
ba426a9602 Update application/loginbasic.class.inc.php
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-08-21 09:59:55 +02:00
Eric Espie
285f64f8db N°9954 - Login-basic incompatible with OAuth2 server 2026-08-20 15:48:40 +02:00
Eric Espie
be5a5b0da1 N°9954 - Login-basic incompatible with OAuth2 server 2026-08-20 15:07:06 +02:00
2 changed files with 130 additions and 30 deletions

View File

@@ -5,7 +5,7 @@ use Combodo\iTop\Application\Helper\Session;
/**
* Class LoginBasic
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -24,11 +24,7 @@ class LoginBasic extends AbstractLoginFSMExtension
protected function OnModeDetection(&$iErrorCode)
{
if (!Session::IsSet('login_mode')) {
if (isset($_SERVER['HTTP_AUTHORIZATION']) && !empty($_SERVER['HTTP_AUTHORIZATION'])) {
Session::Set('login_mode', 'basic');
} elseif (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && !empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {
Session::Set('login_mode', 'basic');
} elseif (isset($_SERVER['PHP_AUTH_USER'])) {
if (!is_null($this->GetAuthUserAndPassword())) {
Session::Set('login_mode', 'basic');
}
}
@@ -86,38 +82,49 @@ class LoginBasic extends AbstractLoginFSMExtension
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
private function GetAuthUserAndPassword()
/**
* @return array|null [$sAuthUser, $sAuthPwd]
*/
private function GetAuthUserAndPassword(): ?array
{
$sAuthUser = '';
$sAuthPwd = null;
$sAuthorization = '';
if (isset($_SERVER['HTTP_AUTHORIZATION']) && !empty($_SERVER['HTTP_AUTHORIZATION'])) {
$sAuthorization = $_SERVER['HTTP_AUTHORIZATION'];
} elseif (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && !empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {
$sAuthorization = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
} elseif (isset($_SERVER['PHP_AUTH_USER'])) {
$sAuthUser = $_SERVER['PHP_AUTH_USER'];
// Unfortunately, the RFC is not clear about the encoding...
// IE and FF supply the user and password encoded in ISO-8859-1 whereas Chrome provides them encoded in UTF-8
// So let's try to guess if it's an UTF-8 string or not... fortunately all encodings share the same ASCII base
if (!LoginWebPage::LooksLikeUTF8($sAuthUser)) {
// Does not look like and UTF-8 string, try to convert it from iso-8859-1 to UTF-8
// Supposed to be harmless in case of a plain ASCII string...
$sAuthUser = iconv('iso-8859-1', 'utf-8', $sAuthUser);
}
$sAuthPwd = $_SERVER['PHP_AUTH_PW'];
if (!LoginWebPage::LooksLikeUTF8($sAuthPwd)) {
// Does not look like and UTF-8 string, try to convert it from iso-8859-1 to UTF-8
// Supposed to be harmless in case of a plain ASCII string...
$sAuthPwd = iconv('iso-8859-1', 'utf-8', $sAuthPwd);
}
return [$sAuthUser, $sAuthPwd];
}
if (!empty($sAuthorization)) {
list($sAuthUser, $sAuthPwd) = explode(':', base64_decode(substr($sAuthorization, 6)));
} else {
if (isset($_SERVER['PHP_AUTH_USER'])) {
$sAuthUser = $_SERVER['PHP_AUTH_USER'];
// Unfortunately, the RFC is not clear about the encoding...
// IE and FF supply the user and password encoded in ISO-8859-1 whereas Chrome provides them encoded in UTF-8
// So let's try to guess if it's an UTF-8 string or not... fortunately all encodings share the same ASCII base
if (!LoginWebPage::LooksLikeUTF8($sAuthUser)) {
// Does not look like and UTF-8 string, try to convert it from iso-8859-1 to UTF-8
// Supposed to be harmless in case of a plain ASCII string...
$sAuthUser = iconv('iso-8859-1', 'utf-8', $sAuthUser);
}
$sAuthPwd = $_SERVER['PHP_AUTH_PW'];
if (!LoginWebPage::LooksLikeUTF8($sAuthPwd)) {
// Does not look like and UTF-8 string, try to convert it from iso-8859-1 to UTF-8
// Supposed to be harmless in case of a plain ASCII string...
$sAuthPwd = iconv('iso-8859-1', 'utf-8', $sAuthPwd);
}
}
if (empty($sAuthorization)) {
return null;
}
return [$sAuthUser, $sAuthPwd];
// Decode without Bearer
if (!utils::StartsWith($sAuthorization, 'Basic ')) {
return null;
}
$sDecodedAuthorisation = base64_decode(substr($sAuthorization, 6));
if (str_contains($sDecodedAuthorisation, ':')) {
return explode(':', $sDecodedAuthorisation);
}
return null;
}
}

View File

@@ -0,0 +1,93 @@
<?php
/*
* @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\Test\UnitTest\Application\LoginFSM;
use Combodo\iTop\Application\Helper\Session;
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
use LoginBasic;
use LoginWebPage;
class LoginBasicTest extends ItopDataTestCase
{
public function testListSupportedLoginModes()
{
// Given
$oLoginBasic = new LoginBasic();
// When
$aActual = $oLoginBasic->ListSupportedLoginModes();
// Then
$this->assertEquals(['basic'], $aActual);
}
public function testOnModeDetectionForLoginPass()
{
// Given
$oLoginBasic = new LoginBasic();
$_SERVER['HTTP_AUTHORIZATION'] = 'Basic '.base64_encode("Login:BasicTest");
// When
$_SESSION = [];
$iErrorCode = 0;
$sActualRes = $oLoginBasic->LoginAction(LoginWebPage::LOGIN_STATE_MODE_DETECTION, $iErrorCode);
// Then
$this->assertEquals('basic', $_SESSION['login_mode'], 'Login mode should have detected basic mode');
$this->assertEquals(LoginWebPage::LOGIN_FSM_CONTINUE, $sActualRes, 'No Login FSM error should have been detected');
}
public function testOnModeDetectionForRedirect()
{
// Given
$oLoginBasic = new LoginBasic();
$_SERVER['REDIRECT_HTTP_AUTHORIZATION'] = 'Basic '.base64_encode('Login:BasicTest');
// When
$_SESSION = [];
$iErrorCode = 0;
$sActualRes = $oLoginBasic->LoginAction(LoginWebPage::LOGIN_STATE_MODE_DETECTION, $iErrorCode);
// Then
$this->assertEquals('basic', $_SESSION['login_mode'], 'Login mode should have detected basic mode');
$this->assertEquals(LoginWebPage::LOGIN_FSM_CONTINUE, $sActualRes, 'No Login FSM error should have been detected');
}
public function testOnModeDetectionForBasicLoginPassword()
{
// Given
$oLoginBasic = new LoginBasic();
$_SERVER['PHP_AUTH_USER'] = 'Login';
$_SERVER['PHP_AUTH_PW'] = 'Passwd';
// When
$_SESSION = [];
$iErrorCode = 0;
$sActualRes = $oLoginBasic->LoginAction(LoginWebPage::LOGIN_STATE_MODE_DETECTION, $iErrorCode);
// Then
$this->assertEquals('basic', $_SESSION['login_mode'], 'Login mode should have detected basic mode');
$this->assertEquals(LoginWebPage::LOGIN_FSM_CONTINUE, $sActualRes, 'No Login FSM error should have been detected');
}
public function testOnModeDetectionForBearerToken()
{
// Given
$oLoginBasic = new LoginBasic();
$_SERVER['HTTP_AUTHORIZATION'] = 'Bearer '.base64_encode('LoginBasicTest');
// When
$_SESSION = [];
$iErrorCode = 0;
$sActualRes = $oLoginBasic->LoginAction(LoginWebPage::LOGIN_STATE_MODE_DETECTION, $iErrorCode);
// Then
$this->assertFalse(Session::IsSet('login_mode'), 'No basic login mode should have been detected');
$this->assertEquals(LoginWebPage::LOGIN_FSM_CONTINUE, $sActualRes, 'No Login FSM error should have been detected');
}
}