Skip to content

Commit 0ba3966

Browse files
committed
Implement forest search to obtain non universal groups from ad
1 parent 8c945ce commit 0ba3966

File tree

1 file changed

+58
-3
lines changed

1 file changed

+58
-3
lines changed

lib/github/ldap.rb

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ def initialize(options = {})
100100

101101
# enables instrumenting queries
102102
@instrumentation_service = options[:instrumentation_service]
103+
104+
# active directory forest
105+
@forest = get_domain_forest(options[:search_forest])
103106
end
104107

105108
# Public - Whether membership checks should recurse into nested groups when
@@ -180,10 +183,10 @@ def search(options, &block)
180183
instrument "search.github_ldap", options.dup do |payload|
181184
result =
182185
if options[:base]
183-
@connection.search(options, &block)
186+
forest_search(options, &block)
184187
else
185188
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)
187190
result.concat Array(rs) unless rs == false
188191
end
189192
end
@@ -193,6 +196,26 @@ def search(options, &block)
193196
end
194197
end
195198

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+
196219
# Internal: Searches the host LDAP server's Root DSE for capabilities and
197220
# extensions.
198221
#
@@ -201,7 +224,8 @@ def capabilities
201224
@capabilities ||=
202225
instrument "capabilities.github_ldap" do |payload|
203226
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)
205229
rescue Net::LDAP::LdapError => error
206230
payload[:error] = error
207231
# stubbed result
@@ -307,6 +331,37 @@ def configure_member_search_strategy(strategy = nil)
307331
end
308332
end
309333

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+
310365
# Internal: Detect whether the LDAP host is an ActiveDirectory server.
311366
#
312367
# See: http://msdn.microsoft.com/en-us/library/cc223359.aspx.

0 commit comments

Comments
 (0)