From 172f26c45365bd2c115f9c2e13b6d76eca6ad2e7 Mon Sep 17 00:00:00 2001 From: prasad <prasad@vtiger.com> Date: Thu, 19 Apr 2018 17:26:56 +0530 Subject: [PATCH] Fixes #28: Default password encryption changed to PHASH mode. --- modules/Users/Users.php | 115 +++++++++++++++++-------------------- vtlib/Vtiger/Functions.php | 8 ++- 2 files changed, 59 insertions(+), 64 deletions(-) diff --git a/modules/Users/Users.php b/modules/Users/Users.php index 0a94f946b..cf70a282d 100755 --- a/modules/Users/Users.php +++ b/modules/Users/Users.php @@ -137,8 +137,10 @@ class Users extends CRMEntity { $this->log = LoggerManager::getLogger('user'); $this->log->debug("Entering Users() method ..."); $this->db = PearDatabase::getInstance(); - $this->DEFAULT_PASSWORD_CRYPT_TYPE = (version_compare(PHP_VERSION, '5.3.0') >= 0)? - 'PHP5.3MD5': 'MD5'; + $this->DEFAULT_PASSWORD_CRYPT_TYPE = (version_compare(PHP_VERSION, '5.3.0') >= 0)? 'PHP5.3MD5': 'MD5'; + if (version_compare(PHP_VERSION, '5.5.0') >= 0) { + $this->DEFAULT_PASSWORD_CRYPT_TYPE = 'PHASH'; + } $this->column_fields = getColumnFields('Users'); $this->column_fields['currency_name'] = ''; $this->column_fields['currency_code'] = ''; @@ -259,9 +261,7 @@ class Users extends CRMEntity { * Contributor(s): ______________________________________.. */ function encrypt_password($user_password, $crypt_type='') { - // encrypt the password. - $salt = substr($this->column_fields["user_name"], 0, 2); - //TODO : remove untill here in the next udpate + $salt = null; /* Recommended */ // Fix for: http://trac.vtiger.com/cgi-bin/trac.cgi/ticket/4923 if($crypt_type == '') { @@ -269,19 +269,27 @@ class Users extends CRMEntity { $crypt_type = $this->get_user_crypt_type(); } - // For more details on salt format look at: http://in.php.net/crypt - if($crypt_type == 'MD5') { - $salt = '$1$' . $salt . '$'; - } elseif($crypt_type == 'BLOWFISH') { - $salt = '$2$' . $salt . '$'; - } elseif($crypt_type == 'PHP5.3MD5') { - //only change salt for php 5.3 or higher version for backward - //compactibility. - //crypt API is lot stricter in taking the value for salt. - $salt = '$1$' . str_pad($salt, 9, '0'); + if ($crypt_type != 'PHASH') { + /* Backward compatible for PHP < 5.5.0 */ + // encrypt the password. + $salt = substr($this->column_fields["user_name"], 0, 2); + // For more details on salt format look at: http://in.php.net/crypt + if($crypt_type == 'MD5') { + $salt = '$1$' . $salt . '$'; + } elseif($crypt_type == 'BLOWFISH') { + $salt = '$2$' . $salt . '$'; + } elseif($crypt_type == 'PHP5.3MD5') { + //only change salt for php 5.3 or higher version for backward + //compactibility. + //crypt API is lot stricter in taking the value for salt. + $salt = '$1$' . str_pad($salt, 9, '0'); + } } - $encrypted_password = crypt($user_password, $salt); + $encrypted_password = ($crypt_type == 'PHASH') ? + password_hash($user_password, PASSWORD_DEFAULT) : /* recommended */ + crypt($user_password, $salt); /* backward compatibility */ + return $encrypted_password; } @@ -326,52 +334,28 @@ class Users extends CRMEntity { * @return true if the user is authenticated, false otherwise */ function doLogin($user_password) { - global $AUTHCFG; $usr_name = $this->column_fields["user_name"]; - switch (strtoupper($AUTHCFG['authType'])) { - case 'LDAP': - $this->log->debug("Using LDAP authentication"); - require_once('modules/Users/authTypes/LDAP.php'); - $result = ldapAuthenticate($this->column_fields["user_name"], $user_password); - if ($result == NULL) { - return false; - } else { - return true; - } - break; - - case 'AD': - $this->log->debug("Using Active Directory authentication"); - require_once('modules/Users/authTypes/adLDAP.php'); - $adldap = new adLDAP(); - if ($adldap->authenticate($this->column_fields["user_name"],$user_password)) { - return true; - } else { - return false; - } - break; + $query = "SELECT crypt_type, user_password, status, user_name FROM $this->table_name WHERE user_name=?"; + $result = $this->db->requirePsSingleResult($query, array($usr_name), false); + if (empty($result)) { + return false; + } + $this->column_fields["user_name"] = $this->db->query_result($result, 0, 'user_name'); + $crypt_type = $this->db->query_result($result, 0, 'crypt_type'); + $user_status = $this->db->query_result($result, 0, 'status'); + $dbuser_password = $this->db->query_result($result, 0, 'user_password'); - default: - $this->log->debug("Using integrated/SQL authentication"); - $query = "SELECT crypt_type, user_name FROM $this->table_name WHERE user_name=?"; - $result = $this->db->requirePsSingleResult($query, array($usr_name), false); - if (empty($result)) { - return false; - } - $crypt_type = $this->db->query_result($result, 0, 'crypt_type'); - $this->column_fields["user_name"] = $this->db->query_result($result, 0, 'user_name'); + $ok = false; + if ($user_status == 'Active') { + if ($crypt_type == 'PHASH') { + $ok = password_verify($user_password, $dbuser_password); + } else { $encrypted_password = $this->encrypt_password($user_password, $crypt_type); - $query = "SELECT 1 from $this->table_name where user_name=? AND user_password=? AND status = ?"; - $result = $this->db->requirePsSingleResult($query, array($usr_name, $encrypted_password, 'Active'), false); - if (empty($result)) { - return false; - } else { - return true; - } - break; + $ok = ($dbuser_password == $encrypted_password); + } } - return false; + return $ok; } @@ -406,8 +390,8 @@ class Users extends CRMEntity { } // Get the fields for the user - $query = "SELECT * from $this->table_name where user_name='$usr_name'"; - $result = $this->db->requireSingleResult($query, false); + $query = "SELECT * from $this->table_name where user_name=?"; + $result = $this->db->requireSingleResult($query, array($usr_name), false); $row = $this->db->fetchByAssoc($result); $this->column_fields = $row; @@ -548,11 +532,16 @@ class Users extends CRMEntity { $row = $this->db->fetchByAssoc($result); $this->log->debug("select old password query: $query"); $this->log->debug("return result of $row"); - $encryptedPassword = $this->encrypt_password($password, $row['crypt_type']); - if($encryptedPassword != $row['user_password']) { - return false; + switch ($row['crypt_type']) { + case 'PHASH': return password_verify($password, $row['user_password']); + default: + $encryptedPassword = $this->encrypt_password($password, $row['crypt_type']); + if($encryptedPassword == $row['user_password']) { + return true; + } + break; } - return true; + return false; } function is_authenticated() { diff --git a/vtlib/Vtiger/Functions.php b/vtlib/Vtiger/Functions.php index 01788619a..3a03fe184 100644 --- a/vtlib/Vtiger/Functions.php +++ b/vtlib/Vtiger/Functions.php @@ -1062,7 +1062,12 @@ class Vtiger_Functions { /* * Function to generate encrypted password. */ - static function generateEncryptedPassword($password, $mode='CRYPT') { + static function generateEncryptedPassword($password, $mode='') { + if ($mode == '') { + $mode = (version_compare(PHP_VERSION, '5.5.0') >= 0)? 'PHASH' : 'CRYPT'; + } + + if ($mode == 'PHASH') return password_hash($password, PASSWORD_DEFAULT); if ($mode == 'MD5') return md5($password); @@ -1085,6 +1090,7 @@ class Vtiger_Functions { static function compareEncryptedPassword($plainText, $encryptedPassword, $mode='CRYPT') { $reEncryptedPassword = null; switch ($mode) { + case 'PHASH': return password_verify($plainText, $encryptedPassword); case 'CRYPT': $reEncryptedPassword = crypt($plainText, $encryptedPassword); break; case 'MD5' : $reEncryptedPassword = md5($plainText); break; default : $reEncryptedPassword = $plainText; break; -- GitLab