ASP.NET Identity 2.0: How to rehash password
Asked Answered
S

2

9

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.

Sisely answered 20/5, 2017 at 0:14 Comment(0)
R
8

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;
    }
}
Resistive answered 21/5, 2017 at 15:23 Comment(1)
You should add await store.UpdateAsync(user); after setting the new password hash to actually write the updated information back to the database. It should be done within the same if, so remember to enclose the updated code in brackets. (This is, by the way, a good reason to always have brackets around block statements, even when there is initially only one statement in the block.)Spar
C
0

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;
    }
}
Cassaba answered 18/6, 2018 at 11:23 Comment(1)
OP implemented IPasswordHasher correctly. As your answer implies, the problem is that ASP.Net Identity (unlike ASP.NET Core Identity) doesn't actually support SuccessRehashNeeded.Whitebeam

© 2022 - 2024 — McMap. All rights reserved.