Authenticates a Ruby on Rails User model via LDAP and saves their LDAP photo if they have one

Software Engineering 1848 views

How to authenticate a Ruby on Rails User model via LDAP:

# LDAP server configuration settings
# Host is a Windows Domain Controller

development:
  host: examplehost
  port: 389
  default_domain: EXAMPLEDOMAIN
  base: examplebase # OU=US-Tampa Bay,OU=North America,OU=Accounts,DC=ourdomain,DC=org

test:
  host: examplehost
  port: 389
  default_domain: EXAMPLEDOMAIN
  base: examplebase # OU=US-Tampa Bay,OU=North America,OU=Accounts,DC=ourdomain,DC=org

production:
  host: examplehost
  port: 389
  default_domain: EXAMPLEDOMAIN
  base: examplebase # OU=US-Tampa Bay,OU=North America,OU=Accounts,DC=ourdomain,DC=org
config/ldap.yml
LDAP_CONFIG = YAML.load_file("#{Rails.root}/config/ldap.yml")[Rails.env]
config/initializers/load_ldap_config.rb
require 'net/ldap'

class User < ActiveRecord::Base

  # Authenticates the User via LDAP and saves their LDAP photo if they have one
  def authenticate_ldap(domain, password)
    raise ArgumentError, 'domain is nil' if domain.nil? or domain.blank?
    raise ArgumentError, 'password is nil' if password.nil? or password.blank?

    ldap      = Net::LDAP.new
    ldap.host = LDAP_CONFIG['host']
    ldap.port = LDAP_CONFIG['port']
    ldap.auth "#{domain}\\#{login}", password
    bound = ldap.bind

    if bound
      photo_path = "#{Rails.public_path}/images/avatars/#{id}.jpg"
      unless File.exists?(photo_path)
        base   = LDAP_CONFIG['base']
        filter = Net::LDAP::Filter.eq('sAMAccountName', login)
        ldap.search(:base => base, :filter => filter, :return_result => true) do |entry|
          [:thumbnailphoto, :jpegphoto, :photo].each do |photo_key|
            if entry.attribute_names.include?(photo_key)
              @ldap_photo = entry[photo_key][0]
              File.open(photo_path, 'wb') { |f| f.write(@ldap_photo) }
              break
            end
          end
        end
      end
    end
    bound
  end

end
app/models/user.rb