I released Authlogic 1.3.3 which has some handy options for migrating passwords to a new and improved algorithm. Without Authlogic this is somewhat of a pain in the ass, because there has to be a transition period in which your users can upgrade their passwords. You can’t just upgrade the algorithm because then no one will be able to log in. Authlogic solves this problem and makes it dead simple:
I recently released BCrypt as an optional crypto provider for Authlogic, let’s say you are using the default crypto provider Sha512 and want to start using BCrypt. No problem:
# app/models/user.rb
class User < ActiveRecord::Base
acts_as_authentic do |c|
c.transition_from_crypto_providers = Authlogic::CryptoProviders::Sha512,
c.crypto_provider = Authlogic::CryptoProviders::BCrypt
end
end
All of your users will be migrated to the new BCrypt method when they log in next or when a user creates a new account.
Let’s pretend a new algorithm came out called “CCrypt”, and its better than BCrypt, and you want to use it. You’re users are in the middle of transitioning from Sha512 to BCrypt. Oh no!
Not to worry, because Authlogic can transition your users from more than one algorithm. Just pass an array to :transition_from_crypto_provider:
# app/models/user.rb
class User < ActiveRecord::Base
acts_as_authentic do |c|
c.transition_from_crypto_providers = [Authlogic::CryptoProviders::Sha512, Authlogic::CryptoProviders::BCrypt],
c.crypto_provider = CCrypt
end
end
That’s it. You can specify as many as you want. When your users login or create a new account their passwords will be encrypted with the CCrypt algorithm.
All that you need to do is create a crypto provider that represents how your passwords are encrypted. Believe it or not, it’s dead simple. Sometimes the easiest way to explain something is by using code example, so please checkout the Authlogic::CryptoProviders module and sub classes in the documentation. All that you need to do is create a class with a class level encrypt and matches? method:
# lib/my_awesome_crypto_provider.rb
class MyAwesomeCryptoProvider
def self.encrypt(*tokens)
# encrypt your password here
end
def self.matches?(crypted_password, *tokens)
# return true if the tokens match the crypted_password
end
end
Transition to a new algorithm doesn’t get any easier than that.
Cool!
This seems to lead naturally to another question. Once you start this sort of transition, you’ll have more than one type of password in your database. Suppose you then decide to transition again – then the transition logic will need to account for two (or more) types of passwords in existing passwords. This could probably be done by supplying multiple CryptoProviders to :transition_from_crypto_provider – is that supported?
Good comment Charlie, I actually thought about doing this and initially decided against it because I thought it would be such a rare case. Regardless it was simple to add it, so I did. :transition_from_crypto_provider now accepts an array as well.