Skip to content

How To: Create a custom encryptor

bquorning edited this page Aug 18, 2011 · 15 revisions

When working with a legacy database where a non-supported password encryption method is used, you can implement a custom encryptor by loading the following in an initializer. (That means it goes in config/initializers/md5_encryptor.rb for example).

module Devise
  module Encryptors
    class Md5 < Base
      def self.digest(password, stretches, salt, pepper)
        str = [password, salt].flatten.compact.join
        Digest::MD5.hexdigest(str)
      end
    end
  end
end

The above will authenticate using non-salted MD5-hashed passwords (a terrible idea, but such are legacy apps). You can then set this as your encryptor in config/initializers/devise.rb:

config.encryptor = :md5

If you do not want this as an initializer, but in lib/md5.rb for instance, add this to your users' class. require File.dirname(__FILE__) + '/../../lib/md5_encryptor'

See also: http://www.markrichman.com/2010/11/22/rails-devise-datamapper-authentication/

Additionally, I had to add the following to my user model in order to be able to log in. Supposedly there is a more elegant way, but I did not get devise_for ... :encryptor => :md5 to work. nor devise :encryptor => :md5. Maybe this is because I do not have a password salt.

+++ b/app/models/user.rb 
+ # debt: we should not need to do this, but seems like setting :encryptor => :md5 on the devise or devise_for
+ # does not do anything. Maybe because we don't use a salt. So this works for now.
+  def valid_password?(password)
+    return false if encrypted_password.blank?
+    Devise.secure_compare(Devise::Encryptors::Md5.digest(password, nil, nil, nil), self.encrypted_password)
+  end

And how I tested it.

+++ b/spec/models/user_spec.rb
+  describe "devise valid_password?" do
+    it "should use our hashing mechanism, not the default bcrypt" do
+      Factory(:member).valid_password?('blahblah').should be_true
+    end
+  end
Clone this wiki locally