Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting existing password hash to Devise

I'm trying to convert an existing Admin model to Devise. We already have a password hash but it's obviously not Devise compatible. What I would like to do is accept the login form and check the provided password against the encrypted password. If it's not correct, use the old hash to check the password and if it matches, empty the old password_hash field and set Devise's password to the provided password and save the model.

What's the best way to move forward? I suspect that I need to override something, perhaps in a custom controller, but I'm not entirely sure how to proceed.

like image 829
jxpx777 Avatar asked May 24 '11 16:05

jxpx777


People also ask

Can you use a hash as a password?

Hashing turns your password (or any other piece of data) into a short string of letters and/or numbers using an encryption algorithm. If a website is hacked, cyber criminals don't get access to your password. Instead, they just get access to the encrypted “hash” created by your password.

How does Devise store passwords?

Devise uses Bcrypt to securely store information. On its website it mentions that it uses “OpenBSD bcrypt() password hashing algorithm, allowing you to easily store a secure hash of your users' passwords”.

Is devise secure?

If you're using Rails to build your application, you can use Devise, a gem which is designed to make authentication easy. Fortunately, Devise has been used in production applications for years. It's known to be secure.


2 Answers

You can let Devise do the "hard work" of encrypting the password with the new crypt scheme, as shown in https://gist.github.com/1704632:

class User < ActiveRecord::Base
  alias :devise_valid_password? :valid_password?

  def valid_password?(password)
    begin
      super(password)
    rescue BCrypt::Errors::InvalidHash
      return false unless Digest::SHA1.hexdigest(password) == encrypted_password
      logger.info "User #{email} is using the old password hashing method, updating attribute."
      self.password = password
      true
    end
  end
end
like image 122
moeffju Avatar answered Sep 19 '22 11:09

moeffju


Using the bcrypt encryptor in Devise, this is what I ended up doing with my legacy data:

In models/user.rb

# Because we have some old legacy users in the database, we need to override Devises method for checking if a password is valid.
# We first ask Devise if the password is valid, and if it throws an InvalidHash exception, we know that we're dealing with a
# legacy user, so we check the password against the SHA1 algorithm that was used to hash the password in the old database.
alias :devise_valid_password? :valid_password?
def valid_password?(password)
  begin
    devise_valid_password?(password)
  rescue BCrypt::Errors::InvalidHash
    Digest::SHA1.hexdigest(password) == encrypted_password
  end
end

As you can see, devise throws an InvalidHash exception when it encounters an invalid hash, which it would do when authenticating a legacy user. I use this to fall back to the hashing-algorithm used to create the original legacy hash.

It doesn't change the password though, but that could simply be added to the method if needed.

like image 42
Thomas Dippel Avatar answered Sep 17 '22 11:09

Thomas Dippel