Rails, authlogic and password history

Posted under: Behind the Scenes

vendorrisk.com client sites use the excellent Authlogic gem to handle user sessions. As mentioned in the previous blog article, we recently added the ability for site admins to declare that users cannot use a password they’ve used in the past.

After a bit of Googling, I didn’t see any solutions out there for dealing with this issue, so we rolled our own.  Here’s how we went about it.  Note that we’re assuming you already have Authlogic integrated into the app with “User” being the model authenticated, although changing to another model should be self-explanatory.

Database migration

create_table "old_passwords" do |t|
  t.integer  "user_id",          :null => false
  t.string   "password_salt",    :null => false
  t.string   "crypted_password", :null => false
  t.timestamps
end

OldPassword model

class OldPassword < ActiveRecord::Base
  belongs_to :user
end

User model (relevant snippets only)

class User < ActiveRecord::Base
  acts_as_authentic

  has_many :old_passwords

  validates_presence_of :password, :on => :create
  validate :password_meets_requirements

  after_create :create_password_history
  after_update :update_password_history

  def password_meets_requirements
    return true if password.blank?
    # do other password-specific validations here, if any
    if not new_record? and already_used?(password)
      errors.add_to_base("Password cannot be one you have used in the past")
    end
  end

  def already_used?(password)
    old_passwords.each do |old|
      return true if Authlogic::CryptoProviders::Sha512.matches?(old.crypted_password, password + old.password_salt)
    end
    return false
  end

  def create_password_history
    old_passwords.create(:crypted_password => crypted_password, :password_salt => password_salt)
  end

  def update_password_history
    create_password_history if password_changed?
  end
end

Explanation

When a user record is first created, there is no need to validate their selected password because there are no past entries to check it against.  For new users, we just add their password to the historical table, which is accomplished with the after_create callback.

When a user record is being updated, it gets a little more complex.  If the password is blank, then the validation passes because the user’s password is not being changed; otherwise, the new password is checked against the old passwords for the user.  If a match is found, an error message is created and the user record will not be updated.  If the new password does not match any old passwords, then validation succeeds and the new password is added to the historical table in the after_update callback.  The password_changed? method is provided by Authlogic.

Hope this helps.  In short, there’s two functions being done:  1) adding the user’s encrypted password to a database table when they enter a new password and 2) querying that table when they attempt to change their password.

Share:
  • Facebook
  • Twitter
  • del.icio.us
  • Digg
  • StumbleUpon

One Comment to “Rails, authlogic and password history”

  1. vbdjames 28 January 2010 at 6:39 pm

    Sweet! I was just in the process of coding this myself when I ran across your implementation. You just saved me a couple of hours!


Leave a Reply