How to: Migrate passwords from legacy systems to Devise

When you’re migrating from a custom authentication solution to Devise, it’s highly likely your users’ passwords are hashed or stored differently from how Devise does it.

If the legacy system has a sane, secure solution then you can implement a custom encryptor for Devise. However if that’s not the case or if you want to migrate to the Devise default way-of-life following convention over configuration and reducing maintenance headaches in the future, you should convert the passwords so that Devise can use them.

Since hopefully you stored hashes of your user’s passwords instead of encrypted or plaintext, the only moment you can retrieve the plaintext password for rehashing is when the user tries to log in.  At that point we’ll convert it to Devise. This way when a user logs in his legacy password will be automatically converted to the new system.

First, add the legacy_password boolean attribute to User. This is to mark the passwords that have already been converted. Make sure to set it to true for the existing (legacy) records.

$ rails g migration AddLegacyPasswordToUser legacy_password:boolean
      invoke  active_record
      create    db/migrate/20120508083355_add_legacy_password_to_users.rb
$ rake db:migrate

Devise creates the method User#valid_password? to check the password. Let’s override it and add our legacy password check or fall through to the default valid_password? if the password was already converted.  This code assumes the old password is stored in the same field as the converted password — encrypted_password.

class User < ActiveRecord::Base
 
...
 
  def valid_password?(password)
    if self.legacy_password?
      # Use Devise's secure_compare to avoid timing attacks
      if Devise.secure_compare(self.encrypted_password, User.legacy_password(password))
 
        self.password = password
        self.password_confirmation = password
        self.legacy_password = false
        self.save!
 
      else
        return false
      end
    end
 
    super(password)
  end
 
  # Put your legacy password hashing method here
  def self.legacy_password(password)
    return Digest::MD5.hexdigest("#{password}-salty-herring");
  end
end

Supporting two different systems like this could soon become a maintenance nightmare After a couple of months, when the most active users have logged in at least once and converted their passwords, you can easily remove the extra code. Legacy users will be forced to reset their password since it won’t match anymore. Using the legacy_user attribute you could send them a targeted mail or alert them of the fact that they won’t be able to log in anymore with their old password.

This entry was posted in How To, Ruby on Rails. Bookmark the permalink.

3 Responses to How to: Migrate passwords from legacy systems to Devise

  1. sdfgsdfh says:

    Animaros!!Y ahora el look de hoy, el protagonista es el jersey amarilloGafas Carrera 2012 es además súper tendencia y como veis me encanta experimentar con mis looks, por lo que me decidí por estas gafas y el sombrero, para darle el toque de los 70's. gafas sol rayban: este web también está especializada en esto gafasGafas Ray Ban sol oakley otro de los puntos tratados en este sitio web. Gafas de sol ray ban se pueden comprar en una gran cantidad de versiones diferentes referentes a color

  2. Sergey says:

    Thx a lot, mate!

  3. Thanks to Google to bring me here, and thanks to you for sharing my desired info.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">