Index: app/views/ldap_auth_sources/_form.rhtml =================================================================== --- app/views/ldap_auth_sources/_form.rhtml (revision 6417) +++ app/views/ldap_auth_sources/_form.rhtml (working copy) @@ -9,10 +9,15 @@ <%= text_field 'auth_source', 'host' %>
-<%= text_field 'auth_source', 'port', :size => 6 %> <%= check_box 'auth_source', 'tls' %> LDAPS
+<%= text_field 'auth_source', 'port', :size => 6 %> +<%= check_box 'auth_source', 'tls' %> LDAPS +<%= check_box 'auth_source', 'starttls' %> START_TLS + ++<%= select 'auth_source', 'protocol_version', [2, 3] %>
-<%= text_field 'auth_source', 'account' %>
+<%= text_field 'auth_source', 'account' %><%= password_field 'auth_source', 'account_password', :name => 'ignore', @@ -20,9 +25,24 @@ :onfocus => "this.value=''; this.name='auth_source[account_password]';", :onchange => "this.name='auth_source[account_password]';" %>
++<%= select 'auth_source', 'require_cert', [ [l(:field_require_cert_never), 0], + [l(:field_require_cert_hard), 1], + [l(:field_require_cert_demand), 2], + [l(:field_require_cert_allow), 3], + [l(:field_require_cert_try), 4] ] %>
+<%= text_field 'auth_source', 'base_dn', :size => 60 %>
+<%= text_field 'auth_source', 'filter' %>
+ ++<%= select 'auth_source', 'dereference', [ [l(:field_dereference_never), 0], + [l(:field_dereference_searching), 1], + [l(:field_dereference_finding), 2], + [l(:field_dereference_always), 3] ] %>
+<%= check_box 'auth_source', 'onthefly_register' %>
Index: app/models/auth_source_ldap.rb =================================================================== --- app/models/auth_source_ldap.rb (revision 6417) +++ app/models/auth_source_ldap.rb (working copy) @@ -14,21 +14,24 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# Modified by Daniel Marczisovszky (marczi@dev-labs.com) +# to allow dereferencing aliases, START_TLS -require 'net/ldap' +require 'ldap' require 'iconv' class AuthSourceLdap < AuthSource validates_presence_of :host, :port, :attr_login validates_length_of :name, :host, :maximum => 60, :allow_nil => true - validates_length_of :account, :account_password, :base_dn, :maximum => 255, :allow_nil => true + validates_length_of :account, :base_dn, :filter, :maximum => 255, :allow_nil => true validates_length_of :attr_login, :attr_firstname, :attr_lastname, :attr_mail, :maximum => 30, :allow_nil => true - validates_numericality_of :port, :only_integer => true - + validates_numericality_of :port, :protocol_version, :only_integer => true + before_validation :strip_ldap_attributes def after_initialize self.port = 389 if self.port == 0 + self.protocol_version = 3 if self.protocol_version == 0 end def authenticate(login, password) @@ -39,16 +42,20 @@ logger.debug "Authentication successful for '#{login}'" if logger && logger.debug? return attrs.except(:dn) end - rescue Net::LDAP::LdapError => text - raise "LdapError: " + text +# rescue Net::LDAP::LdapError => text +# raise "LdapError: " + text + rescue LDAP::Error => text + raise "LDAP Auth Error: " + text end # test the connection to the LDAP def test_connection ldap_con = initialize_ldap_con(self.account, self.account_password) - ldap_con.open { } - rescue Net::LDAP::LdapError => text - raise "LdapError: " + text + rescue LDAP::Error => text + raise "LDAP Error: " + text +# ldap_con.open { } +# rescue Net::LDAP::LdapError => text +# raise "LdapError: " + text end def auth_method_name @@ -64,12 +71,37 @@ end def initialize_ldap_con(ldap_user, ldap_password) - options = { :host => self.host, - :port => self.port, - :encryption => (self.tls ? :simple_tls : nil) - } - options.merge!(:auth => { :method => :simple, :username => ldap_user, :password => ldap_password }) unless ldap_user.blank? && ldap_password.blank? - Net::LDAP.new options +# options = { :host => self.host, +# :port => self.port, +# :encryption => (self.tls ? :simple_tls : nil) +# } +# options.merge!(:auth => { :method => :simple, :username => ldap_user, :password => ldap_password }) unless ldap_user.blank? && ldap_password.blank? +# Net::LDAP.new options + logger.debug "Connecting to #{self.host}:#{self.port}, tls=#{self.tls}" if logger && logger.debug? + if self.tls + conn = LDAP::SSLConn.new(self.host, self.port, self.starttls) + else + conn = LDAP::Conn.new(self.host, self.port) + end + logger.debug "Dereference set option" if logger && logger.debug? + conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, self.protocol_version) + conn.set_option(LDAP::LDAP_OPT_DEREF, self.dereference) + if self.tls && self.starttls + logger.debug "Certificate set option" if logger && logger.debug? + conn.set_option(LDAP::LDAP_OPT_X_TLS_REQUIRE_CERT, self.require_cert) + end + + logger.debug "Trying to bind" if logger && logger.debug? + if !ldap_user.blank? || !ldap_password.blank? then + logger.debug "Bind as user #{ldap_user}" if logger && logger.debug? + conn.bind(ldap_user, ldap_password) + else + logger.debug "Anonymous bind" if logger && logger.debug? + conn.bind + end + rescue LDAP::Error => text + logger.debug "LDAP Connect Error: #{$!}" if logger && logger.debug? + raise end def get_user_attributes_from_ldap_entry(entry) @@ -95,20 +127,47 @@ # Check if a DN (user record) authenticates with the password def authenticate_dn(dn, password) if dn.present? && password.present? - initialize_ldap_con(dn, password).bind + begin + logger.debug "Trying to login as #{dn}" if logger && logger.debug? + initialize_ldap_con(dn, password) + rescue LDAP::Error => bindError + logger.debug "Login failed: #{bindError}" if logger && logger.debug? + return nil + end +# initialize_ldap_con(dn, password).bind end end # Get the user's dn and any attributes for them, given their login def get_user_dn(login) - ldap_con = initialize_ldap_con(self.account, self.account_password) - login_filter = Net::LDAP::Filter.eq( self.attr_login, login ) - object_filter = Net::LDAP::Filter.eq( "objectClass", "*" ) +# ldap_con = initialize_ldap_con(self.account, self.account_password) +# login_filter = Net::LDAP::Filter.eq( self.attr_login, login ) +# object_filter = Net::LDAP::Filter.eq( "objectClass", "*" ) attrs = {} - ldap_con.search( :base => self.base_dn, - :filter => object_filter & login_filter, - :attributes=> search_attributes) do |entry| + + # Ticket #1913 by Adi Kriegisch (adi@cg.tuwien.ac.at) + if self.account.include? "$login" then + logger.debug "LDAP-Auth with User login" if logger && logger.debug? + ldap_con = initialize_ldap_con(self.account.sub("$login", encode(login)), password) + else + logger.debug "LDAP-Auth with Admin User" if logger && logger.debug? + ldap_con = initialize_ldap_con(self.account, self.account_password) + end + + if self.filter.empty? + filter = self.attr_login + "=" + encode(login) + else + filter = self.filter.gsub("$login", encode(login)) + end + + +# ldap_con.search( :base => self.base_dn, +# :filter => object_filter & login_filter, +# :attributes=> search_attributes) do |entry| + logger.debug "Search in DN: #{self.base_dn} with filter: #{filter}" if logger && logger.debug? + ldap_con.search( self.base_dn, LDAP::LDAP_SCOPE_SUBTREE, filter, + (onthefly_register? ? ['dn', self.attr_firstname, self.attr_lastname, self.attr_mail] : ['dn'])) { |entry| if onthefly_register? attrs = get_user_attributes_from_ldap_entry(entry) @@ -117,7 +176,8 @@ end logger.debug "DN found for #{login}: #{attrs[:dn]}" if logger && logger.debug? - end +# end + } attrs end @@ -127,4 +187,12 @@ entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name] end end + + def encode(value) + value = value.gsub("\\", "\\\\5c") + value = value.gsub("*", "\\\\2a") + value = value.gsub("(", "\\\\28") + value = value.gsub(")", "\\\\29") + value = value.gsub("\000", "\\\\00") + end end Index: db/migrate/20110812010830_add_auth_sources_filter_deref_advtls.rb =================================================================== --- db/migrate/20110812010830_add_auth_sources_filter_deref_advtls.rb (revision 0) +++ db/migrate/20110812010830_add_auth_sources_filter_deref_advtls.rb (revision 0) @@ -0,0 +1,17 @@ +class AddAuthSourcesFilterDerefAdvtls < ActiveRecord::Migration + def self.up + add_column :auth_sources, :starttls, :boolean, :default => false, :null => false + add_column :auth_sources, :filter, :string + add_column :auth_sources, :dereference, :integer + add_column :auth_sources, :require_cert, :integer + add_column :auth_sources, :protocol_version, :integer, :default => 3, :null => false + end + + def self.down + remove_column :auth_sources, :starttls + remove_column :auth_sources, :filter + remove_column :auth_sources, :dereference + remove_column :auth_sources, :require_cert + remove_column :auth_sources, :protocol_version + end +end Index: config/locales/de.yml =================================================================== --- config/locales/de.yml (revision 6417) +++ config/locales/de.yml (working copy) @@ -281,6 +281,19 @@ field_port: Port field_account: Konto field_base_dn: Base DN + field_protocol_version: Protokol Version + field_filter: Filter + field_dereference: LDAP Aliase dereferenzieren + field_dereference_never: Nie (standard) + field_dereference_searching: Beim suchen + field_dereference_finding: Beim finden + field_dereference_always: Immer + field_require_cert: Zertifikat verlangen + field_require_cert_never: Nie + field_require_cert_hard: Hart + field_require_cert_demand: Anfordern + field_require_cert_allow: Erlauben + field_require_cert_try: Versuchen field_attr_login: Mitgliedsname-Attribut field_attr_firstname: Vorname-Attribut field_attr_lastname: Name-Attribut Index: config/locales/en.yml =================================================================== --- config/locales/en.yml (revision 6417) +++ config/locales/en.yml (working copy) @@ -265,6 +265,19 @@ field_port: Port field_account: Account field_base_dn: Base DN + field_protocol_version: Protocol version + field_filter: Filter + field_dereference: Dereference LDAP aliases + field_dereference_never: Never (default) + field_dereference_searching: Searching + field_dereference_finding: Finding + field_dereference_always: Always + field_require_cert: Require certificate + field_require_cert_never: Never + field_require_cert_hard: Hard + field_require_cert_demand: Demand + field_require_cert_allow: Allow + field_require_cert_try: Try field_attr_login: Login attribute field_attr_firstname: Firstname attribute field_attr_lastname: Lastname attribute