ldap_fluff 0.2.5 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ldap_fluff might be problematic. Click here for more details.

@@ -18,17 +18,23 @@ class LdapFluff
18
18
  end
19
19
  end
20
20
 
21
- # return true if the user password combination
22
- # authenticates the user, otherwise false
23
21
  def authenticate?(uid, password)
24
22
  if password.nil? || password.empty?
25
- # protect against passwordless auth from ldap server
26
- return false
23
+ false
27
24
  else
28
- @ldap.bind? uid, password
25
+ !!@ldap.bind?(uid, password)
29
26
  end
30
27
  end
31
28
 
29
+ def test
30
+ @ldap.ldap.open {}
31
+ end
32
+
33
+ # return a list[] of users for a given gid
34
+ def user_list(gid)
35
+ @ldap.users_for_gid(gid)
36
+ end
37
+
32
38
  # return a list[] of groups for a given uid
33
39
  def group_list(uid)
34
40
  @ldap.groups_for_uid(uid)
@@ -50,4 +56,13 @@ class LdapFluff
50
56
  @ldap.group_exists? gid
51
57
  end
52
58
 
59
+ # return ldap entry
60
+ def find_user(uid)
61
+ @ldap.member_service.find_user(uid)
62
+ end
63
+
64
+ # return ldap entry
65
+ def find_group(gid)
66
+ @ldap.member_service.find_group(gid)
67
+ end
53
68
  end
@@ -1,25 +1,14 @@
1
- class LdapFluff::Posix
2
-
3
- attr_accessor :ldap, :member_service
1
+ class LdapFluff::Posix < LdapFluff::Generic
4
2
 
5
3
  def initialize(config = {})
6
- @ldap = Net::LDAP.new(:host => config.host,
7
- :base => config.base_dn,
8
- :port => config.port,
9
- :encryption => config.encryption)
10
- @group_base = config.group_base || config.base_dn
11
4
  @base = config.base_dn
12
- @member_service = MemberService.new(@ldap, @group_base)
5
+ super
13
6
  end
14
7
 
15
8
  def bind?(uid = nil, password = nil)
16
9
  @ldap.bind_as(:filter => "(uid=#{uid})", :password => password)
17
10
  end
18
11
 
19
- def groups_for_uid(uid)
20
- @member_service.find_user_groups(uid)
21
- end
22
-
23
12
  # returns whether a user is a member of ALL or ANY particular groups
24
13
  # note: this method is much faster than groups_for_uid
25
14
  #
@@ -31,22 +20,23 @@ class LdapFluff::Posix
31
20
  (gids.empty? || @member_service.times_in_groups(uid, gids, all) > 0)
32
21
  end
33
22
 
34
- def user_exists?(uid)
35
- begin
36
- @member_service.find_user(uid)
37
- rescue MemberService::UIDNotFoundException
38
- return false
39
- end
40
- return true
41
- end
23
+ private
42
24
 
43
- def group_exists?(gid)
44
- begin
45
- @member_service.find_group(gid)
46
- rescue MemberService::GIDNotFoundException
47
- return false
25
+ def users_from_search_results(search, method)
26
+ # To find groups in standard LDAP without group membership attributes
27
+ # we have to look for OUs or posixGroups within the current group scope,
28
+ # i.e: cn=ldapusers,ou=groups,dc=example,dc=com -> cn=myusers,cn=ldapusers,ou=gr...
29
+
30
+ groups = @ldap.search(:base => search.dn,
31
+ :filter => Net::LDAP::Filter.eq('objectClass','posixGroup') |
32
+ Net::LDAP::Filter.eq('objectClass', 'organizationalunit'))
33
+
34
+ members = groups.map { |group| group.send(method) }.flatten.uniq
35
+
36
+ if method == :memberuid
37
+ members
38
+ else
39
+ @member_service.get_logins(members)
48
40
  end
49
- return true
50
41
  end
51
-
52
42
  end
@@ -1,37 +1,29 @@
1
1
  require 'net/ldap'
2
2
 
3
3
  # handles the naughty bits of posix ldap
4
- class LdapFluff::Posix::MemberService
4
+ class LdapFluff::Posix::MemberService < LdapFluff::GenericMemberService
5
5
 
6
- attr_accessor :ldap
6
+ def initialize(ldap, config)
7
+ @attr_login = (config.attr_login || 'memberuid')
8
+ super
9
+ end
7
10
 
8
- def initialize(ldap, group_base)
9
- @ldap = ldap
10
- @group_base = group_base
11
+ def find_user(uid)
12
+ user = @ldap.search(:filter => name_filter(uid), :base => @group_base)
13
+ raise UIDNotFoundException if (user.nil? || user.empty?)
14
+ user
11
15
  end
12
16
 
13
17
  # return an ldap user with groups attached
14
18
  # note : this method is not particularly fast for large ldap systems
15
19
  def find_user_groups(uid)
16
20
  groups = []
17
- find_user(uid).each do |entry|
21
+ @ldap.search(:filter => Net::LDAP::Filter.eq('memberuid', uid)).each do |entry|
18
22
  groups << entry[:cn][0]
19
23
  end
20
24
  groups
21
25
  end
22
26
 
23
- def find_user(uid)
24
- user = @ldap.search(:filter => name_filter(uid), :base => @group_base)
25
- raise UIDNotFoundException if (user.nil? || user.empty?)
26
- user
27
- end
28
-
29
- def find_group(gid)
30
- group = @ldap.search(:filter => group_filter(gid), :base => @group_base)
31
- raise GIDNotFoundException if (group.nil? || group.empty?)
32
- group
33
- end
34
-
35
27
  def times_in_groups(uid, gids, all)
36
28
  filters = []
37
29
  gids.each do |cn|
@@ -42,14 +34,6 @@ class LdapFluff::Posix::MemberService
42
34
  @ldap.search(:base => @group_base, :filter => filter).size
43
35
  end
44
36
 
45
- def name_filter(uid)
46
- Net::LDAP::Filter.eq("memberUid", uid)
47
- end
48
-
49
- def group_filter(cn)
50
- Net::LDAP::Filter.eq("cn", cn)
51
- end
52
-
53
37
  # AND or OR all of the filters together
54
38
  def merge_filters(filters = [], all = false)
55
39
  if !filters.nil? && filters.size >= 1
@@ -61,10 +45,10 @@ class LdapFluff::Posix::MemberService
61
45
  end
62
46
  end
63
47
 
64
- class UIDNotFoundException < StandardError
48
+ class UIDNotFoundException < LdapFluff::Error
65
49
  end
66
50
 
67
- class GIDNotFoundException < StandardError
51
+ class GIDNotFoundException < LdapFluff::Error
68
52
  end
69
53
 
70
54
  end
data/lib/ldap_fluff.rb CHANGED
@@ -1,5 +1,8 @@
1
+ require 'ldap_fluff/error'
1
2
  require 'ldap_fluff/config'
2
3
  require 'ldap_fluff/ldap_fluff'
4
+ require 'ldap_fluff/generic'
5
+ require 'ldap_fluff/generic_member_service'
3
6
  require 'ldap_fluff/active_directory'
4
7
  require 'ldap_fluff/ad_member_service'
5
8
  require 'ldap_fluff/posix'
@@ -4,9 +4,8 @@ class TestADMemberService < MiniTest::Test
4
4
  include LdapTestHelper
5
5
 
6
6
  def setup
7
- config
8
- @ldap = MiniTest::Mock.new
9
- @adms = LdapFluff::ActiveDirectory::MemberService.new(@ldap, @config.group_base)
7
+ super
8
+ @adms = LdapFluff::ActiveDirectory::MemberService.new(@ldap, @config)
10
9
  @gfilter = group_filter('group') & group_class_filter
11
10
  end
12
11
 
data/test/ad_test.rb CHANGED
@@ -4,40 +4,24 @@ class TestAD < MiniTest::Test
4
4
  include LdapTestHelper
5
5
 
6
6
  def setup
7
- config
7
+ super
8
8
  @ad = LdapFluff::ActiveDirectory.new(@config)
9
- @ldap = MiniTest::Mock.new
10
9
  end
11
10
 
12
11
  # default setup for service bind users
13
12
  def service_bind
14
- @ldap.expect(:auth, nil, %w(service@internet.com pass))
15
- @ldap.expect(:bind, true)
16
- @ad.ldap = @ldap
17
- end
18
-
19
- def basic_user
20
- @md = MiniTest::Mock.new
21
- @md.expect(:find_user_groups, %w(bros), %w(john))
22
- @ad.member_service = @md
23
- end
24
-
25
- def bigtime_user
26
- @md = MiniTest::Mock.new
27
- @md.expect(:find_user_groups, %w(bros broskies), %w(john))
28
- @ad.member_service = @md
13
+ @ldap.expect(:auth, nil, %w(service pass))
14
+ super
29
15
  end
30
16
 
31
17
  def test_good_bind
32
- @ldap.expect(:auth, nil, %w(internet@internet.com password))
33
- @ldap.expect(:bind, true)
34
- @ad.ldap = @ldap
35
- assert_equal(@ad.bind?("internet", "password"), true)
18
+ service_bind
19
+ assert_equal(@ad.bind?('service', 'pass'), true)
36
20
  @ldap.verify
37
21
  end
38
22
 
39
23
  def test_bad_bind
40
- @ldap.expect(:auth, nil, %w(internet@internet.com password))
24
+ @ldap.expect(:auth, nil, %w(internet password))
41
25
  @ldap.expect(:bind, false)
42
26
  @ad.ldap = @ldap
43
27
  assert_equal(@ad.bind?("internet", "password"), false)
@@ -52,20 +36,20 @@ class TestAD < MiniTest::Test
52
36
 
53
37
  def test_bad_user
54
38
  service_bind
55
- @md = MiniTest::Mock.new
56
- @md.expect(:find_user_groups, nil, %w(john))
57
- def @md.find_user_groups(*args)
39
+ md = MiniTest::Mock.new
40
+ md.expect(:find_user_groups, nil, %w(john))
41
+ def md.find_user_groups(*args)
58
42
  raise LdapFluff::ActiveDirectory::MemberService::UIDNotFoundException
59
43
  end
60
- @ad.member_service = @md
44
+ @ad.member_service = md
61
45
  assert_equal(@ad.groups_for_uid('john'), [])
62
46
  end
63
47
 
64
48
  def test_bad_service_user
65
- @ldap.expect(:auth, nil, %w(service@internet.com pass))
49
+ @ldap.expect(:auth, nil, %w(service pass))
66
50
  @ldap.expect(:bind, false)
67
51
  @ad.ldap = @ldap
68
- assert_raises(LdapFluff::ActiveDirectory::UnauthenticatedActiveDirectoryException) do
52
+ assert_raises(LdapFluff::ActiveDirectory::UnauthenticatedException) do
69
53
  @ad.groups_for_uid('john')
70
54
  end
71
55
  end
@@ -101,41 +85,63 @@ class TestAD < MiniTest::Test
101
85
  end
102
86
 
103
87
  def test_user_exists
104
- @md = MiniTest::Mock.new
105
- @md.expect(:find_user, 'notnilluser', %w(john))
106
- @ad.member_service = @md
88
+ md = MiniTest::Mock.new
89
+ md.expect(:find_user, 'notnilluser', %w(john))
90
+ @ad.member_service = md
107
91
  service_bind
108
92
  assert(@ad.user_exists?('john'))
109
93
  end
110
94
 
111
95
  def test_missing_user
112
- @md = MiniTest::Mock.new
113
- @md.expect(:find_user, nil, %w(john))
114
- def @md.find_user(uid)
96
+ md = MiniTest::Mock.new
97
+ md.expect(:find_user, nil, %w(john))
98
+ def md.find_user(uid)
115
99
  raise LdapFluff::ActiveDirectory::MemberService::UIDNotFoundException
116
100
  end
117
- @ad.member_service = @md
101
+ @ad.member_service = md
118
102
  service_bind
119
103
  refute(@ad.user_exists?('john'))
120
104
  end
121
105
 
122
106
  def test_group_exists
123
- @md = MiniTest::Mock.new
124
- @md.expect(:find_group, 'notnillgroup', %w(broskies))
125
- @ad.member_service = @md
107
+ md = MiniTest::Mock.new
108
+ md.expect(:find_group, 'notnillgroup', %w(broskies))
109
+ @ad.member_service = md
126
110
  service_bind
127
111
  assert(@ad.group_exists?('broskies'))
128
112
  end
129
113
 
130
114
  def test_missing_group
131
- @md = MiniTest::Mock.new
132
- @md.expect(:find_group, nil, %w(broskies))
133
- def @md.find_group(uid)
115
+ md = MiniTest::Mock.new
116
+ md.expect(:find_group, nil, %w(broskies))
117
+ def md.find_group(uid)
134
118
  raise LdapFluff::ActiveDirectory::MemberService::GIDNotFoundException
135
119
  end
136
- @ad.member_service = @md
120
+ @ad.member_service = md
137
121
  service_bind
138
122
  refute(@ad.group_exists?('broskies'))
139
123
  end
140
124
 
125
+ def test_find_users_in_nested_groups
126
+ group = Net::LDAP::Entry.new('foremaners')
127
+ nested_group = Net::LDAP::Entry.new('katellers')
128
+ nested_user = Net::LDAP::Entry.new('testuser')
129
+
130
+ group[:member] = ['CN=katellers,DC=corp,DC=windows,DC=com']
131
+ nested_group[:member] = ['CN=testuser,CN=Users,DC=corp,DC=windows,DC=com']
132
+ nested_group[:objectclass] = ['organizationalunit']
133
+ nested_user[:objectclass] = ['person']
134
+
135
+ md = MiniTest::Mock.new
136
+ 2.times { md.expect(:find_group, [group], ['foremaners']) }
137
+ 2.times { md.expect(:find_group, [nested_group], ['katellers']) }
138
+ 2.times { service_bind }
139
+
140
+ md.expect(:find_user, [nested_group], ['katellers'])
141
+ md.expect(:find_user, [nested_user], ['testuser'])
142
+ md.expect(:get_logins, 'testuser', [nested_group.member])
143
+ @ad.member_service = md
144
+ assert_equal @ad.users_for_gid('foremaners'), ['testuser']
145
+ end
146
+
141
147
  end
data/test/config_test.rb CHANGED
@@ -4,7 +4,7 @@ class ConfigTest < MiniTest::Test
4
4
  include LdapTestHelper
5
5
 
6
6
  def test_unsupported_type
7
- assert_raises(LdapFluff::ConfigError) { LdapFluff.new(config_hash.update :server_type => 'inactive_directory') }
7
+ assert_raises(LdapFluff::Config::ConfigError) { LdapFluff.new(config_hash.update :server_type => 'inactive_directory') }
8
8
  end
9
9
 
10
10
  def test_load_posix
@@ -4,9 +4,8 @@ class TestIPAMemberService < MiniTest::Test
4
4
  include LdapTestHelper
5
5
 
6
6
  def setup
7
- config
8
- @ldap = MiniTest::Mock.new
9
- @ipams = LdapFluff::FreeIPA::MemberService.new(@ldap, @config.group_base)
7
+ super
8
+ @ipams = LdapFluff::FreeIPA::MemberService.new(@ldap, @config)
10
9
  end
11
10
 
12
11
  def basic_user
data/test/ipa_test.rb CHANGED
@@ -4,35 +4,19 @@ class TestIPA < MiniTest::Test
4
4
  include LdapTestHelper
5
5
 
6
6
  def setup
7
- config
8
- @ipa = LdapFluff::FreeIPA.new(@config)
9
- @ldap = MiniTest::Mock.new
7
+ super
8
+ @ipa = LdapFluff::FreeIPA.new(@config)
10
9
  end
11
10
 
12
11
  # default setup for service bind users
13
12
  def service_bind
14
13
  @ldap.expect(:auth, nil, [ipa_user_bind('service'), "pass"])
15
- @ldap.expect(:bind, true)
16
- @ipa.ldap = @ldap
17
- end
18
-
19
- def basic_user
20
- @md = MiniTest::Mock.new
21
- @md.expect(:find_user_groups, %w(bros), %w(john))
22
- @ipa.member_service = @md
23
- end
24
-
25
- def bigtime_user
26
- @md = MiniTest::Mock.new
27
- @md.expect(:find_user_groups, %w(bros broskies), %w(john))
28
- @ipa.member_service = @md
14
+ super
29
15
  end
30
16
 
31
17
  def test_good_bind
32
- @ldap.expect(:auth, nil, [ipa_user_bind('internet'), "password"])
33
- @ldap.expect(:bind, true)
34
- @ipa.ldap = @ldap
35
- assert_equal(@ipa.bind?("internet", "password"), true)
18
+ service_bind
19
+ assert_equal(@ipa.bind?('service', 'pass'), true)
36
20
  @ldap.verify
37
21
  end
38
22
 
@@ -65,7 +49,7 @@ class TestIPA < MiniTest::Test
65
49
  @ldap.expect(:auth, nil, [ipa_user_bind('service'), "pass"])
66
50
  @ldap.expect(:bind, false)
67
51
  @ipa.ldap = @ldap
68
- assert_raises(LdapFluff::FreeIPA::UnauthenticatedFreeIPAException) do
52
+ assert_raises(LdapFluff::FreeIPA::UnauthenticatedException) do
69
53
  @ipa.groups_for_uid('john')
70
54
  end
71
55
  end
@@ -138,5 +122,23 @@ class TestIPA < MiniTest::Test
138
122
  refute(@ipa.group_exists?('broskies'))
139
123
  end
140
124
 
125
+ def test_find_users_in_nested_groups
126
+ group = Net::LDAP::Entry.new('gid=foremaners,cn=Groups,cn=accounts,dc=localdomain')
127
+ group[:member] = ['gid=katellers,cn=Groups,cn=accounts,dc=localdomain']
128
+ nested_group = Net::LDAP::Entry.new('gid=katellers,cn=Groups,cn=accounts,dc=localdomain')
129
+ nested_group[:member] = ['uid=testuser,cn=users,cn=accounts,dc=localdomain']
130
+
131
+ md = MiniTest::Mock.new
132
+ 2.times { md.expect(:find_group, [group], ['foremaners']) }
133
+ 2.times { md.expect(:find_group, [nested_group], ['katellers']) }
134
+ 2.times { service_bind }
135
+ md.expect(:get_logins, ['testuser'], [['uid=testuser,cn=users,cn=accounts,dc=localdomain']])
136
+
137
+ @ipa.member_service = md
138
+
139
+ assert_equal @ipa.users_for_gid('foremaners'), ['testuser']
140
+ md.verify
141
+ end
142
+
141
143
  end
142
144
 
data/test/ldap_test.rb CHANGED
@@ -4,8 +4,7 @@ class TestLDAP < MiniTest::Test
4
4
  include LdapTestHelper
5
5
 
6
6
  def setup
7
- config
8
- @ldap = MiniTest::Mock.new
7
+ super
9
8
  @fluff = LdapFluff.new(config_hash)
10
9
  end
11
10
 
@@ -7,22 +7,45 @@ module LdapTestHelper
7
7
  attr_accessor :group_base, :class_filter, :user
8
8
 
9
9
  def config_hash
10
- { :host => "internet.com",
11
- :port => "387",
12
- :encryption => :start_tls,
13
- :base_dn => "dc=internet,dc=com",
14
- :group_base => "ou=group,dc=internet,dc=com",
15
- :service_user => "service",
16
- :service_pass => "pass",
17
- :ad_domain => "internet.com",
18
- :server_type => :free_ipa
10
+ { :host => "internet.com",
11
+ :port => "387",
12
+ :encryption => :start_tls,
13
+ :base_dn => "dc=internet,dc=com",
14
+ :group_base => "ou=group,dc=internet,dc=com",
15
+ :service_user => "service",
16
+ :service_pass => "pass",
17
+ :server_type => :free_ipa,
18
+ :attr_login => nil,
19
+ :search_filter => nil
19
20
  }
20
21
  end
21
22
 
23
+ def setup
24
+ config
25
+ @ldap = MiniTest::Mock.new
26
+ end
27
+
22
28
  def config
23
29
  @config ||= LdapFluff::Config.new config_hash
24
30
  end
25
31
 
32
+ def service_bind
33
+ @ldap.expect(:bind, true)
34
+ get_test_instance_variable.ldap = @ldap
35
+ end
36
+
37
+ def basic_user
38
+ @md = MiniTest::Mock.new
39
+ @md.expect(:find_user_groups, %w(bros), %w(john))
40
+ get_test_instance_variable.member_service = @md
41
+ end
42
+
43
+ def bigtime_user
44
+ @md = MiniTest::Mock.new
45
+ @md.expect(:find_user_groups, %w(bros broskies), %w(john))
46
+ get_test_instance_variable.member_service = @md
47
+ end
48
+
26
49
  def ad_name_filter(name)
27
50
  Net::LDAP::Filter.eq("samaccountname", name)
28
51
  end
@@ -52,19 +75,19 @@ module LdapTestHelper
52
75
  end
53
76
 
54
77
  def ad_user_payload
55
- [{ :memberof => ["CN=group,dc=internet,dc=com"] }]
78
+ [{ :memberof => ["cn=group,dc=internet,dc=com"] }]
56
79
  end
57
80
 
58
81
  def ad_group_payload
59
- [{ :cn => "broze", :memberof => ["CN=group,dc=internet,dc=com"] }]
82
+ [{ :cn => "broze", :memberof => ["cn=group,dc=internet,dc=com"] }]
60
83
  end
61
84
 
62
85
  def ad_parent_payload(num)
63
- [{ :memberof => ["CN=bros#{num},dc=internet,dc=com"] }]
86
+ [{ :memberof => ["cn=bros#{num},dc=internet,dc=com"] }]
64
87
  end
65
88
 
66
89
  def ad_double_payload(num)
67
- [{ :memberof => ["CN=bros#{num},dc=internet,dc=com", "CN=broskies#{num},dc=internet,dc=com"] }]
90
+ [{ :memberof => ["cn=bros#{num},dc=internet,dc=com", "cn=broskies#{num},dc=internet,dc=com"] }]
68
91
  end
69
92
 
70
93
  def posix_user_payload
@@ -82,4 +105,10 @@ module LdapTestHelper
82
105
  def ipa_group_payload
83
106
  [{ :cn => 'group' }, { :memberof => ['cn=group,dc=internet,dc=com', 'cn=bros,dc=internet,dc=com'] }]
84
107
  end
108
+
109
+ private
110
+
111
+ def get_test_instance_variable
112
+ instance_variable_get("@#{self.class.to_s.underscore.split('_')[1..-1].join}")
113
+ end
85
114
  end
@@ -4,9 +4,8 @@ class TestPosixMemberService < MiniTest::Test
4
4
  include LdapTestHelper
5
5
 
6
6
  def setup
7
- config
8
- @ldap = MiniTest::Mock.new
9
- @ms = LdapFluff::Posix::MemberService.new(@ldap, @config.group_base)
7
+ super
8
+ @ms = LdapFluff::Posix::MemberService.new(@ldap, @config)
10
9
  end
11
10
 
12
11
  def test_find_user
@@ -14,6 +13,14 @@ class TestPosixMemberService < MiniTest::Test
14
13
  @ldap.expect(:search, user, [:filter => @ms.name_filter('john'),
15
14
  :base => config.group_base])
16
15
  @ms.ldap = @ldap
16
+ assert_equal posix_user_payload, @ms.find_user('john')
17
+ @ldap.verify
18
+ end
19
+
20
+ def test_find_user_groups
21
+ user = posix_user_payload
22
+ @ldap.expect(:search, user, [:filter => @ms.name_filter('john')])
23
+ @ms.ldap = @ldap
17
24
  assert_equal ['bros'], @ms.find_user_groups('john')
18
25
  @ldap.verify
19
26
  end