Changeset 501 for trunk/lib/Auth_SQL.inc.php
- Timestamp:
- Nov 16, 2014 11:07:01 AM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/lib/Auth_SQL.inc.php
r500 r501 32 32 class Auth_SQL { 33 33 34 // Available encryptiontypes for class Auth_SQL.34 // Available hash types for class Auth_SQL. 35 35 const ENCRYPT_PLAINTEXT = 1; 36 36 const ENCRYPT_CRYPT = 2; … … 68 68 'db_login_table' => 'user_login_tbl', 69 69 70 // The type of encryptionto use for passwords stored in the db_table. Use one of the Auth_SQL::ENCRYPT_* types specified above.71 // Hardened password hashes rely on the same key/salt being used to compare encryptions.70 // The type of hash to use for passwords stored in the db_table. Use one of the Auth_SQL::ENCRYPT_* types specified above. 71 // Hardened password hashes rely on the same key/salt being used to compare hashs. 72 72 // Be aware that when using one of the hardened types the App signing_key or $more_salt below cannot change! 73 'encryption_type' => self::ENCRYPT_MD5, 73 'hash_type' => self::ENCRYPT_MD5, 74 'encryption_type' => null, // Backwards misnomer compatibility. 75 76 // Automatically update stored user hashes when the user next authenticates if the hash type changes (requires user_tbl with populated userpass_hashtype column). 77 'hash_type_autoupdate' => true, 74 78 75 79 // The URL to the login script. … … 257 261 public function setParam($params) 258 262 { 263 $app =& App::getInstance(); 264 259 265 if (isset($params['match_remote_ip_exempt_usernames'])) { 260 266 $params['match_remote_ip_exempt_usernames'] = array_map('strtolower', $params['match_remote_ip_exempt_usernames']); … … 263 269 $params['login_abuse_exempt_usernames'] = array_map('strtolower', $params['login_abuse_exempt_usernames']); 264 270 } 265 if (isset($params['encryption_type']) && version_compare(PHP_VERSION, '5.5.0', '<') && in_array($params['encryption_type'], array(self::ENCRYPT_PASSWORD_BCRYPT, self::ENCRYPT_PASSWORD_DEFAULT))) { 271 if (isset($params['encryption_type'])) { 272 // Backwards misnomer compatibility. 273 $params['hash_type'] = $params['encryption_type']; 274 } 275 if (isset($params['hash_type']) && version_compare(PHP_VERSION, '5.5.0', '<') && in_array($params['hash_type'], array(self::ENCRYPT_PASSWORD_BCRYPT, self::ENCRYPT_PASSWORD_DEFAULT))) { 266 276 // These hash types require the password_* userland lib in PHP < 5.5.0 267 277 $pw_compat_lib = 'vendor/ircmaxell/password-compat/lib/password.php'; … … 269 279 include_once $pw_compat_lib; 270 280 } else { 271 $app =& App::getInstance(); 272 $app->logMsg(sprintf('Encryption type %s requires password-compat lib in PHP < 5.5.0; falling back to ENCRYPT_SHA1', $params['encryption_type']), LOG_ERR, __FILE__, __LINE__); 273 $params['encryption_type'] = self::ENCRYPT_SHA1; 274 } 281 $app->logMsg(sprintf('Hash type %s requires password-compat lib in PHP < 5.5.0; falling back to ENCRYPT_SHA1_HARDENED', $params['hash_type']), LOG_ERR, __FILE__, __LINE__); 282 $params['hash_type'] = self::ENCRYPT_SHA1_HARDENED; 283 } 284 } 285 if (isset($params['hash_type']) && !in_array($params['hash_type'], array(self::ENCRYPT_PLAINTEXT, self::ENCRYPT_CRYPT, self::ENCRYPT_SHA1, self::ENCRYPT_SHA1_HARDENED, self::ENCRYPT_MD5, self::ENCRYPT_MD5_HARDENED, self::ENCRYPT_PASSWORD_BCRYPT, self::ENCRYPT_PASSWORD_DEFAULT))) { 286 $app->logMsg(sprintf('Invalid hash type %s; falling back to ENCRYPT_SHA1_HARDENED', $params['hash_type']), LOG_ERR, __FILE__, __LINE__); 287 $params['hash_type'] = self::ENCRYPT_SHA1_HARDENED; 275 288 } 276 289 if (isset($params) && is_array($params)) { … … 393 406 } 394 407 395 if ($this->verifyPassword($password, $user_data['userpass'])) { 408 $old_hash_type = isset($user_data['userpass_hashtype']) && !empty($user_data['userpass_hashtype']) ? $user_data['userpass_hashtype'] : $this->getParam('hash_type'); 409 if ($this->verifyPassword($password, $user_data['userpass'], $old_hash_type)) { 396 410 $app->logMsg(sprintf('Authentication successful for %s (user_id=%s)', $username, $user_data['user_id']), LOG_INFO, __FILE__, __LINE__); 397 411 unset($user_data['userpass']); // Avoid revealing the encrypted password in the $user_data. 412 if ($this->getParam('hash_type_autoupdate') && $old_hash_type != $this->getParam('hash_type')) { 413 // Let's update user's password hash to new type (just run setPassword with this authenticated passwordâŠ). 414 $this->setPassword($user_data['user_id'], $password); 415 $app->logMsg(sprintf('User %s password hash type updated from %s to %s', $username, $old_hash_type, $this->getParam('hash_type')), LOG_INFO, __FILE__, __LINE__); 416 } 398 417 return $user_data; 399 418 } … … 835 854 * 836 855 */ 837 public function encryptPassword($password, $salt=null )856 public function encryptPassword($password, $salt=null, $hash_type=null) 838 857 { 839 858 $app =& App::getInstance(); … … 841 860 $password = (string)$password; 842 861 843 // Existing password hashes rely on the same key/salt being used to compare encryptions.862 // Existing password hashes rely on the same key/salt being used to compare hashs. 844 863 // Don't change this (or the value applied to signing_key) unless you know existing hashes or signatures will not be affected! 845 864 $more_salt = 'B36D18E5-3FE4-4D58-8150-F26642852B81'; 846 865 847 switch ($this->_params['encryption_type']) { 866 $hash_type = isset($hash_type) && !empty($hash_type) ? $hash_type : $this->getParam('hash_type'); 867 868 switch ($hash_type) { 848 869 case self::ENCRYPT_PLAINTEXT : 849 870 $encrypted_password = $password; … … 886 907 887 908 default : 888 $app->logMsg(sprintf(' Authentication encrypt type specified is unrecognized: %s', $this->_params['encryption_type']), LOG_NOTICE, __FILE__, __LINE__);909 $app->logMsg(sprintf('Unknown hash type: %s', $hash_type), LOG_WARNING, __FILE__, __LINE__); 889 910 return false; 890 break;891 911 } 892 912 893 913 // In case our hashing function returns 'false' or another empty value, bail out. 894 914 if ('' == trim((string)$encrypted_password)) { 895 $app->logMsg(sprintf('Invalid password hash returned ; check yo crypto!', null), LOG_ALERT, __FILE__, __LINE__);915 $app->logMsg(sprintf('Invalid password hash returned ("%s") for hash type %s; check yo crypto!', $encrypted_password, $hash_type), LOG_ALERT, __FILE__, __LINE__); 896 916 return false; 897 917 } … … 910 930 * @since 15 Nov 2014 21:37:28 911 931 */ 912 public function verifyPassword($password, $encrypted_password) 913 { 914 switch ($this->_params['encryption_type']) { 932 public function verifyPassword($password, $encrypted_password, $hash_type=null) 933 { 934 $app =& App::getInstance(); 935 936 $hash_type = isset($hash_type) && !empty($hash_type) ? $hash_type : $this->getParam('hash_type'); 937 938 switch ($hash_type) { 915 939 case self::ENCRYPT_CRYPT : 916 940 return $this->encryptPassword($password, $encrypted_password) == $encrypted_password; … … 928 952 return password_verify($password, $encrypted_password); 929 953 } 930 } 931 932 /** 933 * 934 */ 935 public function setPassword($user_id=null, $password) 954 955 $app->logMsg(sprintf('Unknown hash type: %s', $hash_type), LOG_WARNING, __FILE__, __LINE__); 956 return false; 957 } 958 959 /** 960 * 961 */ 962 public function setPassword($user_id=null, $password, $hash_type=null) 936 963 { 937 964 $app =& App::getInstance(); … … 943 970 $user_id = isset($user_id) ? $user_id : $this->get('user_id'); 944 971 945 // Get old password. 946 $qid = $db->query(" 947 SELECT userpass 948 FROM " . $this->_params['db_table'] . " 949 WHERE " . $this->_params['db_primary_key'] . " = '" . $db->escapeString($user_id) . "' 950 "); 951 if (!list($old_encrypted_password) = mysql_fetch_row($qid)) { 952 $app->logMsg(sprintf('Cannot set password for nonexistent user_id %s', $user_id), LOG_WARNING, __FILE__, __LINE__); 953 return false; 954 } 955 956 // Compare old with new to ensure we're actually *changing* the password. 957 if ($this->verifyPassword($password, $old_encrypted_password)) { 958 $app->logMsg(sprintf('Not setting password: new is the same as old.', null), LOG_INFO, __FILE__, __LINE__); 959 return null; 960 } 972 // New hash type. 973 $hash_type = isset($hash_type) ? $hash_type : $this->getParam('hash_type'); 961 974 962 975 // Save the hash method used if a table exists for it. 963 $userpass_hashtype = '';976 $userpass_hashtype_clause = ''; 964 977 if ($db->columnExists($this->_params['db_table'], 'userpass_hashtype', false)) { 965 $userpass_hashtype = ", userpass_hashtype = '" . $db->escapeString($this->getParam('encryption_type')) . "'";978 $userpass_hashtype_clause = ", userpass_hashtype = '" . $db->escapeString($hash_type) . "'"; 966 979 } 967 980 … … 969 982 $db->query(" 970 983 UPDATE " . $this->_params['db_table'] . " 971 SET userpass = '" . $db->escapeString($this->encryptPassword($password )) . "'972 $userpass_hashtype 984 SET userpass = '" . $db->escapeString($this->encryptPassword($password, null, $hash_type)) . "' 985 $userpass_hashtype_clause 973 986 WHERE " . $this->_params['db_primary_key'] . " = '" . $db->escapeString($user_id) . "' 974 987 "); 975 988 976 989 if (mysql_affected_rows($db->getDBH()) != 1) { 977 $app->logMsg(sprintf('Failed to update password for user_id %s ', $user_id), LOG_WARNING, __FILE__, __LINE__);990 $app->logMsg(sprintf('Failed to update password for user_id %s (no affected rows)', $user_id), LOG_WARNING, __FILE__, __LINE__); 978 991 return false; 979 992 }
Note: See TracChangeset
for help on using the changeset viewer.