I recently needed to add a new password hash method by overriding the password.inc file.
While testing the password history constraint, we found that it was not validating correctly. I found that this was because the password_policy_constraint_history_validate() function hard-coded _password_crypt('sha512', $password, $pw) to compare against previous passwords.
Simply modifying the if statement to call user_check_password($password, $account) fixes the issue and makes it compatible with any password.inc modifications a developer might need to make.
Here is my full change:
/**
* Password validation.
*/
function password_policy_constraint_history_validate($password, $constraint, $account) {
require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
$old_passwords = _password_policy_constraint_history_old_passwords($constraint, $account->uid);
foreach($old_passwords as $pw) {
if(user_check_password($password, $account)) {
return false;
}
}
return true;
}
I will upload a patch for review.
Comments
Comment #1
tonylegrone commentedComment #3
tonylegrone commentedSad day. Probably because I took it from my full project repo. I'll clone the password_policy repo and try again.
Comment #4
tonylegrone commentedThis patch should pass the test.
Comment #5
erikwebb commentedGood find! I updated your patch with some adjacent coding standards updates.
http://drupalcode.org/project/password_policy.git/commit/9863f13
Comment #6
tonylegrone commentedThanks!
Comment #8
Pete B commentedThe committed code here doesn't make any sense.
We loop over the old password hashes and then do absolutely nothing with them. Therefore it only checks the most recent password. But LOTS of times.
I think the best we can do here without assuming a hash method is to use sha512 by default and have a drupal_alter so that people can hook in with their own hashing scheme if necessary.
Thanks,
Pete
Comment #9
erikwebb commentedYou're right, but I think it's just a matter of misusing a variable.
Comment #10
Pete B commentedNo, user_check_password expects a plain text password, which I'm happy to say is *not* what is pulled from the password_policy_history table.
Looking at the original post again, I think tonylegrone hacked core to achieve what he wanted (and break this module). So I'm wondering how much of a problem there was with the original code in the first place?
Perhaps upgrades from earlier drupal versions could cause a problem? Not much else I don't think...
Comment #11
Pete B commentedActually, forget that - I notice that a user can legitimately override password.inc by setting the password_inc variable.
Still leaves me without a decent solution for this though... Using user_hash_password would be better, but you might still run into problems with d6 upgrades etc.
Comment #12
erikwebb commentedSince we can't re-hash a password, I don't think we need to worry about that case. So you're thinking we can just swap in
if (user_hash_password($password) == $hashed_old_password;) { ... }and leave the remainder of the code untouched?Comment #13
Pete B commentedI *did* think that yes. But actually that's no good, because if you hash the same thing twice using user_hash_password(), you get a different answer because of salting.
I genuinely think the best thing we can do here is revert to what was there before.
Having learnt a few things about drupal passwords this afternoon, I *think* the best solution to tonylegrone original problem is for him to override _password_crypt(). He will need to work out whether to ignore the 'sha512' parameter he is given by this module by inspecting the value of $stored_hash.
Anything else would need a core patch I think.
So I am proposing:
and it is up to the users version of _password_crypt to choose whether or not 'sha512' is correct using a similar strategy to Core's user_check_password().
Comment #14
erikwebb commenteduser_hash_password() shouldn't create multiple versions of the same password, as long as the salt is the same. Otherwise there'd be no way to validate a previously hashed password.
Comment #15
Pete B commentedWhich is why you can call _password_crypt() with an existing hash (as per the original code this patch removed)
https://api.drupal.org/api/drupal/includes!password.inc/function/_passwo...
But that's not what user_hash_password() does
https://api.drupal.org/api/drupal/includes!password.inc/function/user_ha...
and there's nothing you can do about that as far as I can tell.
Comment #16
Enxebre commentedHi,
I think this approach suits for everyone.
We still use check_password_account so the correct algorithm is applied to the new password depending on the old one.
Whatever you decide, it would be great to commit it because now the functionality is broken.
Thank you.
Regards.
Comment #17
Enxebre commentedComment #18
Enxebre commentedComment #19
deekayen commentedI committed #16, but someone really needs to review and RTBC this before making a new release.
Comment #21
Pete B commentedThis works for me!
Comment #22
erikwebb commented