Skip to content

Commit 2a62c21

Browse files
committed
Find subgroups, then materialize members
1 parent 212816c commit 2a62c21

File tree

1 file changed

+51
-53
lines changed

1 file changed

+51
-53
lines changed

lib/github/ldap/member_search/recursive.rb

Lines changed: 51 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -34,72 +34,70 @@ def initialize(ldap, options = {})
3434
#
3535
# Returns Array of Net::LDAP::Entry objects.
3636
def perform(group)
37-
found = Hash.new
38-
39-
# find members (N queries)
40-
entries = member_entries(group)
41-
return [] if entries.empty?
42-
43-
# track found entries
44-
entries.each do |entry|
45-
found[entry.dn] = entry
37+
found = Hash.new
38+
searched = []
39+
entries = []
40+
41+
# if this is a posixGroup, return members immediately (no nesting)
42+
uids = member_uids(group)
43+
return entries_by_uid(uids) if uids.any?
44+
45+
# track group
46+
searched << group.dn
47+
found[group.dn] = group
48+
49+
# pull out base group's member DNs
50+
dns = member_dns(group)
51+
52+
# search for base group's subgroups
53+
filter = ALL_GROUPS_FILTER
54+
groups = dns.each_with_object([]) do |dn, groups|
55+
groups.concat ldap.search(base: dn, scope: Net::LDAP::SearchScope_BaseObject, attributes: attrs, filter: filter)
56+
searched << dn
4657
end
4758

48-
# descend to `depth` levels, at most
49-
depth.times do |n|
50-
# find every (new, unique) member entry
51-
depth_subentries = entries.each_with_object([]) do |entry, depth_entries|
52-
# find members of subgroup, including subgroups (N queries)
53-
subentries = member_entries(entry, found)
54-
next if subentries.empty?
59+
# track found groups
60+
groups.each { |g| found[g.dn] = g }
5561

56-
# track found subentries
57-
subentries.each { |entry| found[entry.dn] = entry }
62+
# recursively find subgroups
63+
unless groups.empty?
64+
depth.times do |n|
65+
# pull out subgroups' member DNs to search through
66+
sub_dns = groups.each_with_object([]) do |subgroup, sub_dns|
67+
sub_dns.concat member_dns(subgroup)
68+
end
5869

59-
# collect all entries for this depth
60-
depth_entries.concat subentries
61-
end
70+
# give up if there's nothing else to search for
71+
break if sub_dns.empty?
6272

63-
# stop if there are no more subgroups to search
64-
break if depth_subentries.empty?
73+
# filter out if already searched for
74+
sub_dns.reject! { |dn| searched.include?(dn) }
6575

66-
# go one level deeper
67-
entries = depth_subentries
68-
end
76+
# search for subgroups
77+
subgroups = sub_dns.each_with_object([]) do |dn, subgroups|
78+
subgroups.concat ldap.search(base: dn, scope: Net::LDAP::SearchScope_BaseObject, attributes: attrs, filter: filter)
79+
searched << dn
80+
end
6981

70-
# return all found entries
71-
found.values
72-
end
82+
break if subgroups.empty?
7383

74-
# Internal: Fetch member entries, including subgroups, for the given
75-
# entry.
76-
#
77-
# Returns an Array of Net::LDAP::Entry objects.
78-
def member_entries(entry, found = {})
79-
entries = []
80-
dns = member_dns(entry)
81-
uids = member_uids(entry)
84+
# track found groups
85+
subgroups.each { |g| found[g.dn] = g }
8286

83-
# skip any entries we've already found
84-
dns.reject! { |dn| found.key?(dn) }
85-
uids.reject! { |uid| found.any? { |entry| entry['uid'].include?(uid) } }
87+
# descend another level
88+
groups = subgroups
89+
end
90+
end
8691

87-
entries.concat entries_by_uid(uids) unless uids.empty?
88-
entries.concat entries_by_dn(dns) unless dns.empty?
92+
# take found groups and combine groups and members into list of entries
93+
found.values.each do |group|
94+
entries << group
95+
# just need member DNs as Net::LDAP::Entry objects
96+
entries.concat member_dns(group).map { |dn| Net::LDAP::Entry.new(dn) }
97+
end
8998

9099
entries
91100
end
92-
private :member_entries
93-
94-
# Internal: Bind a list of DNs to their respective entries.
95-
#
96-
# Returns an Array of Net::LDAP::Entry objects.
97-
def entries_by_dn(members)
98-
members.map do |dn|
99-
ldap.domain(dn).bind(attributes: attrs)
100-
end.compact
101-
end
102-
private :entries_by_dn
103101

104102
# Internal: Fetch entries by UID.
105103
#

0 commit comments

Comments
 (0)