From b0a764b14c2f2798f7eb223e58d47530f80609c1 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sat, 20 Jan 2018 22:29:03 -0500 Subject: [PATCH] Use password_hash() for passwords - Use legacy_password to update double-hashed passwords --- src/Model/User.php | 46 ++++++++++++++++++++++++++++++++++----------- src/Util/ExAuth.php | 2 +- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/src/Model/User.php b/src/Model/User.php index 382ec62cc2..bbe424ecbc 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -112,7 +112,7 @@ class User if (is_object($user_info)) { $user = (array) $user_info; } elseif (is_int($user_info)) { - $user = dba::selectFirst('user', ['uid', 'password'], + $user = dba::selectFirst('user', ['uid', 'password', 'legacy_password'], [ 'uid' => $user_info, 'blocked' => 0, @@ -122,7 +122,7 @@ class User ] ); } elseif (is_string($user_info)) { - $user = dba::fetch_first('SELECT `uid`, `password` + $user = dba::fetch_first('SELECT `uid`, `password`, `legacy_password` FROM `user` WHERE (`email` = ? OR `username` = ? OR `nickname` = ?) AND `blocked` = 0 @@ -138,17 +138,29 @@ class User $user = $user_info; } - if (!DBM::is_result($user) || !isset($user['uid']) || !isset($user['password'])) { - return false; + if (!DBM::is_result($user) + || !isset($user['uid']) + || !isset($user['password']) + || !isset($user['legacy_password']) + ) { + throw new Exception('Not enough information to authenticate'); } - $password_hashed = self::hashPassword($password); + if ($user['legacy_password']) { + if (password_verify(self::hashPasswordLegacy($password), $user['password'])) { + self::updatePassword($user['uid'], $password); - if ($password_hashed !== $user['password']) { - return false; + return $user['uid']; + } + } elseif (password_verify($password, $user['password'])) { + if (password_needs_rehash($user['password'], PASSWORD_DEFAULT)) { + self::updatePassword($user['uid'], $password); + } + + return $user['uid']; } - return $user['uid']; + return false; } /** @@ -161,15 +173,26 @@ class User return autoname(6) . mt_rand(100, 9999); } + /** + * Legacy hashing function, kept for password migration purposes + * + * @param string $password + * @return string + */ + private static function hashPasswordLegacy($password) + { + return hash('whirlpool', $password); + } + /** * Global user password hashing function * * @param string $password * @return string */ - private static function hashPassword($password) + public static function hashPassword($password) { - return hash('whirlpool', $password); + return password_hash($password, PASSWORD_DEFAULT); } /** @@ -197,7 +220,8 @@ class User $fields = [ 'password' => $pasword_hashed, 'pwdreset' => null, - 'pwdreset_time' => null + 'pwdreset_time' => null, + 'legacy_password' => false ]; return dba::update('user', $fields, ['uid' => $uid]); } diff --git a/src/Util/ExAuth.php b/src/Util/ExAuth.php index 847059d6d7..8940c02055 100644 --- a/src/Util/ExAuth.php +++ b/src/Util/ExAuth.php @@ -226,7 +226,7 @@ class ExAuth if ($a->get_hostname() == $aCommand[2]) { $this->writeLog(LOG_INFO, 'internal auth for ' . $sUser . '@' . $aCommand[2]); - $aUser = dba::selectFirst('user', ['uid', 'password'], ['nickname' => $sUser]); + $aUser = dba::selectFirst('user', ['uid', 'password', 'legacy_password'], ['nickname' => $sUser]); if (DBM::is_result($aUser)) { $uid = $aUser['uid']; $success = User::authenticate($aUser, $aCommand[3]);