Index: branches/5.3.x/core/units/helpers/user_helper.php =================================================================== diff -u -N -r15649 -r15677 --- branches/5.3.x/core/units/helpers/user_helper.php (.../user_helper.php) (revision 15649) +++ branches/5.3.x/core/units/helpers/user_helper.php (.../user_helper.php) (revision 15677) @@ -1,6 +1,6 @@ event)) { + if ( !isset($this->event) ) { $this->event = new kEvent('u:OnLogin'); } - if (!$password && !$remember_login_cookie) { + if ( !$password && !$remember_login_cookie ) { return LoginResult::INVALID_PASSWORD; } $object =& $this->getUserObject(); // process "Save Username" checkbox - if ($this->Application->isAdmin) { + if ( $this->Application->isAdmin ) { $save_username = $this->Application->GetVar('cb_save_username') ? $username : ''; $this->Application->Session->SetCookie('save_username', $save_username, strtotime('+1 year')); @@ -57,24 +57,23 @@ // logging in "root" (admin only) $super_admin = ($username == 'super-root') && $this->verifySuperAdmin(); - if ($this->Application->isAdmin && ($username == 'root') || ($super_admin && $username == 'super-root')) { - $root_password = $this->Application->ConfigValue('RootPass'); + if ( $this->Application->isAdmin && ($username == 'root') || ($super_admin && $username == 'super-root') ) { $password_formatter = $this->Application->recallObject('kPasswordFormatter'); /* @var $password_formatter kPasswordFormatter */ - if ($root_password != $password_formatter->EncryptPassword($password, 'b38')) { + if ( !$password_formatter->checkPasswordFromSetting('RootPass', $password) ) { return LoginResult::INVALID_PASSWORD; } $user_id = USER_ROOT; $object->Clear($user_id); $object->SetDBField('Username', 'root'); - if (!$dry_run) { + if ( !$dry_run ) { $this->loginUserById($user_id, $remember_login_cookie); - if ($super_admin) { + if ( $super_admin ) { $this->Application->StoreVar('super_admin', 1); } @@ -83,39 +82,46 @@ $this->_processLoginRedirect('root', $password); $this->_processInterfaceLanguage(); + $this->_fixNextTemplate(); } return LoginResult::OK; } $user_id = $this->getUserId($username, $password, $remember_login_cookie); - if ($user_id) { + if ( $user_id ) { $object->Load($user_id); - if (!$this->checkBanRules($object)) { + if ( !$this->checkBanRules($object) ) { return LoginResult::BANNED; } - if ($object->GetDBField('Status') == STATUS_ACTIVE) { + if ( $object->GetDBField('Status') == STATUS_ACTIVE ) { if ( !$this->checkLoginPermission() ) { return LoginResult::NO_PERMISSION; } - if (!$dry_run) { + if ( !$dry_run ) { $this->loginUserById($user_id, $remember_login_cookie); - if ($remember_login) { + if ( $remember_login ) { // remember username & password when "Remember Login" checkbox us checked (when user is using login form on Front-End) - $this->Application->Session->SetCookie('remember_login', $username . '|' . md5($password), strtotime('+1 month')); + $sql = 'SELECT MD5(Password) + FROM ' . TABLE_PREFIX . 'Users + WHERE PortalUserId = ' . $user_id; + $remember_login_hash = $this->Conn->GetOne($sql); + + $this->Application->Session->SetCookie('remember_login', $username . '|' . $remember_login_hash, strtotime('+1 month')); } - if (!$remember_login_cookie) { + if ( !$remember_login_cookie ) { // reset counters $this->Application->resetCounters('UserSessions'); $this->_processLoginRedirect($username, $password); $this->_processInterfaceLanguage(); + $this->_fixNextTemplate(); } } @@ -124,7 +130,7 @@ else { $pending_template = $this->Application->GetVar('pending_disabled_template'); - if ($pending_template !== false && !$dry_run) { + if ( $pending_template !== false && !$dry_run ) { // when user found, but it's not yet approved redirect hit to notification template $this->event->redirect = $pending_template; @@ -137,7 +143,7 @@ } } - if (!$dry_run) { + if ( !$dry_run ) { $this->event->SetRedirectParam('pass', 'all'); // $this->event->SetRedirectParam('pass_category', 1); // to test } @@ -161,7 +167,9 @@ if ($user_id != USER_ROOT) { $groups = $this->Application->RecallVar('UserGroups'); - $this->Application->Session->SetField('GroupId', reset( explode(',', $groups) )); + list ($first_group, ) = explode(',', $groups); + + $this->Application->Session->SetField('GroupId', $first_group); $this->Application->Session->SetField('GroupList', $groups); $this->Application->Session->SetField('TimeZone', $object->GetDBField('TimeZone')); } @@ -175,7 +183,9 @@ $this->Application->StorePersistentVar('ThisLogin', adodb_mktime()); } - $this->Application->HandleEvent(new kEvent('u:OnAfterLogin')); + $hook_event = new kEvent('u:OnAfterLogin'); + $hook_event->MasterEvent = $this->event; + $this->Application->HandleEvent($hook_event); } /** @@ -271,13 +281,12 @@ $this->event = new kEvent('u:OnLogout'); } - $sync_manager = $this->Application->recallObject('UsersSyncronizeManager', null, Array(), Array ('InPortalSyncronize')); - /* @var $sync_manager UsersSyncronizeManager */ + $hook_event = new kEvent('u:OnBeforeLogout'); + $hook_event->MasterEvent = $this->event; + $this->Application->HandleEvent($hook_event); - $sync_manager->performAction('LogoutUser'); + $this->_processLoginRedirect(); - $this->Application->HandleEvent(new kEvent('u:OnBeforeLogout')); - $user_id = USER_GUEST; $this->Application->SetVar('u.current_id', $user_id); @@ -304,6 +313,8 @@ // don't pass user prefix on logout, since resulting url will have broken "env" $this->event->SetRedirectParam('pass', MOD_REWRITE ? 'm' : 'all'); + + $this->_fixNextTemplate(); } /** @@ -316,43 +327,90 @@ */ function getUserId($username, $password, $remember_login_cookie) { - $password = md5($password); - - if ($remember_login_cookie) { - list ($username, $password) = explode('|', $remember_login_cookie); // 0 - username, 1 - md5(password) + if ( $remember_login_cookie ) { + list ($username, $password) = explode('|', $remember_login_cookie); // 0 - username, 1 - md5(password_hash) } - $sql = 'SELECT PortalUserId + $sql = 'SELECT PortalUserId, Password, PasswordHashingMethod FROM ' . TABLE_PREFIX . 'Users - WHERE (Email = %1$s OR Username = %1$s) AND (Password = %2$s)'; - return $this->Conn->GetOne( sprintf($sql, $this->Conn->qstr($username), $this->Conn->qstr($password) ) ); + WHERE Email = %1$s OR Username = %1$s'; + $user_info = $this->Conn->GetRow(sprintf($sql, $this->Conn->qstr($username))); + + if ( $user_info ) { + if ( $remember_login_cookie ) { + return md5($user_info['Password']) == $password; + } + else { + $password_formatter = $this->Application->recallObject('kPasswordFormatter'); + /* @var $password_formatter kPasswordFormatter */ + + $hashing_method = $user_info['PasswordHashingMethod']; + + if ( $password_formatter->checkPassword($password, $user_info['Password'], $hashing_method) ) { + if ( $hashing_method != PasswordHashingMethod::PHPPASS ) { + $this->_fixUserPassword($user_info['PortalUserId'], $password); + } + + return $user_info['PortalUserId']; + } + } + } + + return false; } /** + * Apply new password hashing to given user's password + * + * @param int $user_id + * @param string $password + * @return void + * @access protected + */ + protected function _fixUserPassword($user_id, $password) + { + $password_formatter = $this->Application->recallObject('kPasswordFormatter'); + /* @var $password_formatter kPasswordFormatter */ + + $fields_hash = Array ( + 'Password' => $password_formatter->hashPassword($password), + 'PasswordHashingMethod' => PasswordHashingMethod::PHPPASS, + ); + + $this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'Users', 'PortalUserId = ' . $user_id); + } + + /** * Process all required data and redirect logged-in user * * @param string $username * @param string $password + * @return void */ - function _processLoginRedirect($username, $password) + protected function _processLoginRedirect($username = null, $password = null) { // set next template $next_template = $this->Application->GetVar('next_template'); - if ($next_template) { + if ( $next_template ) { $this->event->redirect = $next_template; } // process IIS redirect - if ($this->Application->ConfigValue('UseJSRedirect')) { + if ( $this->Application->ConfigValue('UseJSRedirect') ) { $this->event->SetRedirectParam('js_redirect', 1); } // synchronize login - $sync_manager = $this->Application->recallObject('UsersSyncronizeManager', null, Array(), Array ('InPortalSyncronize')); + $sync_manager = $this->Application->recallObject('UsersSyncronizeManager', null, Array (), Array ('InPortalSyncronize')); /* @var $sync_manager UsersSyncronizeManager */ - $sync_manager->performAction('LoginUser', $username, $password); + if ( isset($username) && isset($password) ) { + $sync_manager->performAction('LoginUser', $username, $password); + } + else { + $sync_manager->performAction('LogoutUser'); + } } /** @@ -400,29 +458,30 @@ // set language for Admin Console & Front-End with disabled Mod-Rewrite $this->event->SetRedirectParam('m_lang', $language_id); // data $this->Application->Session->SetField('Language', $language_id); // interface - - // set language for Front-End with enabled Mod-Rewrite - if ( MOD_REWRITE ) { - $this->_injectLanguageIntoUrl($language_id); - } } /** - * Inject language into whatever page user wants to go after login + * Injects redirect params into next template, which doesn't happen if next template starts with "external:" * - * @param int $language_id * @return void * @access protected */ - protected function _injectLanguageIntoUrl($language_id) + protected function _fixNextTemplate() { + if ( !MOD_REWRITE || !is_object($this->event) ) { + return; + } + // solve problem, when template is "true" instead of actual template name $template = is_string($this->event->redirect) ? $this->event->redirect : ''; $url = $this->Application->HREF($template, '', $this->event->getRedirectParams(), $this->event->redirectScript); $vars = $this->Application->parseRewriteUrl($url, 'pass'); + unset($vars['login'], $vars['logout']); + // merge back url params, because they were ignored if this was "external:" url $vars['pass'] = implode(',', $vars['pass']); - $vars['m_lang'] = $language_id; + $vars = array_merge($vars, $this->event->getRedirectParams()); + $template = $vars['t']; unset($vars['is_virtual'], $vars['t']);