Project

General

Profile

Defect #3253 » advanced_ldap_auth_0.8.3.diff

Daniel Marczisovszky, 2009-05-01 21:16

View differences:

app/models/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
# Modified by Daniel Marczisovszky (marczi@dev-labs.com) 
19
# to allow dereferencing aliases, START_TLS
20

  
21
require 'ldap'
19 22
require 'iconv'
20 23

  
21 24
class AuthSourceLdap < AuthSource 
......
24 27
  validates_length_of :account, :base_dn, :maximum => 255, :allow_nil => true
25 28
  validates_length_of :attr_login, :attr_firstname, :attr_lastname, :attr_mail, :maximum => 30, :allow_nil => true
26 29
  validates_numericality_of :port, :only_integer => true
27
  
30

  
28 31
  before_validation :strip_ldap_attributes
29
  
32

  
30 33
  def after_initialize
31 34
    self.port = 389 if self.port == 0
32 35
  end
33
  
36

  
34 37
  def authenticate(login, password)
35 38
    return nil if login.blank? || password.blank?
36 39
    attrs = []
37 40
    # 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", "*" ) 
41

  
42
    # Ticket #1913 by Adi Kriegisch (adi@cg.tuwien.ac.at)
43
    if self.account.include? "$login" then
44
      logger.debug "LDAP-Auth with User login" if logger && logger.debug?
45
      ldap_con = initialize_ldap_con(self.account.sub("$login", encode(login)), password)
46
    else
47
      logger.debug "LDAP-Auth with Admin User" if logger && logger.debug?
48
      ldap_con = initialize_ldap_con(self.account, self.account_password)
49
    end
50

  
51
    if self.filter.empty?
52
      filter = self.attr_login + "=" + encode(login)
53
    else
54
      filter = self.filter.gsub("$login", encode(login))
55
    end
41 56
    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|
57
    logger.debug "Search in DN: #{self.base_dn} with filter: #{filter}" if logger && logger.debug?
58
    ldap_con.search( self.base_dn, LDAP::LDAP_SCOPE_SUBTREE, filter,
59
                     (onthefly_register? ? ['dn', self.attr_firstname, self.attr_lastname, self.attr_mail] : ['dn'])) { |entry|
46 60
      dn = entry.dn
47 61
      attrs = [:firstname => AuthSourceLdap.get_attr(entry, self.attr_firstname),
48 62
               :lastname => AuthSourceLdap.get_attr(entry, self.attr_lastname),
49 63
               :mail => AuthSourceLdap.get_attr(entry, self.attr_mail),
50 64
               :auth_source_id => self.id ] if onthefly_register?
51
    end
65
    }
52 66
    return nil if dn.empty?
53 67
    logger.debug "DN found for #{login}: #{dn}" if logger && logger.debug?
54 68
    # authenticate user
55
    ldap_con = initialize_ldap_con(dn, password)
56
    return nil unless ldap_con.bind
69
    ldap_con.unbind
70
    begin
71
      result = ldap_con.bind(dn, password)
72
    rescue LDAP::Error => bindError
73
      return nil
74
    end
57 75
    # return user's attributes
58 76
    logger.debug "Authentication successful for '#{login}'" if logger && logger.debug?
59
    attrs    
60
  rescue  Net::LDAP::LdapError => text
77
    attrs
78
  rescue  LDAP::Error => text
61 79
    raise "LdapError: " + text
62 80
  end
63 81

  
64 82
  # test the connection to the LDAP
65 83
  def test_connection
66 84
    ldap_con = initialize_ldap_con(self.account, self.account_password)
67
    ldap_con.open { }
68
  rescue  Net::LDAP::LdapError => text
85
  rescue  LDAP::Error => text
69 86
    raise "LdapError: " + text
70 87
  end
71
 
88

  
72 89
  def auth_method_name
73 90
    "LDAP"
74 91
  end
75
  
92

  
76 93
  private
77
  
94

  
78 95
  def strip_ldap_attributes
79 96
    [:attr_login, :attr_firstname, :attr_lastname, :attr_mail].each do |attr|
80 97
      write_attribute(attr, read_attribute(attr).strip) unless read_attribute(attr).nil?
81 98
    end
82 99
  end
83
  
100

  
84 101
  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
102
    if self.tls
103
      conn = LDAP::SSLConn.new(self.host, self.port, self.starttls)
104
    else
105
      conn = LDAP::Conn.new(self.host, self.port)
106
    end
107
    conn.set_option(LDAP::LDAP_OPT_DEREF, self.dereference)
108
    conn.set_option(LDAP::LDAP_OPT_X_TLS_REQUIRE_CERT, self.require_cert)
109

  
110
    if !ldap_user.blank? || !ldap_password.blank? then
111
      logger.debug "Bind as user #{ldap_user}" if logger && logger.debug?
112
      conn.bind(ldap_user, ldap_password)
113
    else
114
      logger.debug "Anonymous bind" if logger && logger.debug?
115
      conn.bind
116
    end
91 117
  end
92
  
118

  
93 119
  def self.get_attr(entry, attr_name)
94 120
    if !attr_name.blank?
95 121
      entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name]
96 122
    end
97 123
  end
124

  
125
  def encode(value)
126
    value = value.gsub("\\", "\\\\5c")
127
    value = value.gsub("*", "\\\\2a")
128
    value = value.gsub("(", "\\\\28")
129
    value = value.gsub(")", "\\\\29")
130
    value = value.gsub("\000", "\\\\00")
131
  end
98 132
end
app/views/auth_sources/_form.rhtml (working copy)
9 9
<%= text_field 'auth_source', 'host'  %></p>
10 10

  
11 11
<p><label for="auth_source_port"><%=l(:field_port)%> <span class="required">*</span></label>
12
<%= text_field 'auth_source', 'port', :size => 6 %> <%= check_box 'auth_source', 'tls'  %> LDAPS</p>
12
<%= text_field 'auth_source', 'port', :size => 6 %>
13
<%= check_box 'auth_source', 'tls' %> LDAPS
14
<%= check_box 'auth_source', 'starttls' %> START_TLS</p>
13 15

  
14 16
<p><label for="auth_source_account"><%=l(:field_account)%></label>
15 17
<%= text_field 'auth_source', 'account'  %></p>
......
20 22
                                           :onfocus => "this.value=''; this.name='auth_source[account_password]';",
21 23
                                           :onchange => "this.name='auth_source[account_password]';" %></p>
22 24

  
25
<p><label for="auth_source_require_cert"><%=l(:field_require_cert)%></label>
26
<%= select 'auth_source', 'require_cert', [ ["Never", 0], ["Hard", 1], ["Demand", 2], ["Allow", 3], ["Try", 4] ] %></p>
27

  
23 28
<p><label for="auth_source_base_dn"><%=l(:field_base_dn)%> <span class="required">*</span></label>
24 29
<%= text_field 'auth_source', 'base_dn', :size => 60 %></p>
25 30

  
31
<p><label for="auth_source_filter"><%=l(:field_filter)%></label><%= text_field 'auth_source', 'filter' %></p>
32

  
33
<p><label for="auth_source_dereference"><%=l(:field_dereference)%></label>
34
<%= select 'auth_source', 'dereference', [ ["Never", 0], ["Searching", 1], ["Finding", 2], ["Always", 3] ] %></p>
35

  
26 36
<p><label for="auth_source_onthefly_register"><%=l(:field_onthefly)%></label>
27 37
<%= check_box 'auth_source', 'onthefly_register' %></p>
28 38
</div>
lang/en.yml (working copy)
157 157
field_port: Port
158 158
field_account: Account
159 159
field_base_dn: Base DN
160
field_filter: Filter
161
field_dereference: Dereference
162
field_require_cert: Require certificate
160 163
field_attr_login: Login attribute
161 164
field_attr_firstname: Firstname attribute
162 165
field_attr_lastname: Lastname attribute
db/migrate/102_add_auth_sources_filter_deref_advtls.rb (revision 0)
1
class AddAuthSourcesFilterDerefAdvtls < ActiveRecord::Migration
2
  def self.up
3
    add_column :auth_sources, :starttls, :boolean, :default => false, :null => false
4
    add_column :auth_sources, :filter, :string
5
    add_column :auth_sources, :dereference, :integer
6
    add_column :auth_sources, :require_cert, :integer
7
  end
8

  
9
  def self.down
10
    remove_column :auth_sources, :starttls
11
    remove_column :auth_sources, :filter
12
    remove_column :auth_sources, :dereference
13
    remove_column :auth_sources, :require_cert
14
  end
15
end
(1-1/2)