Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Merge pull request #142 from elm/custom-ldap-filter

[#388] Custom LDAP filter
  • Loading branch information...
commit 44cf67032f23a58d23e8532f9b45e49474d9a20e 2 parents b135162 + 48737b0
Felix Schäfer thegcat authored
35 app/models/auth_source_ldap.rb
@@ -21,6 +21,7 @@ class AuthSourceLdap < AuthSource
21 21 validates_length_of :account, :account_password, :base_dn, :maximum => 255, :allow_nil => true
22 22 validates_length_of :attr_login, :attr_firstname, :attr_lastname, :attr_mail, :maximum => 30, :allow_nil => true
23 23 validates_numericality_of :port, :only_integer => true
  24 + validate :custom_filter_should_be_valid_ldap_filter_syntax
24 25
25 26 before_validation :strip_ldap_attributes
26 27
@@ -101,10 +102,17 @@ def get_user_dn(login)
101 102 ldap_con = initialize_ldap_con(self.account, self.account_password)
102 103 login_filter = Net::LDAP::Filter.eq( self.attr_login, login )
103 104 object_filter = Net::LDAP::Filter.eq( "objectClass", "*" )
104   - attrs = {}
  105 + custom_ldap_filter = custom_filter_to_ldap
105 106
106   - ldap_con.search( :base => self.base_dn,
107   - :filter => object_filter & login_filter,
  107 + if custom_ldap_filter.present?
  108 + search_filters = object_filter & login_filter & custom_ldap_filter
  109 + else
  110 + search_filters = object_filter & login_filter
  111 + end
  112 + attrs = {}
  113 +
  114 + ldap_con.search( :base => self.base_dn,
  115 + :filter => search_filters,
108 116 :attributes=> search_attributes) do |entry|
109 117
110 118 if onthefly_register?
@@ -119,6 +127,27 @@ def get_user_dn(login)
119 127 attrs
120 128 end
121 129
  130 + def custom_filter_to_ldap
  131 + return nil unless custom_filter.present?
  132 +
  133 + begin
  134 + return Net::LDAP::Filter.construct(custom_filter)
  135 + rescue Net::LDAP::LdapError # Filter syntax error
  136 + logger.debug "LDAP custom filter syntax error for: #{custom_filter}" if logger && logger.debug?
  137 + return nil
  138 + end
  139 + end
  140 +
  141 + def custom_filter_should_be_valid_ldap_filter_syntax
  142 + return true unless custom_filter.present?
  143 +
  144 + begin
  145 + return Net::LDAP::Filter.construct(custom_filter)
  146 + rescue Net::LDAP::LdapError # Filter syntax error
  147 + errors.add(:custom_filter, :invalid)
  148 + end
  149 + end
  150 +
122 151 def self.get_attr(entry, attr_name)
123 152 if !attr_name.blank?
124 153 entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name]
3  app/views/ldap_auth_sources/_form.rhtml
@@ -25,6 +25,9 @@
25 25
26 26 <p><label for="auth_source_onthefly_register"><%=l(:field_onthefly)%></label>
27 27 <%= check_box 'auth_source', 'onthefly_register' %></p>
  28 +
  29 +<p><label for="auth_source_custom_filter"><%=l(:field_custom_filter)%></label>
  30 +<%= text_field 'auth_source', 'custom_filter', :size => 60 %></p>
28 31 </div>
29 32
30 33 <fieldset class="box"><legend><%=l(:label_attribute_plural)%></legend>
1  config/locales/en.yml
@@ -307,6 +307,7 @@ en:
307 307 field_text: Text field
308 308 field_visible: Visible
309 309 field_warn_on_leaving_unsaved: "Warn me when leaving a page with unsaved text"
  310 + field_custom_filter: Custom LDAP filter
310 311
311 312 setting_app_title: Application title
312 313 setting_app_subtitle: Application subtitle
9 db/migrate/20100217010520_add_custom_filter_to_auth_sources.rb
... ... @@ -0,0 +1,9 @@
  1 +class AddCustomFilterToAuthSources < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :auth_sources, :custom_filter, :string
  4 + end
  5 +
  6 + def self.down
  7 + remove_column :auth_sources, :custom_filter
  8 + end
  9 +end
27 test/fixtures/ldap/backend.redmine.org.ldif
... ... @@ -0,0 +1,27 @@
  1 +# This is a configuration for a new database to test the ldap plugin.
  2 +# It is assumed that you have a ldap server up and running. Do not
  3 +# use this file on a new openldap installation.
  4 +
  5 +# Database settings
  6 +dn: olcDatabase=hdb,cn=config
  7 +objectClass: olcDatabaseConfig
  8 +objectClass: olcHdbConfig
  9 +olcDatabase: hdb
  10 +olcSuffix: dc=redmine,dc=org
  11 +# WARNING: Do not use a directory that already contains a ldap database.
  12 +# Each database has to be stored in a seperate directory. The directory
  13 +# /var/lib/ldap is the default directory on Debian.
  14 +olcDbDirectory: /var/lib/ldap/redmine
  15 +olcRootDN: cn=Manager,dc=redmine,dc=org
  16 +olcRootPW: secret
  17 +olcDbConfig: set_cachesize 0 2097152 0
  18 +olcDbConfig: set_lk_max_objects 1500
  19 +olcDbConfig: set_lk_max_locks 1500
  20 +olcDbConfig: set_lk_max_lockers 1500
  21 +olcDbIndex: objectClass eq
  22 +olcLastMod: TRUE
  23 +olcDbCheckpoint: 512 30
  24 +olcAccess: to attrs=userPassword by dn="cn=Manager,dc=redmine,dc=org" write by anonymous auth by self write by * none
  25 +olcAccess: to attrs=shadowLastChange by self write by * read
  26 +olcAccess: to dn.base="" by * read
  27 +olcAccess: to * by dn="cn=Manager,dc=redmine,dc=org" write by * read
42 test/fixtures/ldap/test-ldap.ldif
@@ -4,39 +4,11 @@ objectClass: dcObject
4 4 objectClass: organization
5 5 o: redmine.org
6 6 dc: redmine
7   -structuralObjectClass: organization
8   -entryUUID: 886f5fca-0a87-102e-8d06-67c361d9bd2d
9   -creatorsName:
10   -createTimestamp: 20090721211642Z
11   -entryCSN: 20090721211642.955188Z#000000#000#000000
12   -modifiersName:
13   -modifyTimestamp: 20090721211642Z
14   -
15   -dn: cn=admin,dc=redmine,dc=org
16   -objectClass: simpleSecurityObject
17   -objectClass: organizationalRole
18   -cn: admin
19   -description: LDAP administrator
20   -userPassword:: e2NyeXB0fWlWTU9DcUt6WWxXRDI=
21   -structuralObjectClass: organizationalRole
22   -entryUUID: 88704e44-0a87-102e-8d07-67c361d9bd2d
23   -creatorsName:
24   -createTimestamp: 20090721211642Z
25   -entryCSN: 20090721211642.961418Z#000000#000#000000
26   -modifiersName:
27   -modifyTimestamp: 20090721211642Z
28 7
29 8 dn: ou=Person,dc=redmine,dc=org
30 9 ou: Person
31 10 objectClass: top
32 11 objectClass: organizationalUnit
33   -structuralObjectClass: organizationalUnit
34   -entryUUID: d39dd388-0c84-102e-82fa-dff86c63a7d6
35   -creatorsName: cn=admin,dc=redmine,dc=org
36   -createTimestamp: 20090724100222Z
37   -entryCSN: 20090724100222.924226Z#000000#000#000000
38   -modifiersName: cn=admin,dc=redmine,dc=org
39   -modifyTimestamp: 20090724100222Z
40 12
41 13 dn: uid=example1,ou=Person,dc=redmine,dc=org
42 14 objectClass: posixAccount
@@ -48,16 +20,9 @@ sn: One
48 20 uid: example1
49 21 homeDirectory: /home/example1
50 22 cn: Example One
51   -structuralObjectClass: inetOrgPerson
52   -entryUUID: 285d304e-0c8a-102e-82fc-dff86c63a7d6
53   -creatorsName: cn=admin,dc=redmine,dc=org
54   -createTimestamp: 20090724104032Z
55 23 uidNumber: 0
56 24 mail: example1@redmine.org
57 25 userPassword:: e1NIQX1mRXFOQ2NvM1lxOWg1WlVnbEQzQ1pKVDRsQnM9
58   -entryCSN: 20090724105945.375801Z#000000#000#000000
59   -modifiersName: cn=admin,dc=redmine,dc=org
60   -modifyTimestamp: 20090724105945Z
61 26
62 27 dn: uid=edavis,ou=Person,dc=redmine,dc=org
63 28 objectClass: posixAccount
@@ -68,15 +33,8 @@ givenName: Eric
68 33 sn: Davis
69 34 uid: edavis
70 35 mail: edavis@littlestreamsoftware.com
71   -structuralObjectClass: inetOrgPerson
72   -entryUUID: 9c5f0502-0c8b-102e-82fe-dff86c63a7d6
73   -creatorsName: cn=admin,dc=redmine,dc=org
74   -createTimestamp: 20090724105056Z
75 36 homeDirectory: /home/edavis
76 37 cn: Eric Davis
77 38 uidNumber: 0
78 39 userPassword:: e1NIQX1mRXFOQ2NvM1lxOWg1WlVnbEQzQ1pKVDRsQnM9
79   -entryCSN: 20090724105937.734480Z#000000#000#000000
80   -modifiersName: cn=admin,dc=redmine,dc=org
81   -modifyTimestamp: 20090724105937Z
82 40
40 test/unit/auth_source_ldap_test.rb
@@ -31,6 +31,20 @@ def test_should_strip_ldap_attributes
31 31 assert_equal 'givenName', a.reload.attr_firstname
32 32 end
33 33
  34 + context "validations" do
  35 + should "validate that custom_filter is a valid LDAP filter" do
  36 + @auth = AuthSourceLdap.new(:name => 'Validation', :host => 'localhost', :port => 389, :attr_login => 'login')
  37 + @auth.custom_filter = "(& (homeDirectory=*) (sn=O*" # Missing ((
  38 + assert @auth.invalid?
  39 + assert_equal "is invalid", @auth.errors.on(:custom_filter)
  40 +
  41 + @auth.custom_filter = "(& (homeDirectory=*) (sn=O*))"
  42 + assert @auth.valid?
  43 + assert_equal nil, @auth.errors.on(:custom_filter)
  44 +
  45 + end
  46 + end
  47 +
34 48 if ldap_configured?
35 49 context '#authenticate' do
36 50 setup do
@@ -69,6 +83,32 @@ def test_should_strip_ldap_attributes
69 83 end
70 84 end
71 85
  86 + context "using a valid custom filter" do
  87 + setup do
  88 + @auth.update_attributes(:custom_filter => "(& (homeDirectory=*) (sn=O*))")
  89 + end
  90 +
  91 + should "find a user who authenticates and matches the custom filter" do
  92 + assert_not_nil @auth.authenticate('example1', '123456')
  93 + end
  94 +
  95 + should "be nil for users who don't match the custom filter" do
  96 + assert_nil @auth.authenticate('edavis', '123456')
  97 + end
  98 + end
  99 +
  100 + context "using an invalid custom filter" do
  101 + setup do
  102 + # missing )) at the end
  103 + @auth.update_attributes(:custom_filter => "(& (homeDirectory=*) (sn=O*")
  104 + end
  105 +
  106 + should "skip the custom filter" do
  107 + assert_not_nil @auth.authenticate('example1', '123456')
  108 + assert_not_nil @auth.authenticate('edavis', '123456')
  109 + end
  110 + end
  111 +
72 112 end
73 113 else
74 114 puts '(Test LDAP server not configured)'

0 comments on commit 44cf670

Please sign in to comment.
Something went wrong with that request. Please try again.