From 55b554e48ad0f0fd50ccede0246891bbde973b14 Mon Sep 17 00:00:00 2001 From: Jerry Cheung Date: Tue, 23 Dec 2014 14:34:17 -0800 Subject: [PATCH 001/161] add ad group filter --- lib/github/ldap/filter.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/github/ldap/filter.rb b/lib/github/ldap/filter.rb index 64f5aa3..6f62af3 100644 --- a/lib/github/ldap/filter.rb +++ b/lib/github/ldap/filter.rb @@ -3,7 +3,8 @@ class Ldap module Filter ALL_GROUPS_FILTER = Net::LDAP::Filter.eq("objectClass", "groupOfNames") | Net::LDAP::Filter.eq("objectClass", "groupOfUniqueNames") | - Net::LDAP::Filter.eq("objectClass", "posixGroup") + Net::LDAP::Filter.eq("objectClass", "posixGroup") | + Net::LDAP::Filter.eq("objectClass", "group") MEMBERSHIP_NAMES = %w(member uniqueMember) From 8446d9d8d2e65dfa9ce001dea8deb5cef4bf6a89 Mon Sep 17 00:00:00 2001 From: Jerry Cheung Date: Tue, 23 Dec 2014 15:58:20 -0800 Subject: [PATCH 002/161] release 1.7.1 --- CHANGELOG.md | 4 ++++ github-ldap.gemspec | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4034f45..b72dbe7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +# v1.7.1 + +* Add Active Directory group filter [#75](https://github.com/github/github-ldap/pull/75) + ## v1.7.0 * Accept `:depth` option for Recursive membership validator strategy instance [#73](https://github.com/github/github-ldap/pull/73) diff --git a/github-ldap.gemspec b/github-ldap.gemspec index 3383960..3ccbd4e 100644 --- a/github-ldap.gemspec +++ b/github-ldap.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |spec| spec.name = "github-ldap" - spec.version = "1.7.0" + spec.version = "1.7.1" spec.authors = ["David Calavera", "Matt Todd"] spec.email = ["david.calavera@gmail.com", "chiology@gmail.com"] spec.description = %q{LDAP authentication for humans} From 9daf749ae74ac81bafc019ae6a15aebf6865aa13 Mon Sep 17 00:00:00 2001 From: Jerry Cheung Date: Tue, 23 Dec 2014 16:04:48 -0800 Subject: [PATCH 003/161] Release 1.7.1 --- test/domain_test.rb | 12 ++++++++++++ test/filter_test.rb | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/test/domain_test.rb b/test/domain_test.rb index 797f716..446a6e0 100644 --- a/test/domain_test.rb +++ b/test/domain_test.rb @@ -224,3 +224,15 @@ def test_membership_for_posixGroups "Expected `#{@cn}` to not include the member `#{user.dn}`" end end + +class GitHubLdapActiveDirectoryGroupsTest < GitHub::Ldap::Test + def run(*) + self.class.test_env != "activedirectory" ? super : self + end + + def test_filter_groups + domain = @ldap.domain("DC=ad,DC=ghe,DC=local") + results = domain.filter_groups("ghe-admins") + assert_equal 1, results.size + end +end diff --git a/test/filter_test.rb b/test/filter_test.rb index 58992a8..9d8160c 100644 --- a/test/filter_test.rb +++ b/test/filter_test.rb @@ -78,4 +78,8 @@ def test_all_members_by_uid assert_equal "(|(uid=calavera)(uid=mtodd))", @subject.all_members_by_uid(%w(calavera mtodd), :uid).to_s end + + def test_active_directory_group + + end end From a5b2a0060eeefd10ee89a1f9cae9983efb56b82a Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Wed, 14 Jan 2015 16:04:28 -0800 Subject: [PATCH 004/161] Fix domain test --- test/domain_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/domain_test.rb b/test/domain_test.rb index 446a6e0..35a6bff 100644 --- a/test/domain_test.rb +++ b/test/domain_test.rb @@ -231,7 +231,7 @@ def run(*) end def test_filter_groups - domain = @ldap.domain("DC=ad,DC=ghe,DC=local") + domain = GitHub::Ldap.new(options).domain("DC=ad,DC=ghe,DC=local") results = domain.filter_groups("ghe-admins") assert_equal 1, results.size end From 7bc49bc5f468edbc5c89e815130ddac4356e4452 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Wed, 14 Jan 2015 16:04:39 -0800 Subject: [PATCH 005/161] Remove unnecessary AD group filter test --- test/filter_test.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/filter_test.rb b/test/filter_test.rb index 9d8160c..58992a8 100644 --- a/test/filter_test.rb +++ b/test/filter_test.rb @@ -78,8 +78,4 @@ def test_all_members_by_uid assert_equal "(|(uid=calavera)(uid=mtodd))", @subject.all_members_by_uid(%w(calavera mtodd), :uid).to_s end - - def test_active_directory_group - - end end From 0d9b7978c2fe9a0b5c76bc710563237a1a34d1d1 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Wed, 14 Jan 2015 16:07:46 -0800 Subject: [PATCH 006/161] Fix AD-specific runner guard --- test/domain_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/domain_test.rb b/test/domain_test.rb index 35a6bff..4480e60 100644 --- a/test/domain_test.rb +++ b/test/domain_test.rb @@ -227,7 +227,7 @@ def test_membership_for_posixGroups class GitHubLdapActiveDirectoryGroupsTest < GitHub::Ldap::Test def run(*) - self.class.test_env != "activedirectory" ? super : self + self.class.test_env == "activedirectory" ? super : self end def test_filter_groups From 2f49d6b494ae8e9b5f951d68f611ca25ff87e8f2 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Wed, 14 Jan 2015 17:00:32 -0800 Subject: [PATCH 007/161] :fire: unnused variables --- lib/github/ldap/member_search/recursive.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/github/ldap/member_search/recursive.rb b/lib/github/ldap/member_search/recursive.rb index 5fe2489..b1af919 100644 --- a/lib/github/ldap/member_search/recursive.rb +++ b/lib/github/ldap/member_search/recursive.rb @@ -49,11 +49,6 @@ def perform(group) depth.times do |n| # find every (new, unique) member entry depth_subentries = entries.each_with_object([]) do |entry, depth_entries| - submembers = entry["member"] - - # skip any members we've already found - submembers.reject! { |dn| found.key?(dn) } - # find members of subgroup, including subgroups (N queries) subentries = member_entries(entry) next if subentries.empty? From 212816c8407d5a72ea332450a56919c5d91a3546 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Wed, 14 Jan 2015 17:00:54 -0800 Subject: [PATCH 008/161] Skip searching for entries already found --- lib/github/ldap/member_search/recursive.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/github/ldap/member_search/recursive.rb b/lib/github/ldap/member_search/recursive.rb index b1af919..f75ebfc 100644 --- a/lib/github/ldap/member_search/recursive.rb +++ b/lib/github/ldap/member_search/recursive.rb @@ -50,7 +50,7 @@ def perform(group) # find every (new, unique) member entry depth_subentries = entries.each_with_object([]) do |entry, depth_entries| # find members of subgroup, including subgroups (N queries) - subentries = member_entries(entry) + subentries = member_entries(entry, found) next if subentries.empty? # track found subentries @@ -75,11 +75,15 @@ def perform(group) # entry. # # Returns an Array of Net::LDAP::Entry objects. - def member_entries(entry) + def member_entries(entry, found = {}) entries = [] dns = member_dns(entry) uids = member_uids(entry) + # skip any entries we've already found + dns.reject! { |dn| found.key?(dn) } + uids.reject! { |uid| found.any? { |entry| entry['uid'].include?(uid) } } + entries.concat entries_by_uid(uids) unless uids.empty? entries.concat entries_by_dn(dns) unless dns.empty? From 2a62c2112def6afd865e7a161955a082a5de492b Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Wed, 14 Jan 2015 21:54:11 -0800 Subject: [PATCH 009/161] Find subgroups, then materialize members --- lib/github/ldap/member_search/recursive.rb | 104 ++++++++++----------- 1 file changed, 51 insertions(+), 53 deletions(-) diff --git a/lib/github/ldap/member_search/recursive.rb b/lib/github/ldap/member_search/recursive.rb index f75ebfc..8eaa2e6 100644 --- a/lib/github/ldap/member_search/recursive.rb +++ b/lib/github/ldap/member_search/recursive.rb @@ -34,72 +34,70 @@ def initialize(ldap, options = {}) # # Returns Array of Net::LDAP::Entry objects. def perform(group) - found = Hash.new - - # find members (N queries) - entries = member_entries(group) - return [] if entries.empty? - - # track found entries - entries.each do |entry| - found[entry.dn] = entry + found = Hash.new + searched = [] + entries = [] + + # 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 + filter = ALL_GROUPS_FILTER + groups = dns.each_with_object([]) do |dn, groups| + groups.concat ldap.search(base: dn, scope: Net::LDAP::SearchScope_BaseObject, attributes: attrs, filter: filter) + searched << dn end - # descend to `depth` levels, at most - depth.times do |n| - # find every (new, unique) member entry - depth_subentries = entries.each_with_object([]) do |entry, depth_entries| - # find members of subgroup, including subgroups (N queries) - subentries = member_entries(entry, found) - next if subentries.empty? + # track found groups + groups.each { |g| found[g.dn] = g } - # track found subentries - subentries.each { |entry| found[entry.dn] = entry } + # 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 - # collect all entries for this depth - depth_entries.concat subentries - end + # give up if there's nothing else to search for + break if sub_dns.empty? - # stop if there are no more subgroups to search - break if depth_subentries.empty? + # filter out if already searched for + sub_dns.reject! { |dn| searched.include?(dn) } - # go one level deeper - entries = depth_subentries - end + # search for subgroups + subgroups = sub_dns.each_with_object([]) do |dn, subgroups| + subgroups.concat ldap.search(base: dn, scope: Net::LDAP::SearchScope_BaseObject, attributes: attrs, filter: filter) + searched << dn + end - # return all found entries - found.values - end + break if subgroups.empty? - # Internal: Fetch member entries, including subgroups, for the given - # entry. - # - # Returns an Array of Net::LDAP::Entry objects. - def member_entries(entry, found = {}) - entries = [] - dns = member_dns(entry) - uids = member_uids(entry) + # track found groups + subgroups.each { |g| found[g.dn] = g } - # skip any entries we've already found - dns.reject! { |dn| found.key?(dn) } - uids.reject! { |uid| found.any? { |entry| entry['uid'].include?(uid) } } + # descend another level + groups = subgroups + end + end - entries.concat entries_by_uid(uids) unless uids.empty? - entries.concat entries_by_dn(dns) unless dns.empty? + # take found groups and combine groups and members into list of entries + found.values.each do |group| + entries << group + # just need member DNs as Net::LDAP::Entry objects + entries.concat member_dns(group).map { |dn| Net::LDAP::Entry.new(dn) } + end entries end - private :member_entries - - # Internal: Bind a list of DNs to their respective entries. - # - # Returns an Array of Net::LDAP::Entry objects. - def entries_by_dn(members) - members.map do |dn| - ldap.domain(dn).bind(attributes: attrs) - end.compact - end - private :entries_by_dn # Internal: Fetch entries by UID. # From cb4bd2ce9f2d18ef627c05f63b2f8105586fcf5c Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Wed, 14 Jan 2015 22:05:24 -0800 Subject: [PATCH 010/161] Ensure unique entries --- lib/github/ldap/member_search/recursive.rb | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/github/ldap/member_search/recursive.rb b/lib/github/ldap/member_search/recursive.rb index 8eaa2e6..ab1374c 100644 --- a/lib/github/ldap/member_search/recursive.rb +++ b/lib/github/ldap/member_search/recursive.rb @@ -89,12 +89,14 @@ def perform(group) end end - # take found groups and combine groups and members into list of entries - found.values.each do |group| + # pull member DNs, discarding dupes and subgroup DNs + member_dns = found.values.each_with_object([]) do |group, member_dns| entries << group - # just need member DNs as Net::LDAP::Entry objects - entries.concat member_dns(group).map { |dn| Net::LDAP::Entry.new(dn) } - end + member_dns.concat member_dns(group) + end.uniq.reject { |dn| found.key?(dn) } + + # wrap member DNs in Net::LDAP::Entry objects + entries.concat member_dns.map { |dn| Net::LDAP::Entry.new(dn) } entries end From 909da53b87a6c7e304fbb97d1afd0747aab7a959 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Thu, 15 Jan 2015 13:37:50 -0800 Subject: [PATCH 011/161] Doc, reorder variables to make purpose explicit --- lib/github/ldap/member_search/recursive.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/github/ldap/member_search/recursive.rb b/lib/github/ldap/member_search/recursive.rb index ab1374c..9b04df3 100644 --- a/lib/github/ldap/member_search/recursive.rb +++ b/lib/github/ldap/member_search/recursive.rb @@ -34,9 +34,11 @@ def initialize(ldap, options = {}) # # Returns Array of Net::LDAP::Entry objects. def perform(group) - found = Hash.new + # track groups found + found = Hash.new + + # track DNs searched for (so we don't repeat searches) searched = [] - entries = [] # if this is a posixGroup, return members immediately (no nesting) uids = member_uids(group) @@ -89,6 +91,9 @@ def perform(group) end end + # entries to return + entries = [] + # pull member DNs, discarding dupes and subgroup DNs member_dns = found.values.each_with_object([]) do |group, member_dns| entries << group From 09e05a67d030739a78b690afe3d1a3576869fade Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Thu, 15 Jan 2015 13:41:11 -0800 Subject: [PATCH 012/161] Use a Set to track DNs searched for --- lib/github/ldap/member_search/recursive.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/github/ldap/member_search/recursive.rb b/lib/github/ldap/member_search/recursive.rb index 9b04df3..fa3d5a8 100644 --- a/lib/github/ldap/member_search/recursive.rb +++ b/lib/github/ldap/member_search/recursive.rb @@ -37,8 +37,8 @@ def perform(group) # track groups found found = Hash.new - # track DNs searched for (so we don't repeat searches) - searched = [] + # 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) From 52654ad40bd92932e93089278ae6e79302f14d48 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Thu, 15 Jan 2015 13:56:13 -0800 Subject: [PATCH 013/161] Short circuit after filtering out already searched DNs --- lib/github/ldap/member_search/recursive.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/github/ldap/member_search/recursive.rb b/lib/github/ldap/member_search/recursive.rb index fa3d5a8..d082de0 100644 --- a/lib/github/ldap/member_search/recursive.rb +++ b/lib/github/ldap/member_search/recursive.rb @@ -69,12 +69,12 @@ def perform(group) sub_dns.concat member_dns(subgroup) end - # give up if there's nothing else to search for - break if sub_dns.empty? - # 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 ldap.search(base: dn, scope: Net::LDAP::SearchScope_BaseObject, attributes: attrs, filter: filter) From 8fce4a79dc48cffaa67c62d7ab68120427a074ca Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Thu, 15 Jan 2015 14:22:47 -0800 Subject: [PATCH 014/161] Extract group search method --- lib/github/ldap/member_search/recursive.rb | 31 ++++++++++++++++++---- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/lib/github/ldap/member_search/recursive.rb b/lib/github/ldap/member_search/recursive.rb index d082de0..5ee8420 100644 --- a/lib/github/ldap/member_search/recursive.rb +++ b/lib/github/ldap/member_search/recursive.rb @@ -52,9 +52,8 @@ def perform(group) dns = member_dns(group) # search for base group's subgroups - filter = ALL_GROUPS_FILTER groups = dns.each_with_object([]) do |dn, groups| - groups.concat ldap.search(base: dn, scope: Net::LDAP::SearchScope_BaseObject, attributes: attrs, filter: filter) + groups.concat find_groups_by_dn(dn) searched << dn end @@ -77,13 +76,14 @@ def perform(group) # search for subgroups subgroups = sub_dns.each_with_object([]) do |dn, subgroups| - subgroups.concat ldap.search(base: dn, scope: Net::LDAP::SearchScope_BaseObject, attributes: attrs, filter: filter) - searched << dn + subgroups.concat find_groups_by_dn(dn) + searched << dn end + # give up if there were no subgroups found break if subgroups.empty? - # track found groups + # track found subgroups subgroups.each { |g| found[g.dn] = g } # descend another level @@ -106,6 +106,27 @@ def perform(group) entries end + # Internal: Search for Groups by DN. + # + # Given a Distinguished Name (DN) String value, find the Group entry + # that matches it. The DN may map to a `person` entry, but we want to + # filter those out. + # + # This will find zero or one entry most of the time, but it's not + # guaranteed so we account for the possibility of more. + # + # This method is intended to be used with `Array#concat` by the caller. + # + # Returns an Array of zero or more Net::LDAP::Entry objects. + def find_groups_by_dn(dn) + ldap.search \ + base: dn, + scope: Net::LDAP::SearchScope_BaseObject, + attributes: attrs, + filter: ALL_GROUPS_FILTER + end + private :find_group_by_dn + # Internal: Fetch entries by UID. # # Returns an Array of Net::LDAP::Entry objects. From 2e5943b9d822a2a2a277ba2bbca33791ac4a9671 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Thu, 15 Jan 2015 14:23:30 -0800 Subject: [PATCH 015/161] Fix spacing [skip ci] --- lib/github/ldap/member_search/recursive.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/github/ldap/member_search/recursive.rb b/lib/github/ldap/member_search/recursive.rb index 5ee8420..5235d5a 100644 --- a/lib/github/ldap/member_search/recursive.rb +++ b/lib/github/ldap/member_search/recursive.rb @@ -77,7 +77,7 @@ def perform(group) # search for subgroups subgroups = sub_dns.each_with_object([]) do |dn, subgroups| subgroups.concat find_groups_by_dn(dn) - searched << dn + searched << dn end # give up if there were no subgroups found From de8d8b46a8d8dcf25589bd46d1cc41f506e6dd6a Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Thu, 15 Jan 2015 14:29:23 -0800 Subject: [PATCH 016/161] Tweak member DN collection, mapping --- lib/github/ldap/member_search/recursive.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/github/ldap/member_search/recursive.rb b/lib/github/ldap/member_search/recursive.rb index 5235d5a..bbc557f 100644 --- a/lib/github/ldap/member_search/recursive.rb +++ b/lib/github/ldap/member_search/recursive.rb @@ -94,14 +94,14 @@ def perform(group) # entries to return entries = [] - # pull member DNs, discarding dupes and subgroup DNs - member_dns = found.values.each_with_object([]) do |group, member_dns| + # collect all member DNs, discarding dupes and subgroup DNs + members = found.values.each_with_object([]) do |group, dns| entries << group - member_dns.concat member_dns(group) + dns.concat member_dns(group) end.uniq.reject { |dn| found.key?(dn) } # wrap member DNs in Net::LDAP::Entry objects - entries.concat member_dns.map { |dn| Net::LDAP::Entry.new(dn) } + entries.concat members.map! { |dn| Net::LDAP::Entry.new(dn) } entries end From 973959d4f4aec8b62bb5e9f837e0cbe2c206cf68 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Thu, 15 Jan 2015 14:29:35 -0800 Subject: [PATCH 017/161] Fix method name --- lib/github/ldap/member_search/recursive.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/github/ldap/member_search/recursive.rb b/lib/github/ldap/member_search/recursive.rb index bbc557f..a36aa4d 100644 --- a/lib/github/ldap/member_search/recursive.rb +++ b/lib/github/ldap/member_search/recursive.rb @@ -125,7 +125,7 @@ def find_groups_by_dn(dn) attributes: attrs, filter: ALL_GROUPS_FILTER end - private :find_group_by_dn + private :find_groups_by_dn # Internal: Fetch entries by UID. # From 196bc17bac97056f99f73853555a922856f741f7 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Mon, 19 Jan 2015 17:50:48 -0800 Subject: [PATCH 018/161] Bump version to 1.8.0 --- github-ldap.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github-ldap.gemspec b/github-ldap.gemspec index 3ccbd4e..50ad02d 100644 --- a/github-ldap.gemspec +++ b/github-ldap.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |spec| spec.name = "github-ldap" - spec.version = "1.7.1" + spec.version = "1.8.0" spec.authors = ["David Calavera", "Matt Todd"] spec.email = ["david.calavera@gmail.com", "chiology@gmail.com"] spec.description = %q{LDAP authentication for humans} From 5107dc7ee9b761940252935731b00cfd23d21a20 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Mon, 19 Jan 2015 17:51:57 -0800 Subject: [PATCH 019/161] Update changelog for 1.8.0 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b72dbe7..f6d0941 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +# v1.8.0 + +* Optimize Recursive *Member Search* strategy [#78](https://github.com/github/github-ldap/pull/78) + # v1.7.1 * Add Active Directory group filter [#75](https://github.com/github/github-ldap/pull/75) From 47be59a7e04b13327b19de5ab48520076504e62a Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Mon, 19 Jan 2015 17:59:03 -0800 Subject: [PATCH 020/161] Release 1.8.0 From e219da1cb86aecd94e09188c930bef655a2b67f7 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Mon, 2 Feb 2015 14:30:48 -0800 Subject: [PATCH 021/161] Expand AD caps support to v60 This adds support for Windows Server 2008 and above, instead of only 2008 R2 and above. --- lib/github/ldap.rb | 4 ++-- test/ldap_test.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index ebdfddc..6384023 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -19,7 +19,7 @@ class Ldap # Internal: The capability required to use ActiveDirectory features. # See: http://msdn.microsoft.com/en-us/library/cc223359.aspx. - ACTIVE_DIRECTORY_V61_R2_OID = "1.2.840.113556.1.4.2080".freeze + ACTIVE_DIRECTORY_V60_OID = "1.2.840.113556.1.4.1935".freeze # Utility method to get the last operation result with a human friendly message. # @@ -313,7 +313,7 @@ def configure_member_search_strategy(strategy = nil) # # Returns true if the host is an ActiveDirectory server, false otherwise. def active_directory_capability? - capabilities[:supportedcapabilities].include?(ACTIVE_DIRECTORY_V61_R2_OID) + capabilities[:supportedcapabilities].include?(ACTIVE_DIRECTORY_V60_OID) end private :active_directory_capability? end diff --git a/test/ldap_test.rb b/test/ldap_test.rb index 48511d8..119c163 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -80,7 +80,7 @@ def test_search_strategy_defaults def test_search_strategy_detects_active_directory caps = Net::LDAP::Entry.new - caps[:supportedcapabilities] = [GitHub::Ldap::ACTIVE_DIRECTORY_V61_R2_OID] + caps[:supportedcapabilities] = [GitHub::Ldap::ACTIVE_DIRECTORY_V60_OID] @ldap.stub :capabilities, caps do @ldap.configure_search_strategy :detect From 5cfcb2f6457e34ebcd4f175aaf2d5913ee64bc31 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Mon, 2 Feb 2015 14:44:59 -0800 Subject: [PATCH 022/161] Bring back further to v51 for 2k3+ support --- lib/github/ldap.rb | 4 ++-- test/ldap_test.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 6384023..0545247 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -19,7 +19,7 @@ class Ldap # Internal: The capability required to use ActiveDirectory features. # See: http://msdn.microsoft.com/en-us/library/cc223359.aspx. - ACTIVE_DIRECTORY_V60_OID = "1.2.840.113556.1.4.1935".freeze + ACTIVE_DIRECTORY_V51_OID = "1.2.840.113556.1.4.1670".freeze # Utility method to get the last operation result with a human friendly message. # @@ -313,7 +313,7 @@ def configure_member_search_strategy(strategy = nil) # # Returns true if the host is an ActiveDirectory server, false otherwise. def active_directory_capability? - capabilities[:supportedcapabilities].include?(ACTIVE_DIRECTORY_V60_OID) + capabilities[:supportedcapabilities].include?(ACTIVE_DIRECTORY_V51_OID) end private :active_directory_capability? end diff --git a/test/ldap_test.rb b/test/ldap_test.rb index 119c163..c7b24c4 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -80,7 +80,7 @@ def test_search_strategy_defaults def test_search_strategy_detects_active_directory caps = Net::LDAP::Entry.new - caps[:supportedcapabilities] = [GitHub::Ldap::ACTIVE_DIRECTORY_V60_OID] + caps[:supportedcapabilities] = [GitHub::Ldap::ACTIVE_DIRECTORY_V51_OID] @ldap.stub :capabilities, caps do @ldap.configure_search_strategy :detect From ba158a024e5d236a6fa42b51c38fadcfc8595723 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Mon, 2 Feb 2015 14:53:39 -0800 Subject: [PATCH 023/161] Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6d0941..f09c1c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +# v1.8.1 + +* Expand supported ActiveDirectory capabilities to include Windows Server 2003 [#80](https://github.com/github/github-ldap/pull/80) + # v1.8.0 * Optimize Recursive *Member Search* strategy [#78](https://github.com/github/github-ldap/pull/78) From f7c44a1a3cc01e25c5db15f6a8266800df98f603 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Mon, 2 Feb 2015 14:54:36 -0800 Subject: [PATCH 024/161] Bump version to 1.8.1 --- github-ldap.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github-ldap.gemspec b/github-ldap.gemspec index 50ad02d..fb15c7f 100644 --- a/github-ldap.gemspec +++ b/github-ldap.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |spec| spec.name = "github-ldap" - spec.version = "1.8.0" + spec.version = "1.8.1" spec.authors = ["David Calavera", "Matt Todd"] spec.email = ["david.calavera@gmail.com", "chiology@gmail.com"] spec.description = %q{LDAP authentication for humans} From 99ab8c6376c4e53bd602c01f494c0b7b183043d1 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Mon, 2 Feb 2015 14:55:17 -0800 Subject: [PATCH 025/161] Release 1.8.1 From 92f18b196f090d8a518a97ceacaa81705ee38b86 Mon Sep 17 00:00:00 2001 From: Ben Gollmer Date: Fri, 8 May 2015 23:56:07 +0200 Subject: [PATCH 026/161] Compare AD DNs case-insensitively when checking group membership --- .../ldap/membership_validators/active_directory.rb | 3 ++- test/membership_validators/active_directory_test.rb | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/github/ldap/membership_validators/active_directory.rb b/lib/github/ldap/membership_validators/active_directory.rb index 0c531c4..69b9bc8 100644 --- a/lib/github/ldap/membership_validators/active_directory.rb +++ b/lib/github/ldap/membership_validators/active_directory.rb @@ -31,7 +31,8 @@ def perform(entry) attributes: ATTRS # membership validated if entry was matched and returned as a result - matched.map(&:dn).include?(entry.dn) + # Active Directory DNs are case-insensitive + matched.map { |m| m.dn.downcase }.include?(entry.dn.downcase) end # Internal: Constructs a membership filter using the "in chain" diff --git a/test/membership_validators/active_directory_test.rb b/test/membership_validators/active_directory_test.rb index 0caafe2..956fbc5 100644 --- a/test/membership_validators/active_directory_test.rb +++ b/test/membership_validators/active_directory_test.rb @@ -123,4 +123,13 @@ def test_validates_user_in_posix_group validator = make_validator(%w(posix-group1)) assert validator.perform(@entry) end + + def test_validates_user_in_group_with_differently_cased_dn + validator = make_validator(%w(all-users)) + @entry[:dn].map(&:upcase!) + assert validator.perform(@entry) + + @entry[:dn].map(&:downcase!) + assert validator.perform(@entry) + end end From 094a3d5ed85ecd71cba1351cade527137db6cde2 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Thu, 14 May 2015 11:36:20 -0700 Subject: [PATCH 027/161] Bump patch version, update changelog --- CHANGELOG.md | 4 ++++ github-ldap.gemspec | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f09c1c9..edd76c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +# v1.8.2 + +* Ignore case when comparing ActiveDirectory DNs [#82](https://github.com/github/github-ldap/pull/82) + # v1.8.1 * Expand supported ActiveDirectory capabilities to include Windows Server 2003 [#80](https://github.com/github/github-ldap/pull/80) diff --git a/github-ldap.gemspec b/github-ldap.gemspec index fb15c7f..c34dc5d 100644 --- a/github-ldap.gemspec +++ b/github-ldap.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |spec| spec.name = "github-ldap" - spec.version = "1.8.1" + spec.version = "1.8.2" spec.authors = ["David Calavera", "Matt Todd"] spec.email = ["david.calavera@gmail.com", "chiology@gmail.com"] spec.description = %q{LDAP authentication for humans} From e2f51d09926725d2c0b055fc4489e5c1eeaac51a Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Fri, 15 May 2015 12:05:11 -0700 Subject: [PATCH 028/161] Depend on net-ldap v0.11.x --- github-ldap.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github-ldap.gemspec b/github-ldap.gemspec index c34dc5d..fb0bb36 100644 --- a/github-ldap.gemspec +++ b/github-ldap.gemspec @@ -15,7 +15,7 @@ Gem::Specification.new do |spec| spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ["lib"] - spec.add_dependency 'net-ldap', '~> 0.10.0' + spec.add_dependency 'net-ldap', '~> 0.11.0' spec.add_development_dependency "bundler", "~> 1.3" spec.add_development_dependency 'ladle' From c076b1ada3829e487c6d470384395fa72682269d Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Fri, 15 May 2015 12:28:52 -0700 Subject: [PATCH 029/161] Setup GitHub::Ldap instance with correct settings --- test/filter_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/filter_test.rb b/test/filter_test.rb index 58992a8..4da83c9 100644 --- a/test/filter_test.rb +++ b/test/filter_test.rb @@ -1,6 +1,6 @@ require_relative 'test_helper' -class FilterTest < Minitest::Test +class FilterTest < GitHub::Ldap::Test class Subject include GitHub::Ldap::Filter def initialize(ldap) @@ -16,7 +16,7 @@ def [](field) end def setup - @ldap = GitHub::Ldap.new(:uid => 'uid') + @ldap = GitHub::Ldap.new(options.merge(:uid => 'uid')) @subject = Subject.new(@ldap) @me = 'uid=calavera,dc=github,dc=com' @uid = "calavera" From 42dc1fca788f148c2de7e11ff136ee91a2042ac8 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Fri, 15 May 2015 12:39:31 -0700 Subject: [PATCH 030/161] Bump version to 1.9.0, update changelog --- CHANGELOG.md | 4 ++++ github-ldap.gemspec | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index edd76c8..70c0eed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +# v1.9.0 + +* Update net-ldap dependency to `~> 0.11.0` [#84](https://github.com/github/github-ldap/pull/84) + # v1.8.2 * Ignore case when comparing ActiveDirectory DNs [#82](https://github.com/github/github-ldap/pull/82) diff --git a/github-ldap.gemspec b/github-ldap.gemspec index fb0bb36..af13ce0 100644 --- a/github-ldap.gemspec +++ b/github-ldap.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |spec| spec.name = "github-ldap" - spec.version = "1.8.2" + spec.version = "1.9.0" spec.authors = ["David Calavera", "Matt Todd"] spec.email = ["david.calavera@gmail.com", "chiology@gmail.com"] spec.description = %q{LDAP authentication for humans} From c3b2401634e169434f80514d156aae02d72dc339 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Fri, 15 May 2015 12:48:22 -0700 Subject: [PATCH 031/161] Release 1.9.0 From f4da8948695be6637cab4cc10d9192c5fb6347f6 Mon Sep 17 00:00:00 2001 From: Colin Seymour Date: Mon, 11 Apr 2016 16:40:18 +0100 Subject: [PATCH 032/161] Bump net-ldap requirement to 0.14.0 We need this so we can take advantage of the `hosts` option --- github-ldap.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github-ldap.gemspec b/github-ldap.gemspec index af13ce0..eb04367 100644 --- a/github-ldap.gemspec +++ b/github-ldap.gemspec @@ -15,7 +15,7 @@ Gem::Specification.new do |spec| spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ["lib"] - spec.add_dependency 'net-ldap', '~> 0.11.0' + spec.add_dependency 'net-ldap', '~> 0.14.0' spec.add_development_dependency "bundler", "~> 1.3" spec.add_development_dependency 'ladle' From baca799d8f7d7431116a48c5fc45c949934d4964 Mon Sep 17 00:00:00 2001 From: Colin Seymour Date: Mon, 11 Apr 2016 16:41:02 +0100 Subject: [PATCH 033/161] Adds support for the `hosts` option now available in net-ldap --- lib/github/ldap.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 0545247..90c6f92 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -50,6 +50,9 @@ class Ldap # # host: required string ldap server host address # port: required string or number ldap server port + # hosts: an enumerable of pairs of hosts and corresponding ports with + # which to attempt opening connections (default [[host, port]]). Overrides + # host and port if set. # encryption: optional string. `ssl` or `tls`. nil by default # admin_user: optional string ldap administrator user dn for authentication # admin_password: optional string ldap administrator user password @@ -72,6 +75,7 @@ def initialize(options = {}) @connection = Net::LDAP.new({ host: options[:host], port: options[:port], + hosts: options[:hosts], instrumentation_service: options[:instrumentation_service] }) From 65e653987f7138b3ce0518fe1a88deb44f70d2c6 Mon Sep 17 00:00:00 2001 From: Colin Seymour Date: Mon, 11 Apr 2016 16:41:39 +0100 Subject: [PATCH 034/161] Add tests for `hosts` option --- test/ldap_test.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/ldap_test.rb b/test/ldap_test.rb index c7b24c4..d00c7a0 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -9,6 +9,21 @@ def test_connection_with_default_options assert @ldap.test_connection, "Ldap connection expected to succeed" end + def test_connection_with_list_of_hosts_with_one_valid_host + ldap = GitHub::Ldap.new(options.merge(hosts: [["localhost", 3897]])) + assert ldap.test_connection, "Ldap connection expected to succeed" + end + + def test_connection_with_list_of_hosts_with_first_valid + ldap = GitHub::Ldap.new(options.merge(hosts: [["localhost", 3897], ["invalid.local", 3897]])) + assert ldap.test_connection, "Ldap connection expected to succeed" + end + + def test_connection_with_list_of_hosts_with_first_invalid + ldap = GitHub::Ldap.new(options.merge(hosts: [["invalid.local", 3897], ["localhost", 3897]])) + assert ldap.test_connection, "Ldap connection expected to succeed" + end + def test_simple_tls assert_equal :simple_tls, @ldap.check_encryption(:ssl) assert_equal :simple_tls, @ldap.check_encryption('SSL') From a87afd0d562871b741ce6e02968a8b9d9261abcf Mon Sep 17 00:00:00 2001 From: Colin Seymour Date: Mon, 11 Apr 2016 16:53:47 +0100 Subject: [PATCH 035/161] Document `hosts` option in README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 482f6ea..eb5fb01 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ There are a few configuration options required to use this adapter: * host: is the host address where the ldap server lives. * port: is the port where the ldap server lives. +* hosts: (optional) an enumerable of pairs of hosts and corresponding ports with which to attempt opening connections (default [[host, port]]). Overrides host and port if set. * encryption: is the encryption protocol, disabled by default. The valid options are `ssl` and `tls`. * uid: is the field name in the ldap server used to authenticate your users, in ActiveDirectory this is `sAMAccountName`. From 0e695c622af73498c692901051c03160b388e863 Mon Sep 17 00:00:00 2001 From: Colin Seymour Date: Fri, 15 Apr 2016 10:49:55 +0100 Subject: [PATCH 036/161] Bump version --- github-ldap.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github-ldap.gemspec b/github-ldap.gemspec index eb04367..b098983 100644 --- a/github-ldap.gemspec +++ b/github-ldap.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |spec| spec.name = "github-ldap" - spec.version = "1.9.0" + spec.version = "1.9.1" spec.authors = ["David Calavera", "Matt Todd"] spec.email = ["david.calavera@gmail.com", "chiology@gmail.com"] spec.description = %q{LDAP authentication for humans} From c2cc6e58c0ca52411a9a7b58c4e6b172e2f2ff29 Mon Sep 17 00:00:00 2001 From: Jerry Cheung Date: Wed, 13 Jul 2016 09:25:55 -0700 Subject: [PATCH 037/161] bump net-ldap 0.15.0 --- github-ldap.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github-ldap.gemspec b/github-ldap.gemspec index af13ce0..4ad193c 100644 --- a/github-ldap.gemspec +++ b/github-ldap.gemspec @@ -15,7 +15,7 @@ Gem::Specification.new do |spec| spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ["lib"] - spec.add_dependency 'net-ldap', '~> 0.11.0' + spec.add_dependency 'net-ldap', '~> 0.15.0' spec.add_development_dependency "bundler", "~> 1.3" spec.add_development_dependency 'ladle' From 0c2efc8bf517ba5b3ad199fc18d1beef9fb55ff7 Mon Sep 17 00:00:00 2001 From: Jerry Cheung Date: Wed, 13 Jul 2016 09:31:10 -0700 Subject: [PATCH 038/161] release 1.10.0 --- CHANGELOG.md | 4 ++++ github-ldap.gemspec | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 70c0eed..2ae6339 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +# v1.10.0 + +* Bump net-ldap to 0.15.0 [#92](https://github.com/github/github-ldap/pull/92) + # v1.9.0 * Update net-ldap dependency to `~> 0.11.0` [#84](https://github.com/github/github-ldap/pull/84) diff --git a/github-ldap.gemspec b/github-ldap.gemspec index 4ad193c..b8514d0 100644 --- a/github-ldap.gemspec +++ b/github-ldap.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |spec| spec.name = "github-ldap" - spec.version = "1.9.0" + spec.version = "1.10.0" spec.authors = ["David Calavera", "Matt Todd"] spec.email = ["david.calavera@gmail.com", "chiology@gmail.com"] spec.description = %q{LDAP authentication for humans} From 8d66502d246cc5ecbe246b0b06fd69c172020d40 Mon Sep 17 00:00:00 2001 From: Jerry Cheung Date: Wed, 13 Jul 2016 09:31:51 -0700 Subject: [PATCH 039/161] Release 1.10.0 From ecf5c434b0ae2338c45e6c8e28d772b267efb2ae Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 25 Jul 2016 09:29:10 -0500 Subject: [PATCH 040/161] Load a global catalog connection & add interface for searching it --- lib/github/ldap.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 0545247..612e245 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -193,6 +193,20 @@ def search(options, &block) end end + def global_catalog_search(options, &block) + options[:base] = "" + Array(global_catalog_connection.search(options, &block)) + end + + def global_catalog_connection + @global_catalog_connection ||= Net::LDAP.new({ + host: @connection.instance_variable_get(:@host), + auth: @connection.instance_variable_get(:@auth), + instrumentation_service: @connection.instance_variable_get(:@instrumentation_service), + port: 3268, + }) + end + # Internal: Searches the host LDAP server's Root DSE for capabilities and # extensions. # From 51e72c0c206926fdb6e337537cbe07724e9a055b Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 25 Jul 2016 09:30:11 -0500 Subject: [PATCH 041/161] Use global catalog to detect user, if server is Active Directory --- lib/github/ldap.rb | 1 - lib/github/ldap/domain.rb | 11 ++++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 612e245..7f7ac39 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -329,6 +329,5 @@ def configure_member_search_strategy(strategy = nil) def active_directory_capability? capabilities[:supportedcapabilities].include?(ACTIVE_DIRECTORY_V51_OID) end - private :active_directory_capability? end end diff --git a/lib/github/ldap/domain.rb b/lib/github/ldap/domain.rb index 8fd904f..2332e9c 100644 --- a/lib/github/ldap/domain.rb +++ b/lib/github/ldap/domain.rb @@ -118,7 +118,12 @@ def user?(login, search_options = {}) options = search_options.merge \ filter: login_filter(@uid, login), size: 1 - search(options).first + + if @ldap.active_directory_capability? + global_catalog_search(options).first + else + search(options).first + end end # Check if a user can be bound with a password. @@ -160,6 +165,10 @@ def search(options, &block) @ldap.search(options, &block) end + def global_catalog_search(options, &block) + @ldap.global_catalog_search(options, &block) + end + # Get the entry for this domain. # # Returns a Net::LDAP::Entry From 203063d6e606eed1772cda85c078d2c6ecdc4cd9 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 25 Jul 2016 09:51:40 -0500 Subject: [PATCH 042/161] Add tests for auth & unauth default Global Catalog settings --- Gemfile | 1 + test/ldap_test.rb | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/Gemfile b/Gemfile index 4abbfe8..edf9461 100644 --- a/Gemfile +++ b/Gemfile @@ -5,4 +5,5 @@ gemspec group :test, :development do gem "byebug", :platforms => [:mri_20, :mri_21] + gem "mocha" end diff --git a/test/ldap_test.rb b/test/ldap_test.rb index c7b24c4..b5e4eb1 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -117,12 +117,40 @@ def test_search_strategy_misconfigured_to_unrecognized_strategy_falls_back_to_de def test_capabilities assert_kind_of Net::LDAP::Entry, @ldap.capabilities end + + module GitHubLdapUnauthenticatedTestCases + def test_global_catalog_default_settings + global_catalog = @ldap.global_catalog_connection + # this is ugly, but currently the only way to test Net::LDAP#auth values + auth = global_catalog.instance_variable_get(:@auth) + + assert_equal "localhost", global_catalog.host + assert_equal 3268, global_catalog.port + assert_equal nil, auth[:password] + assert_equal nil, auth[:username] + end + end + + module GitHubLdapAuthenticatedTestCases + def test_global_catalog_default_settings + global_catalog = @ldap.global_catalog_connection + # this is ugly, but currently the only way to test Net::LDAP#auth values + auth = global_catalog.instance_variable_get(:@auth) + + assert_equal "localhost", global_catalog.host + assert_equal 3268, global_catalog.port + assert_equal "passworD1", auth[:password] + assert_equal "uid=admin,dc=github,dc=com", auth[:username] + end + end end class GitHubLdapTest < GitHub::Ldap::Test include GitHubLdapTestCases + include GitHubLdapAuthenticatedTestCases end class GitHubLdapUnauthenticatedTest < GitHub::Ldap::UnauthenticatedTest include GitHubLdapTestCases + include GitHubLdapUnauthenticatedTestCases end From a23ccef696a825ed32d77396cf1ce165a9f9fecc Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 25 Jul 2016 10:08:17 -0500 Subject: [PATCH 043/161] Test format of Global Catalog search results --- test/ldap_test.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/ldap_test.rb b/test/ldap_test.rb index b5e4eb1..1401486 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -1,4 +1,5 @@ require_relative 'test_helper' +require 'mocha/mini_test' module GitHubLdapTestCases def setup @@ -118,6 +119,23 @@ def test_capabilities assert_kind_of Net::LDAP::Entry, @ldap.capabilities end + def test_global_catalog_returns_empty_array_for_no_results + mock_global_catalog_connection = Object.new + mock_global_catalog_connection.expects(:search).returns(nil) + Net::LDAP.expects(:new).returns(mock_global_catalog_connection) + results = @ldap.global_catalog_search({}) + assert_equal [], results + end + + def test_global_catalog_returns_array_of_results + mock_global_catalog_connection = Object.new + stub_entry = Object.new + mock_global_catalog_connection.expects(:search).returns(stub_entry) + Net::LDAP.expects(:new).returns(mock_global_catalog_connection) + results = @ldap.global_catalog_search({}) + assert_equal [stub_entry], results + end + module GitHubLdapUnauthenticatedTestCases def test_global_catalog_default_settings global_catalog = @ldap.global_catalog_connection From c03c0de4186eaa05f2bf9c64b1f9f6313be033bb Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 25 Jul 2016 10:12:07 -0500 Subject: [PATCH 044/161] Split up auth'd, unauth'd and global default settings tests --- test/ldap_test.rb | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/test/ldap_test.rb b/test/ldap_test.rb index 1401486..8efbc00 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -136,27 +136,30 @@ def test_global_catalog_returns_array_of_results assert_equal [stub_entry], results end + def test_global_catalog_default_settings + global_catalog = @ldap.global_catalog_connection + + assert_equal "localhost", global_catalog.host + assert_equal 3268, global_catalog.port + end + module GitHubLdapUnauthenticatedTestCases - def test_global_catalog_default_settings + def test_global_catalog_unauthenticated_default_settings global_catalog = @ldap.global_catalog_connection # this is ugly, but currently the only way to test Net::LDAP#auth values auth = global_catalog.instance_variable_get(:@auth) - assert_equal "localhost", global_catalog.host - assert_equal 3268, global_catalog.port assert_equal nil, auth[:password] assert_equal nil, auth[:username] end end module GitHubLdapAuthenticatedTestCases - def test_global_catalog_default_settings + def test_global_catalog_authenticated_default_settings global_catalog = @ldap.global_catalog_connection # this is ugly, but currently the only way to test Net::LDAP#auth values auth = global_catalog.instance_variable_get(:@auth) - assert_equal "localhost", global_catalog.host - assert_equal 3268, global_catalog.port assert_equal "passworD1", auth[:password] assert_equal "uid=admin,dc=github,dc=com", auth[:username] end From d4ae1ab3e03f5479e59b61645eb497c26061cbb6 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 25 Jul 2016 10:37:24 -0500 Subject: [PATCH 045/161] Updated documentation --- lib/github/ldap.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 7f7ac39..3c5c8c5 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -198,6 +198,11 @@ def global_catalog_search(options, &block) Array(global_catalog_connection.search(options, &block)) end + # Returns a late-bound, memoized connection to an Active Directory Global Catalog + # if the server is an Active Directory instance, otherwise returns nil. + # + # See: https://technet.microsoft.com/en-us/library/cc728188(v=ws.10).aspx + # def global_catalog_connection @global_catalog_connection ||= Net::LDAP.new({ host: @connection.instance_variable_get(:@host), From 8244f7c484bcd897a215f9cabbe5a97ad35a443c Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 25 Jul 2016 10:38:26 -0500 Subject: [PATCH 046/161] Only initialize global catalog if server is Active Directory --- lib/github/ldap.rb | 14 ++++++++------ test/ldap_test.rb | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 3c5c8c5..128e3c1 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -204,12 +204,14 @@ def global_catalog_search(options, &block) # See: https://technet.microsoft.com/en-us/library/cc728188(v=ws.10).aspx # def global_catalog_connection - @global_catalog_connection ||= Net::LDAP.new({ - host: @connection.instance_variable_get(:@host), - auth: @connection.instance_variable_get(:@auth), - instrumentation_service: @connection.instance_variable_get(:@instrumentation_service), - port: 3268, - }) + if active_directory_capability? + @global_catalog_connection ||= Net::LDAP.new({ + host: @connection.host, + auth: @connection.instance_variable_get(:@auth), + instrumentation_service: @connection.instance_variable_get(:@instrumentation_service), + port: 3268, + }) + end end # Internal: Searches the host LDAP server's Root DSE for capabilities and diff --git a/test/ldap_test.rb b/test/ldap_test.rb index 8efbc00..30cb1f4 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -119,7 +119,18 @@ def test_capabilities assert_kind_of Net::LDAP::Entry, @ldap.capabilities end + def test_global_catalog_connection_is_null_if_not_active_directory + @ldap.expects(:active_directory_capability?).returns(false) + assert_equal nil, @ldap.global_catalog_connection + end + + def test_global_catalog_connection_is_null_if_not_active_directory + @ldap.expects(:active_directory_capability?).returns(true) + refute_nil @ldap.global_catalog_connection, "Expected Global Catalog to not be nil" + end + def test_global_catalog_returns_empty_array_for_no_results + @ldap.expects(:active_directory_capability?).returns(true) mock_global_catalog_connection = Object.new mock_global_catalog_connection.expects(:search).returns(nil) Net::LDAP.expects(:new).returns(mock_global_catalog_connection) @@ -128,6 +139,7 @@ def test_global_catalog_returns_empty_array_for_no_results end def test_global_catalog_returns_array_of_results + @ldap.expects(:active_directory_capability?).returns(true) mock_global_catalog_connection = Object.new stub_entry = Object.new mock_global_catalog_connection.expects(:search).returns(stub_entry) @@ -137,6 +149,7 @@ def test_global_catalog_returns_array_of_results end def test_global_catalog_default_settings + @ldap.expects(:active_directory_capability?).returns(true) global_catalog = @ldap.global_catalog_connection assert_equal "localhost", global_catalog.host @@ -145,6 +158,7 @@ def test_global_catalog_default_settings module GitHubLdapUnauthenticatedTestCases def test_global_catalog_unauthenticated_default_settings + @ldap.expects(:active_directory_capability?).returns(true) global_catalog = @ldap.global_catalog_connection # this is ugly, but currently the only way to test Net::LDAP#auth values auth = global_catalog.instance_variable_get(:@auth) @@ -156,6 +170,7 @@ def test_global_catalog_unauthenticated_default_settings module GitHubLdapAuthenticatedTestCases def test_global_catalog_authenticated_default_settings + @ldap.expects(:active_directory_capability?).returns(true) global_catalog = @ldap.global_catalog_connection # this is ugly, but currently the only way to test Net::LDAP#auth values auth = global_catalog.instance_variable_get(:@auth) From 3cf1c5adfb98a2f7df2ba0788407b2e964f7903d Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 25 Jul 2016 10:39:10 -0500 Subject: [PATCH 047/161] Make capabilities public so domain can decide whether it's Active Dir --- lib/github/ldap.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 128e3c1..deb3809 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -214,7 +214,7 @@ def global_catalog_connection end end - # Internal: Searches the host LDAP server's Root DSE for capabilities and + # Public: Searches the host LDAP server's Root DSE for capabilities and # extensions. # # Returns a Net::LDAP::Entry object. From baef44dc688d3adb43eb0d6227e211d5a417522f Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 25 Jul 2016 10:40:02 -0500 Subject: [PATCH 048/161] Test for default instrumentation service on Global Catalog --- test/ldap_test.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/ldap_test.rb b/test/ldap_test.rb index 30cb1f4..7b24b63 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -151,9 +151,11 @@ def test_global_catalog_returns_array_of_results def test_global_catalog_default_settings @ldap.expects(:active_directory_capability?).returns(true) global_catalog = @ldap.global_catalog_connection + instrumentation_service = global_catalog.instance_variable_get(:@instrumentation_service) assert_equal "localhost", global_catalog.host assert_equal 3268, global_catalog.port + assert_equal "MockInstrumentationService", instrumentation_service.class.name end module GitHubLdapUnauthenticatedTestCases From e05f40caad036e883778644c350b0d82b6f9647d Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 25 Jul 2016 11:01:18 -0500 Subject: [PATCH 049/161] Added doc for global_catalog_search --- lib/github/ldap.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index deb3809..54db4fa 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -193,6 +193,14 @@ def search(options, &block) end end + # Public - Search entries in the configured Active Directory Global Catalog + # + # options: is a hash with the same options that Net::LDAP::Connection#search supports. + # block: is an optional block to pass to the search. + # + # see: http://msdn.microsoft.com/en-us/library/cc223359.aspx. + # + # Returns an Array of Net::LDAP::Entry. def global_catalog_search(options, &block) options[:base] = "" Array(global_catalog_connection.search(options, &block)) From 6125bc5166b9122c85dd666df431ff47c2aa64e6 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 25 Jul 2016 11:01:49 -0500 Subject: [PATCH 050/161] Test for domain to use global catalog if it's Active Directory --- test/domain_test.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/domain_test.rb b/test/domain_test.rb index 4480e60..25c9349 100644 --- a/test/domain_test.rb +++ b/test/domain_test.rb @@ -1,4 +1,5 @@ require_relative 'test_helper' +require 'mocha/mini_test' module GitHubLdapDomainTestCases def setup @@ -140,6 +141,12 @@ def test_auth_does_not_bind assert user = @domain.user?('user1') refute @domain.auth(user, 'foo'), 'Expected user not not bind' end + + def test_use_global_catalog_if_active_directory + @ldap.stubs(:active_directory_capability?).returns(true) + @domain.expects(:global_catalog_search).returns([]) + @domain.user?('user1', :attributes => [:cn]) + end end class GitHubLdapDomainTest < GitHub::Ldap::Test From a34264b8a738bb209c4d12537d676ef350b0c394 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 25 Jul 2016 11:23:21 -0500 Subject: [PATCH 051/161] Test for using default search on non-Active Directory servers --- test/domain_test.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/domain_test.rb b/test/domain_test.rb index 25c9349..207154c 100644 --- a/test/domain_test.rb +++ b/test/domain_test.rb @@ -147,6 +147,12 @@ def test_use_global_catalog_if_active_directory @domain.expects(:global_catalog_search).returns([]) @domain.user?('user1', :attributes => [:cn]) end + + def test_use_default_search_if_not_active_directory + @ldap.stubs(:active_directory_capability?).returns(false) + @domain.expects(:search).returns([]) + @domain.user?('user1', :attributes => [:cn]) + end end class GitHubLdapDomainTest < GitHub::Ldap::Test From a00750f4bde4cb73da754e70fc939f5925a04eb5 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 25 Jul 2016 11:35:37 -0500 Subject: [PATCH 052/161] Keep reference to credentials & instrumentation service for Global Catalog --- lib/github/ldap.rb | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 54db4fa..aae6295 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -68,6 +68,9 @@ class Ldap # def initialize(options = {}) @uid = options[:uid] || "sAMAccountName" + @instrumentation_service = options[:instrumentation_service] + @admin_user = options[:admin_user] + @admin_password = options[:admin_password] @connection = Net::LDAP.new({ host: options[:host], @@ -215,8 +218,8 @@ def global_catalog_connection if active_directory_capability? @global_catalog_connection ||= Net::LDAP.new({ host: @connection.host, - auth: @connection.instance_variable_get(:@auth), - instrumentation_service: @connection.instance_variable_get(:@instrumentation_service), + auth: {username: admin_user, password: admin_password}, + instrumentation_service: instrumentation_service, port: 3268, }) end @@ -344,5 +347,9 @@ def configure_member_search_strategy(strategy = nil) def active_directory_capability? capabilities[:supportedcapabilities].include?(ACTIVE_DIRECTORY_V51_OID) end + + private + + attr_reader :admin_user, :admin_password end end From 678758594b40b808b20d3407a96ac473204ef06f Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 25 Jul 2016 12:26:33 -0500 Subject: [PATCH 053/161] Updates to Domain#user? & use of Global Catalog - Set empty search base in user? rather than in GitHub::Ldap - Get rid of indirection in Domain to global_catalog_search - Update test --- lib/github/ldap.rb | 1 - lib/github/ldap/domain.rb | 9 ++++----- test/domain_test.rb | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index aae6295..41153fe 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -205,7 +205,6 @@ def search(options, &block) # # Returns an Array of Net::LDAP::Entry. def global_catalog_search(options, &block) - options[:base] = "" Array(global_catalog_connection.search(options, &block)) end diff --git a/lib/github/ldap/domain.rb b/lib/github/ldap/domain.rb index 2332e9c..d6b6caa 100644 --- a/lib/github/ldap/domain.rb +++ b/lib/github/ldap/domain.rb @@ -120,7 +120,10 @@ def user?(login, search_options = {}) size: 1 if @ldap.active_directory_capability? - global_catalog_search(options).first + # when doing a global search for a user's DN, set the search base to blank + options[:base] = "" + @ldap.global_catalog_search(options) + else search(options).first end @@ -165,10 +168,6 @@ def search(options, &block) @ldap.search(options, &block) end - def global_catalog_search(options, &block) - @ldap.global_catalog_search(options, &block) - end - # Get the entry for this domain. # # Returns a Net::LDAP::Entry diff --git a/test/domain_test.rb b/test/domain_test.rb index 207154c..b0d9682 100644 --- a/test/domain_test.rb +++ b/test/domain_test.rb @@ -144,7 +144,7 @@ def test_auth_does_not_bind def test_use_global_catalog_if_active_directory @ldap.stubs(:active_directory_capability?).returns(true) - @domain.expects(:global_catalog_search).returns([]) + @ldap.expects(:global_catalog_search).returns([]) @domain.user?('user1', :attributes => [:cn]) end From c38ffca4a4ac860133e94e582efc9ea8d2e875ce Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 25 Jul 2016 13:27:42 -0500 Subject: [PATCH 054/161] Test that global catalog search uses empty base DN --- test/domain_test.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/domain_test.rb b/test/domain_test.rb index b0d9682..ee67f8c 100644 --- a/test/domain_test.rb +++ b/test/domain_test.rb @@ -148,6 +148,12 @@ def test_use_global_catalog_if_active_directory @domain.user?('user1', :attributes => [:cn]) end + def test_global_catalog_has_empty_search_base + @ldap.stubs(:active_directory_capability?).returns(true) + @ldap.expects(:global_catalog_search).with(has_entry(:base => "")).returns([]) + @domain.user?('user1', :attributes => [:cn]) + end + def test_use_default_search_if_not_active_directory @ldap.stubs(:active_directory_capability?).returns(false) @domain.expects(:search).returns([]) From ab2d49a1b49af0dcfdd5e7901c671929e62273f3 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 25 Jul 2016 13:46:01 -0500 Subject: [PATCH 055/161] Set auth method for Global Catalog explicitly to :simple --- lib/github/ldap.rb | 2 +- test/ldap_test.rb | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 41153fe..01397ab 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -217,7 +217,7 @@ def global_catalog_connection if active_directory_capability? @global_catalog_connection ||= Net::LDAP.new({ host: @connection.host, - auth: {username: admin_user, password: admin_password}, + auth: {method: :simple, username: admin_user, password: admin_password}, instrumentation_service: instrumentation_service, port: 3268, }) diff --git a/test/ldap_test.rb b/test/ldap_test.rb index 7b24b63..3c60534 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -153,6 +153,8 @@ def test_global_catalog_default_settings global_catalog = @ldap.global_catalog_connection instrumentation_service = global_catalog.instance_variable_get(:@instrumentation_service) + auth = global_catalog.instance_variable_get(:@auth) + assert_equal :simple, auth[:method] assert_equal "localhost", global_catalog.host assert_equal 3268, global_catalog.port assert_equal "MockInstrumentationService", instrumentation_service.class.name From 3af0a8856112f7f6e17ebc707b79896e973c6103 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 25 Jul 2016 13:49:15 -0500 Subject: [PATCH 056/161] Make sure global catalog search returns first entry from result array --- lib/github/ldap/domain.rb | 3 +-- test/domain_test.rb | 8 ++++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/github/ldap/domain.rb b/lib/github/ldap/domain.rb index d6b6caa..7df8363 100644 --- a/lib/github/ldap/domain.rb +++ b/lib/github/ldap/domain.rb @@ -122,8 +122,7 @@ def user?(login, search_options = {}) if @ldap.active_directory_capability? # when doing a global search for a user's DN, set the search base to blank options[:base] = "" - @ldap.global_catalog_search(options) - + @ldap.global_catalog_search(options).first else search(options).first end diff --git a/test/domain_test.rb b/test/domain_test.rb index ee67f8c..4d541b3 100644 --- a/test/domain_test.rb +++ b/test/domain_test.rb @@ -148,6 +148,14 @@ def test_use_global_catalog_if_active_directory @domain.user?('user1', :attributes => [:cn]) end + def test_global_catalog_search_returns_first_entry + @ldap.stubs(:active_directory_capability?).returns(true) + entry = Object.new + @ldap.expects(:global_catalog_search).returns([entry]) + user = @domain.user?('user1', :attributes => [:cn]) + assert_equal entry, user + end + def test_global_catalog_has_empty_search_base @ldap.stubs(:active_directory_capability?).returns(true) @ldap.expects(:global_catalog_search).with(has_entry(:base => "")).returns([]) From dd24ee7076d5e7039daa06be0bf565e984f33e61 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 25 Jul 2016 17:28:05 -0500 Subject: [PATCH 057/161] Document reason for auth references; remove redundant ivar --- lib/github/ldap.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 01397ab..5ac0444 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -68,7 +68,8 @@ class Ldap # def initialize(options = {}) @uid = options[:uid] || "sAMAccountName" - @instrumentation_service = options[:instrumentation_service] + + # Keep a reference to these as default auth for a Global Catalog if needed @admin_user = options[:admin_user] @admin_password = options[:admin_password] From 8d9eca37f9b249d5f68ea3a6effb6e3af60f9869 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 25 Jul 2016 17:35:53 -0500 Subject: [PATCH 058/161] Update doc --- lib/github/ldap.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 5ac0444..b93c437 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -209,7 +209,7 @@ def global_catalog_search(options, &block) Array(global_catalog_connection.search(options, &block)) end - # Returns a late-bound, memoized connection to an Active Directory Global Catalog + # Returns a memoized connection to an Active Directory Global Catalog # if the server is an Active Directory instance, otherwise returns nil. # # See: https://technet.microsoft.com/en-us/library/cc728188(v=ws.10).aspx From 76db68a6d39cb385ee2edf32750c6e3b70560533 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 25 Jul 2016 17:37:35 -0500 Subject: [PATCH 059/161] Added test group to Gemfile --- Gemfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Gemfile b/Gemfile index edf9461..a409814 100644 --- a/Gemfile +++ b/Gemfile @@ -5,5 +5,8 @@ gemspec group :test, :development do gem "byebug", :platforms => [:mri_20, :mri_21] +end + +group :test do gem "mocha" end From d69b0ba564322b249d3cad5bb1a85f523290a30d Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 25 Jul 2016 17:39:19 -0500 Subject: [PATCH 060/161] Use assert_nil --- test/ldap_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ldap_test.rb b/test/ldap_test.rb index 3c60534..39158a5 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -121,7 +121,7 @@ def test_capabilities def test_global_catalog_connection_is_null_if_not_active_directory @ldap.expects(:active_directory_capability?).returns(false) - assert_equal nil, @ldap.global_catalog_connection + assert_nil @ldap.global_catalog_connection end def test_global_catalog_connection_is_null_if_not_active_directory From 9e9f9e961fd9976a7534117ee4dc3af746dfba65 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 25 Jul 2016 17:40:16 -0500 Subject: [PATCH 061/161] Drop message in test --- test/ldap_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ldap_test.rb b/test/ldap_test.rb index 39158a5..42de9ad 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -126,7 +126,7 @@ def test_global_catalog_connection_is_null_if_not_active_directory def test_global_catalog_connection_is_null_if_not_active_directory @ldap.expects(:active_directory_capability?).returns(true) - refute_nil @ldap.global_catalog_connection, "Expected Global Catalog to not be nil" + refute_nil @ldap.global_catalog_connection end def test_global_catalog_returns_empty_array_for_no_results From ad67b78cb44825ac90ea29ad993b2db92fe9ed8a Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 1 Aug 2016 17:44:48 -0500 Subject: [PATCH 062/161] Created new ActiveDirectory user search class; moved tests --- lib/github/ldap.rb | 4 ++ .../ldap/user_search/active_directory.rb | 44 ++++++++++++ test/ldap_test.rb | 65 ----------------- test/user_search/active_directory_test.rb | 71 +++++++++++++++++++ 4 files changed, 119 insertions(+), 65 deletions(-) create mode 100644 lib/github/ldap/user_search/active_directory.rb create mode 100644 test/user_search/active_directory_test.rb diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index b93c437..5071a4f 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -10,6 +10,10 @@ require 'github/ldap/instrumentation' require 'github/ldap/member_search' require 'github/ldap/membership_validators' +require 'github/ldap/connection_cache' +require 'github/ldap/referral_chaser' +require 'github/ldap/url' +require 'github/ldap/user_search/active_directory.rb' module GitHub class Ldap diff --git a/lib/github/ldap/user_search/active_directory.rb b/lib/github/ldap/user_search/active_directory.rb new file mode 100644 index 0000000..a32b0c3 --- /dev/null +++ b/lib/github/ldap/user_search/active_directory.rb @@ -0,0 +1,44 @@ +module GitHub + class Ldap + module UserSearch + class ActiveDirectory < Default + + def initialize(ldap) + @ldap = ldap + end + + def search(options) + # when doing a global search for a user's DN, set the search base to blank + options[:base] = "" + global_catalog_search(options).first + end + + def global_catalog_search(options, &block) + Array(global_catalog_connection.search(options, &block)) + end + + # Returns a memoized connection to an Active Directory Global Catalog + # if the server is an Active Directory instance, otherwise returns nil. + # + # See: https://technet.microsoft.com/en-us/library/cc728188(v=ws.10).aspx + # + def global_catalog_connection + @global_catalog_connection ||= Net::LDAP.new({ + host: ldap.instance_variable_get(:@host), + auth: { + method: :simple, + username: ldap.instance_variable_get(:@admin_user), + password: ldap.instance_variable_get(:@admin_password) + }, + instrumentation_service: ldap.instrumentation_service, + port: 3268, + }) + end + + private + + attr_reader :ldap + end + end + end +end diff --git a/test/ldap_test.rb b/test/ldap_test.rb index 42de9ad..5ab9fc3 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -118,71 +118,6 @@ def test_search_strategy_misconfigured_to_unrecognized_strategy_falls_back_to_de def test_capabilities assert_kind_of Net::LDAP::Entry, @ldap.capabilities end - - def test_global_catalog_connection_is_null_if_not_active_directory - @ldap.expects(:active_directory_capability?).returns(false) - assert_nil @ldap.global_catalog_connection - end - - def test_global_catalog_connection_is_null_if_not_active_directory - @ldap.expects(:active_directory_capability?).returns(true) - refute_nil @ldap.global_catalog_connection - end - - def test_global_catalog_returns_empty_array_for_no_results - @ldap.expects(:active_directory_capability?).returns(true) - mock_global_catalog_connection = Object.new - mock_global_catalog_connection.expects(:search).returns(nil) - Net::LDAP.expects(:new).returns(mock_global_catalog_connection) - results = @ldap.global_catalog_search({}) - assert_equal [], results - end - - def test_global_catalog_returns_array_of_results - @ldap.expects(:active_directory_capability?).returns(true) - mock_global_catalog_connection = Object.new - stub_entry = Object.new - mock_global_catalog_connection.expects(:search).returns(stub_entry) - Net::LDAP.expects(:new).returns(mock_global_catalog_connection) - results = @ldap.global_catalog_search({}) - assert_equal [stub_entry], results - end - - def test_global_catalog_default_settings - @ldap.expects(:active_directory_capability?).returns(true) - global_catalog = @ldap.global_catalog_connection - instrumentation_service = global_catalog.instance_variable_get(:@instrumentation_service) - - auth = global_catalog.instance_variable_get(:@auth) - assert_equal :simple, auth[:method] - assert_equal "localhost", global_catalog.host - assert_equal 3268, global_catalog.port - assert_equal "MockInstrumentationService", instrumentation_service.class.name - end - - module GitHubLdapUnauthenticatedTestCases - def test_global_catalog_unauthenticated_default_settings - @ldap.expects(:active_directory_capability?).returns(true) - global_catalog = @ldap.global_catalog_connection - # this is ugly, but currently the only way to test Net::LDAP#auth values - auth = global_catalog.instance_variable_get(:@auth) - - assert_equal nil, auth[:password] - assert_equal nil, auth[:username] - end - end - - module GitHubLdapAuthenticatedTestCases - def test_global_catalog_authenticated_default_settings - @ldap.expects(:active_directory_capability?).returns(true) - global_catalog = @ldap.global_catalog_connection - # this is ugly, but currently the only way to test Net::LDAP#auth values - auth = global_catalog.instance_variable_get(:@auth) - - assert_equal "passworD1", auth[:password] - assert_equal "uid=admin,dc=github,dc=com", auth[:username] - end - end end class GitHubLdapTest < GitHub::Ldap::Test diff --git a/test/user_search/active_directory_test.rb b/test/user_search/active_directory_test.rb new file mode 100644 index 0000000..a38943b --- /dev/null +++ b/test/user_search/active_directory_test.rb @@ -0,0 +1,71 @@ +require_relative '../test_helper' +require 'mocha/mini_test' + +class GitHubLdapActiveDirectoryUserSearchTests < GitHub::Ldap::Test + + def setup + @ldap = GitHub::Ldap.new(options) + @ad_user_search = GitHub::Ldap::UserSearch::ActiveDirectory.new(@ldap) + end + + def test_global_catalog_connection_is_null_if_not_active_directory + @ad_user_search.expects(:active_directory_capability?).returns(false) + assert_nil @ad_user_search.global_catalog_connection + end + + def test_global_catalog_connection_is_null_if_not_active_directory + refute_nil @ad_user_search.global_catalog_connection + end + + def test_global_catalog_returns_empty_array_for_no_results + mock_global_catalog_connection = Object.new + mock_global_catalog_connection.expects(:search).returns(nil) + Net::LDAP.expects(:new).returns(mock_global_catalog_connection) + results = @ad_user_search.global_catalog_search({}) + assert_equal [], results + end + + def test_global_catalog_returns_array_of_results + mock_global_catalog_connection = Object.new + stub_entry = Object.new + mock_global_catalog_connection.expects(:search).returns(stub_entry) + Net::LDAP.expects(:new).returns(mock_global_catalog_connection) + results = @ad_user_search.global_catalog_search({}) + assert_equal [stub_entry], results + end + + def test_global_catalog_default_settings + global_catalog = @ad_user_search.global_catalog_connection + instrumentation_service = global_catalog.instance_variable_get(:@instrumentation_service) + + auth = global_catalog.instance_variable_get(:@auth) + assert_equal :simple, auth[:method] + assert_equal "127.0.0.1", global_catalog.host + assert_equal 3268, global_catalog.port + assert_equal "MockInstrumentationService", instrumentation_service.class.name + end + + module GitHubLdapUnauthenticatedTestCases + def test_global_catalog_unauthenticated_default_settings + @ad_user_search.expects(:active_directory_capability?).returns(true) + global_catalog = @ad_user_search.global_catalog_connection + # this is ugly, but currently the only way to test Net::LDAP#auth values + auth = global_catalog.instance_variable_get(:@auth) + + assert_equal nil, auth[:password] + assert_equal nil, auth[:username] + end + end + + module GitHubLdapAuthenticatedTestCases + def test_global_catalog_authenticated_default_settings + @ad_user_search.expects(:active_directory_capability?).returns(true) + global_catalog = @ad_user_search.global_catalog_connection + # this is ugly, but currently the only way to test Net::LDAP#auth values + auth = global_catalog.instance_variable_get(:@auth) + + assert_equal "passworD1", auth[:password] + assert_equal "uid=admin,dc=github,dc=com", auth[:username] + end + end +end From 73ddf22c0528be4bbbff7f205788fb27c4aad8d1 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Wed, 3 Aug 2016 22:08:07 -0500 Subject: [PATCH 063/161] Added default strategy class for UserSearch --- lib/github/ldap/user_search/default.rb | 31 ++++++++++++++++++++++++++ test/user_search/default_test.rb | 20 +++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 lib/github/ldap/user_search/default.rb create mode 100644 test/user_search/default_test.rb diff --git a/lib/github/ldap/user_search/default.rb b/lib/github/ldap/user_search/default.rb new file mode 100644 index 0000000..b9df550 --- /dev/null +++ b/lib/github/ldap/user_search/default.rb @@ -0,0 +1,31 @@ +module GitHub + class Ldap + module UserSearch + class Default + include Filter + + def initialize(ldap) + @ldap = ldap + @options = {} + @options[:attributes] = [] + @options[:paged_searches_supported] = true + @options[:size] = 1 + end + + def perform(login, base_name, uid, search_options) + search_options[:filter] = login_filter(uid, login) + search_options[:base] = base_name + search(search_options.merge(options)) + end + + def search(options) + ldap.search(options) + end + + private + + attr_reader :options, :ldap + end + end + end +end diff --git a/test/user_search/default_test.rb b/test/user_search/default_test.rb new file mode 100644 index 0000000..939e7ff --- /dev/null +++ b/test/user_search/default_test.rb @@ -0,0 +1,20 @@ +require_relative '../test_helper' +require 'mocha/mini_test' + +class GitHubLdapActiveDirectoryUserSearchTests < GitHub::Ldap::Test + def setup + @ldap = GitHub::Ldap.new(options) + @default_user_search = GitHub::Ldap::UserSearch::Default.new(@ldap) + end + + def test_default_search_options + @ldap.expects(:search).with(has_entries( + attributes: [], + size: 1, + paged_searches_supported: true, + base: "CN=HI,CN=McDunnough", + filter: kind_of(Net::LDAP::Filter) + )) + results = @default_user_search.perform("","CN=HI,CN=McDunnough","",{}) + end +end From 3d73e879bf3094f0f4170d704ba57290aabbc115 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Wed, 3 Aug 2016 22:09:36 -0500 Subject: [PATCH 064/161] Load the default user search class; use strategy for Domain#user? --- lib/github/ldap.rb | 4 +--- lib/github/ldap/domain.rb | 12 +----------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 5071a4f..01aa5a6 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -10,9 +10,7 @@ require 'github/ldap/instrumentation' require 'github/ldap/member_search' require 'github/ldap/membership_validators' -require 'github/ldap/connection_cache' -require 'github/ldap/referral_chaser' -require 'github/ldap/url' +require 'github/ldap/user_search/default.rb' require 'github/ldap/user_search/active_directory.rb' module GitHub diff --git a/lib/github/ldap/domain.rb b/lib/github/ldap/domain.rb index 7df8363..76aa2dc 100644 --- a/lib/github/ldap/domain.rb +++ b/lib/github/ldap/domain.rb @@ -115,17 +115,7 @@ def valid_login?(login, password) # Returns the user if the login matches any `uid`. # Returns nil if there are no matches. def user?(login, search_options = {}) - options = search_options.merge \ - filter: login_filter(@uid, login), - size: 1 - - if @ldap.active_directory_capability? - # when doing a global search for a user's DN, set the search base to blank - options[:base] = "" - @ldap.global_catalog_search(options).first - else - search(options).first - end + @ldap.ldap_user_search_strategy.perform(login, @base_name, @uid, search_options) end # Check if a user can be bound with a password. From 3f1838c75ee72ed49d6d5eb69aa6befee5e95a4b Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Wed, 3 Aug 2016 22:11:43 -0500 Subject: [PATCH 065/161] Override search for AD user search --- lib/github/ldap/user_search/active_directory.rb | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/lib/github/ldap/user_search/active_directory.rb b/lib/github/ldap/user_search/active_directory.rb index a32b0c3..a31cc9a 100644 --- a/lib/github/ldap/user_search/active_directory.rb +++ b/lib/github/ldap/user_search/active_directory.rb @@ -3,18 +3,12 @@ class Ldap module UserSearch class ActiveDirectory < Default - def initialize(ldap) - @ldap = ldap - end - - def search(options) + # Public - Overridden from base class to set the base to "", and use the + # Global Catalog to perform the user search. + def search(search_options) # when doing a global search for a user's DN, set the search base to blank options[:base] = "" - global_catalog_search(options).first - end - - def global_catalog_search(options, &block) - Array(global_catalog_connection.search(options, &block)) + Array(global_catalog_connection.search(search_options.merge(options))) end # Returns a memoized connection to an Active Directory Global Catalog From 115abb7bfffa7bf811ad9d4fab79d74d74fbdfe2 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Wed, 3 Aug 2016 22:12:10 -0500 Subject: [PATCH 066/161] Update tests with new method signature for UserSearch#perform --- test/user_search/active_directory_test.rb | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/test/user_search/active_directory_test.rb b/test/user_search/active_directory_test.rb index a38943b..e11eef7 100644 --- a/test/user_search/active_directory_test.rb +++ b/test/user_search/active_directory_test.rb @@ -8,20 +8,11 @@ def setup @ad_user_search = GitHub::Ldap::UserSearch::ActiveDirectory.new(@ldap) end - def test_global_catalog_connection_is_null_if_not_active_directory - @ad_user_search.expects(:active_directory_capability?).returns(false) - assert_nil @ad_user_search.global_catalog_connection - end - - def test_global_catalog_connection_is_null_if_not_active_directory - refute_nil @ad_user_search.global_catalog_connection - end - def test_global_catalog_returns_empty_array_for_no_results mock_global_catalog_connection = Object.new mock_global_catalog_connection.expects(:search).returns(nil) Net::LDAP.expects(:new).returns(mock_global_catalog_connection) - results = @ad_user_search.global_catalog_search({}) + results = @ad_user_search.perform("login", "CN=Joe", "uid", {}) assert_equal [], results end @@ -30,10 +21,17 @@ def test_global_catalog_returns_array_of_results stub_entry = Object.new mock_global_catalog_connection.expects(:search).returns(stub_entry) Net::LDAP.expects(:new).returns(mock_global_catalog_connection) - results = @ad_user_search.global_catalog_search({}) + results = @ad_user_search.perform("login", "CN=Joe", "uid", {}) assert_equal [stub_entry], results end + def test_searches_with_empty_base_dn + mock_global_catalog_connection = Object.new + mock_global_catalog_connection.expects(:search).with(has_entry(:base => "")) + Net::LDAP.expects(:new).returns(mock_global_catalog_connection) + @ad_user_search.perform("login", "CN=Joe", "uid", {}) + end + def test_global_catalog_default_settings global_catalog = @ad_user_search.global_catalog_connection instrumentation_service = global_catalog.instance_variable_get(:@instrumentation_service) From f550ce5dd7010cb11ba829bf15cd72532e5b314d Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Wed, 3 Aug 2016 22:53:57 -0500 Subject: [PATCH 067/161] Configure user search strategy --- lib/github/ldap.rb | 16 +++++++++++++++- lib/github/ldap/domain.rb | 2 +- test/ldap_test.rb | 6 ++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 01aa5a6..4c8c2f5 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -44,7 +44,8 @@ class Ldap attr_reader :uid, :search_domains, :virtual_attributes, :membership_validator, :member_search_strategy, - :instrumentation_service + :instrumentation_service, + :user_search_strategy # Build a new GitHub::Ldap instance # @@ -104,6 +105,9 @@ def initialize(options = {}) # configure both the membership validator and the member search strategies configure_search_strategy(options[:search_strategy]) + # configure both the membership validator and the member search strategies + configure_user_search_strategy(options[:global_catalog_user_search]) + # enables instrumenting queries @instrumentation_service = options[:instrumentation_service] end @@ -315,6 +319,16 @@ def configure_membership_validation_strategy(strategy = nil) end end + def configure_user_search_strategy(global_catalog_user_search) + @user_search_strategy = begin + if global_catalog_user_search && active_directory_capability? + GitHub::Ldap::UserSearch::ActiveDirectory.new(self) + else + GitHub::Ldap::UserSearch::Default.new(self) + end + end + end + # Internal: Configure the member search strategy. # # diff --git a/lib/github/ldap/domain.rb b/lib/github/ldap/domain.rb index 76aa2dc..07af950 100644 --- a/lib/github/ldap/domain.rb +++ b/lib/github/ldap/domain.rb @@ -115,7 +115,7 @@ def valid_login?(login, password) # Returns the user if the login matches any `uid`. # Returns nil if there are no matches. def user?(login, search_options = {}) - @ldap.ldap_user_search_strategy.perform(login, @base_name, @uid, search_options) + @ldap.user_search_strategy.perform(login, @base_name, @uid, search_options).first end # Check if a user can be bound with a password. diff --git a/test/ldap_test.rb b/test/ldap_test.rb index 5ab9fc3..38295e7 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -115,6 +115,12 @@ def test_search_strategy_misconfigured_to_unrecognized_strategy_falls_back_to_de assert_equal GitHub::Ldap::MemberSearch::Recursive, @ldap.member_search_strategy end + def test_user_search_strategy_active_directory_when_configured_and_has_capability + @ldap.configure_user_search_strategy true + @ldap.stubs(:active_directory_capability).returns(false) + assert_equal GitHub::Ldap::UserSearch::Default, @ldap.user_search_strategy.class + end + def test_capabilities assert_kind_of Net::LDAP::Entry, @ldap.capabilities end From 32840bc2f90aa0c1714393a3095a45e36dd4db68 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Wed, 3 Aug 2016 22:54:32 -0500 Subject: [PATCH 068/161] Removed dead code -- was moved to its own class --- lib/github/ldap.rb | 28 ---------------------------- test/ldap_test.rb | 2 -- 2 files changed, 30 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 4c8c2f5..5348a2e 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -203,34 +203,6 @@ def search(options, &block) end end - # Public - Search entries in the configured Active Directory Global Catalog - # - # options: is a hash with the same options that Net::LDAP::Connection#search supports. - # block: is an optional block to pass to the search. - # - # see: http://msdn.microsoft.com/en-us/library/cc223359.aspx. - # - # Returns an Array of Net::LDAP::Entry. - def global_catalog_search(options, &block) - Array(global_catalog_connection.search(options, &block)) - end - - # Returns a memoized connection to an Active Directory Global Catalog - # if the server is an Active Directory instance, otherwise returns nil. - # - # See: https://technet.microsoft.com/en-us/library/cc728188(v=ws.10).aspx - # - def global_catalog_connection - if active_directory_capability? - @global_catalog_connection ||= Net::LDAP.new({ - host: @connection.host, - auth: {method: :simple, username: admin_user, password: admin_password}, - instrumentation_service: instrumentation_service, - port: 3268, - }) - end - end - # Public: Searches the host LDAP server's Root DSE for capabilities and # extensions. # diff --git a/test/ldap_test.rb b/test/ldap_test.rb index 38295e7..d11e13f 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -128,10 +128,8 @@ def test_capabilities class GitHubLdapTest < GitHub::Ldap::Test include GitHubLdapTestCases - include GitHubLdapAuthenticatedTestCases end class GitHubLdapUnauthenticatedTest < GitHub::Ldap::UnauthenticatedTest include GitHubLdapTestCases - include GitHubLdapUnauthenticatedTestCases end From 89eca1e3e9b6ac7bfe1016db766538f93c1c376a Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Wed, 3 Aug 2016 23:18:34 -0500 Subject: [PATCH 069/161] More tests for user search strategy --- test/ldap_test.rb | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/test/ldap_test.rb b/test/ldap_test.rb index d11e13f..9826b5b 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -116,8 +116,19 @@ def test_search_strategy_misconfigured_to_unrecognized_strategy_falls_back_to_de end def test_user_search_strategy_active_directory_when_configured_and_has_capability + @ldap.stubs(:active_directory_capability?).returns(true) @ldap.configure_user_search_strategy true - @ldap.stubs(:active_directory_capability).returns(false) + assert_equal GitHub::Ldap::UserSearch::ActiveDirectory, @ldap.user_search_strategy.class + end + + def test_user_search_strategy_not_active_directory_without_capability + @ldap.stubs(:active_directory_capability?).returns(false) + @ldap.configure_user_search_strategy true + assert_equal GitHub::Ldap::UserSearch::Default, @ldap.user_search_strategy.class + end + + def test_user_search_strategy_default_when_configured + @ldap.configure_user_search_strategy false assert_equal GitHub::Ldap::UserSearch::Default, @ldap.user_search_strategy.class end From faf1a16b6d0103c7edac1afa2cfc40fb8fdf0092 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Wed, 3 Aug 2016 23:28:32 -0500 Subject: [PATCH 070/161] Reverse the merge order for default search --- lib/github/ldap/user_search/default.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/github/ldap/user_search/default.rb b/lib/github/ldap/user_search/default.rb index b9df550..88f723b 100644 --- a/lib/github/ldap/user_search/default.rb +++ b/lib/github/ldap/user_search/default.rb @@ -15,7 +15,7 @@ def initialize(ldap) def perform(login, base_name, uid, search_options) search_options[:filter] = login_filter(uid, login) search_options[:base] = base_name - search(search_options.merge(options)) + search(options.merge(search_options)) end def search(options) From 2538aa0be449fd61ec61989cb5a66ed38a44a6ff Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Wed, 3 Aug 2016 23:38:07 -0500 Subject: [PATCH 071/161] Updated domain tests since adding user search strategy --- test/domain_test.rb | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/test/domain_test.rb b/test/domain_test.rb index 4d541b3..92b9031 100644 --- a/test/domain_test.rb +++ b/test/domain_test.rb @@ -132,6 +132,14 @@ def test_user_returns_subset_of_attributes assert_equal [:dn, :cn], entry.attribute_names end + def test_user_returns_subset_of_attributes_for_global_catalog_search + @ldap.stubs(:active_directory_capability?).returns(true) + @ldap.configure_user_search_strategy(true) + assert_equal GitHub::Ldap::UserSearch::ActiveDirectory, @ldap.user_search_strategy.class + assert entry = @domain.user?('user1', :attributes => [:cn]) + assert_equal [:dn, :cn], entry.attribute_names + end + def test_auth_binds assert user = @domain.user?('user1') assert @domain.auth(user, 'passworD1'), 'Expected user to bind' @@ -142,31 +150,14 @@ def test_auth_does_not_bind refute @domain.auth(user, 'foo'), 'Expected user not not bind' end - def test_use_global_catalog_if_active_directory - @ldap.stubs(:active_directory_capability?).returns(true) - @ldap.expects(:global_catalog_search).returns([]) - @domain.user?('user1', :attributes => [:cn]) - end - - def test_global_catalog_search_returns_first_entry - @ldap.stubs(:active_directory_capability?).returns(true) + def test_user_search_returns_first_entry entry = Object.new - @ldap.expects(:global_catalog_search).returns([entry]) + search_strategy = Object.new + search_strategy.stubs(:perform).returns([entry]) + @ldap.expects(:user_search_strategy).returns(search_strategy) user = @domain.user?('user1', :attributes => [:cn]) assert_equal entry, user end - - def test_global_catalog_has_empty_search_base - @ldap.stubs(:active_directory_capability?).returns(true) - @ldap.expects(:global_catalog_search).with(has_entry(:base => "")).returns([]) - @domain.user?('user1', :attributes => [:cn]) - end - - def test_use_default_search_if_not_active_directory - @ldap.stubs(:active_directory_capability?).returns(false) - @domain.expects(:search).returns([]) - @domain.user?('user1', :attributes => [:cn]) - end end class GitHubLdapDomainTest < GitHub::Ldap::Test From d7590754c656da59b02e3c2ef29bc93ef7414aa5 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Wed, 3 Aug 2016 23:39:26 -0500 Subject: [PATCH 072/161] Removed unnecessary tests --- test/user_search/active_directory_test.rb | 24 ----------------------- 1 file changed, 24 deletions(-) diff --git a/test/user_search/active_directory_test.rb b/test/user_search/active_directory_test.rb index e11eef7..7015686 100644 --- a/test/user_search/active_directory_test.rb +++ b/test/user_search/active_directory_test.rb @@ -42,28 +42,4 @@ def test_global_catalog_default_settings assert_equal 3268, global_catalog.port assert_equal "MockInstrumentationService", instrumentation_service.class.name end - - module GitHubLdapUnauthenticatedTestCases - def test_global_catalog_unauthenticated_default_settings - @ad_user_search.expects(:active_directory_capability?).returns(true) - global_catalog = @ad_user_search.global_catalog_connection - # this is ugly, but currently the only way to test Net::LDAP#auth values - auth = global_catalog.instance_variable_get(:@auth) - - assert_equal nil, auth[:password] - assert_equal nil, auth[:username] - end - end - - module GitHubLdapAuthenticatedTestCases - def test_global_catalog_authenticated_default_settings - @ad_user_search.expects(:active_directory_capability?).returns(true) - global_catalog = @ad_user_search.global_catalog_connection - # this is ugly, but currently the only way to test Net::LDAP#auth values - auth = global_catalog.instance_variable_get(:@auth) - - assert_equal "passworD1", auth[:password] - assert_equal "uid=admin,dc=github,dc=com", auth[:username] - end - end end From 1ab77c0e0b84b79668d47ad1b03b4613914c9997 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Wed, 3 Aug 2016 23:40:41 -0500 Subject: [PATCH 073/161] Don't need this test --- test/domain_test.rb | 8 -------- 1 file changed, 8 deletions(-) diff --git a/test/domain_test.rb b/test/domain_test.rb index 92b9031..324a41a 100644 --- a/test/domain_test.rb +++ b/test/domain_test.rb @@ -132,14 +132,6 @@ def test_user_returns_subset_of_attributes assert_equal [:dn, :cn], entry.attribute_names end - def test_user_returns_subset_of_attributes_for_global_catalog_search - @ldap.stubs(:active_directory_capability?).returns(true) - @ldap.configure_user_search_strategy(true) - assert_equal GitHub::Ldap::UserSearch::ActiveDirectory, @ldap.user_search_strategy.class - assert entry = @domain.user?('user1', :attributes => [:cn]) - assert_equal [:dn, :cn], entry.attribute_names - end - def test_auth_binds assert user = @domain.user?('user1') assert @domain.auth(user, 'passworD1'), 'Expected user to bind' From 2e33e8bb8c41821a0af5aa3aa63f2c15d251a104 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 11:11:55 -0500 Subject: [PATCH 074/161] Clean up requires --- lib/github/ldap.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 5348a2e..66c84f3 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -10,8 +10,8 @@ require 'github/ldap/instrumentation' require 'github/ldap/member_search' require 'github/ldap/membership_validators' -require 'github/ldap/user_search/default.rb' -require 'github/ldap/user_search/active_directory.rb' +require 'github/ldap/user_search/default' +require 'github/ldap/user_search/active_directory' module GitHub class Ldap From cf59b4cea4dc4228a4b534462404cdd204220224 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 11:12:36 -0500 Subject: [PATCH 075/161] Created a GlobalCatalog object; expose :connection on LDAP --- lib/github/ldap.rb | 3 +- .../ldap/user_search/active_directory.rb | 33 ++++++++++++------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 66c84f3..71ec6fe 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -45,7 +45,8 @@ class Ldap :membership_validator, :member_search_strategy, :instrumentation_service, - :user_search_strategy + :user_search_strategy, + :connection # Build a new GitHub::Ldap instance # diff --git a/lib/github/ldap/user_search/active_directory.rb b/lib/github/ldap/user_search/active_directory.rb index a31cc9a..27e2231 100644 --- a/lib/github/ldap/user_search/active_directory.rb +++ b/lib/github/ldap/user_search/active_directory.rb @@ -17,21 +17,30 @@ def search(search_options) # See: https://technet.microsoft.com/en-us/library/cc728188(v=ws.10).aspx # def global_catalog_connection - @global_catalog_connection ||= Net::LDAP.new({ - host: ldap.instance_variable_get(:@host), - auth: { - method: :simple, - username: ldap.instance_variable_get(:@admin_user), - password: ldap.instance_variable_get(:@admin_password) - }, - instrumentation_service: ldap.instrumentation_service, - port: 3268, - }) + GlobalCatalog.connection(ldap) end + end + + class GlobalCatalog < Net::LDAP + STANDARD_GC_PORT = 3268 + LDAPS_GC_PORT = 3269 - private + def self.connection(ldap) + @global_catalog_instance ||= begin + netldap = ldap.connection + # This is ugly, but Net::LDAP doesn't expose encryption or auth + encryption = netldap.instance_variable_get(:@encryption) + auth = netldap.instance_variable_get(:@auth) - attr_reader :ldap + new({ + host: ldap.instance_variable_get(:@host), + instrumentation_service: ldap.instrumentation_service, + port: encryption ? LDAPS_GC_PORT : STANDARD_GC_PORT, + auth: auth, + encryption: encryption + }) + end + end end end end From 0b22addb4b34cf6835846866b6dba9649551a4d2 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 11:13:24 -0500 Subject: [PATCH 076/161] Configure user search consistent with other config strategies --- lib/github/ldap.rb | 15 +++++++++++---- test/ldap_test.rb | 14 +++++++------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 71ec6fe..7ec20cd 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -107,7 +107,7 @@ def initialize(options = {}) configure_search_strategy(options[:search_strategy]) # configure both the membership validator and the member search strategies - configure_user_search_strategy(options[:global_catalog_user_search]) + configure_user_search_strategy(options[:user_search_strategy]) # enables instrumenting queries @instrumentation_service = options[:instrumentation_service] @@ -292,10 +292,17 @@ def configure_membership_validation_strategy(strategy = nil) end end - def configure_user_search_strategy(global_catalog_user_search) + def configure_user_search_strategy(strategy) @user_search_strategy = begin - if global_catalog_user_search && active_directory_capability? - GitHub::Ldap::UserSearch::ActiveDirectory.new(self) + case strategy.to_s + when "default" + GitHub::Ldap::UserSearch::Default.new(self) + when "global_catalog" + if active_directory_capability? + GitHub::Ldap::UserSearch::ActiveDirectory.new(self) + else + GitHub::Ldap::UserSearch::Default.new(self) + end else GitHub::Ldap::UserSearch::Default.new(self) end diff --git a/test/ldap_test.rb b/test/ldap_test.rb index 9826b5b..0af1cb4 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -115,21 +115,21 @@ def test_search_strategy_misconfigured_to_unrecognized_strategy_falls_back_to_de assert_equal GitHub::Ldap::MemberSearch::Recursive, @ldap.member_search_strategy end - def test_user_search_strategy_active_directory_when_configured_and_has_capability + def test_user_search_strategy_global_catalog_when_configured_and_has_capability @ldap.stubs(:active_directory_capability?).returns(true) - @ldap.configure_user_search_strategy true - assert_equal GitHub::Ldap::UserSearch::ActiveDirectory, @ldap.user_search_strategy.class + @ldap.configure_user_search_strategy("global_catalog") + assert_kind_of GitHub::Ldap::UserSearch::ActiveDirectory, @ldap.user_search_strategy end def test_user_search_strategy_not_active_directory_without_capability @ldap.stubs(:active_directory_capability?).returns(false) - @ldap.configure_user_search_strategy true - assert_equal GitHub::Ldap::UserSearch::Default, @ldap.user_search_strategy.class + @ldap.configure_user_search_strategy("global_catalog") + assert_kind_of GitHub::Ldap::UserSearch::Default, @ldap.user_search_strategy end def test_user_search_strategy_default_when_configured - @ldap.configure_user_search_strategy false - assert_equal GitHub::Ldap::UserSearch::Default, @ldap.user_search_strategy.class + @ldap.configure_user_search_strategy("default") + assert_kind_of GitHub::Ldap::UserSearch::Default, @ldap.user_search_strategy end def test_capabilities From 5f9e3d7f03eae3ccf902f8f5590bfddc5ebdd253 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 11:14:07 -0500 Subject: [PATCH 077/161] Make active_directory_capability? private again --- lib/github/ldap.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 7ec20cd..4e5fe97 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -335,6 +335,9 @@ def configure_member_search_strategy(strategy = nil) end end + + private + # Internal: Detect whether the LDAP host is an ActiveDirectory server. # # See: http://msdn.microsoft.com/en-us/library/cc223359.aspx. @@ -344,8 +347,6 @@ def active_directory_capability? capabilities[:supportedcapabilities].include?(ACTIVE_DIRECTORY_V51_OID) end - private - attr_reader :admin_user, :admin_password end end From 0ea4a93851bd8f96db1269c50a6eb4f048422620 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 11:14:45 -0500 Subject: [PATCH 078/161] Use mock utility for mock objects; Don't stub :new on Net::LDAP --- test/user_search/active_directory_test.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/user_search/active_directory_test.rb b/test/user_search/active_directory_test.rb index 7015686..13e8123 100644 --- a/test/user_search/active_directory_test.rb +++ b/test/user_search/active_directory_test.rb @@ -9,26 +9,26 @@ def setup end def test_global_catalog_returns_empty_array_for_no_results - mock_global_catalog_connection = Object.new + mock_global_catalog_connection = mock("GitHub::Ldap::UserSearch::GlobalCatalog") mock_global_catalog_connection.expects(:search).returns(nil) - Net::LDAP.expects(:new).returns(mock_global_catalog_connection) + @ad_user_search.expects(:global_catalog_connection).returns(mock_global_catalog_connection) results = @ad_user_search.perform("login", "CN=Joe", "uid", {}) assert_equal [], results end def test_global_catalog_returns_array_of_results - mock_global_catalog_connection = Object.new - stub_entry = Object.new + mock_global_catalog_connection = mock("GitHub::Ldap::UserSearch::GlobalCatalog") + stub_entry = mock("Net::LDAP::Entry") mock_global_catalog_connection.expects(:search).returns(stub_entry) - Net::LDAP.expects(:new).returns(mock_global_catalog_connection) + @ad_user_search.expects(:global_catalog_connection).returns(mock_global_catalog_connection) results = @ad_user_search.perform("login", "CN=Joe", "uid", {}) assert_equal [stub_entry], results end def test_searches_with_empty_base_dn - mock_global_catalog_connection = Object.new + mock_global_catalog_connection = mock("GitHub::Ldap::UserSearch::GlobalCatalog") mock_global_catalog_connection.expects(:search).with(has_entry(:base => "")) - Net::LDAP.expects(:new).returns(mock_global_catalog_connection) + @ad_user_search.expects(:global_catalog_connection).returns(mock_global_catalog_connection) @ad_user_search.perform("login", "CN=Joe", "uid", {}) end From 18eb39925e392f5ad824faae92cb0b45243af48f Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 11:15:40 -0500 Subject: [PATCH 079/161] Test auth on user search strategy; minor test cleanup --- test/user_search/active_directory_test.rb | 2 ++ test/user_search/default_test.rb | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/test/user_search/active_directory_test.rb b/test/user_search/active_directory_test.rb index 13e8123..ae23146 100644 --- a/test/user_search/active_directory_test.rb +++ b/test/user_search/active_directory_test.rb @@ -38,6 +38,8 @@ def test_global_catalog_default_settings auth = global_catalog.instance_variable_get(:@auth) assert_equal :simple, auth[:method] + assert_equal "uid=admin,dc=github,dc=com", auth[:username] + assert_equal "passworD1", auth[:password] assert_equal "127.0.0.1", global_catalog.host assert_equal 3268, global_catalog.port assert_equal "MockInstrumentationService", instrumentation_service.class.name diff --git a/test/user_search/default_test.rb b/test/user_search/default_test.rb index 939e7ff..6913d0c 100644 --- a/test/user_search/default_test.rb +++ b/test/user_search/default_test.rb @@ -15,6 +15,6 @@ def test_default_search_options base: "CN=HI,CN=McDunnough", filter: kind_of(Net::LDAP::Filter) )) - results = @default_user_search.perform("","CN=HI,CN=McDunnough","",{}) + @default_user_search.perform("","CN=HI,CN=McDunnough","",{}) end end From 32222d596b7c1ac2deae4c55b2dec9e1fc9aa5df Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 11:26:55 -0500 Subject: [PATCH 080/161] Updated documentation --- lib/github/ldap.rb | 14 +++++++++++++- lib/github/ldap/user_search/default.rb | 8 ++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 4e5fe97..7cc4ca3 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -204,7 +204,7 @@ def search(options, &block) end end - # Public: Searches the host LDAP server's Root DSE for capabilities and + # Internal: Searches the host LDAP server's Root DSE for capabilities and # extensions. # # Returns a Net::LDAP::Entry object. @@ -292,6 +292,18 @@ def configure_membership_validation_strategy(strategy = nil) end end + # Internal: Set the user search strategy that will be used by + # Domain#user?. + # + # strategy - Can be either 'default' or 'global_catalog'. + # 'default' strategy will search the configured + # domain controller with a search base relative + # to the controller's domain context. + # 'global_catalog' will search the entire forest + # using Active Directory's Global Catalog + # functionality. If the server is not an Active + # Directory, will use the default strategy regardless + # of the requested configuration. def configure_user_search_strategy(strategy) @user_search_strategy = begin case strategy.to_s diff --git a/lib/github/ldap/user_search/default.rb b/lib/github/ldap/user_search/default.rb index 88f723b..d058ee6 100644 --- a/lib/github/ldap/user_search/default.rb +++ b/lib/github/ldap/user_search/default.rb @@ -1,6 +1,9 @@ module GitHub class Ldap module UserSearch + # The default user search strategy, mainly for allowing Domain#user? to + # search for a user on the configured domain controller, or use the Global + # Catalog to search across the entire Active Directory forest. class Default include Filter @@ -12,12 +15,17 @@ def initialize(ldap) @options[:size] = 1 end + # Performs a normal search on the configured domain controller + # using the default base DN, uid, search_options def perform(login, base_name, uid, search_options) search_options[:filter] = login_filter(uid, login) search_options[:base] = base_name search(options.merge(search_options)) end + # The default search. This can be overridden by a child class + # like GitHub::Ldap::UserSearch::ActiveDirectory to change the + # scope of the search. def search(options) ldap.search(options) end From 50120001ab73aeb17733107e7189c8c83ed20daa Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 11:37:12 -0500 Subject: [PATCH 081/161] Explictly override options for setting the base DN to "" --- lib/github/ldap/user_search/active_directory.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/github/ldap/user_search/active_directory.rb b/lib/github/ldap/user_search/active_directory.rb index 27e2231..133eb6a 100644 --- a/lib/github/ldap/user_search/active_directory.rb +++ b/lib/github/ldap/user_search/active_directory.rb @@ -6,8 +6,6 @@ class ActiveDirectory < Default # Public - Overridden from base class to set the base to "", and use the # Global Catalog to perform the user search. def search(search_options) - # when doing a global search for a user's DN, set the search base to blank - options[:base] = "" Array(global_catalog_connection.search(search_options.merge(options))) end @@ -19,6 +17,11 @@ def search(search_options) def global_catalog_connection GlobalCatalog.connection(ldap) end + + # When doing a global search for a user's DN, set the search base to blank + def options + super.merge(base: "") + end end class GlobalCatalog < Net::LDAP From a52264105004cc706c53bf4e58062dea8026db5c Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 11:39:37 -0500 Subject: [PATCH 082/161] better hash structure --- lib/github/ldap/user_search/default.rb | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/github/ldap/user_search/default.rb b/lib/github/ldap/user_search/default.rb index d058ee6..2f1aa3f 100644 --- a/lib/github/ldap/user_search/default.rb +++ b/lib/github/ldap/user_search/default.rb @@ -9,10 +9,11 @@ class Default def initialize(ldap) @ldap = ldap - @options = {} - @options[:attributes] = [] - @options[:paged_searches_supported] = true - @options[:size] = 1 + @options = { + :attributes => [], + :paged_searches_supported => true, + :size => 1 + } end # Performs a normal search on the configured domain controller From a3163fe2ede5ae58469d9b54dd1477b0fb531299 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 11:41:34 -0500 Subject: [PATCH 083/161] Updated documentation --- lib/github/ldap/user_search/active_directory.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/github/ldap/user_search/active_directory.rb b/lib/github/ldap/user_search/active_directory.rb index 133eb6a..fcf059a 100644 --- a/lib/github/ldap/user_search/active_directory.rb +++ b/lib/github/ldap/user_search/active_directory.rb @@ -9,8 +9,7 @@ def search(search_options) Array(global_catalog_connection.search(search_options.merge(options))) end - # Returns a memoized connection to an Active Directory Global Catalog - # if the server is an Active Directory instance, otherwise returns nil. + # Returns a connection to the Active Directory Global Catalog # # See: https://technet.microsoft.com/en-us/library/cc728188(v=ws.10).aspx # From c3ac0b32b1db953cec18f2668ef715473ab67328 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 11:53:07 -0500 Subject: [PATCH 084/161] Don't fall back on default user search for non-AD controllers --- lib/github/ldap.rb | 6 +----- test/ldap_test.rb | 5 +++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 7cc4ca3..e2b361b 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -310,11 +310,7 @@ def configure_user_search_strategy(strategy) when "default" GitHub::Ldap::UserSearch::Default.new(self) when "global_catalog" - if active_directory_capability? - GitHub::Ldap::UserSearch::ActiveDirectory.new(self) - else - GitHub::Ldap::UserSearch::Default.new(self) - end + GitHub::Ldap::UserSearch::ActiveDirectory.new(self) else GitHub::Ldap::UserSearch::Default.new(self) end diff --git a/test/ldap_test.rb b/test/ldap_test.rb index 0af1cb4..2bbe221 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -121,14 +121,15 @@ def test_user_search_strategy_global_catalog_when_configured_and_has_capability assert_kind_of GitHub::Ldap::UserSearch::ActiveDirectory, @ldap.user_search_strategy end - def test_user_search_strategy_not_active_directory_without_capability + def test_user_search_strategy_is_active_directory_even_without_capability @ldap.stubs(:active_directory_capability?).returns(false) @ldap.configure_user_search_strategy("global_catalog") - assert_kind_of GitHub::Ldap::UserSearch::Default, @ldap.user_search_strategy + assert_kind_of GitHub::Ldap::UserSearch::ActiveDirectory, @ldap.user_search_strategy end def test_user_search_strategy_default_when_configured @ldap.configure_user_search_strategy("default") + refute_kind_of GitHub::Ldap::UserSearch::ActiveDirectory, @ldap.user_search_strategy assert_kind_of GitHub::Ldap::UserSearch::Default, @ldap.user_search_strategy end From 4154214aefbcdf065da85bc56b8a8628277a74ff Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 11:56:45 -0500 Subject: [PATCH 085/161] Make search & options private on ActiveDirectory user search --- lib/github/ldap/user_search/active_directory.rb | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/github/ldap/user_search/active_directory.rb b/lib/github/ldap/user_search/active_directory.rb index fcf059a..a76a6bf 100644 --- a/lib/github/ldap/user_search/active_directory.rb +++ b/lib/github/ldap/user_search/active_directory.rb @@ -3,12 +3,6 @@ class Ldap module UserSearch class ActiveDirectory < Default - # Public - Overridden from base class to set the base to "", and use the - # Global Catalog to perform the user search. - def search(search_options) - Array(global_catalog_connection.search(search_options.merge(options))) - end - # Returns a connection to the Active Directory Global Catalog # # See: https://technet.microsoft.com/en-us/library/cc728188(v=ws.10).aspx @@ -17,6 +11,14 @@ def global_catalog_connection GlobalCatalog.connection(ldap) end + private + + # Private - Overridden from base class to set the base to "", and use the + # Global Catalog to perform the user search. + def search(search_options) + Array(global_catalog_connection.search(search_options.merge(options))) + end + # When doing a global search for a user's DN, set the search base to blank def options super.merge(base: "") From 3da33e4fa099d2937fce3d4d705cbe7dbcaf908d Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 12:02:39 -0500 Subject: [PATCH 086/161] Make global connection interface private --- lib/github/ldap/user_search/active_directory.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/github/ldap/user_search/active_directory.rb b/lib/github/ldap/user_search/active_directory.rb index a76a6bf..d2e0981 100644 --- a/lib/github/ldap/user_search/active_directory.rb +++ b/lib/github/ldap/user_search/active_directory.rb @@ -3,14 +3,6 @@ class Ldap module UserSearch class ActiveDirectory < Default - # Returns a connection to the Active Directory Global Catalog - # - # See: https://technet.microsoft.com/en-us/library/cc728188(v=ws.10).aspx - # - def global_catalog_connection - GlobalCatalog.connection(ldap) - end - private # Private - Overridden from base class to set the base to "", and use the @@ -19,6 +11,10 @@ def search(search_options) Array(global_catalog_connection.search(search_options.merge(options))) end + def global_catalog_connection + GlobalCatalog.connection(ldap) + end + # When doing a global search for a user's DN, set the search base to blank def options super.merge(base: "") @@ -29,6 +25,10 @@ class GlobalCatalog < Net::LDAP STANDARD_GC_PORT = 3268 LDAPS_GC_PORT = 3269 + # Returns a connection to the Active Directory Global Catalog + # + # See: https://technet.microsoft.com/en-us/library/cc728188(v=ws.10).aspx + # def self.connection(ldap) @global_catalog_instance ||= begin netldap = ldap.connection From 735a42b2cd2d2d43b76b4fb83cfd90dec60f4a27 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 12:04:03 -0500 Subject: [PATCH 087/161] update documentation --- lib/github/ldap.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index e2b361b..bdcd748 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -301,9 +301,7 @@ def configure_membership_validation_strategy(strategy = nil) # to the controller's domain context. # 'global_catalog' will search the entire forest # using Active Directory's Global Catalog - # functionality. If the server is not an Active - # Directory, will use the default strategy regardless - # of the requested configuration. + # functionality. def configure_user_search_strategy(strategy) @user_search_strategy = begin case strategy.to_s From 3bc3979429160847dd16ae6d92bf5eb096aff6d9 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 12:06:50 -0500 Subject: [PATCH 088/161] Remove unneded test & condition --- test/ldap_test.rb | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/test/ldap_test.rb b/test/ldap_test.rb index 2bbe221..2d47fac 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -115,14 +115,7 @@ def test_search_strategy_misconfigured_to_unrecognized_strategy_falls_back_to_de assert_equal GitHub::Ldap::MemberSearch::Recursive, @ldap.member_search_strategy end - def test_user_search_strategy_global_catalog_when_configured_and_has_capability - @ldap.stubs(:active_directory_capability?).returns(true) - @ldap.configure_user_search_strategy("global_catalog") - assert_kind_of GitHub::Ldap::UserSearch::ActiveDirectory, @ldap.user_search_strategy - end - - def test_user_search_strategy_is_active_directory_even_without_capability - @ldap.stubs(:active_directory_capability?).returns(false) + def test_user_search_strategy_global_catalog_when_configured @ldap.configure_user_search_strategy("global_catalog") assert_kind_of GitHub::Ldap::UserSearch::ActiveDirectory, @ldap.user_search_strategy end From c05c4d73fb8efc106e2730441cef8dc3b931dd85 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Tue, 26 Jul 2016 17:54:04 -0500 Subject: [PATCH 089/161] First draft of referral chasing: set up referral connection properties --- .../membership_validators/active_directory.rb | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/github/ldap/membership_validators/active_directory.rb b/lib/github/ldap/membership_validators/active_directory.rb index 69b9bc8..cfca450 100644 --- a/lib/github/ldap/membership_validators/active_directory.rb +++ b/lib/github/ldap/membership_validators/active_directory.rb @@ -24,11 +24,24 @@ def perform(entry) # Sets the entry to the base and scopes the search to the base, # according to the source documentation, found here: # http://msdn.microsoft.com/en-us/library/aa746475(v=vs.85).aspx - matched = ldap.search \ - filter: membership_in_chain_filter(entry), + + filter = membership_in_chain_filter(entry) + options = { + filter: filter, base: entry.dn, scope: Net::LDAP::SearchScope_BaseObject, + return_referrals: true, attributes: ATTRS + } + + referral_entries = [] + matched = ldap.search(options) do |ref| + referral_entries << ref + end + + unless !matched.blank? || referral_entries.blank? + matched = chase_referral(referral_entries) + end # membership validated if entry was matched and returned as a result # Active Directory DNs are case-insensitive From 9afe1646fef081392687f26eaab13d471e6e5a2e Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Tue, 26 Jul 2016 17:54:53 -0500 Subject: [PATCH 090/161] WIP: Added referral chasing method, will move to GitHub::Ldap --- .../membership_validators/active_directory.rb | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/lib/github/ldap/membership_validators/active_directory.rb b/lib/github/ldap/membership_validators/active_directory.rb index cfca450..022e0a2 100644 --- a/lib/github/ldap/membership_validators/active_directory.rb +++ b/lib/github/ldap/membership_validators/active_directory.rb @@ -45,7 +45,29 @@ def perform(entry) # membership validated if entry was matched and returned as a result # Active Directory DNs are case-insensitive - matched.map { |m| m.dn.downcase }.include?(entry.dn.downcase) + Array(matched).map { |m| m.dn.downcase }.include?(entry.dn.downcase) + end + + def chase_referral(referral_entries) + referral = referral_entries.first + uri = URI(referral[:search_referrals].first) + + new_filter = "(memberOf:1.2.840.113556.1.4.1941:=CN=ghe-admins,CN=Users,DC=dc4,DC=ghe,DC=local)" + new_auth = {:method=>:simple, :username=>"CN=Administrator,CN=Users,DC=dc4,DC=ghe,DC=local", :password=>"vagrant"} + + new_base = URI.unescape(uri.path.sub(/^\//, '')) + + referral_connection = Net::LDAP.new({ + host: uri.host, + port: uri.port, + filter: new_filter, + base: new_base, + auth: new_auth, + instrumentation_service: ldap.instance_variable_get(:@instrumentation_service) + }) + + referral_connection.bind + referral_connection.search end # Internal: Constructs a membership filter using the "in chain" From 1fce71769267ccaff15621404df2143c471036d7 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Wed, 27 Jul 2016 23:16:09 -0500 Subject: [PATCH 091/161] Moved chase_referral to ldap class --- ldap.sh | 9 +++++++++ lib/github/ldap.rb | 22 ++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 ldap.sh diff --git a/ldap.sh b/ldap.sh new file mode 100644 index 0000000..32a654c --- /dev/null +++ b/ldap.sh @@ -0,0 +1,9 @@ + ldapsearch -x -h dc4.ghe.local \ + -b "CN=Maggie Mae,CN=Users,DC=dc4,DC=ghe,DC=local" \ + -D "GHE\Administrator" -w "vagrant" \ + "(|(|(| \ + (memberOf:1.2.840.113556.1.4.1941:=CN=ghe-users,CN=Users,DC=ghe,DC=local) \ + (memberOf:1.2.840.113556.1.4.1941:=CN=ghe-users,CN=Users, DC=dc4,DC=ghe,DC=local)) \ + (memberOf:1.2.840.113556.1.4.1941:=CN=ghe-admins,CN=Users,DC=ghe,DC=local)) \ + (memberOf:1.2.840.113556.1.4.1941:=CN=ghe-admins,CN=Users,DC=dc4,DC=ghe,DC=local))" + diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index bdcd748..24c3346 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -292,6 +292,7 @@ def configure_membership_validation_strategy(strategy = nil) end end +<<<<<<< 9afe1646fef081392687f26eaab13d471e6e5a2e # Internal: Set the user search strategy that will be used by # Domain#user?. # @@ -313,6 +314,27 @@ def configure_user_search_strategy(strategy) GitHub::Ldap::UserSearch::Default.new(self) end end +======= + def chase_referral(referral_entries, filter) + referral = referral_entries.first + uri = URI(referral[:search_referrals].first) + + #new_filter = "(memberOf:1.2.840.113556.1.4.1941:=CN=ghe-admins,CN=Users,DC=dc4,DC=ghe,DC=local)" + + new_base = URI.unescape(uri.path.sub(/^\//, '')) + options = { + filter: filter, + base: new_base, + instrumentation_service: instrumentation_service, + scope: Net::LDAP::SearchScope_BaseObject, + attributes: ["dn"] + } + + results = [] + referral_connection = get_connection_by_host(uri.host) + puts "OPTIONS #{options}" + referral_connection.search(options) +>>>>>>> Moved chase_referral to ldap class end # Internal: Configure the member search strategy. From 526d63ac3991ed01822390b34ff77600d3604e45 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Wed, 27 Jul 2016 23:16:38 -0500 Subject: [PATCH 092/161] Cache new referral connections as we go --- lib/github/ldap.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 24c3346..fc4eff1 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -337,6 +337,21 @@ def chase_referral(referral_entries, filter) >>>>>>> Moved chase_referral to ldap class end + def get_connection_by_host(host, port=389, auth=nil) + auth ||= {:method => :simple, :username => @admin_user, :password => @admin_password} + + @connections ||= Hash.new do |cache, host| + conn = Net::LDAP.new({ + host: host, + port: port, + auth: auth + }) + conn.authenticate(auth[:username], auth[:password]) + cache[host] = conn + end + @connections[host] + end + # Internal: Configure the member search strategy. # # From 82704e5a13fbdae9e3b42ad86ab7d87a25d5a4a4 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Wed, 27 Jul 2016 23:20:23 -0500 Subject: [PATCH 093/161] removed old chase_referral method --- .../membership_validators/active_directory.rb | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/lib/github/ldap/membership_validators/active_directory.rb b/lib/github/ldap/membership_validators/active_directory.rb index 022e0a2..e6b40d8 100644 --- a/lib/github/ldap/membership_validators/active_directory.rb +++ b/lib/github/ldap/membership_validators/active_directory.rb @@ -48,26 +48,6 @@ def perform(entry) Array(matched).map { |m| m.dn.downcase }.include?(entry.dn.downcase) end - def chase_referral(referral_entries) - referral = referral_entries.first - uri = URI(referral[:search_referrals].first) - - new_filter = "(memberOf:1.2.840.113556.1.4.1941:=CN=ghe-admins,CN=Users,DC=dc4,DC=ghe,DC=local)" - new_auth = {:method=>:simple, :username=>"CN=Administrator,CN=Users,DC=dc4,DC=ghe,DC=local", :password=>"vagrant"} - - new_base = URI.unescape(uri.path.sub(/^\//, '')) - - referral_connection = Net::LDAP.new({ - host: uri.host, - port: uri.port, - filter: new_filter, - base: new_base, - auth: new_auth, - instrumentation_service: ldap.instance_variable_get(:@instrumentation_service) - }) - - referral_connection.bind - referral_connection.search end # Internal: Constructs a membership filter using the "in chain" From 022d455f5061a1409ac5eb7a2d8a3a3f31800946 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Wed, 27 Jul 2016 23:20:59 -0500 Subject: [PATCH 094/161] Add method to reset base dn on search filter for use with referrals --- lib/github/ldap/membership_validators/active_directory.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/github/ldap/membership_validators/active_directory.rb b/lib/github/ldap/membership_validators/active_directory.rb index e6b40d8..4ac7a4d 100644 --- a/lib/github/ldap/membership_validators/active_directory.rb +++ b/lib/github/ldap/membership_validators/active_directory.rb @@ -3,6 +3,7 @@ class Ldap module MembershipValidators ATTRS = %w(dn) OID = "1.2.840.113556.1.4.1941" + DN_BASE_MATCHER = /DC=.*/ # Validates membership using the ActiveDirectory "in chain" matching rule. # @@ -48,6 +49,9 @@ def perform(entry) Array(matched).map { |m| m.dn.downcase }.include?(entry.dn.downcase) end + def set_new_base_dn(filter, entry) + base_dn = DN_BASE_MATCHER.match(entry.dn)[0] + filter.to_s.sub(DN_BASE_MATCHER, base_dn) end # Internal: Constructs a membership filter using the "in chain" From 652633be0edc232d04301fce09eecd3be1b19778 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Wed, 27 Jul 2016 23:21:37 -0500 Subject: [PATCH 095/161] Reset base dn on filter before searcing on referral controller --- lib/github/ldap/membership_validators/active_directory.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/github/ldap/membership_validators/active_directory.rb b/lib/github/ldap/membership_validators/active_directory.rb index 4ac7a4d..b73b129 100644 --- a/lib/github/ldap/membership_validators/active_directory.rb +++ b/lib/github/ldap/membership_validators/active_directory.rb @@ -41,7 +41,8 @@ def perform(entry) end unless !matched.blank? || referral_entries.blank? - matched = chase_referral(referral_entries) + filter = set_new_base_dn(filter, entry) + matched = ldap.chase_referral(referral_entries, filter) end # membership validated if entry was matched and returned as a result From bb149caad12d099257f8ab8692d36dd131bbf9e3 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 28 Jul 2016 22:41:27 -0500 Subject: [PATCH 096/161] cleanup --- lib/github/ldap.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index fc4eff1..cfe0d43 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -319,8 +319,6 @@ def chase_referral(referral_entries, filter) referral = referral_entries.first uri = URI(referral[:search_referrals].first) - #new_filter = "(memberOf:1.2.840.113556.1.4.1941:=CN=ghe-admins,CN=Users,DC=dc4,DC=ghe,DC=local)" - new_base = URI.unescape(uri.path.sub(/^\//, '')) options = { filter: filter, @@ -332,7 +330,6 @@ def chase_referral(referral_entries, filter) results = [] referral_connection = get_connection_by_host(uri.host) - puts "OPTIONS #{options}" referral_connection.search(options) >>>>>>> Moved chase_referral to ldap class end From 218675bd6d21ac444b96e5a3db5c1594b40692b9 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 28 Jul 2016 22:41:41 -0500 Subject: [PATCH 097/161] Use GitHub::Ldap instead of Net::LDAP for referral connections --- lib/github/ldap.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index cfe0d43..e1d42f7 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -338,12 +338,11 @@ def get_connection_by_host(host, port=389, auth=nil) auth ||= {:method => :simple, :username => @admin_user, :password => @admin_password} @connections ||= Hash.new do |cache, host| - conn = Net::LDAP.new({ + conn = GitHub::Ldap.new({ host: host, port: port, auth: auth }) - conn.authenticate(auth[:username], auth[:password]) cache[host] = conn end @connections[host] From 971698c9bd5cd4f754e06b4ab478d5761a4d4a95 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 28 Jul 2016 22:42:56 -0500 Subject: [PATCH 098/161] Don't reset base_dn, will pass in FQDN for groups from client --- .../ldap/membership_validators/active_directory.rb | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/github/ldap/membership_validators/active_directory.rb b/lib/github/ldap/membership_validators/active_directory.rb index b73b129..def44a9 100644 --- a/lib/github/ldap/membership_validators/active_directory.rb +++ b/lib/github/ldap/membership_validators/active_directory.rb @@ -40,19 +40,15 @@ def perform(entry) referral_entries << ref end - unless !matched.blank? || referral_entries.blank? - filter = set_new_base_dn(filter, entry) + if referral_entries.present? matched = ldap.chase_referral(referral_entries, filter) end # membership validated if entry was matched and returned as a result # Active Directory DNs are case-insensitive - Array(matched).map { |m| m.dn.downcase }.include?(entry.dn.downcase) - end - def set_new_base_dn(filter, entry) - base_dn = DN_BASE_MATCHER.match(entry.dn)[0] - filter.to_s.sub(DN_BASE_MATCHER, base_dn) + result = Array(matched).map { |m| m.dn.downcase }.include?(entry.dn.downcase) + result end # Internal: Constructs a membership filter using the "in chain" From 990cca8f6129b2df21aa9f5207b1c7780cf0179e Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 28 Jul 2016 22:44:12 -0500 Subject: [PATCH 099/161] No need for DN matcher --- lib/github/ldap/membership_validators/active_directory.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/github/ldap/membership_validators/active_directory.rb b/lib/github/ldap/membership_validators/active_directory.rb index def44a9..ed336d7 100644 --- a/lib/github/ldap/membership_validators/active_directory.rb +++ b/lib/github/ldap/membership_validators/active_directory.rb @@ -3,7 +3,6 @@ class Ldap module MembershipValidators ATTRS = %w(dn) OID = "1.2.840.113556.1.4.1941" - DN_BASE_MATCHER = /DC=.*/ # Validates membership using the ActiveDirectory "in chain" matching rule. # From 54defdb2b7777ea178ef853f9a6163e38bf46716 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Fri, 29 Jul 2016 13:24:57 -0500 Subject: [PATCH 100/161] Create a ConnectionPool object to encapsulate caching connection objects --- lib/github/ldap/connection_pool.rb | 24 ++++++++++++++++++++++++ test/connection_pool_test.rb | 21 +++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 lib/github/ldap/connection_pool.rb create mode 100644 test/connection_pool_test.rb diff --git a/lib/github/ldap/connection_pool.rb b/lib/github/ldap/connection_pool.rb new file mode 100644 index 0000000..c3c723c --- /dev/null +++ b/lib/github/ldap/connection_pool.rb @@ -0,0 +1,24 @@ +module GitHub + class Ldap + class ConnectionPool + + # Public - Create or return cached instance of GitHub::Ldap created with options, + # where the cache key is the value of options[:host]. + # + # Returns an instance of GitHub::Ldap + def self.get_connection(options={}) + @instance ||= self.new + @instance.get_connection(options) + end + + def get_connection(options) + host = options[:host] + @connections ||= Hash.new do |cache, host| + conn = GitHub::Ldap.new(options) + cache[host] = conn + end + @connections[host] + end + end + end +end diff --git a/test/connection_pool_test.rb b/test/connection_pool_test.rb new file mode 100644 index 0000000..de70be1 --- /dev/null +++ b/test/connection_pool_test.rb @@ -0,0 +1,21 @@ +require_relative 'test_helper' +require 'mocha/mini_test' + +class GitHubLdapConnectionPoolTestCases < GitHub::Ldap::Test + + def test_get_connection + conn = GitHub::Ldap::ConnectionPool.get_connection({:host => "host"}) + assert_equal GitHub::Ldap, conn.class + end + + def test_returns_cached_connection + conn1 = GitHub::Ldap::ConnectionPool.get_connection({:host => "ghe.local"}) + conn2 = GitHub::Ldap::ConnectionPool.get_connection({:host => "ghe.local"}) + assert_equal conn1.object_id, conn2.object_id + + conn3 = GitHub::Ldap::ConnectionPool.get_connection({:host => "ghe.dev"}) + conn4 = GitHub::Ldap::ConnectionPool.get_connection({:host => "ghe.dev"}) + refute_equal conn1.object_id, conn3.object_id + assert_equal conn3.object_id, conn4.object_id + end +end From 4b0ccff95a8a4932cd0326ff784bb4673dcef4b8 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Fri, 29 Jul 2016 13:28:39 -0500 Subject: [PATCH 101/161] Split connection pool tests --- test/connection_pool_test.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/connection_pool_test.rb b/test/connection_pool_test.rb index de70be1..0f65e18 100644 --- a/test/connection_pool_test.rb +++ b/test/connection_pool_test.rb @@ -12,10 +12,13 @@ def test_returns_cached_connection conn1 = GitHub::Ldap::ConnectionPool.get_connection({:host => "ghe.local"}) conn2 = GitHub::Ldap::ConnectionPool.get_connection({:host => "ghe.local"}) assert_equal conn1.object_id, conn2.object_id + end + def test_creates_new_connections_per_host + conn1 = GitHub::Ldap::ConnectionPool.get_connection({:host => "ghe.local"}) + conn2 = GitHub::Ldap::ConnectionPool.get_connection({:host => "ghe.dev"}) conn3 = GitHub::Ldap::ConnectionPool.get_connection({:host => "ghe.dev"}) - conn4 = GitHub::Ldap::ConnectionPool.get_connection({:host => "ghe.dev"}) - refute_equal conn1.object_id, conn3.object_id - assert_equal conn3.object_id, conn4.object_id + refute_equal conn1.object_id, conn2.object_id + assert_equal conn2.object_id, conn3.object_id end end From edd8107d2397cec32b59e0c5d53788814c7999ec Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Fri, 29 Jul 2016 16:27:18 -0500 Subject: [PATCH 102/161] A little cleanup --- lib/github/ldap.rb | 20 +------------------- test/connection_pool_test.rb | 1 - 2 files changed, 1 insertion(+), 20 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index e1d42f7..21660c8 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -12,6 +12,7 @@ require 'github/ldap/membership_validators' require 'github/ldap/user_search/default' require 'github/ldap/user_search/active_directory' +require 'github/ldap/connection_pool' module GitHub class Ldap @@ -292,7 +293,6 @@ def configure_membership_validation_strategy(strategy = nil) end end -<<<<<<< 9afe1646fef081392687f26eaab13d471e6e5a2e # Internal: Set the user search strategy that will be used by # Domain#user?. # @@ -314,24 +314,6 @@ def configure_user_search_strategy(strategy) GitHub::Ldap::UserSearch::Default.new(self) end end -======= - def chase_referral(referral_entries, filter) - referral = referral_entries.first - uri = URI(referral[:search_referrals].first) - - new_base = URI.unescape(uri.path.sub(/^\//, '')) - options = { - filter: filter, - base: new_base, - instrumentation_service: instrumentation_service, - scope: Net::LDAP::SearchScope_BaseObject, - attributes: ["dn"] - } - - results = [] - referral_connection = get_connection_by_host(uri.host) - referral_connection.search(options) ->>>>>>> Moved chase_referral to ldap class end def get_connection_by_host(host, port=389, auth=nil) diff --git a/test/connection_pool_test.rb b/test/connection_pool_test.rb index 0f65e18..15f5fd2 100644 --- a/test/connection_pool_test.rb +++ b/test/connection_pool_test.rb @@ -1,5 +1,4 @@ require_relative 'test_helper' -require 'mocha/mini_test' class GitHubLdapConnectionPoolTestCases < GitHub::Ldap::Test From 5d7c294578d68a8ae76394c9881137d25e8e6303 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Fri, 29 Jul 2016 16:27:39 -0500 Subject: [PATCH 103/161] Abstracted referral chasing into its own class --- lib/github/ldap/referral_chaser.rb | 41 ++++++++++++++++++++++++++ test/referral_chaser_test.rb | 47 ++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 lib/github/ldap/referral_chaser.rb create mode 100644 test/referral_chaser_test.rb diff --git a/lib/github/ldap/referral_chaser.rb b/lib/github/ldap/referral_chaser.rb new file mode 100644 index 0000000..a4289b2 --- /dev/null +++ b/lib/github/ldap/referral_chaser.rb @@ -0,0 +1,41 @@ +module GitHub + class Ldap + class ReferralChaser + + def initialize(referral_entries, admin_user, admin_password) + @referral_entries = referral_entries + @admin_user = admin_user + @admin_password = admin_password + end + + def with_referrals + referral_entries.each do |entry| + entry[:search_referrals].each do |referral_string| + yield(Referral.new(referral_string, admin_user, admin_password)) + end + end + end + + private + + attr_reader :referral_entries, :admin_user, :admin_password + + class Referral + def initialize(referral_string, admin_user, admin_password) + uri = URI(referral_string) + @search_base = URI.unescape(uri.path.sub(/^\//, '')) + + connection_options = { + host: uri.host, + admin_user: admin_user, + admin_password: admin_password + } + + @connection = GitHub::Ldap::ConnectionPool.get_connection(connection_options) + end + + attr_reader :search_base, :connection + end + end + end +end diff --git a/test/referral_chaser_test.rb b/test/referral_chaser_test.rb new file mode 100644 index 0000000..823b7d7 --- /dev/null +++ b/test/referral_chaser_test.rb @@ -0,0 +1,47 @@ +require_relative 'test_helper' + +class GitHubLdapReferralChaserTestCases < GitHub::Ldap::Test + + def setup + referral_entries = [ + {:search_referrals => ["ldap://dc4.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local"]} + ] + @chaser = GitHub::Ldap::ReferralChaser.new(referral_entries, "admin1", "passworD1") + end + + def test_creates_connection + @chaser.with_referrals do |referral| + assert_equal GitHub::Ldap, referral.connection.class + end + end + + def test_returns_url_escaped_search_base + @chaser.with_referrals do |referral| + assert_equal "CN=Maggie Mae,CN=Users,DC=dc4,DC=ghe,DC=local", referral.search_base + end + end + + def test_executes_for_every_entry + referral_entries = [ + {:search_referrals => ["test1"]}, + {:search_referrals => ["test2"]} + ] + chaser = GitHub::Ldap::ReferralChaser.new(referral_entries, "admin1", "passworD1") + + called = 0 + chaser.with_referrals { called += 1 } + assert_equal 2, called + end + + def test_executes_for_every_referral + referral_entries = [ + {:search_referrals => ["test1"]}, + {:search_referrals => ["test2", "test3"]} + ] + chaser = GitHub::Ldap::ReferralChaser.new(referral_entries, "admin1", "passworD1") + + called = 0 + chaser.with_referrals { called += 1 } + assert_equal 3, called + end +end From 96ba488c1e07d7a1f95f1287414805c3b0493b4c Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Fri, 29 Jul 2016 16:28:24 -0500 Subject: [PATCH 104/161] load referral_chaser; exposed admin user & pw for referrals to use --- lib/github/ldap.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 21660c8..31247ba 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -13,6 +13,7 @@ require 'github/ldap/user_search/default' require 'github/ldap/user_search/active_directory' require 'github/ldap/connection_pool' +require 'github/ldap/referral_chaser' module GitHub class Ldap @@ -47,7 +48,9 @@ class Ldap :member_search_strategy, :instrumentation_service, :user_search_strategy, - :connection + :connection, + :admin_user, + :admin_password # Build a new GitHub::Ldap instance # From 9edc1c537408f9e90895b19f11b2c71d16dda63f Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Fri, 29 Jul 2016 16:29:21 -0500 Subject: [PATCH 105/161] Removed dead code --- lib/github/ldap.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 31247ba..4d8bc99 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -296,6 +296,7 @@ def configure_membership_validation_strategy(strategy = nil) end end +<<<<<<< 96ba488c1e07d7a1f95f1287414805c3b0493b4c # Internal: Set the user search strategy that will be used by # Domain#user?. # From 7f3e6f2ca6d7c8ab670a78fd8cfa616c14b9dbc4 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Fri, 29 Jul 2016 16:30:05 -0500 Subject: [PATCH 106/161] Use new referral chaser class in ActiveDirectory validator --- lib/github/ldap/membership_validators/active_directory.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/github/ldap/membership_validators/active_directory.rb b/lib/github/ldap/membership_validators/active_directory.rb index ed336d7..6dae2e4 100644 --- a/lib/github/ldap/membership_validators/active_directory.rb +++ b/lib/github/ldap/membership_validators/active_directory.rb @@ -40,14 +40,17 @@ def perform(entry) end if referral_entries.present? - matched = ldap.chase_referral(referral_entries, filter) + chaser = GitHub::Ldap::ReferralChaser.new(referral_entries, ldap.admin_user, ldap.admin_password) + chaser.with_referrals do |referral| + options[:base] = referral.search_base + matched = referral.connection.search(options) + end end # membership validated if entry was matched and returned as a result # Active Directory DNs are case-insensitive result = Array(matched).map { |m| m.dn.downcase }.include?(entry.dn.downcase) - result end # Internal: Constructs a membership filter using the "in chain" From b7da6e7605b2034da638cc192fa3d81b3af78a56 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Sat, 30 Jul 2016 13:09:45 -0500 Subject: [PATCH 107/161] Pushing referral aggregation from callsite into ReferallChaser --- lib/github/ldap/referral_chaser.rb | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/lib/github/ldap/referral_chaser.rb b/lib/github/ldap/referral_chaser.rb index a4289b2..68371b7 100644 --- a/lib/github/ldap/referral_chaser.rb +++ b/lib/github/ldap/referral_chaser.rb @@ -2,23 +2,33 @@ module GitHub class Ldap class ReferralChaser - def initialize(referral_entries, admin_user, admin_password) - @referral_entries = referral_entries - @admin_user = admin_user - @admin_password = admin_password + def initialize(connection) + @connection = connection + @admin_user = connection.admin_user + @admin_password = connection.admin_password end - def with_referrals + def search(options) + search_results = [] + referral_entries = [] + + search_results = connection.search(options) do |referral_entry| + referral_entries << referral_entry + end + referral_entries.each do |entry| entry[:search_referrals].each do |referral_string| - yield(Referral.new(referral_string, admin_user, admin_password)) + referral = Referral.new(referral_string, admin_user, admin_password) + search_results.concat(referral.search(options)) end end + + search_results end private - attr_reader :referral_entries, :admin_user, :admin_password + attr_reader :connection, :admin_user, :admin_password class Referral def initialize(referral_string, admin_user, admin_password) From 704ea393656354d82302103dce64a2b7342b5649 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 1 Aug 2016 13:28:58 -0500 Subject: [PATCH 108/161] Use base connection's port as the default port --- lib/github/ldap.rb | 6 +++++- lib/github/ldap/connection_cache.rb | 26 ++++++++++++++++++++++++++ lib/github/ldap/connection_pool.rb | 24 ------------------------ lib/github/ldap/referral_chaser.rb | 29 ++++++++++++++++++----------- test/connection_cache_test.rb | 23 +++++++++++++++++++++++ test/connection_pool_test.rb | 23 ----------------------- 6 files changed, 72 insertions(+), 59 deletions(-) create mode 100644 lib/github/ldap/connection_cache.rb delete mode 100644 lib/github/ldap/connection_pool.rb create mode 100644 test/connection_cache_test.rb delete mode 100644 test/connection_pool_test.rb diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 4d8bc99..09df551 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -13,7 +13,9 @@ require 'github/ldap/user_search/default' require 'github/ldap/user_search/active_directory' require 'github/ldap/connection_pool' +require 'github/ldap/connection_cache' require 'github/ldap/referral_chaser' +require 'github/ldap/url' module GitHub class Ldap @@ -50,7 +52,8 @@ class Ldap :user_search_strategy, :connection, :admin_user, - :admin_password + :admin_password, + :port # Build a new GitHub::Ldap instance # @@ -80,6 +83,7 @@ def initialize(options = {}) # Keep a reference to these as default auth for a Global Catalog if needed @admin_user = options[:admin_user] @admin_password = options[:admin_password] + @port = options[:port] @connection = Net::LDAP.new({ host: options[:host], diff --git a/lib/github/ldap/connection_cache.rb b/lib/github/ldap/connection_cache.rb new file mode 100644 index 0000000..d2feab9 --- /dev/null +++ b/lib/github/ldap/connection_cache.rb @@ -0,0 +1,26 @@ +module GitHub + class Ldap + + # A simple cache of GitHub::Ldap objects to prevent creating multiple + # instances of connections that point to the same URI/host. + class ConnectionCache + + # Public - Create or return cached instance of GitHub::Ldap created with options, + # where the cache key is the value of options[:host]. + # + # options - Initialization attributes suitable for creating a new connection with + # GitHub::Ldap.new(options) + # + # Returns true or false. + def self.get_connection(options={}) + @cache ||= self.new + @cache.get_connection(options) + end + + def get_connection(options) + @connections ||= {} + @connections[options[:host]] ||= GitHub::Ldap.new(options) + end + end + end +end diff --git a/lib/github/ldap/connection_pool.rb b/lib/github/ldap/connection_pool.rb deleted file mode 100644 index c3c723c..0000000 --- a/lib/github/ldap/connection_pool.rb +++ /dev/null @@ -1,24 +0,0 @@ -module GitHub - class Ldap - class ConnectionPool - - # Public - Create or return cached instance of GitHub::Ldap created with options, - # where the cache key is the value of options[:host]. - # - # Returns an instance of GitHub::Ldap - def self.get_connection(options={}) - @instance ||= self.new - @instance.get_connection(options) - end - - def get_connection(options) - host = options[:host] - @connections ||= Hash.new do |cache, host| - conn = GitHub::Ldap.new(options) - cache[host] = conn - end - @connections[host] - end - end - end -end diff --git a/lib/github/ldap/referral_chaser.rb b/lib/github/ldap/referral_chaser.rb index 68371b7..90857d2 100644 --- a/lib/github/ldap/referral_chaser.rb +++ b/lib/github/ldap/referral_chaser.rb @@ -16,11 +16,11 @@ def search(options) referral_entries << referral_entry end - referral_entries.each do |entry| - entry[:search_referrals].each do |referral_string| - referral = Referral.new(referral_string, admin_user, admin_password) - search_results.concat(referral.search(options)) - end + unless referral_entries.empty? + entry = referral_entries.first + referral_string = entry[:search_referrals].first + referral = Referral.new(referral_string, admin_user, admin_password, port) + search_results = referral.search(options) end search_results @@ -28,20 +28,27 @@ def search(options) private - attr_reader :connection, :admin_user, :admin_password + attr_reader :connection, :admin_user, :admin_password, :port + # Represents a referral entry from an LDAP search result. Constructs a corresponding + # GitHub::Ldap object from the paramaters on the referral_url and provides a #search + # method to continue the search on the referred domain. class Referral - def initialize(referral_string, admin_user, admin_password) - uri = URI(referral_string) - @search_base = URI.unescape(uri.path.sub(/^\//, '')) + def initialize(referral_url, admin_user, admin_password, port=nil) + url = GitHub::Ldap::URL.new(referral_url) + @search_base = url.dn connection_options = { - host: uri.host, + host: url.host, + port: port || url.port, + scope: url.scope, admin_user: admin_user, admin_password: admin_password } - @connection = GitHub::Ldap::ConnectionPool.get_connection(connection_options) + @connection = GitHub::Ldap::ConnectionCache.get_connection(connection_options) + end + end attr_reader :search_base, :connection diff --git a/test/connection_cache_test.rb b/test/connection_cache_test.rb new file mode 100644 index 0000000..7eb0aa3 --- /dev/null +++ b/test/connection_cache_test.rb @@ -0,0 +1,23 @@ +require_relative 'test_helper' + +class GitHubLdapConnectionCacheTestCases < GitHub::Ldap::Test + + def test_get_connection + conn = GitHub::Ldap::ConnectionCache.get_connection({:host => "host"}) + assert_equal GitHub::Ldap, conn.class + end + + def test_returns_cached_connection + conn1 = GitHub::Ldap::ConnectionCache.get_connection({:host => "ghe.local"}) + conn2 = GitHub::Ldap::ConnectionCache.get_connection({:host => "ghe.local"}) + assert_equal conn1.object_id, conn2.object_id + end + + def test_creates_new_connections_per_host + conn1 = GitHub::Ldap::ConnectionCache.get_connection({:host => "ghe.local"}) + conn2 = GitHub::Ldap::ConnectionCache.get_connection({:host => "ghe.dev"}) + conn3 = GitHub::Ldap::ConnectionCache.get_connection({:host => "ghe.dev"}) + refute_equal conn1.object_id, conn2.object_id + assert_equal conn2.object_id, conn3.object_id + end +end diff --git a/test/connection_pool_test.rb b/test/connection_pool_test.rb deleted file mode 100644 index 15f5fd2..0000000 --- a/test/connection_pool_test.rb +++ /dev/null @@ -1,23 +0,0 @@ -require_relative 'test_helper' - -class GitHubLdapConnectionPoolTestCases < GitHub::Ldap::Test - - def test_get_connection - conn = GitHub::Ldap::ConnectionPool.get_connection({:host => "host"}) - assert_equal GitHub::Ldap, conn.class - end - - def test_returns_cached_connection - conn1 = GitHub::Ldap::ConnectionPool.get_connection({:host => "ghe.local"}) - conn2 = GitHub::Ldap::ConnectionPool.get_connection({:host => "ghe.local"}) - assert_equal conn1.object_id, conn2.object_id - end - - def test_creates_new_connections_per_host - conn1 = GitHub::Ldap::ConnectionPool.get_connection({:host => "ghe.local"}) - conn2 = GitHub::Ldap::ConnectionPool.get_connection({:host => "ghe.dev"}) - conn3 = GitHub::Ldap::ConnectionPool.get_connection({:host => "ghe.dev"}) - refute_equal conn1.object_id, conn2.object_id - assert_equal conn2.object_id, conn3.object_id - end -end From 819955525fb8cf48d9ba83d0978fe0b619feeb43 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 1 Aug 2016 13:39:41 -0500 Subject: [PATCH 109/161] Use ReferralChaser to do all the search heavy lifting for AD --- .../membership_validators/active_directory.rb | 16 ++++------------ lib/github/ldap/referral_chaser.rb | 4 ++++ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/lib/github/ldap/membership_validators/active_directory.rb b/lib/github/ldap/membership_validators/active_directory.rb index 6dae2e4..8be26bd 100644 --- a/lib/github/ldap/membership_validators/active_directory.rb +++ b/lib/github/ldap/membership_validators/active_directory.rb @@ -34,18 +34,10 @@ def perform(entry) attributes: ATTRS } - referral_entries = [] - matched = ldap.search(options) do |ref| - referral_entries << ref - end - - if referral_entries.present? - chaser = GitHub::Ldap::ReferralChaser.new(referral_entries, ldap.admin_user, ldap.admin_password) - chaser.with_referrals do |referral| - options[:base] = referral.search_base - matched = referral.connection.search(options) - end - end + # Chase any potential referrals for an entry that may be owned by a different + # domain controller. + chaser = GitHub::Ldap::ReferralChaser.new(ldap) + matched = chaser.search(options) # membership validated if entry was matched and returned as a result # Active Directory DNs are case-insensitive diff --git a/lib/github/ldap/referral_chaser.rb b/lib/github/ldap/referral_chaser.rb index 90857d2..c37c335 100644 --- a/lib/github/ldap/referral_chaser.rb +++ b/lib/github/ldap/referral_chaser.rb @@ -49,6 +49,10 @@ def initialize(referral_url, admin_user, admin_password, port=nil) @connection = GitHub::Ldap::ConnectionCache.get_connection(connection_options) end + # Search the referred domain controller with options, merging in the referred search + # base DN onto options[:base]. + def search(options) + connection.search(options.merge(base: search_base)) end attr_reader :search_base, :connection From d3dc5c413195a7ba4115612ee95d7a2d258fe745 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 1 Aug 2016 13:40:38 -0500 Subject: [PATCH 110/161] Updated documentation --- lib/github/ldap/referral_chaser.rb | 32 ++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/lib/github/ldap/referral_chaser.rb b/lib/github/ldap/referral_chaser.rb index c37c335..1e0b551 100644 --- a/lib/github/ldap/referral_chaser.rb +++ b/lib/github/ldap/referral_chaser.rb @@ -1,13 +1,45 @@ module GitHub class Ldap + + # This class adds referral chasing capability to a GitHub::Ldap connection. + # + # See: https://technet.microsoft.com/en-us/library/cc978014.aspx + # http://www.umich.edu/~dirsvcs/ldap/doc/other/ldap-ref.html + # class ReferralChaser + # Public - Creates a ReferralChaser that decorates an instance of GitHub::Ldap + # with additional functionality to the #search method, allowing it to chase + # any referral entries and aggregate the results into a single response. + # + # connection - The instance of GitHub::Ldap to use for searching. Will use + # the connection's authentication, (admin_user and admin_password) as credentials + # for connecting to referred domain controllers. def initialize(connection) @connection = connection @admin_user = connection.admin_user @admin_password = connection.admin_password + @port = connection.port end + # Public - Search the domain controller represented by this instance's connection. + # If a referral is returned, search only one of the domain controllers indicated + # by the referral entries, per RFC 4511 (https://tools.ietf.org/html/rfc4511): + # + # "If the client wishes to progress the operation, it contacts one of + # the supported services found in the referral. If multiple URIs are + # present, the client assumes that any supported URI may be used to + # progress the operation." + # + # options - is a hash with the same options that Net::LDAP::Connection#search supports. + # Referral searches will use the given options, but will replace options[:base] + # with the referral URL's base search dn. + # + # Does not take a block argument as GitHub::Ldap and Net::LDAP::Connection#search do. + # + # Will not recursively follow any subsequent referrals. + # + # Returns an Array of Net::LDAP::Entry. def search(options) search_results = [] referral_entries = [] From 644fb68cc74ed05521a3176d2d8fdd462378a60e Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 1 Aug 2016 13:41:30 -0500 Subject: [PATCH 111/161] Updated tests --- test/referral_chaser_test.rb | 109 +++++++++++++++++++++++++---------- 1 file changed, 79 insertions(+), 30 deletions(-) diff --git a/test/referral_chaser_test.rb b/test/referral_chaser_test.rb index 823b7d7..8eb1ba4 100644 --- a/test/referral_chaser_test.rb +++ b/test/referral_chaser_test.rb @@ -1,47 +1,96 @@ require_relative 'test_helper' +require 'mocha/mini_test' class GitHubLdapReferralChaserTestCases < GitHub::Ldap::Test def setup - referral_entries = [ - {:search_referrals => ["ldap://dc4.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local"]} - ] - @chaser = GitHub::Ldap::ReferralChaser.new(referral_entries, "admin1", "passworD1") + @mock_connection = GitHub::Ldap.new({ + admin_user: "Joe", + admin_password: "passworD1", + port: 888 + }) + @chaser = GitHub::Ldap::ReferralChaser.new(@mock_connection) end - def test_creates_connection - @chaser.with_referrals do |referral| - assert_equal GitHub::Ldap, referral.connection.class - end + def test_creates_referral_with_connection_credentials + @mock_connection.expects(:search).yields({ search_referrals: ["referral string"]}).returns([]) + + referral = Object.new + referral.stubs(:search).returns([]) + + GitHub::Ldap::ReferralChaser::Referral.expects(:new) + .with("referral string", "Joe", "passworD1", 888) + .returns(referral) + + @chaser.search({}) + end + + def test_creates_referral_with_default_port + mock_connection = GitHub::Ldap.new({ + admin_user: "Joe", + admin_password: "passworD1" + }) + mock_connection.expects(:search).yields({ search_referrals: ["ldap://dc1.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local"]}).returns([]) + + stub_conn = Object.new + stub_conn.stubs(:search).returns([]) + GitHub::Ldap::ConnectionCache.expects(:get_connection).with(has_entry(port: 389)).returns(stub_conn) + chaser = GitHub::Ldap::ReferralChaser.new(mock_connection) + chaser.search({}) end - def test_returns_url_escaped_search_base - @chaser.with_referrals do |referral| - assert_equal "CN=Maggie Mae,CN=Users,DC=dc4,DC=ghe,DC=local", referral.search_base - end + def test_creates_referral_for_first_referral_string + @mock_connection.expects(:search).multiple_yields([ + { search_referrals: + ["ldap://dc1.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local", + "ldap://dc2.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local"] + } + ],[ + { search_referrals: + ["ldap://dc3.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local", + "ldap://dc4.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local"] + } + ]).returns([]) + + referral = Object.new + referral.stubs(:search).returns([]) + + GitHub::Ldap::ReferralChaser::Referral.expects(:new) + .with("ldap://dc1.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local", "Joe", "passworD1", 888) + .returns(referral) + + @chaser.search({}) end - def test_executes_for_every_entry - referral_entries = [ - {:search_referrals => ["test1"]}, - {:search_referrals => ["test2"]} - ] - chaser = GitHub::Ldap::ReferralChaser.new(referral_entries, "admin1", "passworD1") + def test_returns_referral_search_results + @mock_connection.expects(:search).multiple_yields([ + { search_referrals: + ["ldap://dc1.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local", + "ldap://dc2.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local"] + } + ],[ + { search_referrals: + ["ldap://dc3.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local", + "ldap://dc4.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local"] + } + ]).returns([]) - called = 0 - chaser.with_referrals { called += 1 } - assert_equal 2, called + referral = Object.new + referral.expects(:search).returns(["result", "result"]) + + GitHub::Ldap::ReferralChaser::Referral.expects(:new).returns(referral) + + results = @chaser.search({}) + assert_equal(["result", "result"], results) end - def test_executes_for_every_referral - referral_entries = [ - {:search_referrals => ["test1"]}, - {:search_referrals => ["test2", "test3"]} - ] - chaser = GitHub::Ldap::ReferralChaser.new(referral_entries, "admin1", "passworD1") + def test_referral_should_use_host_from_referral_string + GitHub::Ldap::ConnectionCache.expects(:get_connection).with(has_entry(host: "dc4.ghe.local")) + GitHub::Ldap::ReferralChaser::Referral.new("ldap://dc4.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local", "", "") + end - called = 0 - chaser.with_referrals { called += 1 } - assert_equal 3, called + def test_referral_should_use_host_from_referral_string + GitHub::Ldap::ConnectionCache.expects(:get_connection).with(has_entry(host: "dc4.ghe.local")) + GitHub::Ldap::ReferralChaser::Referral.new("ldap://dc4.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local", "", "") end end From e759522acf0fb7d5a03de2d3c1524cdb870ff6eb Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 1 Aug 2016 13:51:46 -0500 Subject: [PATCH 112/161] Added a GitHub::Ldap::URL object to encapsulate parsing ldap urls --- lib/github/ldap/url.rb | 83 ++++++++++++++++++++++++++++++++++++++++++ test/url_test.rb | 78 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 161 insertions(+) create mode 100644 lib/github/ldap/url.rb create mode 100644 test/url_test.rb diff --git a/lib/github/ldap/url.rb b/lib/github/ldap/url.rb new file mode 100644 index 0000000..605fd1f --- /dev/null +++ b/lib/github/ldap/url.rb @@ -0,0 +1,83 @@ +module GitHub + class Ldap + + # This class represents an LDAP URL + # + # See: https://tools.ietf.org/html/rfc4516#section-2 + # https://docs.oracle.com/cd/E19957-01/817-6707/urls.html + # + class URL + extend Forwardable + SCOPES = { + "base" => Net::LDAP::SearchScope_BaseObject, + "one" => Net::LDAP::SearchScope_SingleLevel, + "sub" => Net::LDAP::SearchScope_WholeSubtree + } + SCOPES.default = Net::LDAP::SearchScope_BaseObject + + attr_reader :dn, :attributes, :scope, :filter + + def_delegators :@uri, :port, :host, :scheme + + # Public - Creates a new GitHub::Ldap::URL object with :port, :host and :scheme + # delegated to a URI object parsed from url_string, and then parses the + # query params according to the LDAP specification. + # + # url_string - An LDAP URL string. + # returns - a GitHub::Ldap::URL with the following attributes: + # host - Name or IP of the LDAP server. + # port - The given port, defaults to 389. + # dn - The base search DN. + # attributes - The comma-delimited list of attributes to be returned. + # scope - The scope of the search. + # filter - Search filter to apply to entries within the specified scope of the search. + # + # Supported LDAP URL strings look like this, where sections in brackets are optional: + # + # ldap[s]://[hostport][/[dn[?[attributes][?[scope][?[filter]]]]]] + # + # where: + # + # hostport is a host name with an optional ":portnumber" + # dn is the base DN to be used for an LDAP search operation + # attributes is a comma separated list of attributes to be retrieved + # scope is one of these three strings: base one sub (default=base) + # filter is LDAP search filter as used in a call to ldap_search + # + # For example: + # + # ldap://dc4.ghe.local:456/CN=Maggie,DC=dc4,DC=ghe,DC=local?cn,mail?base?(cn=Charlie) + # + def initialize(url_string) + @uri = URI(url_string) + unless ["ldap", "ldaps"].include?(@uri.scheme) + raise InvalidSchemeException.new("Invalid scheme: #{@uri.scheme}") + end + @dn = URI.unescape(@uri.path.sub(/^\//, "")) + if @uri.query + @attributes, @scope, @filter = @uri.query.split("?") + end + end + + # Maps the returned scope value from the URL to one of Net::LDAP::Scopes + # + # The URL scope value can be one of: + # "base" - retrieves information only about the DN (base_dn) specified. + # "one" - retrieves information about entries one level below the DN (base_dn) specified. The base entry is not included in this scope. + # "sub" - retrieves information about entries at all levels below the DN (base_dn) specified. The base entry is included in this scope. + # + # Which will map to one of the following Net::LDAP::Scopes: + # SearchScope_BaseObject = 0 + # SearchScope_SingleLevel = 1 + # SearchScope_WholeSubtree = 2 + # + # If no scope or an invalid scope is given, defaults to SearchScope_BaseObject + def net_ldap_scope + Net::LDAP::SearchScopes[SCOPES[scope]] + end + + class InvalidSchemeException < Exception; end + end + end +end + diff --git a/test/url_test.rb b/test/url_test.rb new file mode 100644 index 0000000..a84127e --- /dev/null +++ b/test/url_test.rb @@ -0,0 +1,78 @@ +require_relative 'test_helper' + +class GitHubLdapURLTestCases < GitHub::Ldap::Test + + def setup + @url = GitHub::Ldap::URL.new("ldap://dc4.ghe.local:123/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local?cn,mail,telephoneNumber?base?(cn=Charlie)") + end + + def test_host + assert_equal "dc4.ghe.local", @url.host + end + + def test_port + assert_equal 123, @url.port + end + + def test_scheme + assert_equal "ldap", @url.scheme + end + + def test_default_port + url = GitHub::Ldap::URL.new("ldap://dc4.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local?attributes?scope?filter") + assert_equal 389, url.port + end + + def test_simple_url + url = GitHub::Ldap::URL.new("ldap://dc4.ghe.local") + assert_equal 389, url.port + assert_equal "dc4.ghe.local", url.host + assert_equal "ldap", url.scheme + assert_equal "", url.dn + assert_equal nil, url.attributes + assert_equal nil, url.filter + assert_equal nil, url.scope + end + + def test_invalid_scheme + ex = assert_raises(GitHub::Ldap::URL::InvalidSchemeException) do + GitHub::Ldap::URL.new("http://dc4.ghe.local") + end + assert_equal("Invalid scheme: http", ex.message) + end + + def test_parse_dn + assert_equal "CN=Maggie Mae,CN=Users,DC=dc4,DC=ghe,DC=local", @url.dn + end + + def test_parse_attributes + assert_equal "cn,mail,telephoneNumber", @url.attributes + end + + def test_parse_filter + assert_equal "(cn=Charlie)", @url.filter + end + + def test_parse_scope + assert_equal "base", @url.scope + end + + def test_default_scope + url = GitHub::Ldap::URL.new("ldap://dc4.ghe.local/base_dn?cn=joe??filter") + assert_equal "", url.scope + end + + def test_net_ldap_scopes + sub_scope_url = GitHub::Ldap::URL.new("ldap://ghe.local/base_dn?cn=joe?sub?filter") + one_scope_url = GitHub::Ldap::URL.new("ldap://ghe.local/base_dn?cn=joe?one?filter") + base_scope_url = GitHub::Ldap::URL.new("ldap://ghe.local/base_dn?cn=joe?base?filter") + default_scope_url = GitHub::Ldap::URL.new("ldap://dc4.ghe.local/base_dn?cn=joe??filter") + invalid_scope_url = GitHub::Ldap::URL.new("ldap://dc4.ghe.local/base_dn?cn=joe?invalid?filter") + + assert_equal Net::LDAP::SearchScope_BaseObject, base_scope_url.net_ldap_scope + assert_equal Net::LDAP::SearchScope_SingleLevel, one_scope_url.net_ldap_scope + assert_equal Net::LDAP::SearchScope_WholeSubtree, sub_scope_url.net_ldap_scope + assert_equal Net::LDAP::SearchScope_BaseObject, default_scope_url.net_ldap_scope + assert_equal Net::LDAP::SearchScope_BaseObject, invalid_scope_url.net_ldap_scope + end +end From 5cefd9735c709300248e63b79374fa10da6e5af4 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 1 Aug 2016 13:55:00 -0500 Subject: [PATCH 113/161] Remove redundant test --- test/referral_chaser_test.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/referral_chaser_test.rb b/test/referral_chaser_test.rb index 8eb1ba4..8169681 100644 --- a/test/referral_chaser_test.rb +++ b/test/referral_chaser_test.rb @@ -88,9 +88,4 @@ def test_referral_should_use_host_from_referral_string GitHub::Ldap::ConnectionCache.expects(:get_connection).with(has_entry(host: "dc4.ghe.local")) GitHub::Ldap::ReferralChaser::Referral.new("ldap://dc4.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local", "", "") end - - def test_referral_should_use_host_from_referral_string - GitHub::Ldap::ConnectionCache.expects(:get_connection).with(has_entry(host: "dc4.ghe.local")) - GitHub::Ldap::ReferralChaser::Referral.new("ldap://dc4.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local", "", "") - end end From 0ac330a45911ac161a47b4da40bfd6804e3c2a1a Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Mon, 1 Aug 2016 16:36:40 -0500 Subject: [PATCH 114/161] Only iterate over Referall type entries in ReferralChaser --- lib/github/ldap/referral_chaser.rb | 6 ++++-- test/referral_chaser_test.rb | 7 +++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/github/ldap/referral_chaser.rb b/lib/github/ldap/referral_chaser.rb index 1e0b551..7a36f88 100644 --- a/lib/github/ldap/referral_chaser.rb +++ b/lib/github/ldap/referral_chaser.rb @@ -44,8 +44,10 @@ def search(options) search_results = [] referral_entries = [] - search_results = connection.search(options) do |referral_entry| - referral_entries << referral_entry + search_results = connection.search(options) do |entry| + if entry[:search_referrals] + referral_entries << entry + end end unless referral_entries.empty? diff --git a/test/referral_chaser_test.rb b/test/referral_chaser_test.rb index 8169681..c9ff2e7 100644 --- a/test/referral_chaser_test.rb +++ b/test/referral_chaser_test.rb @@ -84,6 +84,13 @@ def test_returns_referral_search_results assert_equal(["result", "result"], results) end + def test_returns_referral_search_results + @mock_connection.expects(:search).yields({ foo: ["not a referral"] }) + + GitHub::Ldap::ReferralChaser::Referral.expects(:new).never + results = @chaser.search({}) + end + def test_referral_should_use_host_from_referral_string GitHub::Ldap::ConnectionCache.expects(:get_connection).with(has_entry(host: "dc4.ghe.local")) GitHub::Ldap::ReferralChaser::Referral.new("ldap://dc4.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local", "", "") From 1a95540667deab85c51c8000c073d9000c6c0c39 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Tue, 2 Aug 2016 07:44:44 -0500 Subject: [PATCH 115/161] memoize the referral chaser --- lib/github/ldap/membership_validators/active_directory.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/github/ldap/membership_validators/active_directory.rb b/lib/github/ldap/membership_validators/active_directory.rb index 8be26bd..9a79a86 100644 --- a/lib/github/ldap/membership_validators/active_directory.rb +++ b/lib/github/ldap/membership_validators/active_directory.rb @@ -36,8 +36,7 @@ def perform(entry) # Chase any potential referrals for an entry that may be owned by a different # domain controller. - chaser = GitHub::Ldap::ReferralChaser.new(ldap) - matched = chaser.search(options) + matched = referral_chaser.search(options) # membership validated if entry was matched and returned as a result # Active Directory DNs are case-insensitive @@ -45,6 +44,10 @@ def perform(entry) result = Array(matched).map { |m| m.dn.downcase }.include?(entry.dn.downcase) end + def referral_chaser + @referral_chaser ||= GitHub::Ldap::ReferralChaser.new(@ldap) + end + # Internal: Constructs a membership filter using the "in chain" # extended matching rule afforded by ActiveDirectory. # From e2c36758243bb70904ed8452ffec34fad21d6893 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Tue, 2 Aug 2016 07:45:13 -0500 Subject: [PATCH 116/161] check entry for nil when collecting referrals --- lib/github/ldap/referral_chaser.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/github/ldap/referral_chaser.rb b/lib/github/ldap/referral_chaser.rb index 7a36f88..9046cb0 100644 --- a/lib/github/ldap/referral_chaser.rb +++ b/lib/github/ldap/referral_chaser.rb @@ -45,7 +45,7 @@ def search(options) referral_entries = [] search_results = connection.search(options) do |entry| - if entry[:search_referrals] + if entry && entry[:search_referrals] referral_entries << entry end end From a4573d71891f98f13de89461028e8ad4fbcdff21 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 14:40:26 -0500 Subject: [PATCH 117/161] Remove test file; clean up merge --- ldap.sh | 9 --------- lib/github/ldap.rb | 1 - 2 files changed, 10 deletions(-) delete mode 100644 ldap.sh diff --git a/ldap.sh b/ldap.sh deleted file mode 100644 index 32a654c..0000000 --- a/ldap.sh +++ /dev/null @@ -1,9 +0,0 @@ - ldapsearch -x -h dc4.ghe.local \ - -b "CN=Maggie Mae,CN=Users,DC=dc4,DC=ghe,DC=local" \ - -D "GHE\Administrator" -w "vagrant" \ - "(|(|(| \ - (memberOf:1.2.840.113556.1.4.1941:=CN=ghe-users,CN=Users,DC=ghe,DC=local) \ - (memberOf:1.2.840.113556.1.4.1941:=CN=ghe-users,CN=Users, DC=dc4,DC=ghe,DC=local)) \ - (memberOf:1.2.840.113556.1.4.1941:=CN=ghe-admins,CN=Users,DC=ghe,DC=local)) \ - (memberOf:1.2.840.113556.1.4.1941:=CN=ghe-admins,CN=Users,DC=dc4,DC=ghe,DC=local))" - diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 09df551..fa0c8d6 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -300,7 +300,6 @@ def configure_membership_validation_strategy(strategy = nil) end end -<<<<<<< 96ba488c1e07d7a1f95f1287414805c3b0493b4c # Internal: Set the user search strategy that will be used by # Domain#user?. # From 3eddd8b7929d979c865a214a709734dcaf079f8e Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 14:51:02 -0500 Subject: [PATCH 118/161] A bit more merge cleanup --- lib/github/ldap.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index fa0c8d6..f23c2d3 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -12,7 +12,6 @@ require 'github/ldap/membership_validators' require 'github/ldap/user_search/default' require 'github/ldap/user_search/active_directory' -require 'github/ldap/connection_pool' require 'github/ldap/connection_cache' require 'github/ldap/referral_chaser' require 'github/ldap/url' @@ -374,7 +373,5 @@ def configure_member_search_strategy(strategy = nil) def active_directory_capability? capabilities[:supportedcapabilities].include?(ACTIVE_DIRECTORY_V51_OID) end - - attr_reader :admin_user, :admin_password end end From 7cdbe8650ff852d82e9a1b12b9efa6ae7416b86a Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 14:51:21 -0500 Subject: [PATCH 119/161] Minor style/cleanup --- .../membership_validators/active_directory.rb | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/lib/github/ldap/membership_validators/active_directory.rb b/lib/github/ldap/membership_validators/active_directory.rb index 9a79a86..e646460 100644 --- a/lib/github/ldap/membership_validators/active_directory.rb +++ b/lib/github/ldap/membership_validators/active_directory.rb @@ -24,23 +24,18 @@ def perform(entry) # Sets the entry to the base and scopes the search to the base, # according to the source documentation, found here: # http://msdn.microsoft.com/en-us/library/aa746475(v=vs.85).aspx - - filter = membership_in_chain_filter(entry) - options = { - filter: filter, + # + # Use ReferralChaser to chase any potential referrals for an entry that may be owned by a different + # domain controller. + matched = referral_chaser.search \ + filter: membership_in_chain_filter(entry), base: entry.dn, scope: Net::LDAP::SearchScope_BaseObject, return_referrals: true, attributes: ATTRS - } - - # Chase any potential referrals for an entry that may be owned by a different - # domain controller. - matched = referral_chaser.search(options) # membership validated if entry was matched and returned as a result # Active Directory DNs are case-insensitive - result = Array(matched).map { |m| m.dn.downcase }.include?(entry.dn.downcase) end From 80a6127bd668783a56f1ddd2f8f6f3da9275485e Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 14:54:03 -0500 Subject: [PATCH 120/161] Don't need result reference --- lib/github/ldap/membership_validators/active_directory.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/github/ldap/membership_validators/active_directory.rb b/lib/github/ldap/membership_validators/active_directory.rb index e646460..ff4e4fc 100644 --- a/lib/github/ldap/membership_validators/active_directory.rb +++ b/lib/github/ldap/membership_validators/active_directory.rb @@ -36,7 +36,7 @@ def perform(entry) # membership validated if entry was matched and returned as a result # Active Directory DNs are case-insensitive - result = Array(matched).map { |m| m.dn.downcase }.include?(entry.dn.downcase) + Array(matched).map { |m| m.dn.downcase }.include?(entry.dn.downcase) end def referral_chaser From f0525598f25775c160507b951c3fd584e80891cd Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 18:17:57 -0500 Subject: [PATCH 121/161] Better format for private method --- lib/github/ldap.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index f23c2d3..0eb2d36 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -362,9 +362,6 @@ def configure_member_search_strategy(strategy = nil) end end - - private - # Internal: Detect whether the LDAP host is an ActiveDirectory server. # # See: http://msdn.microsoft.com/en-us/library/cc223359.aspx. @@ -373,5 +370,6 @@ def configure_member_search_strategy(strategy = nil) def active_directory_capability? capabilities[:supportedcapabilities].include?(ACTIVE_DIRECTORY_V51_OID) end + private :active_directory_capability? end end From 77b42095b95629fd9b845c7469732fc8ed935fc9 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 18:27:27 -0500 Subject: [PATCH 122/161] Add host interface to ldap; updated tests --- lib/github/ldap.rb | 1 + lib/github/ldap/user_search/active_directory.rb | 2 +- test/user_search/active_directory_test.rb | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 0eb2d36..6ad1143 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -43,6 +43,7 @@ class Ldap # # Returns the return value of the block. def_delegator :@connection, :open + def_delegator :@connection, :host attr_reader :uid, :search_domains, :virtual_attributes, :membership_validator, diff --git a/lib/github/ldap/user_search/active_directory.rb b/lib/github/ldap/user_search/active_directory.rb index d2e0981..2bec4ad 100644 --- a/lib/github/ldap/user_search/active_directory.rb +++ b/lib/github/ldap/user_search/active_directory.rb @@ -37,7 +37,7 @@ def self.connection(ldap) auth = netldap.instance_variable_get(:@auth) new({ - host: ldap.instance_variable_get(:@host), + host: ldap.host, instrumentation_service: ldap.instrumentation_service, port: encryption ? LDAPS_GC_PORT : STANDARD_GC_PORT, auth: auth, diff --git a/test/user_search/active_directory_test.rb b/test/user_search/active_directory_test.rb index ae23146..1728b46 100644 --- a/test/user_search/active_directory_test.rb +++ b/test/user_search/active_directory_test.rb @@ -4,7 +4,7 @@ class GitHubLdapActiveDirectoryUserSearchTests < GitHub::Ldap::Test def setup - @ldap = GitHub::Ldap.new(options) + @ldap = GitHub::Ldap.new(options.merge(host: 'ghe.dev')) @ad_user_search = GitHub::Ldap::UserSearch::ActiveDirectory.new(@ldap) end @@ -33,14 +33,14 @@ def test_searches_with_empty_base_dn end def test_global_catalog_default_settings - global_catalog = @ad_user_search.global_catalog_connection + global_catalog = GitHub::Ldap::UserSearch::GlobalCatalog.connection(@ldap) instrumentation_service = global_catalog.instance_variable_get(:@instrumentation_service) auth = global_catalog.instance_variable_get(:@auth) assert_equal :simple, auth[:method] assert_equal "uid=admin,dc=github,dc=com", auth[:username] assert_equal "passworD1", auth[:password] - assert_equal "127.0.0.1", global_catalog.host + assert_equal "ghe.dev", global_catalog.host assert_equal 3268, global_catalog.port assert_equal "MockInstrumentationService", instrumentation_service.class.name end From 518bd851230a5bf143fdb4cfe9e7c9d9a27b1ecf Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 18:30:30 -0500 Subject: [PATCH 123/161] Moved connection cache to its own class --- lib/github/ldap.rb | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 6ad1143..28dfab4 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -323,20 +323,6 @@ def configure_user_search_strategy(strategy) end end - def get_connection_by_host(host, port=389, auth=nil) - auth ||= {:method => :simple, :username => @admin_user, :password => @admin_password} - - @connections ||= Hash.new do |cache, host| - conn = GitHub::Ldap.new({ - host: host, - port: port, - auth: auth - }) - cache[host] = conn - end - @connections[host] - end - # Internal: Configure the member search strategy. # # From 27cf716c6594e241faa919ae495f4342429f343d Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 18:53:04 -0500 Subject: [PATCH 124/161] move mocha requirement to test_helper --- test/domain_test.rb | 1 - test/ldap_test.rb | 1 - test/referral_chaser_test.rb | 1 - test/test_helper.rb | 2 ++ test/user_search/active_directory_test.rb | 1 - test/user_search/default_test.rb | 1 - 6 files changed, 2 insertions(+), 5 deletions(-) diff --git a/test/domain_test.rb b/test/domain_test.rb index 324a41a..a7397c8 100644 --- a/test/domain_test.rb +++ b/test/domain_test.rb @@ -1,5 +1,4 @@ require_relative 'test_helper' -require 'mocha/mini_test' module GitHubLdapDomainTestCases def setup diff --git a/test/ldap_test.rb b/test/ldap_test.rb index 2d47fac..8be1982 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -1,5 +1,4 @@ require_relative 'test_helper' -require 'mocha/mini_test' module GitHubLdapTestCases def setup diff --git a/test/referral_chaser_test.rb b/test/referral_chaser_test.rb index c9ff2e7..d0ad785 100644 --- a/test/referral_chaser_test.rb +++ b/test/referral_chaser_test.rb @@ -1,5 +1,4 @@ require_relative 'test_helper' -require 'mocha/mini_test' class GitHubLdapReferralChaserTestCases < GitHub::Ldap::Test diff --git a/test/test_helper.rb b/test/test_helper.rb index 5beca09..856cb5c 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -13,6 +13,8 @@ require 'minitest/mock' require 'minitest/autorun' +require 'mocha/mini_test' + if ENV.fetch('TESTENV', "apacheds") == "apacheds" # Make sure we clean up running test server # NOTE: We need to do this manually since its internal `at_exit` hook diff --git a/test/user_search/active_directory_test.rb b/test/user_search/active_directory_test.rb index 1728b46..2cd4a95 100644 --- a/test/user_search/active_directory_test.rb +++ b/test/user_search/active_directory_test.rb @@ -1,5 +1,4 @@ require_relative '../test_helper' -require 'mocha/mini_test' class GitHubLdapActiveDirectoryUserSearchTests < GitHub::Ldap::Test diff --git a/test/user_search/default_test.rb b/test/user_search/default_test.rb index 6913d0c..abc230a 100644 --- a/test/user_search/default_test.rb +++ b/test/user_search/default_test.rb @@ -1,5 +1,4 @@ require_relative '../test_helper' -require 'mocha/mini_test' class GitHubLdapActiveDirectoryUserSearchTests < GitHub::Ldap::Test def setup From ef20459ae631f8823ccbeb84fc569e2003da89d0 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 19:00:37 -0500 Subject: [PATCH 125/161] Better use of mocks --- test/domain_test.rb | 4 ++-- test/referral_chaser_test.rb | 17 +++++++---------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/test/domain_test.rb b/test/domain_test.rb index a7397c8..d54850c 100644 --- a/test/domain_test.rb +++ b/test/domain_test.rb @@ -142,8 +142,8 @@ def test_auth_does_not_bind end def test_user_search_returns_first_entry - entry = Object.new - search_strategy = Object.new + entry = mock("Net::Ldap::Entry") + search_strategy = mock("GitHub::Ldap::UserSearch::Default") search_strategy.stubs(:perform).returns([entry]) @ldap.expects(:user_search_strategy).returns(search_strategy) user = @domain.user?('user1', :attributes => [:cn]) diff --git a/test/referral_chaser_test.rb b/test/referral_chaser_test.rb index d0ad785..f15eaa6 100644 --- a/test/referral_chaser_test.rb +++ b/test/referral_chaser_test.rb @@ -14,7 +14,7 @@ def setup def test_creates_referral_with_connection_credentials @mock_connection.expects(:search).yields({ search_referrals: ["referral string"]}).returns([]) - referral = Object.new + referral = mock("GitHub::Ldap::ReferralChaser::Referral") referral.stubs(:search).returns([]) GitHub::Ldap::ReferralChaser::Referral.expects(:new) @@ -25,15 +25,12 @@ def test_creates_referral_with_connection_credentials end def test_creates_referral_with_default_port - mock_connection = GitHub::Ldap.new({ - admin_user: "Joe", - admin_password: "passworD1" - }) + mock_connection = mock("GitHub::Ldap") mock_connection.expects(:search).yields({ search_referrals: ["ldap://dc1.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local"]}).returns([]) - stub_conn = Object.new - stub_conn.stubs(:search).returns([]) - GitHub::Ldap::ConnectionCache.expects(:get_connection).with(has_entry(port: 389)).returns(stub_conn) + stub_referral_connection = mock("GitHub::Ldap") + stub_referral_connection.stubs(:search).returns([]) + GitHub::Ldap::ConnectionCache.expects(:get_connection).with(has_entry(port: 389)).returns(stub_referral_connection) chaser = GitHub::Ldap::ReferralChaser.new(mock_connection) chaser.search({}) end @@ -51,7 +48,7 @@ def test_creates_referral_for_first_referral_string } ]).returns([]) - referral = Object.new + referral = mock("GitHub::Ldap::ReferralChaser::Referral") referral.stubs(:search).returns([]) GitHub::Ldap::ReferralChaser::Referral.expects(:new) @@ -74,7 +71,7 @@ def test_returns_referral_search_results } ]).returns([]) - referral = Object.new + referral = mock("GitHub::Ldap::ReferralChaser::Referral") referral.expects(:search).returns(["result", "result"]) GitHub::Ldap::ReferralChaser::Referral.expects(:new).returns(referral) From 51f793ce771812c0cd39fd4049147e527be5972a Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 19:31:39 -0500 Subject: [PATCH 126/161] Fix mock for referral_chaser_test --- test/referral_chaser_test.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/referral_chaser_test.rb b/test/referral_chaser_test.rb index f15eaa6..19c220d 100644 --- a/test/referral_chaser_test.rb +++ b/test/referral_chaser_test.rb @@ -25,8 +25,13 @@ def test_creates_referral_with_connection_credentials end def test_creates_referral_with_default_port - mock_connection = mock("GitHub::Ldap") - mock_connection.expects(:search).yields({ search_referrals: ["ldap://dc1.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local"]}).returns([]) + mock_connection = GitHub::Ldap.new({ + admin_user: "Joe", + admin_password: "passworD1" + }) + mock_connection.expects(:search).yields({ + search_referrals: ["ldap://dc1.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local"] + }).returns([]) stub_referral_connection = mock("GitHub::Ldap") stub_referral_connection.stubs(:search).returns([]) From a0f1f24150cb14eaab812be653ffb938bf66d632 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 23:13:28 -0500 Subject: [PATCH 127/161] Fixing CI: don't use a real connection --- test/connection_cache_test.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/connection_cache_test.rb b/test/connection_cache_test.rb index 7eb0aa3..6adf0bd 100644 --- a/test/connection_cache_test.rb +++ b/test/connection_cache_test.rb @@ -2,19 +2,19 @@ class GitHubLdapConnectionCacheTestCases < GitHub::Ldap::Test - def test_get_connection - conn = GitHub::Ldap::ConnectionCache.get_connection({:host => "host"}) - assert_equal GitHub::Ldap, conn.class + def setup + mock_ldap = mock("GitHub::Ldap") + GitHub::Ldap.stubs(:new).returns(mock_ldap) end def test_returns_cached_connection - conn1 = GitHub::Ldap::ConnectionCache.get_connection({:host => "ghe.local"}) - conn2 = GitHub::Ldap::ConnectionCache.get_connection({:host => "ghe.local"}) + conn1 = GitHub::Ldap::ConnectionCache.get_connection({:host => "ghe.gh"}) + conn2 = GitHub::Ldap::ConnectionCache.get_connection({:host => "ghe.gh"}) assert_equal conn1.object_id, conn2.object_id end def test_creates_new_connections_per_host - conn1 = GitHub::Ldap::ConnectionCache.get_connection({:host => "ghe.local"}) + conn1 = GitHub::Ldap::ConnectionCache.get_connection({:host => "ghe.gh"}) conn2 = GitHub::Ldap::ConnectionCache.get_connection({:host => "ghe.dev"}) conn3 = GitHub::Ldap::ConnectionCache.get_connection({:host => "ghe.dev"}) refute_equal conn1.object_id, conn2.object_id From 88319aa24b6d000c00cf68d49d7d5b0dae0d568c Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 23:28:54 -0500 Subject: [PATCH 128/161] CI Fixes: move all setup code inline --- test/user_search/active_directory_test.rb | 31 ++++++++++++++--------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/test/user_search/active_directory_test.rb b/test/user_search/active_directory_test.rb index 2cd4a95..2aec199 100644 --- a/test/user_search/active_directory_test.rb +++ b/test/user_search/active_directory_test.rb @@ -2,37 +2,44 @@ class GitHubLdapActiveDirectoryUserSearchTests < GitHub::Ldap::Test - def setup - @ldap = GitHub::Ldap.new(options.merge(host: 'ghe.dev')) - @ad_user_search = GitHub::Ldap::UserSearch::ActiveDirectory.new(@ldap) - end - def test_global_catalog_returns_empty_array_for_no_results + ldap = GitHub::Ldap.new(options.merge(host: 'ghe.dev')) + ad_user_search = GitHub::Ldap::UserSearch::ActiveDirectory.new(ldap) + mock_global_catalog_connection = mock("GitHub::Ldap::UserSearch::GlobalCatalog") mock_global_catalog_connection.expects(:search).returns(nil) - @ad_user_search.expects(:global_catalog_connection).returns(mock_global_catalog_connection) - results = @ad_user_search.perform("login", "CN=Joe", "uid", {}) + ad_user_search.expects(:global_catalog_connection).returns(mock_global_catalog_connection) + results = ad_user_search.perform("login", "CN=Joe", "uid", {}) assert_equal [], results end def test_global_catalog_returns_array_of_results + ldap = GitHub::Ldap.new(options.merge(host: 'ghe.dev')) + ad_user_search = GitHub::Ldap::UserSearch::ActiveDirectory.new(ldap) + mock_global_catalog_connection = mock("GitHub::Ldap::UserSearch::GlobalCatalog") stub_entry = mock("Net::LDAP::Entry") + mock_global_catalog_connection.expects(:search).returns(stub_entry) - @ad_user_search.expects(:global_catalog_connection).returns(mock_global_catalog_connection) - results = @ad_user_search.perform("login", "CN=Joe", "uid", {}) + ad_user_search.expects(:global_catalog_connection).returns(mock_global_catalog_connection) + + results = ad_user_search.perform("login", "CN=Joe", "uid", {}) assert_equal [stub_entry], results end def test_searches_with_empty_base_dn + ldap = GitHub::Ldap.new(options.merge(host: 'ghe.dev')) + ad_user_search = GitHub::Ldap::UserSearch::ActiveDirectory.new(ldap) + mock_global_catalog_connection = mock("GitHub::Ldap::UserSearch::GlobalCatalog") mock_global_catalog_connection.expects(:search).with(has_entry(:base => "")) - @ad_user_search.expects(:global_catalog_connection).returns(mock_global_catalog_connection) - @ad_user_search.perform("login", "CN=Joe", "uid", {}) + ad_user_search.expects(:global_catalog_connection).returns(mock_global_catalog_connection) + ad_user_search.perform("login", "CN=Joe", "uid", {}) end def test_global_catalog_default_settings - global_catalog = GitHub::Ldap::UserSearch::GlobalCatalog.connection(@ldap) + ldap = GitHub::Ldap.new(options.merge(host: 'ghe.dev')) + global_catalog = GitHub::Ldap::UserSearch::GlobalCatalog.connection(ldap) instrumentation_service = global_catalog.instance_variable_get(:@instrumentation_service) auth = global_catalog.instance_variable_get(:@auth) From cc3fd3a36823ed87a9536b22a5000b7d79dbf235 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 23:33:15 -0500 Subject: [PATCH 129/161] Removing ruby 1.9.3 from CI --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 09e4709..7be9a75 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: ruby rvm: - - 1.9.3 - 2.1.0 env: From 85ab9f85cf1970e4535c31bc66750a8e5610238a Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 23:36:20 -0500 Subject: [PATCH 130/161] Use correct port for LDAP connection --- test/referral_chaser_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/referral_chaser_test.rb b/test/referral_chaser_test.rb index 19c220d..fa512a5 100644 --- a/test/referral_chaser_test.rb +++ b/test/referral_chaser_test.rb @@ -6,7 +6,7 @@ def setup @mock_connection = GitHub::Ldap.new({ admin_user: "Joe", admin_password: "passworD1", - port: 888 + port: 389 }) @chaser = GitHub::Ldap::ReferralChaser.new(@mock_connection) end @@ -18,7 +18,7 @@ def test_creates_referral_with_connection_credentials referral.stubs(:search).returns([]) GitHub::Ldap::ReferralChaser::Referral.expects(:new) - .with("referral string", "Joe", "passworD1", 888) + .with("referral string", "Joe", "passworD1", 389) .returns(referral) @chaser.search({}) From ed66f8da71396f7200959f673d8abadc073bc1d8 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 23:57:36 -0500 Subject: [PATCH 131/161] CI Fixes: use the right credentials to connect to test ldap server --- test/referral_chaser_test.rb | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/test/referral_chaser_test.rb b/test/referral_chaser_test.rb index fa512a5..f853279 100644 --- a/test/referral_chaser_test.rb +++ b/test/referral_chaser_test.rb @@ -4,7 +4,7 @@ class GitHubLdapReferralChaserTestCases < GitHub::Ldap::Test def setup @mock_connection = GitHub::Ldap.new({ - admin_user: "Joe", + admin_user: "uid=admin,dc=github,dc=com", admin_password: "passworD1", port: 389 }) @@ -18,7 +18,7 @@ def test_creates_referral_with_connection_credentials referral.stubs(:search).returns([]) GitHub::Ldap::ReferralChaser::Referral.expects(:new) - .with("referral string", "Joe", "passworD1", 389) + .with("referral string", "uid=admin,dc=github,dc=com", "passworD1", 389) .returns(referral) @chaser.search({}) @@ -26,7 +26,7 @@ def test_creates_referral_with_connection_credentials def test_creates_referral_with_default_port mock_connection = GitHub::Ldap.new({ - admin_user: "Joe", + admin_user: "uid=admin,dc=github,dc=com", admin_password: "passworD1" }) mock_connection.expects(:search).yields({ @@ -57,7 +57,11 @@ def test_creates_referral_for_first_referral_string referral.stubs(:search).returns([]) GitHub::Ldap::ReferralChaser::Referral.expects(:new) - .with("ldap://dc1.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local", "Joe", "passworD1", 888) + .with( + "ldap://dc1.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local", + "uid=admin,dc=github,dc=com", + "passworD1", + 389) .returns(referral) @chaser.search({}) From 6ad401a460974ce473e671f541b6e0de846511ea Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Fri, 5 Aug 2016 00:22:43 -0500 Subject: [PATCH 132/161] CI Fixes: use correct connection attrs for tests --- test/connection_cache_test.rb | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/test/connection_cache_test.rb b/test/connection_cache_test.rb index 6adf0bd..1d2675c 100644 --- a/test/connection_cache_test.rb +++ b/test/connection_cache_test.rb @@ -2,21 +2,24 @@ class GitHubLdapConnectionCacheTestCases < GitHub::Ldap::Test - def setup - mock_ldap = mock("GitHub::Ldap") - GitHub::Ldap.stubs(:new).returns(mock_ldap) + def options + { + admin_user: "uid=admin,dc=github,dc=com", + admin_password: "passworD1", + port: 389 + } end def test_returns_cached_connection - conn1 = GitHub::Ldap::ConnectionCache.get_connection({:host => "ghe.gh"}) - conn2 = GitHub::Ldap::ConnectionCache.get_connection({:host => "ghe.gh"}) + conn1 = GitHub::Ldap::ConnectionCache.get_connection(options.merge(:host => "ghe.gh")) + conn2 = GitHub::Ldap::ConnectionCache.get_connection(options.merge(:host => "ghe.gh")) assert_equal conn1.object_id, conn2.object_id end def test_creates_new_connections_per_host - conn1 = GitHub::Ldap::ConnectionCache.get_connection({:host => "ghe.gh"}) - conn2 = GitHub::Ldap::ConnectionCache.get_connection({:host => "ghe.dev"}) - conn3 = GitHub::Ldap::ConnectionCache.get_connection({:host => "ghe.dev"}) + conn1 = GitHub::Ldap::ConnectionCache.get_connection(options.merge(:host => "ghe.gh")) + conn2 = GitHub::Ldap::ConnectionCache.get_connection(options.merge(:host => "ghe.dev")) + conn3 = GitHub::Ldap::ConnectionCache.get_connection(options.merge(:host => "ghe.dev")) refute_equal conn1.object_id, conn2.object_id assert_equal conn2.object_id, conn3.object_id end From 142e3fd273b2d8ecb59e0127109647aa5b6eab85 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Fri, 5 Aug 2016 09:31:31 -0400 Subject: [PATCH 133/161] Test Ruby 2.0 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 7be9a75..e46ac80 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: ruby rvm: + - 2.0.0 - 2.1.0 env: From 64c6e08eade8c609337aad8f76f3428a699e7576 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Fri, 5 Aug 2016 09:41:21 -0400 Subject: [PATCH 134/161] Configure connection with GitHub::Ldap::Test#options Also use that port value, as it changes depending on the integration test LDAP server in use. --- test/referral_chaser_test.rb | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/test/referral_chaser_test.rb b/test/referral_chaser_test.rb index f853279..95b4da5 100644 --- a/test/referral_chaser_test.rb +++ b/test/referral_chaser_test.rb @@ -3,11 +3,7 @@ class GitHubLdapReferralChaserTestCases < GitHub::Ldap::Test def setup - @mock_connection = GitHub::Ldap.new({ - admin_user: "uid=admin,dc=github,dc=com", - admin_password: "passworD1", - port: 389 - }) + @mock_connection = GitHub::Ldap.new(options) @chaser = GitHub::Ldap::ReferralChaser.new(@mock_connection) end @@ -18,25 +14,21 @@ def test_creates_referral_with_connection_credentials referral.stubs(:search).returns([]) GitHub::Ldap::ReferralChaser::Referral.expects(:new) - .with("referral string", "uid=admin,dc=github,dc=com", "passworD1", 389) + .with("referral string", "uid=admin,dc=github,dc=com", "passworD1", options[:port]) .returns(referral) @chaser.search({}) end def test_creates_referral_with_default_port - mock_connection = GitHub::Ldap.new({ - admin_user: "uid=admin,dc=github,dc=com", - admin_password: "passworD1" - }) - mock_connection.expects(:search).yields({ + @mock_connection.expects(:search).yields({ search_referrals: ["ldap://dc1.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local"] }).returns([]) stub_referral_connection = mock("GitHub::Ldap") stub_referral_connection.stubs(:search).returns([]) - GitHub::Ldap::ConnectionCache.expects(:get_connection).with(has_entry(port: 389)).returns(stub_referral_connection) - chaser = GitHub::Ldap::ReferralChaser.new(mock_connection) + GitHub::Ldap::ConnectionCache.expects(:get_connection).with(has_entry(port: options[:port])).returns(stub_referral_connection) + chaser = GitHub::Ldap::ReferralChaser.new(@mock_connection) chaser.search({}) end @@ -61,7 +53,7 @@ def test_creates_referral_for_first_referral_string "ldap://dc1.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local", "uid=admin,dc=github,dc=com", "passworD1", - 389) + options[:port]) .returns(referral) @chaser.search({}) From 2b8005820670574b9d4d03381d8c808c9fff04c4 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Fri, 5 Aug 2016 09:42:33 -0400 Subject: [PATCH 135/161] Rename mock_connection to ldap Stylistic preference to be more consistent with other tests. --- test/referral_chaser_test.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/referral_chaser_test.rb b/test/referral_chaser_test.rb index 95b4da5..5e51ab5 100644 --- a/test/referral_chaser_test.rb +++ b/test/referral_chaser_test.rb @@ -3,12 +3,12 @@ class GitHubLdapReferralChaserTestCases < GitHub::Ldap::Test def setup - @mock_connection = GitHub::Ldap.new(options) - @chaser = GitHub::Ldap::ReferralChaser.new(@mock_connection) + @ldap = GitHub::Ldap.new(options) + @chaser = GitHub::Ldap::ReferralChaser.new(@ldap) end def test_creates_referral_with_connection_credentials - @mock_connection.expects(:search).yields({ search_referrals: ["referral string"]}).returns([]) + @ldap.expects(:search).yields({ search_referrals: ["referral string"]}).returns([]) referral = mock("GitHub::Ldap::ReferralChaser::Referral") referral.stubs(:search).returns([]) @@ -21,19 +21,19 @@ def test_creates_referral_with_connection_credentials end def test_creates_referral_with_default_port - @mock_connection.expects(:search).yields({ + @ldap.expects(:search).yields({ search_referrals: ["ldap://dc1.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local"] }).returns([]) stub_referral_connection = mock("GitHub::Ldap") stub_referral_connection.stubs(:search).returns([]) GitHub::Ldap::ConnectionCache.expects(:get_connection).with(has_entry(port: options[:port])).returns(stub_referral_connection) - chaser = GitHub::Ldap::ReferralChaser.new(@mock_connection) + chaser = GitHub::Ldap::ReferralChaser.new(@ldap) chaser.search({}) end def test_creates_referral_for_first_referral_string - @mock_connection.expects(:search).multiple_yields([ + @ldap.expects(:search).multiple_yields([ { search_referrals: ["ldap://dc1.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local", "ldap://dc2.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local"] @@ -60,7 +60,7 @@ def test_creates_referral_for_first_referral_string end def test_returns_referral_search_results - @mock_connection.expects(:search).multiple_yields([ + @ldap.expects(:search).multiple_yields([ { search_referrals: ["ldap://dc1.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local", "ldap://dc2.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local"] @@ -82,7 +82,7 @@ def test_returns_referral_search_results end def test_returns_referral_search_results - @mock_connection.expects(:search).yields({ foo: ["not a referral"] }) + @ldap.expects(:search).yields({ foo: ["not a referral"] }) GitHub::Ldap::ReferralChaser::Referral.expects(:new).never results = @chaser.search({}) From e7de8e7e45350fb2a784269d81ac905b66319edc Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Fri, 5 Aug 2016 09:53:59 -0400 Subject: [PATCH 136/161] Setup test hosts for connection caching --- .travis.yml | 6 ++++++ test/connection_cache_test.rb | 18 +++++------------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index e46ac80..798c5c4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,12 @@ env: - TESTENV=openldap - TESTENV=apacheds +# https://docs.travis-ci.com/user/hosts/ +addons: + hosts: + - ad1.ghe.dev + - ad2.ghe.dev + install: - if [ "$TESTENV" = "openldap" ]; then ./script/install-openldap; fi - bundle install diff --git a/test/connection_cache_test.rb b/test/connection_cache_test.rb index 1d2675c..1b55a6b 100644 --- a/test/connection_cache_test.rb +++ b/test/connection_cache_test.rb @@ -2,24 +2,16 @@ class GitHubLdapConnectionCacheTestCases < GitHub::Ldap::Test - def options - { - admin_user: "uid=admin,dc=github,dc=com", - admin_password: "passworD1", - port: 389 - } - end - def test_returns_cached_connection - conn1 = GitHub::Ldap::ConnectionCache.get_connection(options.merge(:host => "ghe.gh")) - conn2 = GitHub::Ldap::ConnectionCache.get_connection(options.merge(:host => "ghe.gh")) + conn1 = GitHub::Ldap::ConnectionCache.get_connection(options.merge(:host => "ad1.ghe.dev")) + conn2 = GitHub::Ldap::ConnectionCache.get_connection(options.merge(:host => "ad1.ghe.dev")) assert_equal conn1.object_id, conn2.object_id end def test_creates_new_connections_per_host - conn1 = GitHub::Ldap::ConnectionCache.get_connection(options.merge(:host => "ghe.gh")) - conn2 = GitHub::Ldap::ConnectionCache.get_connection(options.merge(:host => "ghe.dev")) - conn3 = GitHub::Ldap::ConnectionCache.get_connection(options.merge(:host => "ghe.dev")) + conn1 = GitHub::Ldap::ConnectionCache.get_connection(options.merge(:host => "ad1.ghe.dev")) + conn2 = GitHub::Ldap::ConnectionCache.get_connection(options.merge(:host => "ad2.ghe.dev")) + conn3 = GitHub::Ldap::ConnectionCache.get_connection(options.merge(:host => "ad2.ghe.dev")) refute_equal conn1.object_id, conn2.object_id assert_equal conn2.object_id, conn3.object_id end From 02cef0b9859425527c05c2c225957407f2189cbb Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Fri, 5 Aug 2016 09:40:37 -0500 Subject: [PATCH 137/161] Document user search strategy callsite --- lib/github/ldap.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 28dfab4..2b97111 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -114,7 +114,7 @@ def initialize(options = {}) # configure both the membership validator and the member search strategies configure_search_strategy(options[:search_strategy]) - # configure both the membership validator and the member search strategies + # configure the strategy used by Domain#user? to look up a user entry for login configure_user_search_strategy(options[:user_search_strategy]) # enables instrumenting queries From 15990bef0353a63bca41513c10ec74fb9fc21430 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Fri, 5 Aug 2016 10:05:40 -0500 Subject: [PATCH 138/161] Test for invalid URL strings as well as bad schemes in ReferralChaser --- lib/github/ldap/referral_chaser.rb | 8 +++++--- lib/github/ldap/url.rb | 12 ++++++++---- test/referral_chaser_test.rb | 11 +++++++++-- test/url_test.rb | 11 +++++++++-- 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/lib/github/ldap/referral_chaser.rb b/lib/github/ldap/referral_chaser.rb index 9046cb0..4811c51 100644 --- a/lib/github/ldap/referral_chaser.rb +++ b/lib/github/ldap/referral_chaser.rb @@ -53,11 +53,13 @@ def search(options) unless referral_entries.empty? entry = referral_entries.first referral_string = entry[:search_referrals].first - referral = Referral.new(referral_string, admin_user, admin_password, port) - search_results = referral.search(options) + if GitHub::Ldap::URL.valid?(referral_string) + referral = Referral.new(referral_string, admin_user, admin_password, port) + search_results = referral.search(options) + end end - search_results + Array(search_results) end private diff --git a/lib/github/ldap/url.rb b/lib/github/ldap/url.rb index 605fd1f..5c733a7 100644 --- a/lib/github/ldap/url.rb +++ b/lib/github/ldap/url.rb @@ -49,16 +49,20 @@ class URL # ldap://dc4.ghe.local:456/CN=Maggie,DC=dc4,DC=ghe,DC=local?cn,mail?base?(cn=Charlie) # def initialize(url_string) - @uri = URI(url_string) - unless ["ldap", "ldaps"].include?(@uri.scheme) - raise InvalidSchemeException.new("Invalid scheme: #{@uri.scheme}") + if !self.class.valid?(url_string) + raise InvalidLdapURLException.new("Invalid LDAP URL: #{url_string}") end + @uri = URI(url_string) @dn = URI.unescape(@uri.path.sub(/^\//, "")) if @uri.query @attributes, @scope, @filter = @uri.query.split("?") end end + def self.valid?(url_string) + url_string =~ URI::regexp && ["ldap", "ldaps"].include?(URI(url_string).scheme) + end + # Maps the returned scope value from the URL to one of Net::LDAP::Scopes # # The URL scope value can be one of: @@ -76,7 +80,7 @@ def net_ldap_scope Net::LDAP::SearchScopes[SCOPES[scope]] end - class InvalidSchemeException < Exception; end + class InvalidLdapURLException < Exception; end end end end diff --git a/test/referral_chaser_test.rb b/test/referral_chaser_test.rb index 5e51ab5..a6ca54d 100644 --- a/test/referral_chaser_test.rb +++ b/test/referral_chaser_test.rb @@ -8,13 +8,13 @@ def setup end def test_creates_referral_with_connection_credentials - @ldap.expects(:search).yields({ search_referrals: ["referral string"]}).returns([]) + @ldap.expects(:search).yields({ search_referrals: ["ldap://dc1.ghe.local/"]}).returns([]) referral = mock("GitHub::Ldap::ReferralChaser::Referral") referral.stubs(:search).returns([]) GitHub::Ldap::ReferralChaser::Referral.expects(:new) - .with("referral string", "uid=admin,dc=github,dc=com", "passworD1", options[:port]) + .with("ldap://dc1.ghe.local/", "uid=admin,dc=github,dc=com", "passworD1", options[:port]) .returns(referral) @chaser.search({}) @@ -81,6 +81,13 @@ def test_returns_referral_search_results assert_equal(["result", "result"], results) end + def test_handle_blank_url_string_in_referral + @mock_connection.expects(:search).yields({ search_referrals: [""] }) + + results = @chaser.search({}) + assert_equal([], results) + end + def test_returns_referral_search_results @ldap.expects(:search).yields({ foo: ["not a referral"] }) diff --git a/test/url_test.rb b/test/url_test.rb index a84127e..db44ce2 100644 --- a/test/url_test.rb +++ b/test/url_test.rb @@ -35,10 +35,17 @@ def test_simple_url end def test_invalid_scheme - ex = assert_raises(GitHub::Ldap::URL::InvalidSchemeException) do + ex = assert_raises(GitHub::Ldap::URL::InvalidLdapURLException) do GitHub::Ldap::URL.new("http://dc4.ghe.local") end - assert_equal("Invalid scheme: http", ex.message) + assert_equal("Invalid LDAP URL: http://dc4.ghe.local", ex.message) + end + + def test_invalid_url + ex = assert_raises(GitHub::Ldap::URL::InvalidLdapURLException) do + GitHub::Ldap::URL.new("not a url") + end + assert_equal("Invalid LDAP URL: not a url", ex.message) end def test_parse_dn From 60e7b7fc0b467041f71dfca49a9e6dec02737fa0 Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Fri, 5 Aug 2016 10:17:25 -0500 Subject: [PATCH 139/161] Fixing some merge-fu: use @ldap not @mock_connection --- test/referral_chaser_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/referral_chaser_test.rb b/test/referral_chaser_test.rb index a6ca54d..3a19973 100644 --- a/test/referral_chaser_test.rb +++ b/test/referral_chaser_test.rb @@ -82,7 +82,7 @@ def test_returns_referral_search_results end def test_handle_blank_url_string_in_referral - @mock_connection.expects(:search).yields({ search_referrals: [""] }) + @ldap.expects(:search).yields({ search_referrals: [""] }) results = @chaser.search({}) assert_equal([], results) From 2b248d342e218fe8005f6b694a807073f2e4c63e Mon Sep 17 00:00:00 2001 From: Dave Sims Date: Thu, 4 Aug 2016 19:05:22 -0500 Subject: [PATCH 140/161] Remove unneeded begin --- lib/github/ldap.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 2b97111..0764d2e 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -311,7 +311,7 @@ def configure_membership_validation_strategy(strategy = nil) # using Active Directory's Global Catalog # functionality. def configure_user_search_strategy(strategy) - @user_search_strategy = begin + @user_search_strategy = case strategy.to_s when "default" GitHub::Ldap::UserSearch::Default.new(self) @@ -320,7 +320,6 @@ def configure_user_search_strategy(strategy) else GitHub::Ldap::UserSearch::Default.new(self) end - end end # Internal: Configure the member search strategy. From 9315cee5510b2d2360d745a404411840b154dda8 Mon Sep 17 00:00:00 2001 From: Colin Seymour Date: Fri, 16 Sep 2016 16:28:02 +0100 Subject: [PATCH 141/161] Use port from options We don't care too much about the port in testing. Using the port in the options allows us to test against ApacheDS and OpenLDAP without adding any additional conditionals. --- test/ldap_test.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/ldap_test.rb b/test/ldap_test.rb index 8105fb8..959c0b3 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -10,17 +10,17 @@ def test_connection_with_default_options end def test_connection_with_list_of_hosts_with_one_valid_host - ldap = GitHub::Ldap.new(options.merge(hosts: [["localhost", 3897]])) + ldap = GitHub::Ldap.new(options.merge(hosts: [["localhost", options[:port]]])) assert ldap.test_connection, "Ldap connection expected to succeed" end def test_connection_with_list_of_hosts_with_first_valid - ldap = GitHub::Ldap.new(options.merge(hosts: [["localhost", 3897], ["invalid.local", 3897]])) + ldap = GitHub::Ldap.new(options.merge(hosts: [["localhost", options[:port]], ["invalid.local", options[:port]]])) assert ldap.test_connection, "Ldap connection expected to succeed" end def test_connection_with_list_of_hosts_with_first_invalid - ldap = GitHub::Ldap.new(options.merge(hosts: [["invalid.local", 3897], ["localhost", 3897]])) + ldap = GitHub::Ldap.new(options.merge(hosts: [["invalid.local", options[:port]], ["localhost", options[:port]]])) assert ldap.test_connection, "Ldap connection expected to succeed" end From 04f0d1b1a8eeb86f00e4ec225b931ad0e1ebf899 Mon Sep 17 00:00:00 2001 From: Jerry Cheung Date: Fri, 24 Feb 2017 12:14:43 -0800 Subject: [PATCH 142/161] bump net-ldap to 0.16.0 --- CHANGELOG.md | 4 ++++ github-ldap.gemspec | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ae6339..e082762 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +# v1.10.1 + +* Bump net-ldap to 0.16.0 + # v1.10.0 * Bump net-ldap to 0.15.0 [#92](https://github.com/github/github-ldap/pull/92) diff --git a/github-ldap.gemspec b/github-ldap.gemspec index b8514d0..78938c5 100644 --- a/github-ldap.gemspec +++ b/github-ldap.gemspec @@ -15,7 +15,7 @@ Gem::Specification.new do |spec| spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ["lib"] - spec.add_dependency 'net-ldap', '~> 0.15.0' + spec.add_dependency 'net-ldap', '~> 0.16.0' spec.add_development_dependency "bundler", "~> 1.3" spec.add_development_dependency 'ladle' From b7c0b8901104cdd1c77294de4a0e7d69ce2cc189 Mon Sep 17 00:00:00 2001 From: Jerry Cheung Date: Fri, 24 Feb 2017 12:16:05 -0800 Subject: [PATCH 143/161] bump version to 1.10.1 --- github-ldap.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github-ldap.gemspec b/github-ldap.gemspec index 78938c5..f39a6dd 100644 --- a/github-ldap.gemspec +++ b/github-ldap.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |spec| spec.name = "github-ldap" - spec.version = "1.10.0" + spec.version = "1.10.1" spec.authors = ["David Calavera", "Matt Todd"] spec.email = ["david.calavera@gmail.com", "chiology@gmail.com"] spec.description = %q{LDAP authentication for humans} From cb093d2f1076452bee68752fbc81958489fa8f99 Mon Sep 17 00:00:00 2001 From: Jerry Cheung Date: Fri, 24 Feb 2017 12:16:22 -0800 Subject: [PATCH 144/161] Release 1.10.1 From c8007663132028f0ce41903f47f208807e52f9a4 Mon Sep 17 00:00:00 2001 From: Jon Ruskin Date: Thu, 1 Jun 2017 17:53:09 -0700 Subject: [PATCH 145/161] Enable TLS validation enable by setting `validate_encryption: true` on initialization options --- lib/github/ldap.rb | 11 +++++++---- test/ldap_test.rb | 27 +++++++++++++++++++++------ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index b28e440..06f76f0 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -65,6 +65,7 @@ class Ldap # which to attempt opening connections (default [[host, port]]). Overrides # host and port if set. # encryption: optional string. `ssl` or `tls`. nil by default + # validate_encryption: optional boolean. nil by default # admin_user: optional string ldap administrator user dn for authentication # admin_password: optional string ldap administrator user password # @@ -99,7 +100,7 @@ def initialize(options = {}) @connection.authenticate(options[:admin_user], options[:admin_password]) end - if encryption = check_encryption(options[:encryption]) + if encryption = check_encryption(options[:encryption], options[:validate_encryption]) @connection.encryption(encryption) end @@ -236,16 +237,18 @@ def capabilities # Internal - Determine whether to use encryption or not. # # encryption: is the encryption method, either 'ssl', 'tls', 'simple_tls' or 'start_tls'. + # validate: is true to enable certificate validation # # Returns the real encryption type. - def check_encryption(encryption) + def check_encryption(encryption, validate = false) return unless encryption + tls_options = validate == true ? OpenSSL::SSL::VERIFY_PEER : {} case encryption.downcase.to_sym when :ssl, :simple_tls - :simple_tls + { method: :simple_tls, tls_options: tls_options } when :tls, :start_tls - :start_tls + { method: :start_tls, tls_options: tls_options } end end diff --git a/test/ldap_test.rb b/test/ldap_test.rb index 959c0b3..00324e0 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -25,15 +25,30 @@ def test_connection_with_list_of_hosts_with_first_invalid end def test_simple_tls - assert_equal :simple_tls, @ldap.check_encryption(:ssl) - assert_equal :simple_tls, @ldap.check_encryption('SSL') - assert_equal :simple_tls, @ldap.check_encryption(:simple_tls) + expected = { method: :simple_tls, tls_options: {} } + assert_equal expected, @ldap.check_encryption(:ssl) + assert_equal expected, @ldap.check_encryption('SSL') + assert_equal expected, @ldap.check_encryption(:simple_tls) end def test_start_tls - assert_equal :start_tls, @ldap.check_encryption(:tls) - assert_equal :start_tls, @ldap.check_encryption('TLS') - assert_equal :start_tls, @ldap.check_encryption(:start_tls) + expected = { method: :start_tls, tls_options: {} } + assert_equal expected, @ldap.check_encryption(:tls) + assert_equal expected, @ldap.check_encryption('TLS') + assert_equal expected, @ldap.check_encryption(:start_tls) + end + + def test_tls_validation + assert_equal({ method: :start_tls, tls_options: OpenSSL::SSL::VERIFY_PEER }, + @ldap.check_encryption(:tls, true)) + assert_equal({ method: :start_tls, tls_options: {} }, + @ldap.check_encryption(:tls, false)) + assert_equal({ method: :start_tls, tls_options: {} }, + @ldap.check_encryption(:tls, nil)) + assert_equal({ method: :start_tls, tls_options: {} }, + @ldap.check_encryption(:tls, 'true')) + assert_equal({ method: :start_tls, tls_options: {} }, + @ldap.check_encryption(:tls)) end def test_search_delegator From b52284ca3519be60bea4e8e26690b59466fa3d20 Mon Sep 17 00:00:00 2001 From: Sean Bryant Date: Mon, 5 Jun 2017 18:05:22 -0700 Subject: [PATCH 146/161] Use tls_options as a Hash `:verify_mode` is used to specify how the certificate is verified, if at all. --- lib/github/ldap.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 06f76f0..1008d94 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -243,7 +243,7 @@ def capabilities def check_encryption(encryption, validate = false) return unless encryption - tls_options = validate == true ? OpenSSL::SSL::VERIFY_PEER : {} + tls_options = { verify_mode: (validate == true ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE } case encryption.downcase.to_sym when :ssl, :simple_tls { method: :simple_tls, tls_options: tls_options } From 07adb9baab59b138f3db5d42eb96ca8cbff4a705 Mon Sep 17 00:00:00 2001 From: Sean Bryant Date: Mon, 5 Jun 2017 18:06:13 -0700 Subject: [PATCH 147/161] Update test to reflect verify_mode --- test/ldap_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ldap_test.rb b/test/ldap_test.rb index 00324e0..4678361 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -39,7 +39,7 @@ def test_start_tls end def test_tls_validation - assert_equal({ method: :start_tls, tls_options: OpenSSL::SSL::VERIFY_PEER }, + assert_equal({ method: :start_tls, tls_options: { verify_mode: OpenSSL::SSL::VERIFY_PEER } }, @ldap.check_encryption(:tls, true)) assert_equal({ method: :start_tls, tls_options: {} }, @ldap.check_encryption(:tls, false)) From 79065bae794fef53475be01403b4cbf412a01011 Mon Sep 17 00:00:00 2001 From: Sean Bryant Date: Mon, 5 Jun 2017 18:06:44 -0700 Subject: [PATCH 148/161] Fix missing paren --- lib/github/ldap.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 1008d94..192d20d 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -243,7 +243,7 @@ def capabilities def check_encryption(encryption, validate = false) return unless encryption - tls_options = { verify_mode: (validate == true ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE } + tls_options = { verify_mode: (validate == true ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE) } case encryption.downcase.to_sym when :ssl, :simple_tls { method: :simple_tls, tls_options: tls_options } From d2be945fe9421ff2452c2764a26ba3519ca77f87 Mon Sep 17 00:00:00 2001 From: Sean Bryant Date: Mon, 5 Jun 2017 18:14:46 -0700 Subject: [PATCH 149/161] Missed a couple of empty tls_options --- test/ldap_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/ldap_test.rb b/test/ldap_test.rb index 4678361..2f7a7af 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -25,14 +25,14 @@ def test_connection_with_list_of_hosts_with_first_invalid end def test_simple_tls - expected = { method: :simple_tls, tls_options: {} } + expected = { method: :simple_tls, tls_options: { verify_mode: OpenSSL::SSL::VERIFY_NONE } } assert_equal expected, @ldap.check_encryption(:ssl) assert_equal expected, @ldap.check_encryption('SSL') assert_equal expected, @ldap.check_encryption(:simple_tls) end def test_start_tls - expected = { method: :start_tls, tls_options: {} } + expected = { method: :start_tls, tls_options: { verify_mode: OpenSSL::SSL::VERIFY_NONE } } assert_equal expected, @ldap.check_encryption(:tls) assert_equal expected, @ldap.check_encryption('TLS') assert_equal expected, @ldap.check_encryption(:start_tls) From a7380b20ff9a3a1f04055256376fbc502704084d Mon Sep 17 00:00:00 2001 From: Sean Bryant Date: Mon, 5 Jun 2017 18:24:57 -0700 Subject: [PATCH 150/161] Fix up tests --- test/ldap_test.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/ldap_test.rb b/test/ldap_test.rb index 2f7a7af..5408adc 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -41,13 +41,13 @@ def test_start_tls def test_tls_validation assert_equal({ method: :start_tls, tls_options: { verify_mode: OpenSSL::SSL::VERIFY_PEER } }, @ldap.check_encryption(:tls, true)) - assert_equal({ method: :start_tls, tls_options: {} }, + assert_equal({ method: :start_tls, tls_options: { verify_mode: OpenSSL::SSL::VERIFY_NONE } }, @ldap.check_encryption(:tls, false)) - assert_equal({ method: :start_tls, tls_options: {} }, + assert_equal({ method: :start_tls, tls_options: { verify_mode: OpenSSL::SSL::VERIFY_NONE } }, @ldap.check_encryption(:tls, nil)) - assert_equal({ method: :start_tls, tls_options: {} }, + assert_equal({ method: :start_tls, tls_options: { verify_mode: OpenSSL::SSL::VERIFY_NONE } }, @ldap.check_encryption(:tls, 'true')) - assert_equal({ method: :start_tls, tls_options: {} }, + assert_equal({ method: :start_tls, tls_options: { verify_mode: OpenSSL::SSL::VERIFY_NONE } }, @ldap.check_encryption(:tls)) end From 5a50c9cd75a6fbcacaa2115c4203bc9de468aac9 Mon Sep 17 00:00:00 2001 From: Dirkjan Bussink Date: Tue, 6 Jun 2017 10:41:34 +0200 Subject: [PATCH 151/161] Expose TLS options directly --- lib/github/ldap.rb | 7 +++---- test/ldap_test.rb | 16 ++++++---------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 192d20d..2ba8831 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -65,7 +65,7 @@ class Ldap # which to attempt opening connections (default [[host, port]]). Overrides # host and port if set. # encryption: optional string. `ssl` or `tls`. nil by default - # validate_encryption: optional boolean. nil by default + # tls_options: optional hash with TLS options for encrypted connections. Empty by default. # admin_user: optional string ldap administrator user dn for authentication # admin_password: optional string ldap administrator user password # @@ -100,7 +100,7 @@ def initialize(options = {}) @connection.authenticate(options[:admin_user], options[:admin_password]) end - if encryption = check_encryption(options[:encryption], options[:validate_encryption]) + if encryption = check_encryption(options[:encryption], options[:tls_options]) @connection.encryption(encryption) end @@ -240,10 +240,9 @@ def capabilities # validate: is true to enable certificate validation # # Returns the real encryption type. - def check_encryption(encryption, validate = false) + def check_encryption(encryption, tls_options = {}) return unless encryption - tls_options = { verify_mode: (validate == true ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE) } case encryption.downcase.to_sym when :ssl, :simple_tls { method: :simple_tls, tls_options: tls_options } diff --git a/test/ldap_test.rb b/test/ldap_test.rb index 5408adc..2fe9411 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -25,14 +25,14 @@ def test_connection_with_list_of_hosts_with_first_invalid end def test_simple_tls - expected = { method: :simple_tls, tls_options: { verify_mode: OpenSSL::SSL::VERIFY_NONE } } + expected = { method: :simple_tls, tls_options: { } } assert_equal expected, @ldap.check_encryption(:ssl) assert_equal expected, @ldap.check_encryption('SSL') assert_equal expected, @ldap.check_encryption(:simple_tls) end def test_start_tls - expected = { method: :start_tls, tls_options: { verify_mode: OpenSSL::SSL::VERIFY_NONE } } + expected = { method: :start_tls, tls_options: { } } assert_equal expected, @ldap.check_encryption(:tls) assert_equal expected, @ldap.check_encryption('TLS') assert_equal expected, @ldap.check_encryption(:start_tls) @@ -40,15 +40,11 @@ def test_start_tls def test_tls_validation assert_equal({ method: :start_tls, tls_options: { verify_mode: OpenSSL::SSL::VERIFY_PEER } }, - @ldap.check_encryption(:tls, true)) + @ldap.check_encryption(:tls, verify_mode: OpenSSL::SSL::VERIFY_PEER)) assert_equal({ method: :start_tls, tls_options: { verify_mode: OpenSSL::SSL::VERIFY_NONE } }, - @ldap.check_encryption(:tls, false)) - assert_equal({ method: :start_tls, tls_options: { verify_mode: OpenSSL::SSL::VERIFY_NONE } }, - @ldap.check_encryption(:tls, nil)) - assert_equal({ method: :start_tls, tls_options: { verify_mode: OpenSSL::SSL::VERIFY_NONE } }, - @ldap.check_encryption(:tls, 'true')) - assert_equal({ method: :start_tls, tls_options: { verify_mode: OpenSSL::SSL::VERIFY_NONE } }, - @ldap.check_encryption(:tls)) + @ldap.check_encryption(:tls, verify_mode: OpenSSL::SSL::VERIFY_NONE)) + assert_equal({ method: :start_tls, tls_options: { cert_store: "some/path" } }, + @ldap.check_encryption(:tls, cert_store: "some/path")) end def test_search_delegator From d88eb773c46b3d1cb467fed2d40291b4ed71b5b4 Mon Sep 17 00:00:00 2001 From: Jon Ruskin Date: Tue, 6 Jun 2017 11:13:26 -0700 Subject: [PATCH 152/161] update comments --- lib/github/ldap.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 2ba8831..d63282d 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -65,7 +65,9 @@ class Ldap # which to attempt opening connections (default [[host, port]]). Overrides # host and port if set. # encryption: optional string. `ssl` or `tls`. nil by default - # tls_options: optional hash with TLS options for encrypted connections. Empty by default. + # tls_options: optional hash with TLS options for encrypted connections. + # Empty by default. See http://ruby-doc.org/stdlib/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html + # for available values # admin_user: optional string ldap administrator user dn for authentication # admin_password: optional string ldap administrator user password # @@ -237,7 +239,7 @@ def capabilities # Internal - Determine whether to use encryption or not. # # encryption: is the encryption method, either 'ssl', 'tls', 'simple_tls' or 'start_tls'. - # validate: is true to enable certificate validation + # tls_options: is the options hash for tls encryption method # # Returns the real encryption type. def check_encryption(encryption, tls_options = {}) From 272c61d02f1400b50180173fcf9bd725b5356295 Mon Sep 17 00:00:00 2001 From: Jon Ruskin Date: Tue, 6 Jun 2017 11:13:44 -0700 Subject: [PATCH 153/161] fix tls_options on nil input --- lib/github/ldap.rb | 1 + test/ldap_test.rb | 2 ++ 2 files changed, 3 insertions(+) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index d63282d..0bf5be2 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -245,6 +245,7 @@ def capabilities def check_encryption(encryption, tls_options = {}) return unless encryption + tls_options ||= {} case encryption.downcase.to_sym when :ssl, :simple_tls { method: :simple_tls, tls_options: tls_options } diff --git a/test/ldap_test.rb b/test/ldap_test.rb index 2fe9411..d5e9297 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -45,6 +45,8 @@ def test_tls_validation @ldap.check_encryption(:tls, verify_mode: OpenSSL::SSL::VERIFY_NONE)) assert_equal({ method: :start_tls, tls_options: { cert_store: "some/path" } }, @ldap.check_encryption(:tls, cert_store: "some/path")) + assert_equal({ method: :start_tls, tls_options: {} }, + @ldap.check_encryption(:tls, nil)) end def test_search_delegator From 395488a1a615bdc8928981e4d006766e406e1d11 Mon Sep 17 00:00:00 2001 From: HParker Date: Thu, 13 May 2021 09:37:36 -0700 Subject: [PATCH 154/161] Loosen net-ldap requirement this allows for ldap 0.17.0 This version of net-ldap is required to run ruby 3 without warnings --- github-ldap.gemspec | 2 +- lib/github/ldap.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/github-ldap.gemspec b/github-ldap.gemspec index f39a6dd..a2dad47 100644 --- a/github-ldap.gemspec +++ b/github-ldap.gemspec @@ -15,7 +15,7 @@ Gem::Specification.new do |spec| spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ["lib"] - spec.add_dependency 'net-ldap', '~> 0.16.0' + spec.add_dependency 'net-ldap', '> 0.16.0' spec.add_development_dependency "bundler", "~> 1.3" spec.add_development_dependency 'ladle' diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 0bf5be2..33e6627 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -228,7 +228,7 @@ def capabilities instrument "capabilities.github_ldap" do |payload| begin @connection.search_root_dse - rescue Net::LDAP::LdapError => error + rescue Net::LDAP::Error => error payload[:error] = error # stubbed result Net::LDAP::Entry.new From 3f1216f0df1ee1e48dbcb95a930a618457f65104 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Tue, 1 Jun 2021 21:17:06 +0000 Subject: [PATCH 155/161] Fix minitest require --- test/test_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_helper.rb b/test/test_helper.rb index 856cb5c..c29703b 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -13,7 +13,7 @@ require 'minitest/mock' require 'minitest/autorun' -require 'mocha/mini_test' +require 'mocha/minitest' if ENV.fetch('TESTENV', "apacheds") == "apacheds" # Make sure we clean up running test server From b1b0361d7d74acbfee6e1a3c18b94fe276ecbe82 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Tue, 1 Jun 2021 21:25:52 +0000 Subject: [PATCH 156/161] Fix Minitest::Result requirement --- test/member_search/active_directory_test.rb | 6 ++++-- test/membership_validators/active_directory_test.rb | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/test/member_search/active_directory_test.rb b/test/member_search/active_directory_test.rb index e3f367a..19f2c96 100644 --- a/test/member_search/active_directory_test.rb +++ b/test/member_search/active_directory_test.rb @@ -3,7 +3,8 @@ class GitHubLdapActiveDirectoryMemberSearchStubbedTest < GitHub::Ldap::Test # Only run when AD integration tests aren't run def run(*) - self.class.test_env != "activedirectory" ? super : self + return super if self.class.test_env != "activedirectory" + Minitest::Result.from(self) end def find_group(cn) @@ -46,7 +47,8 @@ def test_finds_deeply_nested_group_members class GitHubLdapActiveDirectoryMemberSearchIntegrationTest < GitHub::Ldap::Test # Only run this test suite if ActiveDirectory is configured def run(*) - self.class.test_env == "activedirectory" ? super : self + return super if self.class.test_env == "activedirectory" + Minitest::Result.from(self) end def find_group(cn) diff --git a/test/membership_validators/active_directory_test.rb b/test/membership_validators/active_directory_test.rb index 956fbc5..2160f8d 100644 --- a/test/membership_validators/active_directory_test.rb +++ b/test/membership_validators/active_directory_test.rb @@ -3,7 +3,8 @@ class GitHubLdapActiveDirectoryMembershipValidatorsStubbedTest < GitHub::Ldap::Test # Only run when AD integration tests aren't run def run(*) - self.class.test_env != "activedirectory" ? super : self + return super if self.class.test_env != "activedirectory" + Minitest::Result.from(self) end def setup @@ -72,7 +73,8 @@ def test_does_not_validate_user_not_in_any_group class GitHubLdapActiveDirectoryMembershipValidatorsIntegrationTest < GitHub::Ldap::Test # Only run this test suite if ActiveDirectory is configured def run(*) - self.class.test_env == "activedirectory" ? super : self + return super if self.class.test_env == "activedirectory" + Minitest::Result.from(self) end def setup From 16b8a38e43288e9fb9ddbf642428ac855220a0af Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Tue, 1 Jun 2021 21:26:32 +0000 Subject: [PATCH 157/161] Fix libodbc1 dependency Add source to make slapd dependency available. --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 798c5c4..d9fd02b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,10 @@ addons: - ad1.ghe.dev - ad2.ghe.dev +before_install: + - echo "deb http://ftp.br.debian.org/debian stable main" | sudo tee -a /etc/apt/sources.list + - sudo apt-get update + install: - if [ "$TESTENV" = "openldap" ]; then ./script/install-openldap; fi - bundle install From ebfe3c589fe6df5a4a0da70a7babe4d8b5c181c7 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Tue, 1 Jun 2021 21:34:59 +0000 Subject: [PATCH 158/161] Remove DB_CONFIG instructions This config file is not installed anymore. --- script/install-openldap | 2 -- 1 file changed, 2 deletions(-) diff --git a/script/install-openldap b/script/install-openldap index bb0033f..2deddad 100755 --- a/script/install-openldap +++ b/script/install-openldap @@ -13,10 +13,8 @@ TMPDIR=$(mktemp -d) cd $TMPDIR # Delete data and reconfigure. -sudo cp -v /var/lib/ldap/DB_CONFIG ./DB_CONFIG sudo rm -rf /etc/ldap/slapd.d/* sudo rm -rf /var/lib/ldap/* -sudo cp -v ./DB_CONFIG /var/lib/ldap/DB_CONFIG sudo slapadd -F /etc/ldap/slapd.d -b "cn=config" -l $BASE_PATH/slapd.conf.ldif # Load memberof and ref-int overlays and configure them. sudo slapadd -F /etc/ldap/slapd.d -b "cn=config" -l $BASE_PATH/memberof.ldif From 8cd5fb162295e0b0e11a1eef0fbc8127c14c5562 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Tue, 1 Jun 2021 21:36:22 +0000 Subject: [PATCH 159/161] Return a Result --- test/test_helper.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test_helper.rb b/test/test_helper.rb index c29703b..e92caa6 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -31,8 +31,9 @@ def self.test_env def self.run(reporter, options = {}) start_server - super + result = super stop_server + result end def self.stop_server From 1f623fd6559b2c0ef65a30d211fb76fe06786fcb Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Tue, 1 Jun 2021 21:43:00 +0000 Subject: [PATCH 160/161] Fix Minitest::Result requirement --- test/domain_test.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/domain_test.rb b/test/domain_test.rb index d54850c..4fc0dee 100644 --- a/test/domain_test.rb +++ b/test/domain_test.rb @@ -236,7 +236,8 @@ def test_membership_for_posixGroups class GitHubLdapActiveDirectoryGroupsTest < GitHub::Ldap::Test def run(*) - self.class.test_env == "activedirectory" ? super : self + return super if self.class.test_env == "activedirectory" + Minitest::Result.from(self) end def test_filter_groups From f676fc1d894ef1e1139871e138a3f0c71a8ebcf6 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Tue, 1 Jun 2021 22:08:01 +0000 Subject: [PATCH 161/161] Fix stub to return an Array Fixes issue with calling to_ary on stubbed result. --- test/user_search/active_directory_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/user_search/active_directory_test.rb b/test/user_search/active_directory_test.rb index 2aec199..32bed79 100644 --- a/test/user_search/active_directory_test.rb +++ b/test/user_search/active_directory_test.rb @@ -20,7 +20,7 @@ def test_global_catalog_returns_array_of_results mock_global_catalog_connection = mock("GitHub::Ldap::UserSearch::GlobalCatalog") stub_entry = mock("Net::LDAP::Entry") - mock_global_catalog_connection.expects(:search).returns(stub_entry) + mock_global_catalog_connection.expects(:search).returns([stub_entry]) ad_user_search.expects(:global_catalog_connection).returns(mock_global_catalog_connection) results = ad_user_search.perform("login", "CN=Joe", "uid", {})