Project

General

Profile

Defect #1420 » defect_1420_adriano_crestani_rev_2482.patch

Patch for revision 2482 - Adriano Crestani Campos, 2009-02-20 22:21

View differences:

auth_source_ldap.rb (working copy)
15 15
# along with this program; if not, write to the Free Software
16 16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 17

  
18
require 'net/ldap'
18
require 'ldap'
19 19
require 'iconv'
20 20

  
21
# Contributed by mathew <meta@pobox.com>
22
# Alternative AuthSourceLdap which uses Ruby's interface to native OpenLDAP.
23
# I found this more reliable than net/ldap (pure Ruby LDAP).
24
# OpenLDAP doesn't appear to support authentication in order to connect to
25
# the LDAP server, or if it does I can't find any documentation about it.
26
# Since the LDAP server I care about doesn't require auth, that's fine with me;
27
# I just note it here as an FYI.
28
# There's also a start_tls parameter to LDAP::SSLConn which I don't know what
29
# to do with. For me, both options fail, so I tunnel my LDAP instead of 
30
# using SSLConn.
21 31
class AuthSourceLdap < AuthSource 
22 32
  validates_presence_of :host, :port, :attr_login
23 33
  validates_length_of :name, :host, :account_password, :maximum => 60, :allow_nil => true
24 34
  validates_length_of :account, :base_dn, :maximum => 255, :allow_nil => true
25 35
  validates_length_of :attr_login, :attr_firstname, :attr_lastname, :attr_mail, :maximum => 30, :allow_nil => true
26 36
  validates_numericality_of :port, :only_integer => true
27
  
37

  
28 38
  before_validation :strip_ldap_attributes
29 39
  
30 40
  def after_initialize
......
32 42
  end
33 43
  
34 44
  def authenticate(login, password)
45
    login.downcase!
46
    logger.debug "replacement LDAP auth called" if logger && logger.debug?
35 47
    return nil if login.blank? || password.blank?
36 48
    attrs = []
37
    # get user's DN
38
    ldap_con = initialize_ldap_con(self.account, self.account_password)
39
    login_filter = Net::LDAP::Filter.eq( self.attr_login, login ) 
40
    object_filter = Net::LDAP::Filter.eq( "objectClass", "*" ) 
49
    # Get user's DN
50
    ldap_con = initialize_ldap_con()
51
    filter = "(&(objectClass=person)(#{self.attr_login}=#{login}))"
52
    logger.debug "filter = #{filter}" if logger && logger.debug?
53
    logger.debug "base dn = #{self.base_dn}" if logger && logger.debug?
41 54
    dn = String.new
42
    ldap_con.search( :base => self.base_dn, 
43
                     :filter => object_filter & login_filter, 
44
                     # only ask for the DN if on-the-fly registration is disabled
45
                     :attributes=> (onthefly_register? ? ['dn', self.attr_firstname, self.attr_lastname, self.attr_mail] : ['dn'])) do |entry|
46
      dn = entry.dn
55
    # ruby-ldap appears to give you the dn whether you ask for it or not,
56
    # but via a special get_dn method rather than as an attribute.
57
    attrlist = [self.attr_firstname,self.attr_lastname,self.attr_mail]
58
    logger.debug "SEARCH" if logger && logger.debug?
59
    ldap_con.search(self.base_dn, LDAP::LDAP_SCOPE_SUBTREE, filter, attrlist) do |entry|
60
      logger.debug "search_ext returned >= 1 result" if logger && logger.debug?
61
      dn = entry.get_dn
47 62
      attrs = [:firstname => AuthSourceLdap.get_attr(entry, self.attr_firstname),
48 63
               :lastname => AuthSourceLdap.get_attr(entry, self.attr_lastname),
49 64
               :mail => AuthSourceLdap.get_attr(entry, self.attr_mail),
50 65
               :auth_source_id => self.id ] if onthefly_register?
51 66
    end
67
    logger.debug "Passed search_ext block" if logger && logger.debug?
52 68
    return nil if dn.empty?
53 69
    logger.debug "DN found for #{login}: #{dn}" if logger && logger.debug?
54
    # authenticate user
55
    ldap_con = initialize_ldap_con(dn, password)
56
    return nil unless ldap_con.bind
57
    # return user's attributes
70
    # Found user, so try to authenticate
71
    ldap_con.unbind
72
    if ldap_con.bind(dn,password)
73
    # Return user's attributes
58 74
    logger.debug "Authentication successful for '#{login}'" if logger && logger.debug?
59
    attrs    
60
  rescue  Net::LDAP::LdapError => text
61
    raise "LdapError: " + text
75
      return attrs    
76
    end
77
  rescue LDAP::ResultError => text
78
    logger.info "Authentication failure: #{text}" if logger && logger.info?
79
    return nil
62 80
  end
63 81

  
64 82
  # test the connection to the LDAP
65 83
  def test_connection
66
    ldap_con = initialize_ldap_con(self.account, self.account_password)
67
    ldap_con.open { }
68
  rescue  Net::LDAP::LdapError => text
84
    ldap_con = initialize_ldap_con
85
  rescue Net::LDAP::LdapError => text
69 86
    raise "LdapError: " + text
70 87
  end
71 88
 
......
73 90
    "LDAP"
74 91
  end
75 92
  
76
  private
77
  
93
private
78 94
  def strip_ldap_attributes
79 95
    [:attr_login, :attr_firstname, :attr_lastname, :attr_mail].each do |attr|
80 96
      write_attribute(attr, read_attribute(attr).strip) unless read_attribute(attr).nil?
81 97
    end
82 98
  end
83
  
84
  def initialize_ldap_con(ldap_user, ldap_password)
85
    options = { :host => self.host,
86
                :port => self.port,
87
                :encryption => (self.tls ? :simple_tls : nil)
88
              }
89
    options.merge!(:auth => { :method => :simple, :username => ldap_user, :password => ldap_password }) unless ldap_user.blank? && ldap_password.blank?
90
    Net::LDAP.new options
99

  
100
  def initialize_ldap_con
101
    logger.debug "Setting up LDAP connection to #{self.host}:#{self.port}"
102
    if self.tls
103
      # Last parameter determines if START_TLS is used for the SSL connection.
104
      return LDAP::SSLConn.new(self.host, self.port, true)
105
    else
106
      return LDAP::Conn.new(self.host, self.port)
107
    end
91 108
  end
92 109
  
93 110
  def self.get_attr(entry, attr_name)
(2-2/2)