ldap_fluff 0.4.4 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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