ldap_groups_lookup 0.8.0 → 0.10.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.
- checksums.yaml +4 -4
- data/lib/ldap_groups_lookup/configuration.rb +6 -1
- data/lib/ldap_groups_lookup/version.rb +1 -1
- data/spec/lib/ldap_groups_lookup_spec.rb +196 -178
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4d6da72dceefbf3ea333aeb46b7288da0d3ec3517c05fbcbc77f53eb3fc955f2
|
4
|
+
data.tar.gz: 1720d92a5e416dbb2f4fafec7c2fc85239d82bb8ef6982909646217260d91457
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b05d74e63567fb0e0272cf2242a395c9a0dc0125306112e1671eba47bd9460c73c1fff154d1b5708fc4669f0877d9d30dd87320256fcbdf7f39ca56269d8d9cc
|
7
|
+
data.tar.gz: 5becbdb0a9356bfa9b53df4133d9ffc955b77a0c50757265d80457ee7a0c86b59d74cca811732fefbb8700879d1210de3cd120c50095bd81cc4fb464f686f468
|
@@ -4,12 +4,17 @@ require 'erb'
|
|
4
4
|
# Provides access to the configuration YAML file.
|
5
5
|
module LDAPGroupsLookup
|
6
6
|
module Configuration
|
7
|
+
attr_writer :config
|
7
8
|
|
8
9
|
# Attempts to create a connection to LDAP and returns a cached Net::LDAP instance if successful.
|
9
10
|
def service
|
10
11
|
return nil if config[:enabled] == false
|
11
12
|
if @ldap_service.nil?
|
12
|
-
|
13
|
+
if config[:config].is_a? Hash
|
14
|
+
@ldap_service = Net::LDAP.new(**config[:config])
|
15
|
+
else
|
16
|
+
@ldap_service = Net::LDAP.new(host: config[:host], port: config[:port] || Net::LDAP::DefaultPort, auth: config[:auth])
|
17
|
+
end
|
13
18
|
raise Net::LDAP::Error unless @ldap_service.bind
|
14
19
|
end
|
15
20
|
@ldap_service
|
@@ -13,245 +13,263 @@ RSpec.describe LDAPGroupsLookup do
|
|
13
13
|
end
|
14
14
|
let(:user) { user_class.new }
|
15
15
|
|
16
|
-
# Load the example config from fixtures
|
17
|
-
let(:config) { YAML.load(ERB.new(File.read(File.join(File.dirname(__dir__), 'fixtures', 'ldap_groups_lookup.yml.example'))).result) }
|
18
|
-
|
19
|
-
before do
|
20
|
-
allow(LDAPGroupsLookup).to receive(:config).and_return(config)
|
21
|
-
end
|
22
|
-
|
23
16
|
after do
|
24
17
|
LDAPGroupsLookup.reset
|
25
18
|
end
|
26
19
|
|
27
|
-
describe '#
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
expect(File).to receive(:exist?).with(/config\/ldap_groups_lookup\.yml$/)
|
32
|
-
end
|
33
|
-
it 'should return nil' do
|
34
|
-
expect(LDAPGroupsLookup.service).to be_nil
|
35
|
-
end
|
20
|
+
describe '#config' do
|
21
|
+
it 'sets the config directly' do
|
22
|
+
LDAPGroupsLookup.config = { direct_config: 'works' }
|
23
|
+
expect(LDAPGroupsLookup.config).to eq({ direct_config: 'works' })
|
36
24
|
end
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'with a config file' do
|
28
|
+
# Load the example config from fixtures
|
29
|
+
let(:config) { YAML.load(ERB.new(File.read(File.join(File.dirname(__dir__), 'fixtures', 'ldap_groups_lookup.yml.example'))).result) }
|
30
|
+
|
31
|
+
before do
|
32
|
+
allow(LDAPGroupsLookup).to receive(:config).and_return(config)
|
44
33
|
end
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
end
|
49
|
-
context 'when the auth credentials are incorrect' do
|
34
|
+
|
35
|
+
describe '#service' do
|
36
|
+
context 'when the config file is missing' do
|
50
37
|
before do
|
51
|
-
|
38
|
+
allow(LDAPGroupsLookup).to receive(:config).and_call_original
|
39
|
+
expect(File).to receive(:exist?).with(/config\/ldap_groups_lookup\.yml$/)
|
52
40
|
end
|
53
|
-
it 'should
|
54
|
-
expect
|
41
|
+
it 'should return nil' do
|
42
|
+
expect(LDAPGroupsLookup.service).to be_nil
|
55
43
|
end
|
56
44
|
end
|
57
|
-
context 'when
|
45
|
+
context 'when disabled in the configuration file' do
|
58
46
|
before do
|
59
|
-
|
47
|
+
config[:enabled] = false
|
60
48
|
end
|
61
|
-
it 'should return
|
62
|
-
expect(LDAPGroupsLookup.service).to
|
49
|
+
it 'should return nil' do
|
50
|
+
expect(LDAPGroupsLookup.service).to be_nil
|
63
51
|
end
|
64
52
|
end
|
65
|
-
|
66
|
-
|
53
|
+
context 'when enabled in the configuration file' do
|
54
|
+
it 'should be enabled' do
|
55
|
+
expect(config[:enabled]).to eq(true)
|
56
|
+
end
|
57
|
+
context 'when the auth credentials are incorrect' do
|
58
|
+
before do
|
59
|
+
allow_any_instance_of(Net::LDAP).to receive(:bind).and_return(false)
|
60
|
+
end
|
61
|
+
it 'should raise an LdapError' do
|
62
|
+
expect { LDAPGroupsLookup.service }.to raise_error(Net::LDAP::Error)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
context 'when the auth credentials are correct' do
|
66
|
+
before do
|
67
|
+
allow_any_instance_of(Net::LDAP).to receive(:bind).and_return(true)
|
68
|
+
end
|
69
|
+
it 'should return a Net::LDAP instance' do
|
70
|
+
expect(LDAPGroupsLookup.service).to be_an_instance_of(Net::LDAP)
|
71
|
+
end
|
67
72
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
it 'should return ''' do
|
78
|
-
expect(user.ldap_mail).to eq('')
|
73
|
+
context 'when the :config key is set' do
|
74
|
+
let(:config_hash) { { host: 'localhost', port: 636, encryption: { method: :simple_tls, tls_options: OpenSSL::SSL::SSLContext::DEFAULT_PARAMS } } }
|
75
|
+
before { config[:config] = config_hash }
|
76
|
+
it 'uses that config' do
|
77
|
+
expect(Net::LDAP).to receive(:new).with(config_hash).and_call_original
|
78
|
+
expect(LDAPGroupsLookup.service).to be_an_instance_of(Net::LDAP)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
79
82
|
end
|
80
83
|
end
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
84
|
+
|
85
|
+
describe '#ldap_mail' do
|
86
|
+
before(:each) do
|
87
|
+
entry = Net::LDAP::Entry.new('CN=user,DC=ads,DC=example,DC=net')
|
88
|
+
entry['mail'] = ['user@domain.ext']
|
89
|
+
allow_any_instance_of(Net::LDAP).to receive(:search).and_return([entry])
|
90
|
+
allow_any_instance_of(Net::LDAP).to receive(:bind).and_return(true)
|
85
91
|
end
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
config[:enabled] = false
|
92
|
+
context 'when subject does not provide ldap_lookup_key method' do
|
93
|
+
before(:each) { user.class.send(:remove_method, :ldap_lookup_key) }
|
94
|
+
it 'should return ''' do
|
95
|
+
expect(user.ldap_mail).to eq('')
|
91
96
|
end
|
92
|
-
|
97
|
+
end
|
98
|
+
context 'when subject does not provide ldap_lookup_key value' do
|
99
|
+
before(:each) { allow(user).to receive(:ldap_lookup_key).and_return(nil) }
|
100
|
+
it 'should return ''' do
|
93
101
|
expect(user.ldap_mail).to eq('')
|
94
102
|
end
|
95
103
|
end
|
96
|
-
context 'when
|
97
|
-
|
98
|
-
|
104
|
+
context 'when subject provides ldap_lookup_key' do
|
105
|
+
context 'when LDAP is not configured' do
|
106
|
+
before(:each) do
|
107
|
+
config[:enabled] = false
|
108
|
+
end
|
109
|
+
it 'should return a blank string' do
|
110
|
+
expect(user.ldap_mail).to eq('')
|
111
|
+
end
|
112
|
+
end
|
113
|
+
context 'when LDAP is configured' do
|
114
|
+
it 'user should should have a mail attribute in mock LDAP' do
|
115
|
+
expect(user.ldap_mail).to eq 'user@domain.ext'
|
116
|
+
end
|
99
117
|
end
|
100
118
|
end
|
101
119
|
end
|
102
|
-
end
|
103
120
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
end
|
112
|
-
context 'when subject does not provide ldap_lookup_key method' do
|
113
|
-
before(:each) { user.class.send(:remove_method, :ldap_lookup_key) }
|
114
|
-
it 'should return []' do
|
115
|
-
expect(user.ldap_groups).to eq([])
|
121
|
+
describe '#ldap_groups' do
|
122
|
+
before(:each) do
|
123
|
+
entry = Net::LDAP::Entry.new('CN=user,DC=ads,DC=example,DC=net')
|
124
|
+
entry['memberof'] = ['CN=Group1,DC=ads,DC=example,DC=net',
|
125
|
+
'CN=Group2,DC=ads,DC=example,DC=net']
|
126
|
+
allow_any_instance_of(Net::LDAP).to receive(:search).and_return([entry])
|
127
|
+
allow_any_instance_of(Net::LDAP).to receive(:bind).and_return(true)
|
116
128
|
end
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
expect(user.ldap_groups).to eq([])
|
122
|
-
end
|
123
|
-
end
|
124
|
-
context 'when subject provides ldap_lookup_key' do
|
125
|
-
context 'when LDAP is not configured' do
|
126
|
-
before(:each) do
|
127
|
-
config[:enabled] = false
|
129
|
+
context 'when subject does not provide ldap_lookup_key method' do
|
130
|
+
before(:each) { user.class.send(:remove_method, :ldap_lookup_key) }
|
131
|
+
it 'should return []' do
|
132
|
+
expect(user.ldap_groups).to eq([])
|
128
133
|
end
|
134
|
+
end
|
135
|
+
context 'when subject does not provide ldap_lookup_key value' do
|
136
|
+
before(:each) { allow(user).to receive(:ldap_lookup_key).and_return(nil) }
|
129
137
|
it 'should return []' do
|
130
138
|
expect(user.ldap_groups).to eq([])
|
131
139
|
end
|
132
140
|
end
|
133
|
-
context 'when
|
134
|
-
|
135
|
-
|
141
|
+
context 'when subject provides ldap_lookup_key' do
|
142
|
+
context 'when LDAP is not configured' do
|
143
|
+
before(:each) do
|
144
|
+
config[:enabled] = false
|
145
|
+
end
|
146
|
+
it 'should return []' do
|
147
|
+
expect(user.ldap_groups).to eq([])
|
148
|
+
end
|
149
|
+
end
|
150
|
+
context 'when LDAP is configured' do
|
151
|
+
it 'user should belong to Group1 and Group2 in mock LDAP' do
|
152
|
+
expect(user.ldap_groups).to eq(%w(Group1 Group2))
|
153
|
+
end
|
136
154
|
end
|
137
155
|
end
|
138
156
|
end
|
139
|
-
end
|
140
157
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
end
|
147
|
-
end
|
148
|
-
context 'when subject does not provide ldap_lookup_key value' do
|
149
|
-
before(:each) { allow(user).to receive(:ldap_lookup_key).and_return(nil) }
|
150
|
-
it 'should return false' do
|
151
|
-
expect(user.member_of_ldap_group?('Test-Group')).to eq(false)
|
152
|
-
end
|
153
|
-
end
|
154
|
-
context 'when subject provides ldap_lookup_key' do
|
155
|
-
context 'when LDAP is not configured' do
|
156
|
-
before(:each) do
|
157
|
-
config[:enabled] = false
|
158
|
+
describe '#member_of_ldap_group?' do
|
159
|
+
context 'when subject does not provide ldap_lookup_key method' do
|
160
|
+
before(:each) { user.class.send(:remove_method, :ldap_lookup_key) }
|
161
|
+
it 'should return false' do
|
162
|
+
expect(user.member_of_ldap_group?('Test-Group')).to eq(false)
|
158
163
|
end
|
164
|
+
end
|
165
|
+
context 'when subject does not provide ldap_lookup_key value' do
|
166
|
+
before(:each) { allow(user).to receive(:ldap_lookup_key).and_return(nil) }
|
159
167
|
it 'should return false' do
|
160
168
|
expect(user.member_of_ldap_group?('Test-Group')).to eq(false)
|
161
169
|
end
|
162
170
|
end
|
163
|
-
context 'when
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
allow(LDAPGroupsLookup).to receive(:lookup_dn) do |args|
|
169
|
-
Net::LDAP::Entry.new("CN=#{args},DC=ads,DC=example,DC=net").dn
|
171
|
+
context 'when subject provides ldap_lookup_key' do
|
172
|
+
context 'when LDAP is not configured' do
|
173
|
+
before(:each) do
|
174
|
+
config[:enabled] = false
|
170
175
|
end
|
176
|
+
it 'should return false' do
|
177
|
+
expect(user.member_of_ldap_group?('Test-Group')).to eq(false)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
context 'when LDAP is configured' do
|
181
|
+
before(:each) do
|
182
|
+
@service = double('ldap_service')
|
183
|
+
allow(LDAPGroupsLookup).to receive(:service).and_return(@service)
|
171
184
|
|
172
|
-
|
173
|
-
|
185
|
+
allow(LDAPGroupsLookup).to receive(:lookup_dn) do |args|
|
186
|
+
Net::LDAP::Entry.new("CN=#{args},DC=ads,DC=example,DC=net").dn
|
187
|
+
end
|
174
188
|
|
175
|
-
|
176
|
-
|
189
|
+
@other_group = Net::LDAP::Entry.new('CN=Other-Group,OU=Groups,DC=ads,DC=example,DC=net')
|
190
|
+
@other_group['member;range=0-*'] = ['CN=otheruser,DC=ads,DC=example,DC=net']
|
177
191
|
|
178
|
-
|
179
|
-
|
192
|
+
@nested_group_page_1 = Net::LDAP::Entry.new('CN=Nested-Group,OU=Groups,DC=ads,DC=example,DC=net')
|
193
|
+
@nested_group_page_1['member;range=0-0'] = ['CN=otheruser,DC=ads,DC=example,DC=net']
|
180
194
|
|
181
|
-
|
182
|
-
|
195
|
+
@nested_group_page_2 = Net::LDAP::Entry.new('CN=Nested-Group,OU=Groups,DC=ads,DC=example,DC=net')
|
196
|
+
@nested_group_page_2['member;range=1-*'] = ['CN=user,DC=ads,DC=example,DC=net']
|
183
197
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
expect(@service).to receive(:search).with(
|
189
|
-
hash_including(filter: Net::LDAP::Filter.equals('cn', 'Fake-Group'))).and_return([])
|
190
|
-
expect(user.member_of_ldap_group?('Fake-Group')).to eq(false)
|
191
|
-
end
|
192
|
-
end
|
193
|
-
context 'when searching for a group that user is not a member of' do
|
194
|
-
it 'should return false' do
|
195
|
-
expect(@service).to receive(:search).with(
|
196
|
-
hash_including(filter: Net::LDAP::Filter.equals('cn', 'Other-Group'))).and_return([@other_group])
|
197
|
-
expect(user.member_of_ldap_group?('Other-Group')).to eq(false)
|
198
|
-
end
|
199
|
-
end
|
200
|
-
context 'when searching for a group that has no members' do
|
201
|
-
it 'should return false' do
|
202
|
-
expect(@service).to receive(:search).with(
|
203
|
-
hash_including(filter: Net::LDAP::Filter.equals('cn', 'No-Member-Group'))).and_return([@no_member_group])
|
204
|
-
expect(user.member_of_ldap_group?('No-Member-Group')).to eq(false)
|
198
|
+
@top_group = Net::LDAP::Entry.new('CN=Top-Group,OU=Groups,DC=ads,DC=example,DC=net')
|
199
|
+
@top_group['member;range=0-*'] = ['CN=Nested-Group,OU=Groups,DC=ads,DC=example,DC=net']
|
200
|
+
|
201
|
+
@no_member_group = Net::LDAP::Entry.new('CN=No-Member-Group,OU=Groups,DC=ads,DC=example,DC=net')
|
205
202
|
end
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
expect(@service).to receive(:search).with(
|
213
|
-
hash_including(filter: Net::LDAP::Filter.equals('cn', 'Nested-Group'),
|
214
|
-
attributes: ['member;range=1-*'])).and_return([@nested_group_page_2])
|
215
|
-
expect(user.member_of_ldap_group?('Nested-Group')).to eq(true)
|
203
|
+
context 'when searching for a group that does not exist' do
|
204
|
+
it 'should return false' do
|
205
|
+
expect(@service).to receive(:search).with(
|
206
|
+
hash_including(filter: Net::LDAP::Filter.equals('cn', 'Fake-Group'))).and_return([])
|
207
|
+
expect(user.member_of_ldap_group?('Fake-Group')).to eq(false)
|
208
|
+
end
|
216
209
|
end
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
hash_including(filter: Net::LDAP::Filter.equals('cn', 'Nested-Group'),
|
224
|
-
attributes: ['member;range=0-*'])).and_return([@nested_group_page_1])
|
225
|
-
allow(@service).to receive(:search).with(
|
226
|
-
hash_including(filter: Net::LDAP::Filter.equals('cn', 'Nested-Group'),
|
227
|
-
attributes: ['member;range=1-*'])).and_return([@nested_group_page_2])
|
210
|
+
context 'when searching for a group that user is not a member of' do
|
211
|
+
it 'should return false' do
|
212
|
+
expect(@service).to receive(:search).with(
|
213
|
+
hash_including(filter: Net::LDAP::Filter.equals('cn', 'Other-Group'))).and_return([@other_group])
|
214
|
+
expect(user.member_of_ldap_group?('Other-Group')).to eq(false)
|
215
|
+
end
|
228
216
|
end
|
229
|
-
context 'when
|
230
|
-
|
231
|
-
|
217
|
+
context 'when searching for a group that has no members' do
|
218
|
+
it 'should return false' do
|
219
|
+
expect(@service).to receive(:search).with(
|
220
|
+
hash_including(filter: Net::LDAP::Filter.equals('cn', 'No-Member-Group'))).and_return([@no_member_group])
|
221
|
+
expect(user.member_of_ldap_group?('No-Member-Group')).to eq(false)
|
232
222
|
end
|
223
|
+
end
|
224
|
+
context 'when searching for a group that user is a direct member of on the second page' do
|
233
225
|
it 'should return true' do
|
234
|
-
expect(
|
226
|
+
expect(@service).to receive(:search).with(
|
227
|
+
hash_including(filter: Net::LDAP::Filter.equals('cn', 'Nested-Group'),
|
228
|
+
attributes: ['member;range=0-*'])).and_return([@nested_group_page_1])
|
229
|
+
expect(@service).to receive(:search).with(
|
230
|
+
hash_including(filter: Net::LDAP::Filter.equals('cn', 'Nested-Group'),
|
231
|
+
attributes: ['member;range=1-*'])).and_return([@nested_group_page_2])
|
232
|
+
expect(user.member_of_ldap_group?('Nested-Group')).to eq(true)
|
235
233
|
end
|
236
234
|
end
|
237
|
-
context 'when
|
235
|
+
context 'when searching for a group that user is a nested member of' do
|
238
236
|
before do
|
239
|
-
|
237
|
+
expect(@service).to receive(:search).with(
|
238
|
+
hash_including(filter: Net::LDAP::Filter.equals('cn', 'Top-Group'))).and_return([@top_group])
|
239
|
+
allow(@service).to receive(:search).with(
|
240
|
+
hash_including(filter: Net::LDAP::Filter.equals('cn', 'Nested-Group'),
|
241
|
+
attributes: ['member;range=0-*'])).and_return([@nested_group_page_1])
|
242
|
+
allow(@service).to receive(:search).with(
|
243
|
+
hash_including(filter: Net::LDAP::Filter.equals('cn', 'Nested-Group'),
|
244
|
+
attributes: ['member;range=1-*'])).and_return([@nested_group_page_2])
|
240
245
|
end
|
241
|
-
|
242
|
-
|
246
|
+
context 'when the group is whitelisted' do
|
247
|
+
before do
|
248
|
+
allow(LDAPGroupsLookup).to receive(:member_whitelist).and_return(['OU=Groups'])
|
249
|
+
end
|
250
|
+
it 'should return true' do
|
251
|
+
expect(user.member_of_ldap_group?('Top-Group')).to eq(true)
|
252
|
+
end
|
243
253
|
end
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
254
|
+
context 'when the whitelist is empty' do
|
255
|
+
before do
|
256
|
+
allow(LDAPGroupsLookup).to receive(:member_whitelist).and_return([])
|
257
|
+
end
|
258
|
+
it 'should return true (whitelisting is disabled)' do
|
259
|
+
expect(user.member_of_ldap_group?('Top-Group')).to eq(true)
|
260
|
+
end
|
248
261
|
end
|
249
|
-
|
250
|
-
|
262
|
+
context 'when the group is not whitelisted' do
|
263
|
+
before do
|
264
|
+
allow(LDAPGroupsLookup).to receive(:member_whitelist).and_return(['OU=Not-A-Match'])
|
265
|
+
end
|
266
|
+
it 'should return false' do
|
267
|
+
expect(user.member_of_ldap_group?('Top-Group')).to eq(false)
|
268
|
+
end
|
251
269
|
end
|
252
270
|
end
|
253
271
|
end
|
254
272
|
end
|
255
273
|
end
|
256
274
|
end
|
257
|
-
end
|
275
|
+
end
|