ldap_fluff 0.4.4 → 0.6.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.
@@ -1,17 +1,17 @@
1
1
  require 'net/ldap'
2
2
 
3
3
  class LdapFluff::GenericMemberService
4
-
5
4
  attr_accessor :ldap
6
5
 
7
6
  def initialize(ldap, config)
8
7
  @ldap = ldap
9
8
  @base = config.base_dn
10
9
  @group_base = (config.group_base.empty? ? config.base_dn : config.group_base)
10
+ @search_filter = nil
11
11
  begin
12
12
  @search_filter = Net::LDAP::Filter.construct(config.search_filter) unless (config.search_filter.nil? || config.search_filter.empty?)
13
- rescue Net::LDAP::LdapError => error
14
- puts "Search filter unavailable - #{error}"
13
+ rescue Net::LDAP::Error => e
14
+ puts "Search filter unavailable - #{e}"
15
15
  end
16
16
  end
17
17
 
@@ -57,6 +57,11 @@ class LdapFluff::GenericMemberService
57
57
  grouplist.map(&:downcase).collect { |g| g.sub(/.*?cn=(.*?),.*/, '\1') }
58
58
  end
59
59
 
60
+ def get_netgroup_users(netgroup_triples)
61
+ return [] if netgroup_triples.nil?
62
+ netgroup_triples.map { |m| m.split(',')[1] }
63
+ end
64
+
60
65
  def get_logins(userlist)
61
66
  userlist.map(&:downcase!)
62
67
  [@attr_login, 'uid', 'cn'].map do |attribute|
@@ -75,5 +80,4 @@ class LdapFluff::GenericMemberService
75
80
  end
76
81
  nil
77
82
  end
78
-
79
83
  end
@@ -20,7 +20,7 @@ class LdapFluff
20
20
  end
21
21
 
22
22
  def authenticate?(uid, password)
23
- instrument('authenticate.ldap_fluff', :uid => uid) do |payload|
23
+ instrument('authenticate.ldap_fluff', :uid => uid) do |_payload|
24
24
  if password.nil? || password.empty?
25
25
  false
26
26
  else
@@ -30,21 +30,21 @@ class LdapFluff
30
30
  end
31
31
 
32
32
  def test
33
- instrument('test.ldap_fluff') do |payload|
33
+ instrument('test.ldap_fluff') do |_payload|
34
34
  @ldap.ldap.open {}
35
35
  end
36
36
  end
37
37
 
38
38
  # return a list[] of users for a given gid
39
39
  def user_list(gid)
40
- instrument('user_list.ldap_fluff', :gid => gid) do |payload|
40
+ instrument('user_list.ldap_fluff', :gid => gid) do |_payload|
41
41
  @ldap.users_for_gid(gid)
42
42
  end
43
43
  end
44
44
 
45
45
  # return a list[] of groups for a given uid
46
46
  def group_list(uid)
47
- instrument('group_list.ldap_fluff', :uid => uid) do |payload|
47
+ instrument('group_list.ldap_fluff', :uid => uid) do |_payload|
48
48
  @ldap.groups_for_uid(uid)
49
49
  end
50
50
  end
@@ -52,35 +52,35 @@ class LdapFluff
52
52
  # return true if a user is in all of the groups
53
53
  # in grouplist
54
54
  def is_in_groups?(uid, grouplist)
55
- instrument('is_in_groups?.ldap_fluff', :uid => uid, :grouplist => grouplist) do |payload|
55
+ instrument('is_in_groups?.ldap_fluff', :uid => uid, :grouplist => grouplist) do |_payload|
56
56
  @ldap.is_in_groups(uid, grouplist, true)
57
57
  end
58
58
  end
59
59
 
60
60
  # return true if uid exists
61
61
  def valid_user?(uid)
62
- instrument('valid_user?.ldap_fluff', :uid => uid) do |payload|
62
+ instrument('valid_user?.ldap_fluff', :uid => uid) do |_payload|
63
63
  @ldap.user_exists? uid
64
64
  end
65
65
  end
66
66
 
67
67
  # return true if group exists
68
68
  def valid_group?(gid)
69
- instrument('valid_group?.ldap_fluff', :gid => gid) do |payload|
69
+ instrument('valid_group?.ldap_fluff', :gid => gid) do |_payload|
70
70
  @ldap.group_exists? gid
71
71
  end
72
72
  end
73
73
 
74
74
  # return ldap entry
75
75
  def find_user(uid)
76
- instrument('find_user.ldap_fluff', :uid => uid) do |payload|
76
+ instrument('find_user.ldap_fluff', :uid => uid) do |_payload|
77
77
  @ldap.member_service.find_user(uid)
78
78
  end
79
79
  end
80
80
 
81
81
  # return ldap entry
82
82
  def find_group(gid)
83
- instrument('find_group.ldap_fluff', :gid => gid) do |payload|
83
+ instrument('find_group.ldap_fluff', :gid => gid) do |_payload|
84
84
  @ldap.member_service.find_group(gid)
85
85
  end
86
86
  end
@@ -1,27 +1,14 @@
1
1
  class LdapFluff::Posix < LdapFluff::Generic
2
-
3
2
  def bind?(uid = nil, password = nil, opts = {})
4
3
  unless uid.include?(',') || opts[:search] == false
5
4
  service_bind
6
5
  user = @member_service.find_user(uid)
7
- uid = user.first.dn if user && user.first
6
+ uid = user.first.dn if user&.first
8
7
  end
9
8
  @ldap.auth(uid, password)
10
9
  @ldap.bind
11
10
  end
12
11
 
13
- # returns whether a user is a member of ALL or ANY particular groups
14
- # note: this method is much faster than groups_for_uid
15
- #
16
- # gids should be an array of group common names
17
- #
18
- # returns true if owner is in ALL of the groups if all=true, otherwise
19
- # returns true if owner is in ANY of the groups
20
- def is_in_groups(uid, gids = [], all = true)
21
- service_bind
22
- (gids.empty? || @member_service.times_in_groups(uid, gids, all) > 0)
23
- end
24
-
25
12
  private
26
13
 
27
14
  def users_from_search_results(search, method)
@@ -29,16 +16,21 @@ class LdapFluff::Posix < LdapFluff::Generic
29
16
  # we have to look for OUs or posixGroups within the current group scope,
30
17
  # i.e: cn=ldapusers,ou=groups,dc=example,dc=com -> cn=myusers,cn=ldapusers,ou=gr...
31
18
 
32
- groups = @ldap.search(:base => search.dn,
33
- :filter => Net::LDAP::Filter.eq('objectClass','posixGroup') |
34
- Net::LDAP::Filter.eq('objectClass', 'organizationalunit') |
35
- Net::LDAP::Filter.eq('objectClass', 'groupOfUniqueNames') |
36
- Net::LDAP::Filter.eq('objectClass', 'groupOfNames'))
37
-
19
+ filter = if @use_netgroups
20
+ Net::LDAP::Filter.eq('objectClass', 'nisNetgroup')
21
+ else
22
+ Net::LDAP::Filter.eq('objectClass', 'posixGroup') |
23
+ Net::LDAP::Filter.eq('objectClass', 'organizationalunit') |
24
+ Net::LDAP::Filter.eq('objectClass', 'groupOfUniqueNames') |
25
+ Net::LDAP::Filter.eq('objectClass', 'groupOfNames')
26
+ end
27
+ groups = @ldap.search(:base => search.dn, :filter => filter)
38
28
  members = groups.map { |group| group.send(method) }.flatten.uniq
39
29
 
40
30
  if method == :memberuid
41
31
  members
32
+ elsif method == :nisnetgrouptriple
33
+ @member_service.get_netgroup_users(members)
42
34
  else
43
35
  @member_service.get_logins(members)
44
36
  end
@@ -2,14 +2,13 @@ require 'net/ldap'
2
2
 
3
3
  # handles the naughty bits of posix ldap
4
4
  class LdapFluff::Posix::MemberService < LdapFluff::GenericMemberService
5
-
6
5
  def initialize(ldap, config)
7
6
  @attr_login = (config.attr_login || 'memberuid')
8
7
  super
9
8
  end
10
9
 
11
- def find_user(uid)
12
- user = @ldap.search(:filter => name_filter(uid), :base => @base)
10
+ def find_user(uid, base_dn = @base)
11
+ user = @ldap.search(:filter => name_filter(uid), :base => base_dn)
13
12
  raise UIDNotFoundException if (user.nil? || user.empty?)
14
13
  user
15
14
  end
@@ -18,7 +17,7 @@ class LdapFluff::Posix::MemberService < LdapFluff::GenericMemberService
18
17
  # note : this method is not particularly fast for large ldap systems
19
18
  def find_user_groups(uid)
20
19
  groups = []
21
- @ldap.search(:filter => Net::LDAP::Filter.eq('memberuid', uid)).each do |entry|
20
+ @ldap.search(:filter => Net::LDAP::Filter.eq('memberuid', uid), :base => @group_base).each do |entry|
22
21
  groups << entry[:cn][0]
23
22
  end
24
23
  groups
@@ -41,7 +40,7 @@ class LdapFluff::Posix::MemberService < LdapFluff::GenericMemberService
41
40
  filters[1..(filters.size - 1)].each do |gfilter|
42
41
  filter = (all ? filter & gfilter : filter | gfilter)
43
42
  end
44
- return filter
43
+ filter
45
44
  end
46
45
  end
47
46
 
@@ -50,5 +49,4 @@ class LdapFluff::Posix::MemberService < LdapFluff::GenericMemberService
50
49
 
51
50
  class GIDNotFoundException < LdapFluff::Error
52
51
  end
53
-
54
52
  end
@@ -0,0 +1,14 @@
1
+ require 'net/ldap'
2
+
3
+ # handles the naughty bits of posix ldap
4
+ class LdapFluff::Posix::NetgroupMemberService < LdapFluff::Posix::MemberService
5
+ # return list of group CNs for a user
6
+ def find_user_groups(uid)
7
+ groups = []
8
+ @ldap.search(:filter => Net::LDAP::Filter.eq('objectClass', 'nisNetgroup'), :base => @group_base).each do |entry|
9
+ members = get_netgroup_users(entry[:nisnetgrouptriple])
10
+ groups << entry[:cn][0] if members.include? uid
11
+ end
12
+ groups
13
+ end
14
+ end
@@ -11,6 +11,7 @@ class TestADMemberService < MiniTest::Test
11
11
 
12
12
  def basic_user
13
13
  @ldap.expect(:search, ad_user_payload, [:filter => ad_name_filter("john")])
14
+ @ldap.expect(:search, [{ :domainfunctionality => ['5'] }], [:base => "", :scope => 0, :attributes => ['domainFunctionality']])
14
15
  @ldap.expect(:search, ad_parent_payload(1), [:base => ad_group_dn, :scope => 0, :attributes => ['memberof']])
15
16
  end
16
17
 
@@ -20,7 +21,7 @@ class TestADMemberService < MiniTest::Test
20
21
 
21
22
  def nest_deep(n)
22
23
  # add all the expects
23
- 1.upto(n-1) do |i|
24
+ 1.upto(n - 1) do |i|
24
25
  @ldap.expect(:search, ad_parent_payload(i + 1), [:base => ad_group_dn("bros#{i}"), :scope => 0, :attributes => ['memberof']])
25
26
  end
26
27
  # terminate or we loop FOREVER
@@ -39,11 +40,19 @@ class TestADMemberService < MiniTest::Test
39
40
  end
40
41
  end
41
42
 
43
+ def transitive_user
44
+ ad_transitive_payload = [{ 'msds-memberoftransitive' => [ad_group_dn("bros#1"), ad_group_dn("bros#2"), ad_group_dn("bros#3"), ad_group_dn("bros#4"), ad_group_dn("bros#5")] }]
45
+
46
+ @ldap.expect(:search, ad_user_payload('john'), [:filter => ad_name_filter("john")])
47
+ @ldap.expect(:search, [{ :domainfunctionality => ['6'] }], [:base => "", :scope => 0, :attributes => ['domainFunctionality']])
48
+ @ldap.expect(:search, ad_transitive_payload, [:base => ad_user_dn("john"), :scope => 0, :attributes => ['msds-memberOfTransitive']])
49
+ end
50
+
42
51
  def test_find_user
43
52
  basic_user
44
53
  @ldap.expect(:search, [], [:base => ad_group_dn('bros1'), :scope => 0, :attributes => ['memberof']])
45
54
  @adms.ldap = @ldap
46
- assert_equal(%w(group bros1), @adms.find_user_groups("john"))
55
+ assert_equal(%w[group bros1], @adms.find_user_groups("john"))
47
56
  @ldap.verify
48
57
  end
49
58
 
@@ -53,7 +62,7 @@ class TestADMemberService < MiniTest::Test
53
62
  # now make 'bros1' be memberof 'group' again
54
63
  @ldap.expect(:search, ad_user_payload, [:base => ad_group_dn('bros1'), :scope => 0, :attributes => ['memberof']])
55
64
  @adms.ldap = @ldap
56
- assert_equal(%w(group bros1), @adms.find_user_groups("john"))
65
+ assert_equal(%w[group bros1], @adms.find_user_groups("john"))
57
66
  @ldap.verify
58
67
  end
59
68
 
@@ -82,6 +91,13 @@ class TestADMemberService < MiniTest::Test
82
91
  @ldap.verify
83
92
  end
84
93
 
94
+ def test_transitive_groups
95
+ transitive_user
96
+ @adms.ldap = @ldap
97
+ assert_equal(5, @adms.find_user_groups('john').size)
98
+ @ldap.verify
99
+ end
100
+
85
101
  def test_nil_payload
86
102
  assert_equal([], @adms._groups_from_ldap_data(nil))
87
103
  end
@@ -160,5 +176,4 @@ class TestADMemberService < MiniTest::Test
160
176
  entry = Net::LDAP::Entry.new('Example User')
161
177
  assert_nil(@adms.get_login_from_entry(entry))
162
178
  end
163
-
164
179
  end
data/test/ad_test.rb CHANGED
@@ -5,12 +5,12 @@ class TestAD < MiniTest::Test
5
5
 
6
6
  def setup
7
7
  super
8
- @ad = LdapFluff::ActiveDirectory.new(@config)
8
+ @ad = LdapFluff::ActiveDirectory.new(@config)
9
9
  end
10
10
 
11
11
  # default setup for service bind users
12
12
  def service_bind
13
- @ldap.expect(:auth, nil, %w(service pass))
13
+ @ldap.expect(:auth, nil, %w[service pass])
14
14
  super
15
15
  end
16
16
 
@@ -37,7 +37,7 @@ class TestAD < MiniTest::Test
37
37
  @md = MiniTest::Mock.new
38
38
  user_result = MiniTest::Mock.new
39
39
  user_result.expect(:dn, ad_user_dn('Internet User'))
40
- @md.expect(:find_user, [user_result], %w(internet))
40
+ @md.expect(:find_user, [user_result], %w[internet])
41
41
  @ad.member_service = @md
42
42
  service_bind
43
43
  @ldap.expect(:auth, nil, [ad_user_dn('Internet User'), "password"])
@@ -47,7 +47,7 @@ class TestAD < MiniTest::Test
47
47
  end
48
48
 
49
49
  def test_bad_bind
50
- @ldap.expect(:auth, nil, %w(EXAMPLE\\internet password))
50
+ @ldap.expect(:auth, nil, %w[EXAMPLE\\internet password])
51
51
  @ldap.expect(:bind, false)
52
52
  @ad.ldap = @ldap
53
53
  assert_equal(@ad.bind?("EXAMPLE\\internet", "password"), false)
@@ -57,14 +57,14 @@ class TestAD < MiniTest::Test
57
57
  def test_groups
58
58
  service_bind
59
59
  basic_user
60
- assert_equal(@ad.groups_for_uid('john'), %w(bros))
60
+ assert_equal(@ad.groups_for_uid('john'), %w[bros])
61
61
  end
62
62
 
63
63
  def test_bad_user
64
64
  service_bind
65
65
  md = MiniTest::Mock.new
66
- md.expect(:find_user_groups, nil, %w(john))
67
- def md.find_user_groups(*args)
66
+ md.expect(:find_user_groups, nil, %w[john])
67
+ def md.find_user_groups(*_args)
68
68
  raise LdapFluff::ActiveDirectory::MemberService::UIDNotFoundException
69
69
  end
70
70
  @ad.member_service = md
@@ -72,7 +72,7 @@ class TestAD < MiniTest::Test
72
72
  end
73
73
 
74
74
  def test_bad_service_user
75
- @ldap.expect(:auth, nil, %w(service pass))
75
+ @ldap.expect(:auth, nil, %w[service pass])
76
76
  @ldap.expect(:bind, false)
77
77
  @ad.ldap = @ldap
78
78
  assert_raises(LdapFluff::ActiveDirectory::UnauthenticatedException) do
@@ -83,36 +83,49 @@ class TestAD < MiniTest::Test
83
83
  def test_is_in_groups
84
84
  service_bind
85
85
  basic_user
86
- assert_equal(@ad.is_in_groups("john", %w(bros), false), true)
86
+ assert_equal(@ad.is_in_groups("john", %w[bros], false), true)
87
87
  end
88
88
 
89
89
  def test_is_some_groups
90
90
  service_bind
91
91
  basic_user
92
- assert_equal(@ad.is_in_groups("john", %w(bros buds), false), true)
92
+ assert_equal(@ad.is_in_groups("john", %w[bros buds], false), true)
93
93
  end
94
94
 
95
95
  def test_isnt_in_all_groups
96
96
  service_bind
97
97
  basic_user
98
- assert_equal(@ad.is_in_groups("john", %w(bros buds), true), false)
98
+ assert_equal(@ad.is_in_groups("john", %w[bros buds], true), false)
99
99
  end
100
100
 
101
101
  def test_isnt_in_groups
102
102
  service_bind
103
103
  basic_user
104
- assert_equal(@ad.is_in_groups("john", %w(broskies), false), false)
104
+ assert_equal(@ad.is_in_groups("john", %w[broskies], false), false)
105
105
  end
106
106
 
107
107
  def test_group_subset
108
108
  service_bind
109
109
  bigtime_user
110
- assert_equal(@ad.is_in_groups("john", %w(broskies), true), true)
110
+ assert_equal(@ad.is_in_groups("john", %w[broskies], true), true)
111
+ end
112
+
113
+ def test_subgroups_in_groups_are_ignored
114
+ group = Net::LDAP::Entry.new('foremaners')
115
+ md = MiniTest::Mock.new
116
+ 2.times { md.expect(:find_group, [group], ['foremaners']) }
117
+ 2.times { service_bind }
118
+ def md.find_by_dn(_dn)
119
+ raise LdapFluff::ActiveDirectory::MemberService::UIDNotFoundException
120
+ end
121
+ @ad.member_service = md
122
+ assert_equal @ad.users_for_gid('foremaners'), []
123
+ md.verify
111
124
  end
112
125
 
113
126
  def test_user_exists
114
127
  md = MiniTest::Mock.new
115
- md.expect(:find_user, 'notnilluser', %w(john))
128
+ md.expect(:find_user, 'notnilluser', %w[john])
116
129
  @ad.member_service = md
117
130
  service_bind
118
131
  assert(@ad.user_exists?('john'))
@@ -120,8 +133,8 @@ class TestAD < MiniTest::Test
120
133
 
121
134
  def test_missing_user
122
135
  md = MiniTest::Mock.new
123
- md.expect(:find_user, nil, %w(john))
124
- def md.find_user(uid)
136
+ md.expect(:find_user, nil, %w[john])
137
+ def md.find_user(_uid)
125
138
  raise LdapFluff::ActiveDirectory::MemberService::UIDNotFoundException
126
139
  end
127
140
  @ad.member_service = md
@@ -131,7 +144,7 @@ class TestAD < MiniTest::Test
131
144
 
132
145
  def test_group_exists
133
146
  md = MiniTest::Mock.new
134
- md.expect(:find_group, 'notnillgroup', %w(broskies))
147
+ md.expect(:find_group, 'notnillgroup', %w[broskies])
135
148
  @ad.member_service = md
136
149
  service_bind
137
150
  assert(@ad.group_exists?('broskies'))
@@ -139,8 +152,8 @@ class TestAD < MiniTest::Test
139
152
 
140
153
  def test_missing_group
141
154
  md = MiniTest::Mock.new
142
- md.expect(:find_group, nil, %w(broskies))
143
- def md.find_group(uid)
155
+ md.expect(:find_group, nil, %w[broskies])
156
+ def md.find_group(_uid)
144
157
  raise LdapFluff::ActiveDirectory::MemberService::GIDNotFoundException
145
158
  end
146
159
  @ad.member_service = md
@@ -181,7 +194,7 @@ class TestAD < MiniTest::Test
181
194
  nested_group[:cn] = ['katellers']
182
195
  nested_group[:objectclass] = ['organizationalunit']
183
196
  nested_group[:memberof] = ['CN=foremaners,DC=corp,DC=windows,DC=com']
184
- nested_user[:objectclass] = ['person']
197
+ nested_user[:objectclass] = ['person']
185
198
 
186
199
  md = MiniTest::Mock.new
187
200
  2.times { md.expect(:find_group, [group], ['foremaners']) }
@@ -195,5 +208,4 @@ class TestAD < MiniTest::Test
195
208
  assert_equal @ad.users_for_gid('foremaners'), ['testuser']
196
209
  md.verify
197
210
  end
198
-
199
211
  end