Page Menu
Home
In-Portal Phabricator
Search
Configure Global Search
Log In
Files
F774049
in-portal
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Mon, Feb 3, 6:18 AM
Size
20 KB
Mime Type
text/x-diff
Expires
Wed, Feb 5, 6:18 AM (3 h, 35 m)
Engine
blob
Format
Raw Data
Handle
557189
Attached To
rINP In-Portal
in-portal
View Options
Index: branches/5.2.x/core/units/helpers/user_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/user_helper.php (revision 15663)
+++ branches/5.2.x/core/units/helpers/user_helper.php (revision 15664)
@@ -1,693 +1,694 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class UserHelper extends kHelper {
/**
* Event to be used during login processings
*
* @var kEvent
*/
var $event = null;
/**
* Performs user login and returns the result
*
* @param string $username
* @param string $password
* @param bool $dry_run
* @param bool $remember_login
* @param string $remember_login_cookie
* @return int
*/
function loginUser($username, $password, $dry_run = false, $remember_login = false, $remember_login_cookie = '')
{
if ( !isset($this->event) ) {
$this->event = new kEvent('u:OnLogin');
}
if ( !$password && !$remember_login_cookie ) {
return LoginResult::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') ) {
$password_formatter = $this->Application->recallObject('kPasswordFormatter');
/* @var $password_formatter kPasswordFormatter */
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 ) {
$this->loginUserById($user_id, $remember_login_cookie);
if ( $super_admin ) {
$this->Application->StoreVar('super_admin', 1);
}
// reset counters
$this->Application->resetCounters('UserSessions');
$this->_processLoginRedirect('root', $password);
$this->_processInterfaceLanguage();
$this->_fixNextTemplate();
}
return LoginResult::OK;
}
$user_id = $this->getUserId($username, $password, $remember_login_cookie);
if ( $user_id ) {
$object->Load($user_id);
if ( !$this->checkBanRules($object) ) {
return LoginResult::BANNED;
}
if ( $object->GetDBField('Status') == STATUS_ACTIVE ) {
if ( !$this->checkLoginPermission() ) {
return LoginResult::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)
$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 ) {
// reset counters
$this->Application->resetCounters('UserSessions');
$this->_processLoginRedirect($username, $password);
$this->_processInterfaceLanguage();
$this->_fixNextTemplate();
}
}
return LoginResult::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 LoginResult::OK;
}
else {
// when no notification template given return an error
return LoginResult::INVALID_PASSWORD;
}
}
}
if ( !$dry_run ) {
$this->event->SetRedirectParam('pass', 'all');
// $this->event->SetRedirectParam('pass_category', 1); // to test
}
return LoginResult::INVALID_PASSWORD;
}
/**
* Login user by it's id
*
* @param int $user_id
* @param bool $remember_login_cookie
*/
function loginUserById($user_id, $remember_login_cookie = false)
{
$object =& $this->getUserObject();
+ $this->Application->removeObject($object->getPrefixSpecial());
$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');
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'));
}
$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());
}
$hook_event = new kEvent('u:OnAfterLogin');
$hook_event->MasterEvent = $this->event;
$this->Application->HandleEvent($hook_event);
}
/**
* Checks login permission
*
* @return bool
*/
function checkLoginPermission()
{
$object =& $this->getUserObject();
$ip_restrictions = $object->GetDBField('IPRestrictions');
if ( $ip_restrictions && !$this->Application->isDebugMode() && !kUtil::ipMatch($ip_restrictions, "\n") ) {
return false;
}
$groups = $object->getMembershipGroups(true);
if ( !$groups ) {
$groups = Array ();
}
$default_group = $this->getUserTypeGroup();
if ( $default_group !== false ) {
array_push($groups, $default_group);
}
// store groups, because kApplication::CheckPermission will use them!
array_push($groups, $this->Application->ConfigValue('User_LoggedInGroup'));
$groups = array_unique($groups);
$this->Application->StoreVar('UserGroups', implode(',', $groups), true); // true for optional
return $this->Application->CheckPermission($this->Application->isAdmin ? 'ADMIN' : 'LOGIN', 1);
}
/**
* Returns default user group for it's type
*
* @return bool|string
* @access protected
*/
protected function getUserTypeGroup()
{
$group_id = false;
$object =& $this->getUserObject();
if ( $object->GetDBField('UserType') == UserType::USER ) {
$group_id = $this->Application->ConfigValue('User_NewGroup');
}
elseif ( $object->GetDBField('UserType') == UserType::ADMIN ) {
$group_id = $this->Application->ConfigValue('User_AdminGroup');
}
$ip_restrictions = $this->getGroupsWithIPRestrictions();
if ( !isset($ip_restrictions[$group_id]) || kUtil::ipMatch($ip_restrictions[$group_id], "\n") ) {
return $group_id;
}
return false;
}
/**
* Returns groups with IP restrictions
*
* @return Array
* @access public
*/
public function getGroupsWithIPRestrictions()
{
static $cache = null;
if ( $this->Application->isDebugMode() ) {
return Array ();
}
if ( !isset($cache) ) {
$sql = 'SELECT IPRestrictions, GroupId
FROM ' . TABLE_PREFIX . 'UserGroups
WHERE IPRestrictions IS NOT NULL';
$cache = $this->Conn->GetCol($sql, 'GroupId');
}
return $cache;
}
/**
* Performs user logout
*
*/
function logoutUser()
{
if (!isset($this->event)) {
$this->event = new kEvent('u:OnLogout');
}
$hook_event = new kEvent('u:OnBeforeLogout');
$hook_event->MasterEvent = $this->event;
$this->Application->HandleEvent($hook_event);
$this->_processLoginRedirect();
$user_id = USER_GUEST;
$this->Application->SetVar('u.current_id', $user_id);
$object = $this->Application->recallObject('u.current', null, Array('skip_autoload' => true));
/* @var $object UsersItem */
$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('UserSessions');
$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');
$this->_fixNextTemplate();
}
/**
* 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)
{
if ( $remember_login_cookie ) {
list ($username, $password) = explode('|', $remember_login_cookie); // 0 - username, 1 - md5(password_hash)
}
$sql = 'SELECT PortalUserId, Password, PasswordHashingMethod
FROM ' . TABLE_PREFIX . 'Users
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
*/
protected function _processLoginRedirect($username = null, $password = null)
{
// 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);
}
// synchronize login
$sync_manager = $this->Application->recallObject('UsersSyncronizeManager', null, Array (), Array ('InPortalSyncronize'));
/* @var $sync_manager UsersSyncronizeManager */
if ( isset($username) && isset($password) ) {
$sync_manager->performAction('LoginUser', $username, $password);
}
else {
$sync_manager->performAction('LogoutUser');
}
}
/**
* Sets correct interface language after successful login, based on user settings
*
* @return void
* @access protected
*/
protected function _processInterfaceLanguage()
{
if ( defined('IS_INSTALL') && IS_INSTALL ) {
$this->event->SetRedirectParam('m_lang', 1); // data
$this->Application->Session->SetField('Language', 1); // interface
return;
}
$language_field = $this->Application->isAdmin ? 'AdminLanguage' : 'FrontLanguage';
$primary_language_field = $this->Application->isAdmin ? 'AdminInterfaceLang' : 'PrimaryLang';
$is_root = $this->Application->RecallVar('user_id') == USER_ROOT;
$object =& $this->getUserObject();
$user_language_id = $is_root ? $this->Application->RecallPersistentVar($language_field) : $object->GetDBField($language_field);
$sql = 'SELECT LanguageId, IF(LanguageId = ' . (int)$user_language_id . ', 2, ' . $primary_language_field . ') AS SortKey
FROM ' . TABLE_PREFIX . 'Languages
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 login OR language was deleted or disabled
if ( $is_root ) {
$this->Application->StorePersistentVar($language_field, $language_id);
}
else {
$object->SetDBField($language_field, $language_id);
$object->Update();
}
}
// 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
}
/**
* Injects redirect params into next template, which doesn't happen if next template starts with "external:"
*
* @return void
* @access protected
*/
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 = array_merge($vars, $this->event->getRedirectParams());
$template = $vars['t'];
unset($vars['is_virtual'], $vars['t']);
$this->event->redirect = $template;
$this->event->setRedirectParams($vars, false);
}
/**
* Checks that user is allowed to use super admin mode
*
* @return bool
*/
function verifySuperAdmin()
{
$sa_mode = kUtil::ipMatch(defined('SA_IP') ? SA_IP : '');
return $sa_mode || $this->Application->isDebugMode();
}
/**
* Returns user object, used during login processing
*
* @return UsersItem
* @access public
*/
public 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));
/* @var $object UsersItem */
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);
}
public function validateUserCode($user_code, $code_type, $expiration_timeout = null)
{
$expiration_timeouts = Array (
'forgot_password' => 'config:Users_AllowReset',
'activation' => 'config:UserEmailActivationTimeout',
'verify_email' => 'config:Users_AllowReset',
'custom' => '',
);
if ( !$user_code ) {
return 'code_is_not_valid';
}
$sql = 'SELECT PwRequestTime, PortalUserId
FROM ' . TABLE_PREFIX . 'Users
WHERE PwResetConfirm = ' . $this->Conn->qstr( trim($user_code) );
$user_info = $this->Conn->GetRow($sql);
if ( $user_info === false ) {
return 'code_is_not_valid';
}
$expiration_timeout = isset($expiration_timeout) ? $expiration_timeout : $expiration_timeouts[$code_type];
if ( preg_match('/^config:(.*)$/', $expiration_timeout, $regs) ) {
$expiration_timeout = $this->Application->ConfigValue( $regs[1] );
}
if ( $expiration_timeout && $user_info['PwRequestTime'] < strtotime('-' . $expiration_timeout . ' minutes') ) {
return 'code_expired';
}
return $user_info['PortalUserId'];
}
/**
* Restores user's email, returns error label, if error occurred
*
* @param string $hash
* @return string
* @access public
*/
public function restoreEmail($hash)
{
if ( !preg_match('/^[a-f0-9]{32}$/', $hash) ) {
return 'invalid_hash';
}
$sql = 'SELECT PortalUserId, PrevEmails
FROM ' . TABLE_PREFIX . 'Users
WHERE PrevEmails LIKE ' . $this->Conn->qstr('%' . $hash . '%');
$user_info = $this->Conn->GetRow($sql);
if ( $user_info === false ) {
return 'invalid_hash';
}
$prev_emails = $user_info['PrevEmails'];
$prev_emails = $prev_emails ? unserialize($prev_emails) : Array ();
if ( !isset($prev_emails[$hash]) ) {
return 'invalid_hash';
}
$email_to_restore = $prev_emails[$hash];
unset($prev_emails[$hash]);
$object = $this->Application->recallObject('u.email-restore', null, Array ('skip_autoload' => true));
/* @var $object UsersItem */
$object->Load($user_info['PortalUserId']);
$object->SetDBField('PrevEmails', serialize($prev_emails));
$object->SetDBField('Email', $email_to_restore);
$object->SetDBField('EmailVerified', 1);
return $object->Update() ? '' : 'restore_impossible';
}
}
Event Timeline
Log In to Comment