@@ -100,6 +100,9 @@ def initialize(options = {})
100
100
101
101
# enables instrumenting queries
102
102
@instrumentation_service = options [ :instrumentation_service ]
103
+
104
+ # active directory forest
105
+ @forest = get_domain_forest ( options [ :search_forest ] )
103
106
end
104
107
105
108
# Public - Whether membership checks should recurse into nested groups when
@@ -180,10 +183,10 @@ def search(options, &block)
180
183
instrument "search.github_ldap" , options . dup do |payload |
181
184
result =
182
185
if options [ :base ]
183
- @connection . search ( options , &block )
186
+ forest_search ( options , &block )
184
187
else
185
188
search_domains . each_with_object ( [ ] ) do |base , result |
186
- rs = @connection . search ( options . merge ( :base => base ) , &block )
189
+ rs = forest_search ( options . merge ( :base => base ) , &block )
187
190
result . concat Array ( rs ) unless rs == false
188
191
end
189
192
end
@@ -193,6 +196,26 @@ def search(options, &block)
193
196
end
194
197
end
195
198
199
+ # Internal: Search within a ldap forest
200
+ #
201
+ # Returns an Array of Net::LDAP::Entry.
202
+ def forest_search ( options , &block )
203
+ instrument "forest_search.github_ldap" do |payload |
204
+ result =
205
+ if @forest . empty?
206
+ @connection . search ( options , &block )
207
+ else
208
+ @forest . each_with_object ( [ ] ) do |( rootdn , server ) , res |
209
+ if options [ :base ] . end_with? ( rootdn )
210
+ rs = server . search ( options , &block )
211
+ res . concat Array ( rs ) unless rs == false
212
+ end
213
+ end
214
+ end
215
+ return result
216
+ end
217
+ end
218
+
196
219
# Internal: Searches the host LDAP server's Root DSE for capabilities and
197
220
# extensions.
198
221
#
@@ -201,7 +224,8 @@ def capabilities
201
224
@capabilities ||=
202
225
instrument "capabilities.github_ldap" do |payload |
203
226
begin
204
- @connection . search_root_dse
227
+ rs = @connection . search ( :ignore_server_caps => true , :base => "" , :scope => Net ::LDAP ::SearchScope_BaseObject )
228
+ ( rs and rs . first )
205
229
rescue Net ::LDAP ::LdapError => error
206
230
payload [ :error ] = error
207
231
# stubbed result
@@ -307,6 +331,37 @@ def configure_member_search_strategy(strategy = nil)
307
331
end
308
332
end
309
333
334
+ # Internal: Queries configuration for available domains
335
+ #
336
+ # Membership of local or global groups need to be evaluated by contacting referral Donmain Controllers
337
+ #
338
+ # Returns all Domain Controllers within the forest
339
+ def get_domain_forest ( search_forest )
340
+ instrument "get_domain_forest.github_ldap" do |payload |
341
+
342
+ # if we are talking to an active directory
343
+ if search_forest and active_directory_capability? and capabilities [ :configurationnamingcontext ] . any?
344
+ domains = @connection . search (
345
+ base : capabilities [ :configurationnamingcontext ] . first ,
346
+ search_referrals : true ,
347
+ filter : Net ::LDAP ::Filter . eq ( "nETBIOSName" , "*" )
348
+ )
349
+ return domains . each_with_object ( { } ) do |server , result |
350
+ if server [ :ncname ] . any? and server [ :dnsroot ] . any?
351
+ result [ server [ :ncname ] . first ] = Net ::LDAP . new ( {
352
+ host : server [ :dnsroot ] . first ,
353
+ port : @connection . instance_variable_get ( :@encryption ) ? 636 : 389 ,
354
+ auth : @connection . instance_variable_get ( :@auth ) ,
355
+ encryption : @connection . instance_variable_get ( :@encryption ) ,
356
+ instrumentation_service : @connection . instance_variable_get ( :@instrumentation_service )
357
+ } )
358
+ end
359
+ end
360
+ end
361
+ return { }
362
+ end
363
+ end
364
+
310
365
# Internal: Detect whether the LDAP host is an ActiveDirectory server.
311
366
#
312
367
# See: http://msdn.microsoft.com/en-us/library/cc223359.aspx.
0 commit comments