Jelajahi Sumber

- Integrated all the authentications methods and various logon methods...

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@665 a333f486-631f-4898-b8df-5754b55c2be0
dflaven 15 tahun lalu
induk
melakukan
9a604cfc9b

+ 6 - 1
application/itopwebpage.class.inc.php

@@ -492,7 +492,12 @@ EOF
 		}
 		$sLogOffMenu = "<span id=\"logOffBtn\"><ul><li><img src=\"../images/onOffBtn.png\"><ul>";
 		$sLogOffMenu .= "<li><span>$sLogonMessage</span></li>\n";
-		$sLogOffMenu .= "<li><a href=\"../pages/UI.php?loginop=logoff\">".Dict::S('UI:LogOffMenu')."</a></li>\n";
+		
+		if (utils::CanLogOff() && UserRights::CanLogOff())
+		{
+			//$sLogOffMenu .= "<li><a href=\"../pages/UI.php?loginop=logoff\">".Dict::S('UI:LogOffMenu')."</a></li>\n";
+			$sLogOffMenu .= "<li><a href=\"../pages/logoff.php\">".Dict::S('UI:LogOffMenu')."</a></li>\n";
+		}
 		if (UserRights::CanChangePassword())
 		{
 			$sLogOffMenu .= "<li><a href=\"../pages/UI.php?loginop=change_pwd\">".Dict::S('UI:ChangePwdMenu')."</a></li>\n";

+ 174 - 93
application/loginwebpage.class.inc.php

@@ -84,32 +84,47 @@ EOF
 );
 	}
 	
-	public function DisplayLoginForm($bFailedLogin = false)
+	public function DisplayLoginForm($sLoginType, $bFailedLogin = false)
 	{
-		$sAuthUser = utils::ReadParam('auth_user', '');
-		$sAuthPwd = utils::ReadParam('suggest_pwd', '');
-
-		$sVersionShort = Dict::Format('UI:iTopVersion:Short', ITOP_VERSION);
-		$this->add("<div id=\"login-logo\"><a href=\"http://www.combodo.com/itop\"><img title=\"$sVersionShort\" src=\"../images/itop-logo.png\"></a></div>\n");
-		$this->add("<div id=\"login\">\n");
-		$this->add("<h1>".Dict::S('UI:Login:Welcome')."</h1>\n");
-		if ($bFailedLogin)
-		{
-			$this->add("<p class=\"hilite\">".Dict::S('UI:Login:IncorrectLoginPassword')."</p>\n");
-		}
-		else
+		switch($sLoginType)
 		{
-			$this->add("<p>".Dict::S('UI:Login:IdentifyYourself')."</p>\n");
+			case 'popup':
+			case 'url':
+			$this->add_header('WWW-Authenticate: Basic realm="'.Dict::Format('UI:iTopVersion:Short', ITOP_VERSION));
+			$this->add_header('HTTP/1.0 401 Unauthorized');
+			// Note: displayed when the user will click on Cancel
+			$this->add('<p><strong>'.Dict::S('UI:Login:Error:AccessRestricted').'</strong></p>');
+			break;
+			
+			case 'remote':
+			case 'form':
+			default: // In case the settings get messed up...
+			$sAuthUser = utils::ReadParam('auth_user', '');
+			$sAuthPwd = utils::ReadParam('suggest_pwd', '');
+	
+			$sVersionShort = Dict::Format('UI:iTopVersion:Short', ITOP_VERSION);
+			$this->add("<div id=\"login-logo\"><a href=\"http://www.combodo.com/itop\"><img title=\"$sVersionShort\" src=\"../images/itop-logo.png\"></a></div>\n");
+			$this->add("<div id=\"login\">\n");
+			$this->add("<h1>".Dict::S('UI:Login:Welcome')."</h1>\n");
+			if ($bFailedLogin)
+			{
+				$this->add("<p class=\"hilite\">".Dict::S('UI:Login:IncorrectLoginPassword')."</p>\n");
+			}
+			else
+			{
+				$this->add("<p>".Dict::S('UI:Login:IdentifyYourself')."</p>\n");
+			}
+			$this->add("<form method=\"post\">\n");
+			$this->add("<table>\n");
+			$this->add("<tr><td><label for=\"user\">".Dict::S('UI:Login:UserNamePrompt').":</label></td><td><input id=\"user\" type=\"text\" name=\"auth_user\" value=\"$sAuthUser\" /></td></tr>\n");
+			$this->add("<tr><td><label for=\"pwd\">".Dict::S('UI:Login:PasswordPrompt').":</label></td><td><input id=\"pwd\" type=\"password\" name=\"auth_pwd\" value=\"$sAuthPwd\" /></td></tr>\n");
+			$this->add("<tr><td colspan=\"2\" class=\"center v-spacer\"> <input type=\"submit\" value=\"".Dict::S('UI:Button:Login')."\" /></td></tr>\n");
+			$this->add("</table>\n");
+			$this->add("<input type=\"hidden\" name=\"loginop\" value=\"login\" />\n");
+			$this->add("</form>\n");
+			$this->add("</div>\n");
+			break;
 		}
-		$this->add("<form method=\"post\">\n");
-		$this->add("<table>\n");
-		$this->add("<tr><td><label for=\"user\">".Dict::S('UI:Login:UserNamePrompt').":</label></td><td><input id=\"user\" type=\"text\" name=\"auth_user\" value=\"$sAuthUser\" /></td></tr>\n");
-		$this->add("<tr><td><label for=\"pwd\">".Dict::S('UI:Login:PasswordPrompt').":</label></td><td><input id=\"pwd\" type=\"password\" name=\"auth_pwd\" value=\"$sAuthPwd\" /></td></tr>\n");
-		$this->add("<tr><td colspan=\"2\" class=\"center v-spacer\"> <input type=\"submit\" value=\"".Dict::S('UI:Button:Login')."\" /></td></tr>\n");
-		$this->add("</table>\n");
-		$this->add("<input type=\"hidden\" name=\"loginop\" value=\"login\" />\n");
-		$this->add("</form>\n");
-		$this->add("</div>\n");
 	}
 
 	public function DisplayChangePwdForm($bFailedLogin = false)
@@ -155,8 +170,16 @@ EOF
 		$this->add("</div>\n");
 	}
 
-	static protected function ResetSession()
+	static function ResetSession()
 	{
+		if (isset($_SESSION['login_mode']))
+		{
+			$sPreviousLoginMode = $_SESSION['login_mode'];
+		}
+		else
+		{
+			$sPreviousLoginMode = '';
+		}
 		// Unset all of the session variables.
 		$_SESSION = array();
 		// If it's desired to kill the session, also delete the session cookie.
@@ -186,7 +209,7 @@ EOF
 		return $bSecured;
 	}
 	
-	static function DoLogin()
+	protected static function Login()
 	{
 		if (self::SecureConnectionRequired() && !self::IsConnectionSecure())
 		{
@@ -195,52 +218,147 @@ EOF
 			header("Location: $sUrl");			
 			exit;
 		}
-		$bHTTPBasicAuthentication  = (utils::ReadParam('auth', '', 'get') == 'http_basic');
-		if ($bHTTPBasicAuthentication)
+		
+		$aAllowedLoginTypes = utils::GetConfig()->GetAllowedLoginTypes();
+
+		if (isset($_SESSION['auth_user']))
+		{
+			//echo "User: ".$_SESSION['auth_user']."\n";
+			// Already authentified
+			UserRights::Login($_SESSION['auth_user']); // Login & set the user's language
+			return true;
+		}
+		else
 		{
-			// Basic HTTP/PHP authentication mecanism
-			//
-			// meme avec ca c'est pourri - return;
-			if (!isset($_SERVER['PHP_AUTH_USER']))
+			$index = 0;
+			$sLoginMode = '';
+			$sAuthentication = 'internal';
+			while(($sLoginMode == '') && ($index < count($aAllowedLoginTypes)))
 			{
-				header('WWW-Authenticate: Basic realm="iTop access is restricted"');
-				header('HTTP/1.0 401 Unauthorized');
-					// Note: accessed when the user will click on Cancel
-				echo '<p><strong>'.Dict::S('UI:Login:Error:AccessRestricted').'</strong></p>';
+				$sLoginType = $aAllowedLoginTypes[$index];
+				switch($sLoginType)
+				{
+					case 'form':
+					// iTop standard mode: form based authentication
+					$sAuthUser = utils::ReadParam('auth_user', '', 'post');
+					$sAuthPwd = utils::ReadParam('auth_pwd', '', 'post');
+					if ($sAuthUser != '')
+					{
+						$sLoginMode = 'form';
+					}
+					break;
+					
+					case 'popup':
+					// Standard PHP authentication method, works with Apache...
+					// Case 1) Apache running in CGI mode + rewrite rules in .htaccess
+					if (isset($_SERVER['HTTP_AUTHORIZATION']) && !empty($_SERVER['HTTP_AUTHORIZATION']))
+					{
+						list($sAuthUser, $sAuthPwd) = explode(':' , base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
+						$sLoginMode = 'popup';
+					}
+					else if (isset($_SERVER['PHP_AUTH_USER']))
+					{
+						$sAuthUser = $_SERVER['PHP_AUTH_USER'];
+						$sAuthPwd = $_SERVER['PHP_AUTH_PW'];
+						$sLoginMode = 'popup';
+					}
+					break;
+
+					case 'remote':
+					// Web server supplied authentication
+					if (isset($_SERVER['REMOTE_USER']))
+					{
+						$sAuthUser = $_SERVER['REMOTE_USER'];
+						$sAuthPwd = ''; // No password in this case the web server already authentified the user...
+						$sLoginMode = 'remote';
+						$sAuthentication = 'external';
+					}
+					break;
+
+					case 'url':
+					// Credentials passed directly in the url
+					$sAuthUser = utils::ReadParam('auth_user', '', 'get');
+					if ($sAuthUser != '')
+					{
+						$sAuthPwd = utils::ReadParam('auth_pwd', '', 'post');
+						$sLoginMode = 'url';
+					}		
+					break;	
+				}
+				$index++;
+			}
+			//echo "\nsLoginMode: $sLoginMode (user: $sAuthUser / pwd: $sAuthPwd\n)";
+			if ($sLoginMode == '')
+			{
+				// First connection
+				$sDesiredLoginMode = utils::ReadParam('login_mode');
+				if (in_array($sDesiredLoginMode, $aAllowedLoginTypes))
+				{
+					$sLoginMode = $sDesiredLoginMode;
+				}
+				else
+				{
+					$sLoginMode = $aAllowedLoginTypes[0]; // First in the list...
+				}
+				$oPage = new LoginWebPage();
+				$oPage->DisplayLoginForm( $sLoginMode, false /* no previous failed attempt */);
+				$oPage->output();
 				exit;
 			}
 			else
 			{
-				$sAuthUser = $_SERVER['PHP_AUTH_USER'];
-				$sAuthPwd = $_SERVER['PHP_AUTH_PW'];
-				if (!UserRights::Login($sAuthUser, $sAuthPwd))
+				if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, $sAuthentication))
 				{
-					header('WWW-Authenticate: Basic realm="Unknown user \''.$sAuthUser.'\'"');
-					header('HTTP/1.0 401 Unauthorized');
-					// Note: accessed when the user will click on Cancel
-					// Todo: count the attempts
-					echo '<p><strong>'.Dict::S('UI:Login:Error:AccessRestricted').'</strong></p>';
+					self::ResetSession();
+					$oPage = new LoginWebPage();
+					$oPage->DisplayLoginForm( $sLoginMode, true /* failed attempt */);
+					$oPage->output();
 					exit;
 				}
+				else
+				{
+					// User is Ok, let's save it in the session and proceed with normal login
+					UserRights::Login($sAuthUser, $sAuthentication); // Login & set the user's language
+					$_SESSION['auth_user'] = $sAuthUser;
+					$_SESSION['login_mode'] = $sLoginMode;
+				}
 			}
-			return;
 		}
-
-		// Home-made authentication mecanism
-		//
+	}
+	
+	static function DoLogin()
+	{
 		$operation = utils::ReadParam('loginop', '');
 		session_start();
 
 		if ($operation == 'logoff')
 		{
+			if (isset($_SESSION['login_mode']))
+			{
+				$sLoginMode = $_SESSION['login_mode'];
+			}
+			else
+			{
+				$aAllowedLoginTypes = utils::GetConfig()->GetAllowedLoginTypes();
+				if (count($aAllowedLoginTypes) > 0)
+				{
+					$sLoginMode = $aAllowedLoginTypes[0];
+				}
+				else
+				{
+					$sLoginMode = 'form';
+				}
+			}
 			self::ResetSession();
-		}
-		
-		if ($operation == 'change_pwd')
+			$oPage = new LoginWebPage();
+			$oPage->DisplayLoginForm( $sLoginMode, false /* not a failed attempt */);
+			$oPage->output();
+			exit;
+		}		
+		else if ($operation == 'change_pwd')
 		{
 			$sAuthUser = $_SESSION['auth_user'];
-			$sAuthPwd = $_SESSION['auth_pwd'];
-			UserRights::Login($sAuthUser, $sAuthPwd); // Set the user's language
+			UserRights::Login($sAuthUser); // Set the user's language
 			$oPage = new LoginWebPage();
 			$oPage->DisplayChangePwdForm();
 			$oPage->output();
@@ -249,11 +367,10 @@ EOF
 		if ($operation == 'do_change_pwd')
 		{
 			$sAuthUser = $_SESSION['auth_user'];
-			$sAuthPwd = $_SESSION['auth_pwd'];
-			UserRights::Login($sAuthUser, $sAuthPwd); // Set the user's language
+			UserRights::Login($sAuthUser); // Set the user's language
 			$sOldPwd = utils::ReadPostedParam('old_pwd');
 			$sNewPwd = utils::ReadPostedParam('new_pwd');
-			if (UserRights::CanChangePassword() && ((!UserRights::Login($sAuthUser, $sOldPwd)) || (!UserRights::ChangePassword($sOldPwd, $sNewPwd))))
+			if (UserRights::CanChangePassword() && ((!UserRights::CheckCredentials($sAuthUser, $sOldPwd)) || (!UserRights::ChangePassword($sOldPwd, $sNewPwd))))
 			{
 				$oPage = new LoginWebPage();
 				$oPage->DisplayChangePwdForm(true); // old pwd was wrong
@@ -268,44 +385,8 @@ EOF
 			}
 		}
 		
-		if (!isset($_SESSION['auth_user']) || !isset($_SESSION['auth_pwd']))
-		{
-			if ($operation == 'loginurl')
-			{
-				$sAuthUser = utils::ReadParam('auth_user', '', 'get');
-				$sAuthPwd = utils::ReadParam('auth_pwd', '', 'get');
-			}
-			else if ($operation == 'login')
-			{
-				$sAuthUser = utils::ReadParam('auth_user', '', 'post');
-				$sAuthPwd = utils::ReadParam('auth_pwd', '', 'post');
-			}
-			else
-			{
-				$oPage = new LoginWebPage();
-				$oPage->DisplayLoginForm();
-				$oPage->output();
-				exit;
-			}
-		}
-		else
-		{
-			$sAuthUser = $_SESSION['auth_user'];
-			$sAuthPwd = $_SESSION['auth_pwd'];
-		}
-		if (!UserRights::Login($sAuthUser, $sAuthPwd))
-		{
-			self::ResetSession();
-			$oPage = new LoginWebPage();
-			$oPage->DisplayLoginForm( true /* failed attempt */);
-			$oPage->output();
-			exit;
-		}
-		else
-		{
-			$_SESSION['auth_user'] = $sAuthUser ;
-			$_SESSION['auth_pwd'] = $sAuthPwd;
-		}
+		self::Login();
 	}
+
 } // End of class
 ?>

+ 12 - 0
application/utils.inc.php

@@ -231,5 +231,17 @@ class utils
 		
 		return $sUrl;
 	}
+	
+	/**
+	 * Tells whether or not log off operation is supported.
+	 * Actually in only one case:
+	 * 1) iTop is using an internal authentication
+	 * 2) the user did not log-in using the "popup" mode (i.e basic authentication) or by passing credentials in the URL
+	 * @return boolean True if logoff is supported, false otherwise
+	 */
+	static function CanLogOff()
+	{
+		return (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'form');
+	}
 }
 ?>

+ 21 - 1
core/config.class.inc.php

@@ -43,6 +43,7 @@ define ('DEFAULT_MAX_DISPLAY_LIMIT', 15);
 define ('DEFAULT_STANDARD_RELOAD_INTERVAL', 5*60);
 define ('DEFAULT_FAST_RELOAD_INTERVAL', 1*60);
 define ('DEFAULT_SECURE_CONNECTION_REQUIRED', false);
+define ('DEFAULT_ALLOWED_LOGIN_TYPES', 'form|popup|remote|url');
 
 /**
  * Config
@@ -103,6 +104,11 @@ class Config
 	 * @var string Langage code, default if the user language is undefined
 	 */	 	
 	protected $m_sDefaultLanguage;
+	
+	/**
+	 * @var string Type of login process allowed: form|popup|url|remote
+	 */
+	 protected $m_sAllowedLoginTypes;
 
 	public function __construct($sConfigFile, $bLoadConfig = true)
 	{
@@ -149,7 +155,8 @@ class Config
 		$this->m_iFastReloadInterval = DEFAULT_FAST_RELOAD_INTERVAL;
 		$this->m_bSecureConnectionRequired = DEFAULT_SECURE_CONNECTION_REQUIRED;
 		$this->m_sDefaultLanguage = 'EN US';
-
+		$this->m_sAllowedLoginTypes = DEFAULT_ALLOWED_LOGIN_TYPES;
+		
 		$this->m_aModuleSettings = array();
 
 		if ($bLoadConfig)
@@ -247,6 +254,7 @@ class Config
 		$this->m_aModuleSettings = isset($MyModuleSettings) ?  $MyModuleSettings : array();
 
 		$this->m_sDefaultLanguage = isset($MySettings['default_language']) ? trim($MySettings['default_language']) : 'EN US';
+		$this->m_sAllowedLoginTypes = isset($MySettings['allowed_login_types']) ? trim($MySettings['allowed_login_types']) : DEFAULT_ALLOWED_LOGIN_TYPES;
 	}
 
 	protected function Verify()
@@ -394,6 +402,12 @@ class Config
 		return $this->m_sDefaultLanguage;
 	}
 
+
+	public function GetAllowedLoginTypes()
+	{
+		return explode('|', $this->m_sAllowedLoginTypes);
+	}
+
 	public function SetDBHost($sDBHost)
 	{
 		$this->m_sDBHost = $sDBHost;
@@ -469,6 +483,11 @@ class Config
 		$this->m_sDefaultLanguage = $sLanguageCode;
 	}
 
+	public function SetAllowedLoginTypes($aAllowedLoginTypes)
+	{
+		$this->m_sAllowedLoginTypes = implode('|', $aAllowedLoginTypes);
+	}
+
 	public function FileIsWritable()
 	{
 		return is_writable($this->m_sFile);
@@ -516,6 +535,7 @@ class Config
 			fwrite($hFile, "\t'fast_reload_interval' => {$this->m_iFastReloadInterval},\n");
 			fwrite($hFile, "\t'secure_connection_required' => ".($this->m_bSecureConnectionRequired ? 'true' : 'false').",\n");
 			fwrite($hFile, "\t'default_language' => '{$this->m_sDefaultLanguage}',\n");
+			fwrite($hFile, "\t'allowed_login_types' => '{$this->m_sAllowedLoginTypes}',\n");
 			fwrite($hFile, ");\n");
 
 			fwrite($hFile, "\n");

+ 102 - 14
core/userrights.class.inc.php

@@ -200,7 +200,41 @@ abstract class User extends cmdbAbstractObject
 	}
 }
 
+/**
+ * Abstract class for all types of "internal" authentication i.e. users
+ * for which the application is supplied a login and a password opposed
+ * to "external" users for whom the authentication is performed outside
+ * of the application (by the web server for example).
+ * Note that "internal" users do not necessary correspond to a local authentication
+ * they may be authenticated by a remote system, like in authent-ldap.
+ */
+abstract class UserInternal extends User
+{
+	// Nothing special, just a base class to categorize this type of authenticated users	
+	public static function Init()
+	{
+		$aParams = array
+		(
+			"category" => "core",
+			"key_type" => "autoincrement",
+			"name_attcode" => "login",
+			"state_attcode" => "",
+			"reconc_keys" => array('login'),
+			"db_table" => "priv_internalUser",
+			"db_key_field" => "id",
+			"db_finalclass_field" => "",
+		);
+		MetaModel::Init_Params($aParams);
+		MetaModel::Init_InheritAttributes();
 
+		// Display lists
+		MetaModel::Init_SetZListItems('details', array('contactid', 'first_name', 'email', 'login', 'language', 'profile_list')); // Attributes to be displayed for the complete details
+		MetaModel::Init_SetZListItems('list', array('finalclass', 'first_name', 'last_name', 'login')); // Attributes to be displayed for a list
+		// Search criteria
+		MetaModel::Init_SetZListItems('standard_search', array('login', 'contactid')); // Criteria of the std search form
+		MetaModel::Init_SetZListItems('advanced_search', array('login', 'contactid')); // Criteria of the advanced search form
+	}
+}
 
 /**
  * User management core API  
@@ -261,9 +295,21 @@ class UserRights
 		}	
 	}
 
-	public static function Login($sName, $sPassword)
+	public static function Login($sName, $sAuthentication = 'any')
 	{
-		$oUser = self::FindUser($sName);
+		$oUser = self::FindUser($sName, $sAuthentication);
+		if (is_null($oUser))
+		{
+			return false;
+		}
+		self::$m_oUser = $oUser;
+		Dict::SetUserLanguage(self::GetUserLanguage());
+		return true;
+	}
+
+	public static function CheckCredentials($sName, $sPassword, $sAuthentication = 'any')
+	{
+		$oUser = self::FindUser($sName, $sAuthentication);
 		if (is_null($oUser))
 		{
 			return false;
@@ -273,8 +319,6 @@ class UserRights
 		{
 			return false;
 		}
-		self::$m_oUser = $oUser;
-		Dict::SetUserLanguage(self::GetUserLanguage());
 		return true;
 	}
 
@@ -302,6 +346,18 @@ class UserRights
 		}
 	}
 
+	public static function CanLogOff()
+	{
+		if (!is_null(self::$m_oUser))
+		{
+ 			return self::$m_oUser->CanLogOff();
+		}
+		else
+		{
+			return false;
+		}
+	}
+
 	public static function ChangePassword($sCurrentPassword, $sNewPassword)
 	{
 		if (!is_null(self::$m_oUser))
@@ -521,22 +577,54 @@ class UserRights
 	}
 
 	static $m_aCacheUsers;
-	protected static function FindUser($sLogin)
+	/**
+	 * Find a user based on its login and its type of authentication
+	 * @param string $sLogin Login/identifier of the user
+	 * @param string $sAuthentication Type of authentication used: internal|external|any
+	 * @return User The found user or null
+	 */
+	protected static function FindUser($sLogin, $sAuthentication = 'any')
 	{
-		if (!isset(self::$m_aCacheUsers))
+		if ($sAuthentication == 'any')
 		{
-			self::$m_aCacheUsers = array();
+			$oUser = self::FindUser($sLogin, 'internal');
+			if ($oUser == null)
+			{
+				$oUser = self::FindUser($sLogin, 'external');
+			}
 		}
-		if (!isset(self::$m_aCacheUsers[$sLogin]))
+		else
 		{
-			$oSearch = DBObjectSearch::FromOQL("SELECT User WHERE login = :login");
-			$oSet = new DBObjectSet($oSearch, array(), array('login' => $sLogin));
-			$oUser = $oSet->fetch();
-			self::$m_aCacheUsers[$sLogin] = $oUser;
+			if (!isset(self::$m_aCacheUsers))
+			{
+				self::$m_aCacheUsers = array('internal' => array(), 'external' => array());
+			}
+			
+			if (!isset(self::$m_aCacheUsers[$sAuthentication][$sLogin]))
+			{
+				switch($sAuthentication)
+				{
+					case 'external':
+					$sBaseClass = 'UserExternal';
+					break;
+					
+					case 'internal':
+					$sBaseClass = 'UserInternal';
+					break;
+					
+					default:
+					echo "<p>sAuthentication = $sAuthentication</p>\n";
+					assert(false); // should never happen
+				}
+				$oSearch = DBObjectSearch::FromOQL("SELECT $sBaseClass WHERE login = :login");
+				$oSet = new DBObjectSet($oSearch, array(), array('login' => $sLogin));
+				$oUser = $oSet->fetch();
+				self::$m_aCacheUsers[$sAuthentication][$sLogin] = $oUser;
+			}
+			$oUser = self::$m_aCacheUsers[$sAuthentication][$sLogin];
 		}
-		return self::$m_aCacheUsers[$sLogin];
+		return $oUser;
 	}
 }
 
-
 ?>

+ 2 - 0
dictionaries/dictionary.itop.ui.php

@@ -409,6 +409,8 @@ Dict::Add('EN US', 'English', 'English', array(
 	'UI:Login:RetypeNewPasswordPrompt' => 'Retype new password',
 	'UI:Login:IncorrectOldPassword' => 'Error: the old password is incorrect',
 	'UI:LogOffMenu' => 'Log off',
+	'UI:LogOff:ThankYou' => 'Thank you for using iTop',
+	'UI:LogOff:ClickHereToLoginAgain' => 'Click here to login again...',
 	'UI:ChangePwdMenu' => 'Change Password...',
 	'UI:Login:RetypePwdDoesNotMatch' => 'New password and retyped new password do not match !',
 	'UI:Button:Login' => 'Enter iTop',

+ 2 - 0
dictionaries/fr.dictionary.itop.ui.php

@@ -410,6 +410,8 @@ Dict::Add('FR FR', 'French', 'Français', array(
 	'UI:Login:RetypeNewPasswordPrompt' => 'Resaisir le nouveau mot de passe',
 	'UI:Login:IncorrectOldPassword' => 'Erreur: l\'ancien mot de passe est incorrect',
 	'UI:LogOffMenu' => 'Déconnexion',
+	'UI:LogOff:ThankYou' => 'Merci d\'avoir utilisé iTop',
+	'UI:LogOff:ClickHereToLoginAgain' => 'Cliquez ici pour vous reconnecter...',
 	'UI:ChangePwdMenu' => 'Changer de mot de passe...',
 	'UI:Login:RetypePwdDoesNotMatch' => 'Les deux saisies du nouveau mot de passe ne sont pas identiques !',
 	'UI:Button:Login' => 'Entrer dans iTop',

+ 7 - 1
modules/authent-ldap/model.authent-ldap.php

@@ -25,7 +25,7 @@
  */
 
 
-class UserLDAP extends User
+class UserLDAP extends UserInternal
 {
 	public static function Init()
 	{
@@ -157,6 +157,12 @@ class UserLDAP extends User
 		return false;
 	}
 
+	public function CanLogOff()
+	{
+		// Internal authentication allows everybody to log off
+		return true;
+	}
+
 	public function ChangePassword($sOldPassword, $sNewPassword)
 	{
 		return false;

+ 7 - 1
modules/authent-local/model.authent-local.php

@@ -25,7 +25,7 @@
  */
 
 
-class UserLocal extends User
+class UserLocal extends UserInternal
 {
 	public static function Init()
 	{
@@ -74,6 +74,12 @@ class UserLocal extends User
 		return true;
 	}
 
+	public function CanLogOff()
+	{
+		// Internal authentication allows everybody to log off
+		return true;
+	}
+
 	public function ChangePassword($sOldPassword, $sNewPassword)
 	{
 		if ($this->Get('password') == $sOldPassword)

+ 2 - 2
pages/UI.php

@@ -1389,7 +1389,7 @@ EOF
 	////MetaModel::ShowQueryTrace();
 	$oP->output();
 }
-catch(CoreException $e)
+catch(ZZCoreException $e)
 {
 	require_once('../setup/setuppage.class.inc.php');
 	$oP = new SetupWebPage(Dict::S('UI:PageTitle:FatalError'));
@@ -1418,7 +1418,7 @@ catch(CoreException $e)
 	// For debugging only
 	//throw $e;
 }
-catch(Exception $e)
+catch(ZZException $e)
 {
 	require_once('../setup/setuppage.class.inc.php');
 	$oP = new SetupWebPage(Dict::S('UI:PageTitle:FatalError'));

+ 4 - 13
pages/ajax.csvimport.php

@@ -168,19 +168,10 @@ function GetMappingForField($sClassName, $sFieldName, $iFieldIndex, $bAdvancedMo
 }
 
 require_once('../application/startup.inc.php');
-session_start();
-if (isset($_SESSION['auth_user']))
-{
-	$sAuthUser = $_SESSION['auth_user'];
-	$sAuthPwd = $_SESSION['auth_pwd'];
-	// Attempt to login, fails silently
-	UserRights::Login($sAuthUser, $sAuthPwd);
-}
-else
-{
-	// No session information
-	echo "<p>No session information</p>\n";
-}
+
+require_once('../application/loginwebpage.class.inc.php');
+LoginWebPage::DoLogin(); // Check user rights and prompt if needed
+
 
 
 $oContext = new UserContext();

+ 2 - 13
pages/ajax.render.php

@@ -32,19 +32,8 @@ require_once('../application/ui.linkswidget.class.inc.php');
 require_once('../application/startup.inc.php');
 require_once('../application/user.preferences.class.inc.php');
 
-session_start();
-if (isset($_SESSION['auth_user']))
-{
-	$sAuthUser = $_SESSION['auth_user'];
-	$sAuthPwd = $_SESSION['auth_pwd'];
-	// Attempt to login, fails silently
-	UserRights::Login($sAuthUser, $sAuthPwd);
-}
-else
-{
-	// No session information
-	echo "<p>No session information</p>\n";
-}
+require_once('../application/loginwebpage.class.inc.php');
+LoginWebPage::DoLogin(); // Check user rights and prompt if needed
 
 $oPage = new ajax_page("");
 $oPage->no_cache();

+ 2 - 2
pages/testlist.inc.php

@@ -347,8 +347,8 @@ class TestUserRightsMatrixItop extends TestUserRights
 	protected function DoExecute()
 	{
 		$sUser = 'Romain';
-		echo "<p>Totor: ".(UserRights::Login('Totor', 'toto') ? 'ok' : 'NO')."</p>\n";
-		echo "<p>Romain: ".(UserRights::Login('Romain', 'toto') ? 'ok' : 'NO')."</p>\n";
+		echo "<p>Totor: ".(UserRights::CheckCredentials('Totor', 'toto') ? 'ok' : 'NO')."</p>\n";
+		echo "<p>Romain: ".(UserRights::CheckCredentials('Romain', 'toto') ? 'ok' : 'NO')."</p>\n";
 		echo "<p>User: ".UserRights::GetUser()."</p>\n";
 		echo "<p>On behalf of...".UserRights::GetRealUser()."</p>\n";
 

+ 3 - 2
setup/index.php

@@ -959,10 +959,11 @@ function SetupFinished(SetupWebPage $oP, $aParamValues, $iCurrentStep, Config $o
 
 		// Start the application
 		InitDataModel($oP, FINAL_CONFIG_FILE, false); // Load model and startup DB
-		if (UserRights::Login($sAuthUser, $sAuthPwd))
+		if (UserRights::CheckCredentials($sAuthUser, $sAuthPwd))
 		{
+			UserRights::Login($sAuthUser);
 			$_SESSION['auth_user'] = $sAuthUser;
-			$_SESSION['auth_pwd'] = $sAuthPwd;
+			
 			// remove the tmp config file
 			@unlink(TMP_CONFIG_FILE);
 			// try to make the final config file read-only

+ 2 - 1
webservices/webservices.class.inc.php

@@ -556,13 +556,14 @@ class WebServices
 
 	public function CreateIncidentTicket($sLogin, $sPassword, $sTitle, $sDescription, $oCallerDesc, $oCustomerDesc, $oServiceDesc, $oServiceSubcategoryDesc, $sProduct, $oWorkgroupDesc, $aSOAPImpactedCIs, $sImpact, $sUrgency)
 	{
-		if (!UserRights::Login($sLogin, $sPassword))
+		if (!UserRights::CheckCredentials($sLogin, $sPassword))
 		{
 			$oRes = new WebServiceResultFailedLogin($sLogin);
 			$this->LogUsage(__FUNCTION__, $oRes);
 
 			return $oRes->ToSoapStructure();
 		}
+		UserRights::Login($sLogin);
 
 		$aCallerDesc = self::SoapStructToExternalKeySearch($oCallerDesc);
 		$aCustomerDesc = self::SoapStructToExternalKeySearch($oCustomerDesc);