diff --git a/application/logindefault.class.inc.php b/application/logindefault.class.inc.php index 436af8436..73f9ff590 100644 --- a/application/logindefault.class.inc.php +++ b/application/logindefault.class.inc.php @@ -119,6 +119,11 @@ class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExte protected function OnConnected(&$iErrorCode) { Session::Unset('login_temp_auth_user'); + if (is_null(UserRights::GetUserObject())){ + //N°7085 avoid infinite loop + IssueLog::Error("No user logged in. exit"); + exit(-1); + } return LoginWebPage::LOGIN_FSM_CONTINUE; } @@ -134,4 +139,4 @@ class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExte } } } -} \ No newline at end of file +} diff --git a/core/config.class.inc.php b/core/config.class.inc.php index 177cee489..3c1378797 100644 --- a/core/config.class.inc.php +++ b/core/config.class.inc.php @@ -1904,7 +1904,7 @@ class Config } if (strlen($sNoise) > 0) { - // Note: sNoise is an html output, but so far it was ok for me (e.g. showing the entire call stack) + // Note: sNoise is an html output, but so far it was ok for me (e.g. showing the entire call stack) throw new ConfigException('Syntax error in configuration file', array('file' => $sConfigFile, 'error' => ''.htmlentities($sNoise, ENT_QUOTES, 'UTF-8').'')); } @@ -2193,6 +2193,24 @@ class Config $this->m_sAllowedLoginTypes = implode('|', $aAllowedLoginTypes); } + /** + * @since 2.7.11 N°7085 + * Add login mode if not configured already + * @param string $sLoginMode + * + * @return void + */ + public function AddAllowedLoginTypes($sLoginMode) + { + $aAllowedLoginTypes = $this->GetAllowedLoginTypes(); + if (in_array($sLoginMode, $aAllowedLoginTypes)){ + return; + } + + $aAllowedLoginTypes[] = $sLoginMode; + $this->SetAllowedLoginTypes($aAllowedLoginTypes); + } + public function SetExternalAuthenticationVariable($sExtAuthVariable) { $this->m_sExtAuthVariable = $sExtAuthVariable; @@ -2714,7 +2732,7 @@ class ConfigPlaceholdersResolver } $sPattern = '/\%(env|server)\((\w+)\)(?:\?:(\w*))?\%/'; //3 capturing groups, ie `%env(HTTP_PORT)?:8080%` produce: `env` `HTTP_PORT` and `8080`. - + if (! preg_match_all($sPattern, $rawValue, $aMatchesCollection, PREG_SET_ORDER)) { return $rawValue; diff --git a/tests/php-unit-tests/unitary-tests/application/LoginTest.php b/tests/php-unit-tests/unitary-tests/application/LoginTest.php new file mode 100644 index 000000000..52b4b70c9 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/application/LoginTest.php @@ -0,0 +1,67 @@ +sConfigPath = MetaModel::GetConfig()->GetLoadedFile(); + $this->sConfigTmpBackupFile = tempnam(sys_get_temp_dir(), "config_"); + file_put_contents($this->sConfigTmpBackupFile, file_get_contents($this->sConfigPath)); + + $oConfig = new \Config($this->sConfigPath); + $this->sLoginMode = "unimplemented_loginmode"; + $oConfig->AddAllowedLoginTypes($this->sLoginMode); + + @chmod($this->sConfigPath, 0770); + $oConfig->WriteToFile(); + @chmod($this->sConfigPath, 0440); + } + + protected function tearDown(): void { + if (! is_null($this->sConfigTmpBackupFile) && is_file($this->sConfigTmpBackupFile)){ + //put config back + @chmod($this->sConfigPath, 0770); + file_put_contents($this->sConfigPath, file_get_contents($this->sConfigTmpBackupFile)); + @chmod($this->sConfigPath, 0440); + @unlink($this->sConfigTmpBackupFile); + } + parent::tearDown(); + } + + public function testLoginInfiniteLoopFix() { + $iTimeStamp = microtime(true); + $sOutput = $this->CallItopUrlByCurl(sprintf("/pages/UI.php?login_mode=%s", $this->sLoginMode)); + $iElapsedInMs = (microtime(true) - $iTimeStamp) * 1000; + $sMaxExecutionInS = 1; + $this->assertTrue($iElapsedInMs < $sMaxExecutionInS * 1000, "iTop answered in $iElapsedInMs ms. it should do it in less than $sMaxExecutionInS seconds (max_execution_time)"); + $this->assertFalse(strpos($sOutput, "Fatal error"), "no fatal error due to max execution time should be returned" . $sOutput); + } + + protected function CallItopUrlByCurl($sUri, ?array $aPostFields=[]){ + $ch = curl_init(); + + $sUrl = MetaModel::GetConfig()->Get('app_root_url') . "/$sUri"; + curl_setopt($ch, CURLOPT_URL, $sUrl); + if (0 !== sizeof($aPostFields)){ + curl_setopt($ch, CURLOPT_POST, 1);// set post data to true + curl_setopt($ch, CURLOPT_POSTFIELDS, $aPostFields); + } + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + $sOutput = curl_exec($ch); + curl_close ($ch); + + return $sOutput; + } +}