Project

General

Profile

Patch #3358 » advanced_ldap_auth_2.2.3.diff

Diff for post-Redmine 2 - Phil Weir, 2014-02-28 11:28

View differences:

app/models/auth_source_ldap.rb
14 14
# You should have received a copy of the GNU General Public License
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
# Modified by Daniel Marczisovszky (marczi@dev-labs.com) 
18
# to allow dereferencing aliases, START_TLS
17 19

  
18 20
require 'iconv'
19
require 'net/ldap'
20
require 'net/ldap/dn'
21
require 'ldap'
21 22
require 'timeout'
22 23

  
23 24
class AuthSourceLdap < AuthSource
24 25
  validates_presence_of :host, :port, :attr_login
25 26
  validates_length_of :name, :host, :maximum => 60, :allow_nil => true
26
  validates_length_of :account, :account_password, :base_dn, :filter, :maximum => 255, :allow_blank => true
27
  validates_length_of :account, :base_dn, :filter, :maximum => 255, :allow_blank => true
27 28
  validates_length_of :attr_login, :attr_firstname, :attr_lastname, :attr_mail, :maximum => 30, :allow_nil => true
28
  validates_numericality_of :port, :only_integer => true
29
  validates_numericality_of :port, :protocol_version, :only_integer => true
29 30
  validates_numericality_of :timeout, :only_integer => true, :allow_blank => true
30 31
  validate :validate_filter
31 32

  
......
34 35
  def initialize(attributes=nil, *args)
35 36
    super
36 37
    self.port = 389 if self.port == 0
38
    self.protocol_version = 3 if self.protocol_version == 0
37 39
  end
38 40

  
39 41
  def authenticate(login, password)
......
46 48
        return attrs.except(:dn)
47 49
      end
48 50
    end
49
  rescue Net::LDAP::LdapError => e
50
    raise AuthSourceException.new(e.message)
51
  rescue LDAP::Error => text
52
    raise AuthSourceException.new(text)
51 53
  end
52 54

  
53 55
  # test the connection to the LDAP
54 56
  def test_connection
55 57
    with_timeout do
56 58
      ldap_con = initialize_ldap_con(self.account, self.account_password)
57
      ldap_con.open { }
58 59
    end
59
  rescue Net::LDAP::LdapError => e
60
    raise AuthSourceException.new(e.message)
60
  rescue LDAP::Error => text
61
    raise AuthSourceException.new(text)
61 62
  end
62 63

  
63 64
  def auth_method_name
......
78 79

  
79 80
  def ldap_filter
80 81
    if filter.present?
81
      Net::LDAP::Filter.construct(filter)
82
      LDAP::Filter.construct(filter)
82 83
    end
83
  rescue Net::LDAP::LdapError
84
  rescue LDAP::Error
84 85
    nil
85 86
  end
86 87

  
87 88
  def validate_filter
88
    if filter.present? && ldap_filter.nil?
89
      errors.add(:filter, :invalid)
90
    end
89
    #if filter.present? && ldap_filter.nil?
90
    #  errors.add(:filter, :invalid)
91
    #end
91 92
  end
92 93

  
93 94
  def strip_ldap_attributes
......
97 98
  end
98 99

  
99 100
  def initialize_ldap_con(ldap_user, ldap_password)
100
    options = { :host => self.host,
101
                :port => self.port,
102
                :encryption => (self.tls ? :simple_tls : nil)
103
              }
104
    options.merge!(:auth => { :method => :simple, :username => ldap_user, :password => ldap_password }) unless ldap_user.blank? && ldap_password.blank?
105
    Net::LDAP.new options
101
    logger.debug "Connecting to #{self.host}:#{self.port}, tls=#{self.tls}" if logger && logger.debug?
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
    logger.debug "Dereference set option" if logger && logger.debug?
108
    conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, self.protocol_version)
109
    conn.set_option(LDAP::LDAP_OPT_DEREF, self.dereference)
110
    if self.tls && self.starttls
111
      logger.debug "Certificate set option" if logger && logger.debug?
112
      conn.set_option(LDAP::LDAP_OPT_X_TLS_REQUIRE_CERT, self.require_cert)
113
    end
114

  
115
    logger.debug "Trying to bind" if logger && logger.debug?
116
    if !ldap_user.blank? || !ldap_password.blank? then
117
      logger.debug "Bind as user #{ldap_user}" if logger && logger.debug?
118
      conn.bind(ldap_user, ldap_password)
119
    else
120
      logger.debug "Anonymous bind" if logger && logger.debug?
121
      conn.bind
122
    end
123
  rescue LDAP::Error => text
124
    logger.debug "LDAP Connect Error: #{$!}" if logger && logger.debug?
125
    raise
106 126
  end
107 127

  
108 128
  def get_user_attributes_from_ldap_entry(entry)
......
128 148
  # Check if a DN (user record) authenticates with the password
129 149
  def authenticate_dn(dn, password)
130 150
    if dn.present? && password.present?
131
      initialize_ldap_con(dn, password).bind
151
      begin
152
        logger.debug "Trying to login as #{dn}" if logger && logger.debug?
153
        initialize_ldap_con(dn, password)
154
      rescue LDAP::Error => bindError
155
        logger.debug "Login failed: #{bindError}" if logger && logger.debug?
156
        return nil
157
      end
132 158
    end
133 159
  end
134 160

  
135 161
  # Get the user's dn and any attributes for them, given their login
136 162
  def get_user_dn(login, password)
137
    ldap_con = nil
138
    if self.account && self.account.include?("$login")
139
      ldap_con = initialize_ldap_con(self.account.sub("$login", Net::LDAP::DN.escape(login)), password)
163
    #ldap_con = nil
164
    #if self.account && self.account.include?("$login")
165
    #  ldap_con = initialize_ldap_con(self.account.sub("$login", Net::LDAP::DN.escape(login)), password)
166
    #else
167
    #  ldap_con = initialize_ldap_con(self.account, self.account_password)
168
    #end
169
    #login_filter = Net::LDAP::Filter.eq( self.attr_login, login )
170
    #object_filter = Net::LDAP::Filter.eq( "objectClass", "*" )
171
    attrs = {}
172

  
173
    #search_filter = object_filter & login_filter
174
    #if f = ldap_filter
175
    #  search_filter = search_filter & f
176
    #end
177

  
178
    #ldap_con.search( :base => self.base_dn,
179
    #                 :filter => search_filter,
180
    #                 :attributes=> search_attributes) do |entry|
181

  
182
    # Ticket #1913 by Adi Kriegisch (adi@cg.tuwien.ac.at)
183
    if self.account.include? "$login" then
184
      logger.debug "LDAP-Auth with User login" if logger && logger.debug?
185
      ldap_con = initialize_ldap_con(self.account.sub("$login", encode(login)), password)
140 186
    else
187
      logger.debug "LDAP-Auth with Admin User" if logger && logger.debug?
141 188
      ldap_con = initialize_ldap_con(self.account, self.account_password)
142 189
    end
143
    login_filter = Net::LDAP::Filter.eq( self.attr_login, login )
144
    object_filter = Net::LDAP::Filter.eq( "objectClass", "*" )
145
    attrs = {}
146 190

  
147
    search_filter = object_filter & login_filter
148
    if f = ldap_filter
149
      search_filter = search_filter & f
191
    if self.filter.empty?
192
      filter = self.attr_login + "=" + encode(login)
193
    else
194
      filter = self.filter.gsub("$login", encode(login))
150 195
    end
151

  
152
    ldap_con.search( :base => self.base_dn,
153
                     :filter => search_filter,
154
                     :attributes=> search_attributes) do |entry|
196
      
197
      
198
#    ldap_con.search( :base => self.base_dn, 
199
#                     :filter => object_filter & login_filter, 
200
#                     :attributes=> search_attributes) do |entry|
201
    logger.debug "Search in DN: #{self.base_dn} with filter: #{filter}" if logger && logger.debug?
202
    ldap_con.search( self.base_dn, LDAP::LDAP_SCOPE_SUBTREE, filter,
203
                     (onthefly_register? ? ['dn', self.attr_firstname, self.attr_lastname, self.attr_mail] : ['dn'])) { |entry|
155 204

  
156 205
      if onthefly_register?
157 206
        attrs = get_user_attributes_from_ldap_entry(entry)
......
160 209
      end
161 210

  
162 211
      logger.debug "DN found for #{login}: #{attrs[:dn]}" if logger && logger.debug?
163
    end
212
    }
164 213

  
165 214
    attrs
166 215
  end
......
170 219
      entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name]
171 220
    end
172 221
  end
222

  
223
  def encode(value)
224
    value = value.gsub("\\", "\\\\5c")
225
    value = value.gsub("*", "\\\\2a")
226
    value = value.gsub("(", "\\\\28")
227
    value = value.gsub(")", "\\\\29")
228
    value = value.gsub("\000", "\\\\00")
229
  end
173 230
end
app/views/auth_sources/_form_auth_source_ldap.html.erb
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>
15

  
16
<p><label for="auth_source_protocol_version"><%=l(:field_protocol_version)%></label>
17
<%= select 'auth_source', 'protocol_version', [2, 3] %></p>
13 18

  
14 19
<p><label for="auth_source_account"><%=l(:field_account)%></label>
15
<%= text_field 'auth_source', 'account'  %></p>
20
<%= text_field 'auth_source', 'account' %></p>
16 21

  
17 22
<p><label for="auth_source_account_password"><%=l(:field_password)%></label>
18 23
<%= password_field 'auth_source', 'account_password', :name => 'ignore',
......
20 25
                                           :onfocus => "this.value=''; this.name='auth_source[account_password]';",
21 26
                                           :onchange => "this.name='auth_source[account_password]';" %></p>
22 27

  
28
<p><label for="auth_source_require_cert"><%=l(:field_require_cert)%></label>
29
<%= select 'auth_source', 'require_cert', [ [l(:field_require_cert_never), 0],
30
                                            [l(:field_require_cert_hard), 1],
31
                                            [l(:field_require_cert_demand), 2],
32
                                            [l(:field_require_cert_allow), 3],
33
                                            [l(:field_require_cert_try), 4] ] %></p>
34

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

  
26
<p><label for="auth_source_custom_filter"><%=l(:field_auth_source_ldap_filter)%></label>
27
<%= text_field 'auth_source', 'filter', :size => 60 %></p>
38
<p><label for="auth_source_filter"><%=l(:field_filter)%></label><%= text_field 'auth_source', 'filter' %></p>
39

  
40
<p><label for="auth_source_dereference"><%=l(:field_dereference)%></label>
41
<%= select 'auth_source', 'dereference', [ [l(:field_dereference_never), 0],
42
                                         [l(:field_dereference_searching), 1],
43
                                         [l(:field_dereference_finding), 2],
44
                                         [l(:field_dereference_always), 3] ] %></p>
28 45

  
29 46
<p><label for="auth_source_timeout"><%=l(:field_timeout)%></label>
30 47
<%= text_field 'auth_source', 'timeout', :size => 4 %></p>
config/locales/de.yml
281 281
  field_port: Port
282 282
  field_account: Konto
283 283
  field_base_dn: Base DN
284
  field_protocol_version: Protokol Version
285
  field_filter: Filter
286
  field_dereference: LDAP Aliase dereferenzieren
287
  field_dereference_never: Nie (standard)
288
  field_dereference_searching: Beim suchen
289
  field_dereference_finding: Beim finden
290
  field_dereference_always: Immer
291
  field_require_cert: Zertifikat verlangen
292
  field_require_cert_never: Nie
293
  field_require_cert_hard: Hart
294
  field_require_cert_demand: Anfordern
295
  field_require_cert_allow: Erlauben
296
  field_require_cert_try: Versuchen
284 297
  field_attr_login: Mitgliedsname-Attribut
285 298
  field_attr_firstname: Vorname-Attribut
286 299
  field_attr_lastname: Name-Attribut
config/locales/en.yml
275 275
  field_port: Port
276 276
  field_account: Account
277 277
  field_base_dn: Base DN
278
  field_protocol_version: Protocol version
279
  field_filter: Filter
280
  field_dereference: Dereference LDAP aliases
281
  field_dereference_never: Never (default)
282
  field_dereference_searching: Searching
283
  field_dereference_finding: Finding
284
  field_dereference_always: Always
285
  field_require_cert: Require certificate
286
  field_require_cert_never: Never
287
  field_require_cert_hard: Hard
288
  field_require_cert_demand: Demand
289
  field_require_cert_allow: Allow
290
  field_require_cert_try: Try
278 291
  field_attr_login: Login attribute
279 292
  field_attr_firstname: Firstname attribute
280 293
  field_attr_lastname: Lastname attribute
db/migrate/20110812010830_add_auth_sources_filter_deref_advtls.rb
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
    add_column :auth_sources, :protocol_version, :integer, :default => 3, :null => false
8
  end
9

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