Ok, 2.x definitely gives more control. I only hash the passwords in my User model's beforeSave method just like you do:
public function beforeSave() {
if (isset($this->data['User']['password'])) {
$this->data['User']['password'] = AuthComponent::password($this->data['User']['password']);
}
return true;
}
This allows you to create a password in your Controller's password reset action as plain text, email it to the user, and then you set the password in the User model and persist it (password is hashed before it hits the database). The important thing here is that your password stays plain text until your controller calls the save method.
Generally I always add an unset on the password field in controller actions that will save the User record just to make sure it won't get rehashed. A second option would be to add an afterFind callback to your user model that does the unset each time the User model(s) are loaded.
About the one time reset key.... I have an additional field in my User object that I use in two cases. Email verification and password reset. When the user is created it is set to the SHA1( + + ). A link is emailed to the user that sends them to the User controller's validate action. Once that key is verified, that column gets cleared out in the database.
Same with the password reset. When they request a reset, the value gets generated in the same way and a link to the User controller's reset action gets emailed to the user. They enter their userid and if the key in the link matches the one in their database row, they can change their password. When their password is changed, this value is again cleared.
The biggest issue with sending temporary passwords is that it creates a DoS mechanism (against users, not your site). If I decided to harass someone, I could create a task that keeps resetting their password every hour. They can't get in until they check their email, but then it'll change again. Using a key, they'll get an email with a reset link, but their current password will still work as the presence of a reset code would not keep them from logging in.