##// END OF EJS Templates
Adds a configurable timeout for LDAP authentication (#8978)....
Jean-Philippe Lang -
r9748:3b207ee77caf
parent child
Show More
@@ -0,0 +1,9
1 class AddAuthSourcesTimeout < ActiveRecord::Migration
2 def up
3 add_column :auth_sources, :timeout, :integer
4 end
5
6 def self.down
7 remove_column :auth_sources, :timeout
8 end
9 end
@@ -18,6 +18,7
18 18 # Generic exception for when the AuthSource can not be reached
19 19 # (eg. can not connect to the LDAP)
20 20 class AuthSourceException < Exception; end
21 class AuthSourceTimeoutException < AuthSourceException; end
21 22
22 23 class AuthSource < ActiveRecord::Base
23 24 include Redmine::SubclassFactory
@@ -18,6 +18,7
18 18 require 'iconv'
19 19 require 'net/ldap'
20 20 require 'net/ldap/dn'
21 require 'timeout'
21 22
22 23 class AuthSourceLdap < AuthSource
23 24 validates_presence_of :host, :port, :attr_login
@@ -25,6 +26,7 class AuthSourceLdap < AuthSource
25 26 validates_length_of :account, :account_password, :base_dn, :filter, :maximum => 255, :allow_blank => true
26 27 validates_length_of :attr_login, :attr_firstname, :attr_lastname, :attr_mail, :maximum => 30, :allow_nil => true
27 28 validates_numericality_of :port, :only_integer => true
29 validates_numericality_of :timeout, :only_integer => true, :allow_blank => true
28 30 validate :validate_filter
29 31
30 32 before_validation :strip_ldap_attributes
@@ -44,22 +46,26 class AuthSourceLdap < AuthSource
44 46
45 47 def authenticate(login, password)
46 48 return nil if login.blank? || password.blank?
47 attrs = get_user_dn(login, password)
48 49
49 if attrs && attrs[:dn] && authenticate_dn(attrs[:dn], password)
50 logger.debug "Authentication successful for '#{login}'" if logger && logger.debug?
51 return attrs.except(:dn)
50 with_timeout do
51 attrs = get_user_dn(login, password)
52 if attrs && attrs[:dn] && authenticate_dn(attrs[:dn], password)
53 logger.debug "Authentication successful for '#{login}'" if logger && logger.debug?
54 return attrs.except(:dn)
55 end
52 56 end
53 rescue Net::LDAP::LdapError => e
57 rescue Net::LDAP::LdapError => e
54 58 raise AuthSourceException.new(e.message)
55 59 end
56 60
57 61 # test the connection to the LDAP
58 62 def test_connection
59 ldap_con = initialize_ldap_con(self.account, self.account_password)
60 ldap_con.open { }
61 rescue Net::LDAP::LdapError => e
62 raise "LdapError: " + e.message
63 with_timeout do
64 ldap_con = initialize_ldap_con(self.account, self.account_password)
65 ldap_con.open { }
66 end
67 rescue Net::LDAP::LdapError => e
68 raise AuthSourceException.new(e.message)
63 69 end
64 70
65 71 def auth_method_name
@@ -68,6 +74,16 class AuthSourceLdap < AuthSource
68 74
69 75 private
70 76
77 def with_timeout(&block)
78 timeout = self.timeout
79 timeout = 20 unless timeout && timeout > 0
80 Timeout.timeout(timeout) do
81 return yield
82 end
83 rescue Timeout::Error => e
84 raise AuthSourceTimeoutException.new(e.message)
85 end
86
71 87 def ldap_filter
72 88 if filter.present?
73 89 Net::LDAP::Filter.construct(filter)
@@ -26,6 +26,9
26 26 <p><label for="auth_source_custom_filter"><%=l(:field_ldap_filter)%></label>
27 27 <%= text_field 'auth_source', 'filter', :size => 60 %></p>
28 28
29 <p><label for="auth_source_timeout"><%=l(:field_timeout)%></label>
30 <%= text_field 'auth_source', 'timeout', :size => 4 %></p>
31
29 32 <p><label for="auth_source_onthefly_register"><%=l(:field_onthefly)%></label>
30 33 <%= check_box 'auth_source', 'onthefly_register' %></p>
31 34 </div>
@@ -329,6 +329,7 en:
329 329 field_multiple: Multiple values
330 330 field_ldap_filter: LDAP filter
331 331 field_core_fields: Standard fields
332 field_timeout: "Timeout (in seconds)"
332 333
333 334 setting_app_title: Application title
334 335 setting_app_subtitle: Application subtitle
@@ -328,6 +328,7 fr:
328 328 field_multiple: Valeurs multiples
329 329 field_ldap_filter: Filtre LDAP
330 330 field_core_fields: Champs standards
331 field_timeout: "Timeout (en secondes)"
331 332
332 333 setting_app_title: Titre de l'application
333 334 setting_app_subtitle: Sous-titre de l'application
@@ -114,6 +114,16 class AuthSourceLdapTest < ActiveSupport::TestCase
114 114 end
115 115 end
116 116 end
117
118 def test_authenticate_should_timeout
119 auth_source = AuthSourceLdap.find(1)
120 auth_source.timeout = 1
121 def auth_source.initialize_ldap_con(*args); sleep(5); end
122
123 assert_raise AuthSourceTimeoutException do
124 auth_source.authenticate 'example1', '123456'
125 end
126 end
117 127 else
118 128 puts '(Test LDAP server not configured)'
119 129 end
General Comments 0
You need to be logged in to leave comments. Login now