CPasswordHelper::hashPassword() uses Blowfish as the crypt algorithm.
This introduces excellent security on the password but, it also introduces some complexity.
The first is that you can’t directly pre-propulate a MySQL table of users by enclosing the password field with MD5. You must first write a PHP script that hashes the password using the CPasswordHelper::hashPassword() function and insert the hashed value into the database.
The second is that you also can not simply do this
if($model->password == CPasswordHelper::hashPassword($form->password)) {
}
The reason is because CPasswordHelper::hashPassword() generates a different hash for the same input every time that it is called. You must instead use something like
if(CPasswordHelper::verifyPassword($form->password, $model->password)) {
}
The third thing you need to be aware of is the $cost parameter to CPasswordHelper::hashPassword($password, $cost = 13). The default of 13 may be too high for a hosted server.
You can use something like this to find the optimal cost for your server:
// Find an optimal cost to use
$timeTarget = 0.2;
$cost = 5;
do {
$cost++;
$start = microtime(true);
CPasswordHelper::hashPassword("test", $cost);
$end = microtime(true);
} while (($end - $start) < $timeTarget);
echo "Optimal Cost: " . $cost . "\n";
Lastly, the PHP manual for the crypt() function states that in versions of PHP 5.3.7 and later, you should no longer prefix the salt with $2a$ and instead should use $2y$ because of a security flaw. Well, CPasswordHelper’s generateSalt function uses the $2a$ and so, like I did, you should extend CPasswordHelper and fix the generateSalt function by changing the prefix to $2y$ if you are using PHP 5.3.7 or later.
And here is my UserIdentity::authenticate() function. Please note that it calls methods and properties that are specific to my implementation but, I hope it helps you.
/**
* Authenticates a user by either username or e-mail address.
* Searching is case insensitive!
* Uses CPasswordHelper which uses the Blowfish Crypto Algo.
* @return boolean whether authentication succeeded.
*/
public function authenticate()
{
$this->findUser();
if($this->_user === null) {
if($this->_useemail) {
$this->errorCode = self::ERROR_EMAIL_INVALID;
} else {
$this->errorCode = self::ERROR_USERNAME_INVALID;
}
} else {
// We have a valid user account that we need to authenticate!
if(!$this->_user->verifyPassword($this->password)) {
$this->errorCode = self::ERROR_PASSWORD_INVALID;
$this->_user->loginFailed();
} else {
$this->processUserStatus();
}
}
return !$this->errorCode;
} // end authenticate()