Class: GitHub::Ldap::MemberSearch::Recursive

Inherits:
Base
  • Object
show all
Includes:
Filter
Defined in:
lib/github/ldap/member_search/recursive.rb

Overview

Look up group members recursively.

This results in a maximum of ‘depth` iterations/recursions to look up members of a group and its subgroups.

Constant Summary collapse

DEFAULT_MAX_DEPTH =
9
DEFAULT_ATTRS =
%w(member uniqueMember memberUid)

Constants included from Filter

Filter::ALL_GROUPS_FILTER, Filter::MEMBERSHIP_NAMES

Instance Attribute Summary collapse

Attributes inherited from Base

#ldap

Instance Method Summary collapse

Methods included from Filter

#all_members_by_uid, #group_contains_filter, #group_filter, #login_filter, #member_filter, #members_of_group, #posix_member_filter, #subgroups_of_group

Constructor Details

#initialize(ldap, options = {}) ⇒ Recursive

Public: Instantiate new search strategy.

  • ldap: GitHub::Ldap object

  • options: Hash of options

NOTE: This overrides default behavior to configure ‘depth` and `attrs`.



26
27
28
29
30
# File 'lib/github/ldap/member_search/recursive.rb', line 26

def initialize(ldap, options = {})
  super
  @depth = options[:depth] || DEFAULT_MAX_DEPTH
  @attrs = Array(options[:attrs]).concat DEFAULT_ATTRS
end

Instance Attribute Details

#attrsObject (readonly)

Internal: The attributes to search for.



18
19
20
# File 'lib/github/ldap/member_search/recursive.rb', line 18

def attrs
  @attrs
end

#depthObject (readonly)

Internal: The maximum depth to search for members.



15
16
17
# File 'lib/github/ldap/member_search/recursive.rb', line 15

def depth
  @depth
end

Instance Method Details

#perform(group) ⇒ Object

Public: Performs search for group members, including groups and members of subgroups recursively.

Returns Array of Net::LDAP::Entry objects.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/github/ldap/member_search/recursive.rb', line 36

def perform(group)
  # track groups found
  found = Hash.new

  # track all DNs searched for (so we don't repeat searches)
  searched = Set.new

  # if this is a posixGroup, return members immediately (no nesting)
  uids = member_uids(group)
  return entries_by_uid(uids) if uids.any?

  # track group
  searched << group.dn
  found[group.dn] = group

  # pull out base group's member DNs
  dns = member_dns(group)

  # search for base group's subgroups
  groups = dns.each_with_object([]) do |dn, groups|
    groups.concat find_groups_by_dn(dn)
    searched << dn
  end

  # track found groups
  groups.each { |g| found[g.dn] = g }

  # recursively find subgroups
  unless groups.empty?
    depth.times do |n|
      # pull out subgroups' member DNs to search through
      sub_dns = groups.each_with_object([]) do |subgroup, sub_dns|
        sub_dns.concat member_dns(subgroup)
      end

      # filter out if already searched for
      sub_dns.reject! { |dn| searched.include?(dn) }

      # give up if there's nothing else to search for
      break if sub_dns.empty?

      # search for subgroups
      subgroups = sub_dns.each_with_object([]) do |dn, subgroups|
        subgroups.concat find_groups_by_dn(dn)
        searched << dn
      end

      # give up if there were no subgroups found
      break if subgroups.empty?

      # track found subgroups
      subgroups.each { |g| found[g.dn] = g }

      # descend another level
      groups = subgroups
    end
  end

  # entries to return
  entries  = []

  # collect all member DNs, discarding dupes and subgroup DNs
  members = found.values.each_with_object([]) do |group, dns|
    entries << group
    dns.concat member_dns(group)
  end.uniq.reject { |dn| found.key?(dn) }

  # wrap member DNs in Net::LDAP::Entry objects
  entries.concat members.map! { |dn| Net::LDAP::Entry.new(dn) }

  entries
end