From 1318ac204eee242a46e145204cd02df64d0d2080 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Tue, 16 Feb 2010 17:59:50 -0800 Subject: [PATCH 1/5] [#3619] Allow defining a custom ldap filter for AuthSourceLdap. Conflicts: app/models/auth_source_ldap.rb config/locales/en.yml test/unit/auth_source_ldap_test.rb --- app/models/auth_source_ldap.rb | 24 ++++++++++++++--- app/views/ldap_auth_sources/_form.rhtml | 3 +++ config/locales/en.yml | 1 + ...10520_add_custom_filter_to_auth_sources.rb | 9 +++++++ test/unit/auth_source_ldap_test.rb | 26 +++++++++++++++++++ 5 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 db/migrate/20100217010520_add_custom_filter_to_auth_sources.rb diff --git a/app/models/auth_source_ldap.rb b/app/models/auth_source_ldap.rb index d009ae33..1e2bf243 100644 --- a/app/models/auth_source_ldap.rb +++ b/app/models/auth_source_ldap.rb @@ -101,10 +101,17 @@ class AuthSourceLdap < AuthSource 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 = {} + custom_ldap_filter = custom_filter_to_ldap - ldap_con.search( :base => self.base_dn, - :filter => object_filter & login_filter, + if custom_ldap_filter.present? + search_filters = object_filter & login_filter & custom_ldap_filter + else + search_filters = object_filter & login_filter + end + attrs = {} + + ldap_con.search( :base => self.base_dn, + :filter => search_filters, :attributes=> search_attributes) do |entry| if onthefly_register? @@ -119,6 +126,17 @@ class AuthSourceLdap < AuthSource attrs end + def custom_filter_to_ldap + return nil unless custom_filter.present? + + begin + return Net::LDAP::Filter.construct(custom_filter) + rescue Net::LDAP::LdapError # Filter syntax error + logger.debug "LDAP custom filter syntax error for: #{custom_filter}" if logger && logger.debug? + return nil + end + end + def self.get_attr(entry, attr_name) if !attr_name.blank? entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name] diff --git a/app/views/ldap_auth_sources/_form.rhtml b/app/views/ldap_auth_sources/_form.rhtml index 9ffffafc..ef0fd5b1 100644 --- a/app/views/ldap_auth_sources/_form.rhtml +++ b/app/views/ldap_auth_sources/_form.rhtml @@ -25,6 +25,9 @@

<%= check_box 'auth_source', 'onthefly_register' %>

+ +

+<%= text_field 'auth_source', 'custom_filter', :size => 60 %>

<%=l(:label_attribute_plural)%> diff --git a/config/locales/en.yml b/config/locales/en.yml index 8560fc8f..c89a1fa3 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -307,6 +307,7 @@ en: field_text: Text field field_visible: Visible field_warn_on_leaving_unsaved: "Warn me when leaving a page with unsaved text" + field_custom_ldap_filter: Custom LDAP filter setting_app_title: Application title setting_app_subtitle: Application subtitle diff --git a/db/migrate/20100217010520_add_custom_filter_to_auth_sources.rb b/db/migrate/20100217010520_add_custom_filter_to_auth_sources.rb new file mode 100644 index 00000000..8543c297 --- /dev/null +++ b/db/migrate/20100217010520_add_custom_filter_to_auth_sources.rb @@ -0,0 +1,9 @@ +class AddCustomFilterToAuthSources < ActiveRecord::Migration + def self.up + add_column :auth_sources, :custom_filter, :string + end + + def self.down + remove_column :auth_sources, :custom_filter + end +end diff --git a/test/unit/auth_source_ldap_test.rb b/test/unit/auth_source_ldap_test.rb index b383b906..9fcdace9 100644 --- a/test/unit/auth_source_ldap_test.rb +++ b/test/unit/auth_source_ldap_test.rb @@ -69,6 +69,32 @@ class AuthSourceLdapTest < ActiveSupport::TestCase end end + context "using a valid custom filter" do + setup do + @auth.update_attributes(:custom_filter => "(& (homeDirectory=*) (sn=O*))") + end + + should "find a user who authenticates and matches the custom filter" do + assert_not_nil @auth.authenticate('example1', '123456') + end + + should "be nil for users who don't match the custom filter" do + assert_nil @auth.authenticate('edavis', '123456') + end + end + + context "using an invalid custom filter" do + setup do + # missing )) at the end + @auth.update_attributes(:custom_filter => "(& (homeDirectory=*) (sn=O*") + end + + should "skip the custom filter" do + assert_not_nil @auth.authenticate('example1', '123456') + assert_not_nil @auth.authenticate('edavis', '123456') + end + end + end else puts '(Test LDAP server not configured)' From 0f8a040d28a3041fa86937fcfd4b2839934c05b2 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Tue, 12 Jul 2011 14:43:50 -0700 Subject: [PATCH 2/5] [#3619] Validate the AuthSourceLdap#custom_filter Conflicts: app/models/auth_source_ldap.rb test/unit/auth_source_ldap_test.rb --- app/models/auth_source_ldap.rb | 11 +++++++++++ test/unit/auth_source_ldap_test.rb | 14 ++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/app/models/auth_source_ldap.rb b/app/models/auth_source_ldap.rb index 1e2bf243..3536b4f6 100644 --- a/app/models/auth_source_ldap.rb +++ b/app/models/auth_source_ldap.rb @@ -21,6 +21,7 @@ class AuthSourceLdap < AuthSource validates_length_of :account, :account_password, :base_dn, :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 + validate :custom_filter_should_be_valid_ldap_filter_syntax before_validation :strip_ldap_attributes @@ -136,6 +137,16 @@ class AuthSourceLdap < AuthSource return nil end end + + def custom_filter_should_be_valid_ldap_filter_syntax + return true unless custom_filter.present? + + begin + return Net::LDAP::Filter.construct(custom_filter) + rescue Net::LDAP::LdapError # Filter syntax error + errors.add(:custom_filter, :invalid) + end + end def self.get_attr(entry, attr_name) if !attr_name.blank? diff --git a/test/unit/auth_source_ldap_test.rb b/test/unit/auth_source_ldap_test.rb index 9fcdace9..0effa103 100644 --- a/test/unit/auth_source_ldap_test.rb +++ b/test/unit/auth_source_ldap_test.rb @@ -31,6 +31,20 @@ class AuthSourceLdapTest < ActiveSupport::TestCase assert_equal 'givenName', a.reload.attr_firstname end + context "validations" do + should "validate that custom_filter is a valid LDAP filter" do + @auth = AuthSourceLdap.new(:name => 'Validation', :host => 'localhost', :port => 389, :attr_login => 'login') + @auth.custom_filter = "(& (homeDirectory=*) (sn=O*" # Missing (( + assert @auth.invalid? + assert_equal "is invalid", @auth.errors.on(:custom_filter) + + @auth.custom_filter = "(& (homeDirectory=*) (sn=O*))" + assert @auth.valid? + assert_equal nil, @auth.errors.on(:custom_filter) + + end + end + if ldap_configured? context '#authenticate' do setup do From 532c9cc55b4c8e957a6c90e8b1ccc74b02995fff Mon Sep 17 00:00:00 2001 From: elm Date: Mon, 12 Dec 2011 16:46:55 +0100 Subject: [PATCH 3/5] Use consistent naming to fix translation in error message --- app/views/ldap_auth_sources/_form.rhtml | 2 +- config/locales/en.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/ldap_auth_sources/_form.rhtml b/app/views/ldap_auth_sources/_form.rhtml index ef0fd5b1..8699a2cd 100644 --- a/app/views/ldap_auth_sources/_form.rhtml +++ b/app/views/ldap_auth_sources/_form.rhtml @@ -26,7 +26,7 @@

<%= check_box 'auth_source', 'onthefly_register' %>

-

+

<%= text_field 'auth_source', 'custom_filter', :size => 60 %>

diff --git a/config/locales/en.yml b/config/locales/en.yml index c89a1fa3..afce4f4c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -307,7 +307,7 @@ en: field_text: Text field field_visible: Visible field_warn_on_leaving_unsaved: "Warn me when leaving a page with unsaved text" - field_custom_ldap_filter: Custom LDAP filter + field_custom_filter: Custom LDAP filter setting_app_title: Application title setting_app_subtitle: Application subtitle From bf7bcec1da2fc94c60f97700bd091cc1a0d01b59 Mon Sep 17 00:00:00 2001 From: elm Date: Tue, 13 Dec 2011 19:38:33 +0100 Subject: [PATCH 4/5] Remove internal LDAP entries to make the ldif importable. --- test/fixtures/ldap/test-ldap.ldif | 42 ------------------------------- 1 file changed, 42 deletions(-) diff --git a/test/fixtures/ldap/test-ldap.ldif b/test/fixtures/ldap/test-ldap.ldif index 7d9e109c..8a4ce5aa 100644 --- a/test/fixtures/ldap/test-ldap.ldif +++ b/test/fixtures/ldap/test-ldap.ldif @@ -4,39 +4,11 @@ objectClass: dcObject objectClass: organization o: redmine.org dc: redmine -structuralObjectClass: organization -entryUUID: 886f5fca-0a87-102e-8d06-67c361d9bd2d -creatorsName: -createTimestamp: 20090721211642Z -entryCSN: 20090721211642.955188Z#000000#000#000000 -modifiersName: -modifyTimestamp: 20090721211642Z - -dn: cn=admin,dc=redmine,dc=org -objectClass: simpleSecurityObject -objectClass: organizationalRole -cn: admin -description: LDAP administrator -userPassword:: e2NyeXB0fWlWTU9DcUt6WWxXRDI= -structuralObjectClass: organizationalRole -entryUUID: 88704e44-0a87-102e-8d07-67c361d9bd2d -creatorsName: -createTimestamp: 20090721211642Z -entryCSN: 20090721211642.961418Z#000000#000#000000 -modifiersName: -modifyTimestamp: 20090721211642Z dn: ou=Person,dc=redmine,dc=org ou: Person objectClass: top objectClass: organizationalUnit -structuralObjectClass: organizationalUnit -entryUUID: d39dd388-0c84-102e-82fa-dff86c63a7d6 -creatorsName: cn=admin,dc=redmine,dc=org -createTimestamp: 20090724100222Z -entryCSN: 20090724100222.924226Z#000000#000#000000 -modifiersName: cn=admin,dc=redmine,dc=org -modifyTimestamp: 20090724100222Z dn: uid=example1,ou=Person,dc=redmine,dc=org objectClass: posixAccount @@ -48,16 +20,9 @@ sn: One uid: example1 homeDirectory: /home/example1 cn: Example One -structuralObjectClass: inetOrgPerson -entryUUID: 285d304e-0c8a-102e-82fc-dff86c63a7d6 -creatorsName: cn=admin,dc=redmine,dc=org -createTimestamp: 20090724104032Z uidNumber: 0 mail: example1@redmine.org userPassword:: e1NIQX1mRXFOQ2NvM1lxOWg1WlVnbEQzQ1pKVDRsQnM9 -entryCSN: 20090724105945.375801Z#000000#000#000000 -modifiersName: cn=admin,dc=redmine,dc=org -modifyTimestamp: 20090724105945Z dn: uid=edavis,ou=Person,dc=redmine,dc=org objectClass: posixAccount @@ -68,15 +33,8 @@ givenName: Eric sn: Davis uid: edavis mail: edavis@littlestreamsoftware.com -structuralObjectClass: inetOrgPerson -entryUUID: 9c5f0502-0c8b-102e-82fe-dff86c63a7d6 -creatorsName: cn=admin,dc=redmine,dc=org -createTimestamp: 20090724105056Z homeDirectory: /home/edavis cn: Eric Davis uidNumber: 0 userPassword:: e1NIQX1mRXFOQ2NvM1lxOWg1WlVnbEQzQ1pKVDRsQnM9 -entryCSN: 20090724105937.734480Z#000000#000#000000 -modifiersName: cn=admin,dc=redmine,dc=org -modifyTimestamp: 20090724105937Z From 48737b0c6f872e8d573c2758db33dfa423629c04 Mon Sep 17 00:00:00 2001 From: elm Date: Tue, 13 Dec 2011 19:39:56 +0100 Subject: [PATCH 5/5] Add OpenLDAP config ldif for redmine database --- test/fixtures/ldap/backend.redmine.org.ldif | 27 +++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 test/fixtures/ldap/backend.redmine.org.ldif diff --git a/test/fixtures/ldap/backend.redmine.org.ldif b/test/fixtures/ldap/backend.redmine.org.ldif new file mode 100644 index 00000000..b08dddbc --- /dev/null +++ b/test/fixtures/ldap/backend.redmine.org.ldif @@ -0,0 +1,27 @@ +# This is a configuration for a new database to test the ldap plugin. +# It is assumed that you have a ldap server up and running. Do not +# use this file on a new openldap installation. + +# Database settings +dn: olcDatabase=hdb,cn=config +objectClass: olcDatabaseConfig +objectClass: olcHdbConfig +olcDatabase: hdb +olcSuffix: dc=redmine,dc=org +# WARNING: Do not use a directory that already contains a ldap database. +# Each database has to be stored in a seperate directory. The directory +# /var/lib/ldap is the default directory on Debian. +olcDbDirectory: /var/lib/ldap/redmine +olcRootDN: cn=Manager,dc=redmine,dc=org +olcRootPW: secret +olcDbConfig: set_cachesize 0 2097152 0 +olcDbConfig: set_lk_max_objects 1500 +olcDbConfig: set_lk_max_locks 1500 +olcDbConfig: set_lk_max_lockers 1500 +olcDbIndex: objectClass eq +olcLastMod: TRUE +olcDbCheckpoint: 512 30 +olcAccess: to attrs=userPassword by dn="cn=Manager,dc=redmine,dc=org" write by anonymous auth by self write by * none +olcAccess: to attrs=shadowLastChange by self write by * read +olcAccess: to dn.base="" by * read +olcAccess: to * by dn="cn=Manager,dc=redmine,dc=org" write by * read