From f050f12663a046feafca8a75dbd6a4e40d687796 Mon Sep 17 00:00:00 2001 From: prasad <prasad@vtiger.com> Date: Fri, 17 Jun 2016 12:14:11 +0530 Subject: [PATCH] Adopting php crypt mode for portal password instead of md5. --- modules/Contacts/ContactsHandler.php | 6 ++--- modules/Migration/schema/640_to_650.php | 15 +++++++++++ schema/DatabaseSchema.xml | 2 +- soap/customerportal.php | 34 +++++++++++++++++------ vtlib/Vtiger/Functions.php | 36 +++++++++++++++++++++++-- 5 files changed, 79 insertions(+), 14 deletions(-) diff --git a/modules/Contacts/ContactsHandler.php b/modules/Contacts/ContactsHandler.php index 000f807e..815c09b2 100644 --- a/modules/Contacts/ContactsHandler.php +++ b/modules/Contacts/ContactsHandler.php @@ -40,15 +40,15 @@ function Contacts_sendCustomerPortalLoginDetails($entityData){ } } $password = makeRandomPassword(); - $md5_password = md5($password); + $enc_password = Vtiger_Functions::generateEncryptedPassword($password); if ($insert == true) { $sql = "INSERT INTO vtiger_portalinfo(id,user_name,user_password,cryptmode,type,isactive) VALUES(?,?,?,?,?,?)"; - $params = array($entityId, $email, $md5_password, 'MD5', 'C', 1); + $params = array($entityId, $email, $enc_password, 'CRYPT', 'C', 1); $adb->pquery($sql, $params); } if ($update == true && $portalChanged == true) { $sql = "UPDATE vtiger_portalinfo SET user_password=?, cryptmode=? WHERE id=?"; - $params = array($md5_password, 'MD5', $entityId); + $params = array($enc_password, 'CRYPT', $entityId); $adb->pquery($sql, $params); } if (($insert == true || ($update = true && $portalChanged == true)) && $entityData->get('emailoptout') == 0) { diff --git a/modules/Migration/schema/640_to_650.php b/modules/Migration/schema/640_to_650.php index 206bd8cf..fe46fb26 100644 --- a/modules/Migration/schema/640_to_650.php +++ b/modules/Migration/schema/640_to_650.php @@ -14,8 +14,23 @@ if(defined('VTIGER_UPGRADE')) { global $adb; Vtiger_Utils::AddColumn('vtiger_portalinfo', 'cryptmode', 'varchar(20)'); +$adb->pquery("ALTER TABLE vtiger_portalinfo MODIFY COLUMN user_password varchar(255)", array()); //Updating existing users password to thier md5 hash +$portalinfo_hasmore = true; +do { + $result = $adb->pquery('SELECT id, user_password FROM vtiger_portalinfo WHERE cryptmode is null limit 1000', array()); + + $portalinfo_hasmore = false; // assume we are done. + while ($row = $adb->fetch_array($result)) { + $portalinfo_hasmore = true; // we found at-least one so there could be more. + + $enc_password = Vtiger_Functions::generateEncryptedPassword(decode_html($row['user_password'])); + $adb->pquery('UPDATE vtiger_portalinfo SET user_password=?, cryptmode = ? WHERE id=?', array($enc_password, 'CRYPT', $row['id'])); + } + +} while ($portalinfo_hasmore); + $updateQuery = "UPDATE vtiger_portalinfo SET user_password=MD5(user_password),cryptmode='MD5' WHERE cryptmode is null"; $adb->pquery($updateQuery, array()); diff --git a/schema/DatabaseSchema.xml b/schema/DatabaseSchema.xml index f9a3b22c..2aff1397 100644 --- a/schema/DatabaseSchema.xml +++ b/schema/DatabaseSchema.xml @@ -588,7 +588,7 @@ <key /> </field> <field name="user_name" type="C" size="50" /> - <field name="user_password" type="C" size="30" /> + <field name="user_password" type="C" size="255" /> <field name="type" type="C" size="5" /> <field name="cryptmode" type="C" size="20" /> <field name="last_login_time" type="T" /> diff --git a/soap/customerportal.php b/soap/customerportal.php index 77f640a5..12d8f47f 100755 --- a/soap/customerportal.php +++ b/soap/customerportal.php @@ -18,6 +18,7 @@ if (file_exists('config_override.php')) { } include_once 'vtlib/Vtiger/Module.php'; +include_once 'vtlib/Vtiger/Functions.php'; include_once 'includes/main/WebUI.php'; require_once('libraries/nusoap/nusoap.php'); @@ -996,23 +997,33 @@ function authenticate_user($username,$password,$version,$login = 'true') $password = $adb->sql_escape_string($password); $current_date = date("Y-m-d"); - $sql = "select id, user_name, user_password,last_login_time, support_start_date, support_end_date + $sql = "select id, user_name, user_password,last_login_time, support_start_date, support_end_date, cryptmode from vtiger_portalinfo inner join vtiger_customerdetails on vtiger_portalinfo.id=vtiger_customerdetails.customerid inner join vtiger_crmentity on vtiger_crmentity.crmid=vtiger_portalinfo.id - where vtiger_crmentity.deleted=0 and user_name=? and user_password = ? + where vtiger_crmentity.deleted=0 and user_name=? and isactive=1 and vtiger_customerdetails.portal=1 and vtiger_customerdetails.support_start_date <= ? and vtiger_customerdetails.support_end_date >= ?"; - $result = $adb->pquery($sql, array($username, $password, $current_date, $current_date)); + $result = $adb->pquery($sql, array($username, $current_date, $current_date)); $err[0]['err1'] = "MORE_THAN_ONE_USER"; $err[1]['err1'] = "INVALID_USERNAME_OR_PASSWORD"; $num_rows = $adb->num_rows($result); - if($num_rows > 1) return $err[0];//More than one user - elseif($num_rows <= 0) return $err[1];//No user + if($num_rows <= 0) return $err[1];//No user - $customerid = $adb->query_result($result,0,'id'); + // Match password against multiple user and decide. + $customerid = null; + for ($i = 0; $i < $num_rows; ++$i) { + $customerid = $adb->query_result($result, $i,'id'); + if (Vtiger_Function::compareEncryptedPassword($password, $adb->query_result($result, $i, 'id'), $adb->query_result($result, $i, 'cryptmode'))) { + break; + } else { + $customerid = null; + } + } + + if (!$customerid) return $err[1];//No user again. $list[0]['id'] = $customerid; $list[0]['user_name'] = $adb->query_result($result,0,'user_name'); @@ -1064,8 +1075,8 @@ function change_password($input_array) if(!empty($list[0]['id'])){ return array('MORE_THAN_ONE_USER'); } - $sql = "update vtiger_portalinfo set user_password=? where id=? and user_name=?"; - $result = $adb->pquery($sql, array(md5($password), $id, $username)); + $sql = "update vtiger_portalinfo set user_password=?, cryptmode=? where id=? and user_name=?"; + $result = $adb->pquery($sql, array(Vtiger_Functions::generateEncryptedPassword($password), 'CRYPT', $id, $username)); $log->debug("Exiting customer portal function change_password"); return $list; @@ -1123,6 +1134,13 @@ function send_mail_for_password($mailid) $password = $adb->query_result($res,0,'user_password'); $isactive = $adb->query_result($res,0,'isactive'); + // We no longer have the original password! + if (!empty($adb->query_result($res, 0, 'cryptmode'))) { + $password = '*****'; + // TODO - we need to send link to reset the password + // For now CRM user can do the same. + } + $fromquery = "select vtiger_users.user_name, vtiger_users.email1 from vtiger_users inner join vtiger_crmentity on vtiger_users.id = vtiger_crmentity.smownerid inner join vtiger_contactdetails on vtiger_contactdetails.contactid=vtiger_crmentity.crmid where vtiger_contactdetails.email =?"; $from_res = $adb->pquery($fromquery, array($mailid)); $initialfrom = $adb->query_result($from_res,0,'user_name'); diff --git a/vtlib/Vtiger/Functions.php b/vtlib/Vtiger/Functions.php index a3e5f8eb..f0b1c660 100644 --- a/vtlib/Vtiger/Functions.php +++ b/vtlib/Vtiger/Functions.php @@ -969,6 +969,38 @@ class Vtiger_Functions { return false; } return true; - } - + } + + /* + * Function to generate encrypted password. + */ + static function generateEncryptedPassword($password, $mode='CRYPT') { + + if ($mode == 'MD5') return md5($password); + + if ($mode == 'CRYPT') { + $salt = null; + if (function_exists('password_hash')) { // php 5.5+ + $salt = password_hash(); + } else { + $salt = '$2y$11$'.str_replace("+",".",substr(base64_encode(openssl_random_pseudo_bytes(17)),0,22)); + } + return crypt($password, $salt); + } + + throw new Exception('Invalid encryption mode: '.$mode); + } + + /* + * Function to compare encrypted password. + */ + static function compareEncryptedPassword($plainText, $encryptedPassword, $mode='CRYPT') { + $reEncryptedPassword = null; + switch ($mode) { + case 'CRYPT': $reEncryptedPassword = crypt($plainText, $encryptedPassword); break; + case 'MD5' : $reEncryptedPassword = md5($plainText); + default : $reEncryptedPassword = $plainText; + } + return ($reEncryptedPassword == $encryptedPassword); + } } -- GitLab