brockallen / BrockAllen.MembershipReboot

MembershipReboot is a user identity management and authentication library.
Other
742 stars 238 forks source link

Per-user configuration of password hashing algorithm #623

Closed mroskamp closed 8 years ago

mroskamp commented 8 years ago

I'm migrating over to IdentityServer and MembershipReboot. My current system stores passwords using a few different hashing algorithms. As part of the migration I'd like to include the hashed password, hashing algorithm, and hashing iterations. When verifying passwords, I'd like IdentityServer/Membership reboot to use the same algorithm as was used to hash the password. When the user changes their password, I'd like the password to be hashed using the default algorithm and the stored algorithm and iteration fields to be updated.

Is there a clean way of doing this right now?

My first thought was to implement this at the UserService level. I think having the algorithm selection occur at the VerifyHashedPassword step would make sense, but the method isn't overrideable. I think the ICryto is too low-level, since we don't have access to the user account for getting the hashing algorithm or iterations.

Our main goal in doing this is to migrate our existing users so they can keep their current passwords and they don't have to jump through any hoops the first time they try to log in. Our alternative is probably to just mark all of the accounts as needing a password reset, but I'm hoping there's a better option so our switch to IdentityServer/MembershipReboot is more transparent to the end users.

brockallen commented 8 years ago

How do you know with the old system which algorithm to use?

cbomkamp commented 8 years ago

We implemented a custom ICrypto implementation to migrate existing users from straight up SHA1. DefaultCrypto already prepends the iteration count with a period as the separator. So the custom crypto checks if the hashed password contains the separator. If not, we know it's SHA1. If it does have the separator, we just use the DefaultCrypto implementation. Then in the custom UserAccountService we rehash with the new algorithm.

mroskamp commented 8 years ago

Our current system has a separate field for specifying the hashing algorithm. It currently has options for plaintext, MD5 and salted MD5. During migration, plaintext passwords would use the DefaultCrypto.

A solution similar to cbomkamp's might work for us, we'd just have to figure out how to get it to work the a few different possible hashing algorithms.

brockallen commented 8 years ago

There's an interface called ICrypto on the MR config (IIRC) that does the hashing. Not sure you can get away with implementing that interface, since I don't think any account info is passed (just the password to hash or verify). There's not a great abstraction in MR to support exactly what you're looking for.

If you could merge the alg into the password column, then you might get away with it.

neilhosey commented 8 years ago

Im also running into the exact same problem. Im trying to migrate several systems with different hashing algorithms to MR, but I am stuck, as i need to be able to switch between algorithm based on system the user was synced from.

Was there any work around for this in the end?

CSharped commented 8 years ago

Hi @brockallen

I am also facing the same challenge as @neilhosey and @mroskamp . I was looking at the code in github for UserAccountService and the DefaultCrypto class which has the hashing algo implementation. May be what could help is instead of ICrypto interface we could use an abstract class which will also have all the default functionalities and also lets us override any required methods which in this case is the HashingAlgo

mroskamp commented 8 years ago

@neilhosey & @FullyCSharped, I was able to implement multiple hashing algorithms, much like how @brockallen described.

On a basic level, the passwords coming in from our current system are in the format <alg>.<password>, so we implemented the ICrypto service and created a few new classes for verifying our custom hashing algorithms. In our VerifyHashedPassword we parse hashedPassword and verify the password based on the <alg>. When a user changes his or her password, the default MR algorithm is used.