Using Authlogic and Active Directory together for user logins

I just built a Rails app to replace a crotchety old .NET tool (original coding time: spread out over months; Rails: 5-6 hours!). The tool has both public and protected access needs, with the internal users being part of an Active Directory network. I always use authlogic for my authentication needs, but had never needed to deal with AD before. I didn't want to piece together a hack of Apache, mod_ldap, and authlogic's basic auth support, since that just muddies the cleanliness of an otherwise very simple design!

So I found a post about authenticating with Active Directory in Ruby that handled the AD authentication side of things. That wasn't enough for authlogic though, which wants an AR model. I didn't want to make it into a table-less model (and I haven't jumped into Rails3 yet), so I needed another way.

Steve had a post about supporting a sudo-like feature with authlogic that matched my need to a good degree, so I adapted his idea to achieve the following.

First, I saved down the final ActiveDirectoryUser class and put it in app/models/active_directory_user.rb, with no changes.

I created a standard User model for authlogic that looks like this:

class User < ActiveRecord::Base
  acts_as_authentic
 
  def self.from_ad(ad_user)
    user = User.find_by_login(ad_user.login)
    if user.nil?
      User.create! ad_user
    end
    return user
  end
end

My UserSession model looks like:

class UserSession < Authlogic::Session::Base
 
  def self.new_from_ad(params)
    ad_user = ActiveDirectoryUser.authenticate(params[:login], params[:password])
    return nil if ad_user.nil?
 
    @current_user = User.from_ad(ad_user)
    @user_session = UserSession.create!(@current_user)
    return @user_session
  end
end

Then in my user_sessions_controller.rb, I have:

class UserSessionsController < ApplicationController
 
  def new
    @user_session = UserSession.new
  end
 
  def create
 
    @user_session = UserSession.new_from_ad(params[:user_session])
    if @user_session.nil?
      @user_session = UserSession.new(params[:user_session])
    end
 
    if @user_session.save
      flash[:notice] = "Login successful!"
      redirect_to presentations_url
    else
      render :action => :new
    end
  end
 
  def destroy
    current_user_session.destroy
    flash[:notice] = "Logout successful!"
    redirect_back_or_default login_url
  end
 
end

And that's it! Now I can authenticate my AD users as needed, but still get all the authlogic goodness. Hope his helps some other folks leverage their enterprise network for their new Rails project. Enjoy!