Thursday, May 24, 2012

Catalyst Credentialing

I really like the Catalyst web framework. It handles all of the boring, repetitive details while leaving me the juicy, fun pieces of coding. For the most recent web application, I added authentication. I pieced together the functionality by reading module documentation. Here's what I learned - all in one place.

Catalyst has a plugin for authentication - Catalyst::Plugin::Authentication. It performs authentication in two steps: look up and password check. Catalyst calls these store and credential respectively. The store accesses your list of users (look up). The credential then compares the password.

Okay, let's walk through this. Henry comes to your web site. You greet him with a normal looking login screen. Henry types in his user name and password. Then he hits theLogin button. Your backend code passes off the user name and password to Catalyst::Plugin::Authentication. The plugin searches the store for the user name. At this point, all we know is that this user is on our list of valid users.

Next, the plugin compares the password Henry typed to the password in his user record. If they match, Catalyst::Plugin::Authentication authenticates Henry and he logs in successfully. Now we know that Henry is who he claims.

The User List

To use Catalyst::Plugin::Authentication, you first configure a store. Remember, the store is where you keep your list of users. Search CPAN for Catalyst::Authentication::Store. There's a whole bunch of them. Shoot, they even have one for when you don't need a store

The store populates a user object with the user's information. The exact fields depend on what your store holds. That's good news. Catalyst::Plugin::Authentication provides standard ways of checking the user without limiting the information you keep.

I used Catalyst::Plugin::Authentication::Store::DBIx::Class. The application keeps a list of valid users in an SQL database. The examples had everything to get it up and running.

Check the Password

99% of the time, you can use the simple Catalyst::Authentication::Credential::Password. It compares the password Henry typed with the password in his user record. Catalyst::Authentication::Credential::Password fully supports encrypted passwords. This part was dead simple to setup.

Unfortunately, my application required a little more. Work uses Active Directory as a single sign-on system. My Linux server accesses it through LDAP. To validate a password, I actually have to log into LDAP with that user name and password. If the query returns a record, then the password is valid. My code never sees a password from the LDAP server. And anonymous queries fails.

I couldn't find an existing Catalyst credential for this type of password check. So I wrote one. Turns out much easier than I thought. Catalyst::Plugin::Authentication calls the authentication method in the credential. Then the credential code calls down into the store for loading the user.

My custom module loads the user from the database with Catalyst::Plugin::Authentication::Store::DBIx::Class. If that succeeds, it then queries the LDAP server with the login and password typed by the user. This is not the normal way that you authenticate with LDAP. Our setup at work is, well, odd.

I created the custom credential module specifically for our setup. Server name, dn, and all of the LDAP settings are hard coded into the module. On the up side, it makes adding single sign-on a piece of cake.