8
votes

I am migrating users from a legacy user store to ASP.NET Identity 2.0 in my ASP.NET 5.0 web application. I have a means of verifying legacy hashes, but I want to upgrade them at login-time to ASP.NET Identity 2.0 hashes.

I've created a custom IPasswordHasher that is able to detect and verify legacy hashes, and return PasswordVerificationResult.SuccessRehashNeeded at the appropriate time. (If it detects that the hash is not legacy, it simply falls through to the built-in ASP.NET Identity hash verification.)

However, returning PasswordVerificationResult.SuccessRehashNeeded doesn't seem to cause ASP.NET Identity to actually do anything. Is there a configuration option somewhere that would cause the system to re-hash the passwords when IPasswordHasher returns this result?

If the answer is no to the above, then is it recommended that I simply re-hash and update the user manually? Where would I do this? I don't see any place at the controller level where I can see the PasswordVerificationResult.

I'm new to ASP.NET Identity so I'm sure I'm missing something simple. Thank you in advance for any pointers.

2

2 Answers

7
votes

It seems rehashing mechanism is not implemented in the built-in user manager. But hopefully you could easily implemented. consider this:

public class ApplicationUserManager : UserManager<ApplicationUser>
{
    protected override async Task<bool> VerifyPasswordAsync(
          IUserPasswordStore<ApplicationUser, string> store, 
          ApplicationUser user, string password)
    {
        var hash = await store.GetPasswordHashAsync(user);
        var verifyRes = PasswordHasher.VerifyHashedPassword(hash, password);

        if (verifyRes == PasswordVerificationResult.SuccessRehashNeeded)
           await store.SetPasswordHashAsync(user, PasswordHasher.HashPassword(password));

        return verifyRes != PasswordVerificationResult.Failed;
    }
}
0
votes

If you have implemented IPasswordHasher correctly, when returning a PasswordVerificationResult.SuccessRehashNeeded result, ASP.NET Core Identity will call the HashPassword method automatically for you, successfully authenticating the user and updating the hash in the database.

The class would look something like this:

public class PasswordHasherWithOldHashingSupport : IPasswordHasher<ApplicationUser>
{
    private readonly IPasswordHasher<ApplicationUser> _identityPasswordHasher;

    public PasswordHasherWithOldHashingSupport()
    {
        _identityPasswordHasher = new PasswordHasher<ApplicationUser>();
    }

    public string HashPassword(ApplicationUser user, string password)
    {
        return _identityPasswordHasher.HashPassword(user, password);
    }

    public PasswordVerificationResult VerifyHashedPassword(ApplicationUser user, string hashedPassword, string providedPassword)
    {
        var passwordVerificationResult = _identityPasswordHasher.VerifyHashedPassword(user, hashedPassword, providedPassword);

        if (passwordVerificationResult == PasswordVerificationResult.Failed)
        {
            /* Do your custom verification logic and if successful, return PasswordVerificationResult.SuccessRehashNeeded */
            passwordVerificationResult = PasswordVerificationResult.SuccessRehashNeeded;
        }

        return passwordVerificationResult;
    }
}