event)) { $this->event = new kEvent('u:OnLogin'); } if (!$password && !$remember_login_cookie) { return LOGIN_RESULT_INVALID_PASSWORD; } $object =& $this->getUserObject(); // process "Save Username" checkbox if ($this->Application->isAdmin) { $save_username = $this->Application->GetVar('cb_save_username') ? $username : ''; $this->Application->Session->SetCookie('save_username', $save_username, strtotime('+1 year')); // cookie will be set on next refresh, but refresh won't occur if // login error present, so duplicate cookie in kHTTPQuery $this->Application->SetVar('save_username', $save_username); } // 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'); $password_formatter =& $this->Application->recallObject('kPasswordFormatter'); if ($root_password != $password_formatter->EncryptPassword($password, 'b38')) { return LOGIN_RESULT_INVALID_PASSWORD; } $user_id = USER_ROOT; $object->Clear($user_id); $object->SetDBField('Login', 'root'); if (!$dry_run) { $this->loginUserById($user_id, $remember_login_cookie); if ($super_admin) { $this->Application->StoreVar('super_admin', 1); } // reset counters $this->Application->resetCounters('UserSession'); $this->_processLoginRedirect('root', $password); $this->_processInterfaceLanguage(); } return LOGIN_RESULT_OK; } $user_id = $this->getUserId($username, $password, $remember_login_cookie); if ($user_id) { $object->Load($user_id); if (!$this->checkBanRules($object)) { return LOGIN_RESULT_BANNED; } if ($object->GetDBField('Status') == STATUS_ACTIVE) { if ( !$this->checkLoginPermission() ) { return LOGIN_RESULT_NO_PERMISSION; } if (!$dry_run) { $this->loginUserById($user_id, $remember_login_cookie); 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')); } if (!$remember_login_cookie) { // reset counters $this->Application->resetCounters('UserSession'); $this->_processLoginRedirect($username, $password); $this->_processInterfaceLanguage(); } } return LOGIN_RESULT_OK; } else { $pending_template = $this->Application->GetVar('pending_disabled_template'); 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; return LOGIN_RESULT_OK; } else { // when no notification template given return an error return LOGIN_RESULT_INVALID_PASSWORD; } } } if (!$dry_run) { $this->event->SetRedirectParam('pass', 'all'); // $this->event->SetRedirectParam('pass_category', 1); // to test } return LOGIN_RESULT_INVALID_PASSWORD; } /** * Login username by it's PortalUserId * * @param int $user_id * @param bool $remember_login_cookie */ function loginUserById($user_id, $remember_login_cookie = false) { $object =& $this->getUserObject(); $this->Application->StoreVar('user_id', $user_id); $this->Application->SetVar('u.current_id', $user_id); $this->Application->Session->SetField('PortalUserId', $user_id); if ($user_id != USER_ROOT) { $groups = $this->Application->RecallVar('UserGroups'); $this->Application->Session->SetField('GroupId', reset( explode(',', $groups) )); $this->Application->Session->SetField('GroupList', $groups); } $this->Application->LoadPersistentVars(); if (!$remember_login_cookie) { // don't change last login time when auto-login is used $this_login = (int)$this->Application->RecallPersistentVar('ThisLogin'); $this->Application->StorePersistentVar('LastLogin', $this_login); $this->Application->StorePersistentVar('ThisLogin', adodb_mktime()); } $this->Application->HandleEvent($dummy, 'u:OnAfterLogin'); } /** * Checks login permission * * @return bool */ function checkLoginPermission() { $object =& $this->getUserObject(); $groups = $object->getMembershipGroups(true); if (!$groups) { $groups = Array(); } // store groups, because kApplication::CheckPermission will use them! array_push($groups, $this->Application->ConfigValue('User_LoggedInGroup') ); $this->Application->StoreVar( 'UserGroups', implode(',', $groups), true ); // true for optional return $this->Application->CheckPermission($this->Application->isAdmin ? 'ADMIN' : 'LOGIN', 1); } /** * Performs user logout * */ function logoutUser() { if (!isset($this->event)) { $this->event = new kEvent('u:OnLogout'); } $sync_manager =& $this->Application->recallObjectP('UsersSyncronizeManager', null, Array(), 'InPortalSyncronize'); $sync_manager->performAction('LogoutUser'); $this->Application->HandleEvent($dummy, 'u:OnBeforeLogout'); $user_id = USER_GUEST; $this->Application->SetVar('u.current_id', $user_id); $object =& $this->Application->recallObject('u.current', null, Array('skip_autoload' => true)); $object->Load($user_id); $this->Application->DestroySession(); $this->Application->StoreVar('user_id', $user_id, true); $this->Application->Session->SetField('PortalUserId', $user_id); $group_list = $this->Application->ConfigValue('User_GuestGroup') . ',' . $this->Application->ConfigValue('User_LoggedInGroup'); $this->Application->StoreVar('UserGroups', $group_list, true); $this->Application->Session->SetField('GroupList', $group_list); if ($this->Application->ConfigValue('UseJSRedirect')) { $this->event->SetRedirectParam('js_redirect', 1); } $this->Application->resetCounters('UserSession'); $this->Application->Session->SetCookie('remember_login', '', strtotime('-1 hour')); // don't pass user prefix on logout, since resulting url will have broken "env" $this->event->SetRedirectParam('pass', MOD_REWRITE ? 'm' : 'all'); } /** * Returns user id based on given criteria * * @param string $username * @param string $password * @param string $remember_login_cookie * @return int */ 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) } $sql = 'SELECT PortalUserId FROM ' . TABLE_PREFIX . 'PortalUser WHERE (Email = %1$s OR Login = %1$s) AND (Password = %2$s)'; return $this->Conn->GetOne( sprintf($sql, $this->Conn->qstr($username), $this->Conn->qstr($password) ) ); } /** * Process all required data and redirect logged-in user * * @param string $username * @param string $password */ function _processLoginRedirect($username, $password) { // set next template $next_template = $this->Application->GetVar('next_template'); if ($next_template) { $this->event->redirect = $next_template; } // process IIS redirect if ($this->Application->ConfigValue('UseJSRedirect')) { $this->event->SetRedirectParam('js_redirect', 1); } // syncronize login $sync_manager =& $this->Application->recallObjectP('UsersSyncronizeManager', null, Array(), 'InPortalSyncronize'); $sync_manager->performAction('LoginUser', $username, $password); } /** * Sets correct interface language after sucessful login, based on user settings * * @param kEvent $event */ function _processInterfaceLanguage() { if (!$this->Application->isAdmin) { return ; } $is_root = $this->Application->RecallVar('user_id') == USER_ROOT; $object =& $this->getUserObject(); $user_language_id = $is_root ? $this->Application->RecallPersistentVar('AdminLanguage') : $object->GetDBField('AdminLanguage'); $sql = 'SELECT LanguageId, IF(LanguageId = ' . (int)$user_language_id . ', 2, AdminInterfaceLang) AS SortKey FROM ' . TABLE_PREFIX . 'Language WHERE Enabled = 1 HAVING SortKey <> 0 ORDER BY SortKey DESC'; $language_info = $this->Conn->GetRow($sql); $language_id = $language_info && $language_info['LanguageId'] ? $language_info['LanguageId'] : $user_language_id; if ($user_language_id != $language_id) { // first admin login OR language was delelted or disabled if ($is_root) { $this->Application->StorePersistentVar('AdminLanguage', $language_id); } else { $object->SetDBField('AdminLanguage', $language_id); $object->Update(); } } $this->event->SetRedirectParam('m_lang', $language_id); // data $this->Application->Session->SetField('Language', $language_id); // interface } /** * Checks that user is allowed to use super admin mode * * @return bool */ function verifySuperAdmin() { $sa_mode = ipMatch(defined('SA_IP') ? SA_IP : ''); return $sa_mode || $this->Application->isDebugMode(); } /** * Returns user object, used during login processings * * @return UsersItem */ function &getUserObject() { $prefix_special = $this->Application->isAdmin ? 'u.current' : 'u'; // "u" used on front not to change theme $object =& $this->Application->recallObject($prefix_special, null, Array('skip_autoload' => true)); return $object; } /** * Checks, if given user fields matches at least one of defined ban rules * * @param kDBItem $object * @return bool */ function checkBanRules(&$object) { $table = $this->Application->getUnitOption('ban-rule', 'TableName'); if (!$this->Conn->TableFound($table)) { // when ban table not found -> assume user is ok by default return true; } $sql = 'SELECT * FROM ' . $table . ' WHERE ItemType = 6 AND Status = ' . STATUS_ACTIVE . ' ORDER BY Priority DESC'; $rules = $this->Conn->Query($sql); $found = false; foreach ($rules as $rule) { $field = $rule['ItemField']; $this_value = mb_strtolower( $object->GetDBField($field) ); $test_value = mb_strtolower( $rule['ItemValue'] ); switch ( $rule['ItemVerb'] ) { case 1: // is if ($this_value == $test_value) { $found = true; } break; case 2: // is not if ($this_value != $test_value) { $found = true; } break; case 3: // contains if ( strstr($this_value, $test_value) ) { $found = true; } break; case 4: // not contains if ( !strstr($this_value, $test_value) ) { $found = true; } break; case 7: // exists if ( strlen($this_value) > 0 ) { $found = true; } break; case 8: // unique if ( $this->_checkValueExist($field, $this_value) ) { $found = true; } break; } if ( $found ) { // check ban rules, until one of them matches if ( $rule['RuleType'] ) { // invert rule type $found = false; } break; } } return !$found; } /** * Checks if value is unique in Users table against the specified field * * @param string $field * @param string $value * @return string */ function _checkValueExist($field, $value) { $sql = 'SELECT * FROM ' . $this->Application->getUnitOption('u', 'TableName') . ' WHERE '. $field .' = ' . $this->Conn->qstr($value); return $this->Conn->GetOne($sql); } }