I had a computer that was hosting a number of simple rails programs that I needed to upgrade. So, I updated everything and reloaded the mysql data and everything was good. That is, until I tried to login. I had a number of unsuccessful attempts and just assumed it was because I forgot the password. There were actually three programs that I had to reinstall and after the third one, I realized that I hadn’t forgotten the password but that something had changed.

I use authlogic to handle authentication and that also takes care of storing the encrypted password. I honestly never really thought about this much, aside from checking the database that the password was stored encrypted. Since I’m not a mathematician, I never really concerned myself with how this was done. And I still don’t think that I could explain in detail how this works, but I think I have enough of an understanding to be able to use it.

The basic idea is we don’t want to store a password in plaintext because if the system was compromised, the bad guy would get all the passwords. Then that person could log into our system whenever they wanted or to people’s other accounts, since many people use the same password in different places. So we want to store the password in a way that it would be meaningless if it were stolen. How do we do this? We do some mathematical shenanigans (technically called hashing functions) on the password to make it look like a random collection of characters. Are then we able to unscramble this collection to get the original password back? No, because even we as the owners of the website, should not be able to read someone’s password. This is called one-way encryption, I think. So then, how will we know if a person enters in their correct password? We run whatever they enter through the same hashing function and compare the output to what we have stored. If it’s the same, they entered the correct password, if different, they didn’t.

Now the issue I had with my programs is that when I updated the system, I also updated the version of authlogic that I was using. In my specific case, I think I went from 3.2.0 to 3.4.2. I should have realized immediately that something had changed since I’m sure I couldn’t login when I was testing. But since I only had two accounts, an admin one and a regular user, it was simple for me to just add another admin user. Then I could use that admin user to change the passwords on the other two accounts. And I could get back to seeing if the rest of the program worked. If I had more users, I would have been in a ton of trouble. This is where (if I were a better programmer) I would have read up on differences between the two versions of authlogic to see what had changed. As I’m still basically a beginner, I’m not exactly sure where I would find this info. But I’ll try to figure that out later.

After a bit of googling, I found this webpage, which solves the exact problem that I had. The guy who wrote authlogic is a much better programmer than me and knew this would be a problem, so he has a fix. My only concern is that I didn’t know which hashing algorithm I had been using nor what the new version was using. A bit more googling led me to the file that tells me this. (It’s probably in release notes somewhere, but I didn’t find it.)

In the authlogic gem directory, there’s a file, lib/authlogic/acts_as_authentic/passwd.rb. In this file, I found this, from the 3.2.0 version.

# The class you want to use to encrypt and verify your encrypted passwords. See the Authlogic::CryptoProviders module for more info
        # on the available methods and how to create your own.
        #
        # * Default: CryptoProviders::Sha512
        # * Accepts: Class
        def crypto_provider(value = nil)
          rw_config(:crypto_provider, value, CryptoProviders::Sha512)
        end
        alias_method :crypto_provider=, :crypto_provider

And if I look at the same file in the 3.4.2 version, I see:

# The class you want to use to encrypt and verify your encrypted passwords. See the Authlogic::CryptoProviders module for more info
        # on the available methods and how to create your own.
        #
        # * Default: CryptoProviders::SCrypt
        # * Accepts: Class
        def crypto_provider(value = nil)
          if value.nil? and !acts_as_authentic_config.include?(:crypto_provider)
            rw_config(:crypto_provider, CryptoProviders::SCrypt)
          else
            rw_config(:crypto_provider, value)
          end
        end
        alias_method :crypto_provider=, :crypto_provider

So it appears that the default hashing algorithm changed from Sha512 to SCrypt. Thus, in my user model, I should have done something like this:

class User < ActiveRecord::Base
  acts_as_authentic do |c|
    c.transition_from_crypto_providers = Authlogic::CryptoProviders::Sha512,
    c.crypto_provider = Authlogic::CryptoProviders::SCrypt
  end
end

Unfortunately, I’ve already manually changed both my passwords. But I’ll try to load the old version of my database somewhere and see if this works as I think it’s supposed to.

Happy I learned something, but just more evidence to me that I’m still a very inexperienced programmer. I won’t go looking for a programming job anytime soon.

Update: I had another site that I upgraded and I followed these instructions. Worked perfectly.