Archive for November, 2010

We have an openldap server running. I wrote a little rails app that required authentication and that I wanted to authenticate against users in the openldap server. Here’s how I did it.

Here is the relevant part of my Gemfile. I’m using Rails 3.0.3.

gem 'authlogic'
gem 'declarative_authorization'
gem 'net-ldap', :require => 'net/ldap'

My user migration:

class CreateUsers < ActiveRecord::Migration
  def self.up
    create_table :users do |t|
      t.string :username
      t.string :firstname
      t.string :lastname
      t.string :persistence_token
      t.datetime :last_request_at
      t.string :role

      t.timestamps
    end
  end

Add to my user model:

  acts_as_authentic do |c|
    c.validate_password_field = false
    c.logged_in_timeout = 2.hours
  end    

  def valid_password?(password)
    ldap_settings = YAML.load_file("#{Rails.root.to_s}/config/ldap.yml")[Rails.env]
    #logger.info ldap_settings.inspect
    
    ldap_settings[:host] = ldap_settings['host']
    ldap_settings[:port] = ldap_settings['port']
    ldap_settings[:encryption] = { :method => :simple_tls } if ldap_settings['ssl']
    ldap_settings[:auth] = 
      { :method => :simple, :username => "uid=#{self.username},#{ldap_settings['base']}", :password => password}

    #logger.info ldap_settings.inspect
    
    ldap = Net::LDAP.new(ldap_settings)
    ldap.bind
  end

Add to my user_session model:

  logout_on_timeout true

My new user_session:

<%= form_for @user_session, :as => :user_session, :url => { :action => 'create' } do |f| -%>
  

<%= f.label :username %>
<%= f.text_field :username %>

<%= f.label :password %>
<%= f.password_field :password %>

<%= f.submit 'Login' %>

<% end %> <%= link_to 'Back', :back %>

Needed the stuff after @user_session because of a problem with authlogic and rails3.

Finally, I created a yaml file with the info for my ldap server. It's in config/ldap.yml.

development:
    host: eagle.example.com
    port: 636
    base: ou=people,dc=group,dc=example,dc=com
    ssl: true

production:
    host: eagle.example.com
    port: 636
    base: ou=people,dc=group,dc=example,dc=com
    ssl: true

That pretty much did it. You MUST use port 636 and ssl:true for this to work. Starttls over port 389 will not work. (At least, it didn't for me.)