Module: LDAPGroupsLookup::Search

Included in:
LDAPGroupsLookup
Defined in:
lib/ldap_groups_lookup/search.rb

Instance Method Summary collapse

Instance Method Details

#all_ldap_groups(username) ⇒ Object

Lists all groups that a user belongs to. Warning: Utilizes server-side recursive search but may be slower than walking the tree client-side.

Parameters:

  • username (string)

    the user to search by



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/ldap_groups_lookup/search.rb', line 110

def all_ldap_groups(username)
  return [] if service.nil?
  results = service.search(base: group_tree,
               filter: Net::LDAP::Filter.eq('objectcategory', 'group') &
                   Net::LDAP::Filter.ex('member:1.2.840.113556.1.4.1941',
                                        "CN=#{Net::LDAP::Filter.escape(username)},#{account_tree}"),
               attributes: ['cn'])
  if results.nil?
    []
  else
    results.collect do |entry|
      entry[:cn].first
    end
  end
end

#belongs_to_ldap_group?(username, groupname) ⇒ Boolean

Checks if a user is in a group’s membership tree

Parameters:

  • username (String)

    to search for

  • groupname (String)

    to search within

Returns:

  • (Boolean)


97
98
99
100
101
102
103
104
105
# File 'lib/ldap_groups_lookup/search.rb', line 97

def belongs_to_ldap_group?(username, groupname)
  return false if service.nil?
  group_filter = Net::LDAP::Filter.equals('cn', groupname)
  member_filter = Net::LDAP::Filter.equals('member', "cn=#{username},#{account_tree}")
  entry = service.search(base: tree,
                         filter: group_filter & member_filter,
                         attributes: ['cn'])
  entry.count > 0
end

#dn_to_cn(dn) ⇒ Object

Strips a DN string down to just its CN segment.



44
45
46
# File 'lib/ldap_groups_lookup/search.rb', line 44

def dn_to_cn(dn)
  dn.match(/CN=(.+?),/)[1]
end

#ldap_member_of(cn) ⇒ Array

Searches (without recursion) LDAP groups

Parameters:

  • cn (String)

    the group or user to search by

Returns:

  • (Array)

    LDAP groups for cn, one level deep, unsorted



6
7
8
9
10
11
12
13
14
15
16
# File 'lib/ldap_groups_lookup/search.rb', line 6

def ldap_member_of(cn)
  return [] if service.nil?
  entry = service.search(base: tree,
                            filter: Net::LDAP::Filter.equals('cn', cn),
                            attributes: ['memberof']).first
  if entry.nil?
    []
  else
    entry['memberof'].collect { |mo| mo.split(',').first.split('=')[1] }
  end
end

#ldap_members(cn, start = 0) ⇒ Array

Gets the entire list of members for a CN. Handles range results.

Parameters:

  • cn (String)

    of the entry to fetch.

  • start (Integer) (defaults to: 0)

    index of range result

Returns:

  • (Array)

    list of member CNs



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/ldap_groups_lookup/search.rb', line 75

def ldap_members(cn, start=0)
  return [] if service.nil?
  # print "Getting members of #{cn} at index #{start}\n"
  entry = service.search(base: tree,
                         filter: Net::LDAP::Filter.equals('cn', cn),
                         attributes: ["member;range=#{start}-*"]).first
  return [] if entry.nil?

  field_name = entry.attribute_names[1] # Is this always ordered [dn, member]?
  return [] if field_name.nil? # Sometimes member is not present.

  range_end = field_name.to_s.match(/^member;range=\d+-([0-9*]+)$/)[1]
  # print "#{start}-#{range_end}\n"
  members = entry[field_name]#.collect { |mo| mo.split(',').first.split('=')[1] }
  members.concat ldap_members(cn, range_end.to_i+1) unless range_end == '*'
  return members
end

#lookup_dn(cn) ⇒ Object

Returns the DN for the given CN attribute



32
33
34
# File 'lib/ldap_groups_lookup/search.rb', line 32

def lookup_dn(cn)
  service.search(base: tree, filter: Net::LDAP::Filter.equals('cn', cn), attributes: 'dn').first&.dn
end

#lookup_mail(cn) ⇒ Object

Returns the mail for a given CN attribute



37
38
39
40
41
# File 'lib/ldap_groups_lookup/search.rb', line 37

def lookup_mail(cn)
  service&.search(base: tree,
                 filter: Net::LDAP::Filter.equals('cn', cn),
                 attributes: 'mail')&.first&.mail&.first.to_s
end

#walk_ldap_groups(groups, seen = []) ⇒ Array

Searches (recursively) LDAP group membership tree

Parameters:

  • groups (Array)

    to search group membership of

  • seen (Array) (defaults to: [])

    the accumulated list of group membership, defaults to []

Returns:

  • (Array)

    results of searching group membership tree



22
23
24
25
26
27
28
29
# File 'lib/ldap_groups_lookup/search.rb', line 22

def walk_ldap_groups(groups, seen = [])
  groups.each do |g|
    next if seen.include? g
    seen << g
    walk_ldap_groups(ldap_member_of(g), seen)
  end
  seen
end

#walk_ldap_members(groups, dn, seen = []) ⇒ Boolean

Searches a group and its nested member groups for a member DN

Parameters:

  • groups (Array)

    CNs to search

  • dn (String)

    the DN to search for

  • seen (Array) (defaults to: [])

    groups that have already been traversed

Returns:

  • (Boolean)

    true if dn was seen in groups



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/ldap_groups_lookup/search.rb', line 53

def walk_ldap_members(groups, dn, seen = [])
  groups.each do |g|
    members = ldap_members(g)
    return true if members.include? dn
    next if seen.include? g
    seen << g
    member_groups = members.collect do |mg|
      dn_to_cn(mg) if member_whitelist.empty? || member_whitelist.any? do |fil|
        mg.include? fil
      end
    end
    member_groups.compact!
    return true if walk_ldap_members(member_groups, dn, seen)
  end
  return false
end