Index: app/views/ldap_auth_sources/_form.rhtml
===================================================================
--- app/views/ldap_auth_sources/_form.rhtml	(revision 6416)
+++ app/views/ldap_auth_sources/_form.rhtml	(working copy)
@@ -9,10 +9,15 @@
 <%= text_field 'auth_source', 'host'  %></p>
 
 <p><label for="auth_source_port"><%=l(:field_port)%> <span class="required">*</span></label>
-<%= text_field 'auth_source', 'port', :size => 6 %> <%= check_box 'auth_source', 'tls'  %> LDAPS</p>
+<%= text_field 'auth_source', 'port', :size => 6 %>
+<%= check_box 'auth_source', 'tls' %> LDAPS
+<%= check_box 'auth_source', 'starttls' %> START_TLS</p>
+
+<p><label for="auth_source_protocol_version"><%=l(:field_protocol_version)%></label>
+<%= select 'auth_source', 'protocol_version', [2, 3] %></p>
 
 <p><label for="auth_source_account"><%=l(:field_account)%></label>
-<%= text_field 'auth_source', 'account'  %></p>
+<%= text_field 'auth_source', 'account' %></p>
 
 <p><label for="auth_source_account_password"><%=l(:field_password)%></label>
 <%= 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]';" %></p>
 
+<p><label for="auth_source_require_cert"><%=l(:field_require_cert)%></label>
+<%= 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] ] %></p>
+
 <p><label for="auth_source_base_dn"><%=l(:field_base_dn)%> <span class="required">*</span></label>
 <%= text_field 'auth_source', 'base_dn', :size => 60 %></p>
 
+<p><label for="auth_source_filter"><%=l(:field_filter)%></label><%= text_field 'auth_source', 'filter' %></p>
+
+<p><label for="auth_source_dereference"><%=l(:field_dereference)%></label>
+<%= select 'auth_source', 'dereference', [ [l(:field_dereference_never), 0],
+                                         [l(:field_dereference_searching), 1],
+                                         [l(:field_dereference_finding), 2],
+                                         [l(:field_dereference_always), 3] ] %></p>
+
 <p><label for="auth_source_onthefly_register"><%=l(:field_onthefly)%></label>
 <%= check_box 'auth_source', 'onthefly_register' %></p>
 </div>
Index: app/models/auth_source_ldap.rb
===================================================================
--- app/models/auth_source_ldap.rb	(revision 6416)
+++ 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 6416)
+++ 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 6416)
+++ config/locales/en.yml	(working copy)
@@ -266,6 +266,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
