From 12ba663ed4f53b46c552913993407ae4a58f56c2 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Wed, 3 Dec 2014 15:23:22 -0800 Subject: [PATCH 1/7] Rename Members to MemberSearch --- lib/github/ldap.rb | 2 +- lib/github/ldap/{members.rb => member_search.rb} | 12 ++++++------ .../ldap/{members => member_search}/classic.rb | 2 +- .../ldap/{members => member_search}/recursive.rb | 2 +- test/{members => member_search}/classic_test.rb | 6 +++--- test/{members => member_search}/recursive_test.rb | 6 +++--- 6 files changed, 15 insertions(+), 15 deletions(-) rename lib/github/ldap/{members.rb => member_search.rb} (52%) rename lib/github/ldap/{members => member_search}/classic.rb (97%) rename lib/github/ldap/{members => member_search}/recursive.rb (99%) rename test/{members => member_search}/classic_test.rb (84%) rename test/{members => member_search}/recursive_test.rb (84%) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 43c3f3b..40db8be 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -9,7 +9,7 @@ class Ldap require 'github/ldap/virtual_group' require 'github/ldap/virtual_attributes' require 'github/ldap/instrumentation' - require 'github/ldap/members' + require 'github/ldap/member_search' require 'github/ldap/membership_validators' include Instrumentation diff --git a/lib/github/ldap/members.rb b/lib/github/ldap/member_search.rb similarity index 52% rename from lib/github/ldap/members.rb rename to lib/github/ldap/member_search.rb index 85b7f37..10e0b38 100644 --- a/lib/github/ldap/members.rb +++ b/lib/github/ldap/member_search.rb @@ -1,5 +1,5 @@ -require 'github/ldap/members/classic' -require 'github/ldap/members/recursive' +require 'github/ldap/member_search/classic' +require 'github/ldap/member_search/recursive' module GitHub class Ldap @@ -8,14 +8,14 @@ class Ldap # For example: # # group = domain.groups(%w(Engineering)).first - # strategy = GitHub::Ldap::Members::Recursive.new(ldap) + # strategy = GitHub::Ldap::MemberSearch::Recursive.new(ldap) # strategy.perform(group) #=> [#] # - module Members + module MemberSearch # Internal: Mapping of strategy name to class. STRATEGIES = { - :classic => GitHub::Ldap::Members::Classic, - :recursive => GitHub::Ldap::Members::Recursive + :classic => GitHub::Ldap::MemberSearch::Classic, + :recursive => GitHub::Ldap::MemberSearch::Recursive } end end diff --git a/lib/github/ldap/members/classic.rb b/lib/github/ldap/member_search/classic.rb similarity index 97% rename from lib/github/ldap/members/classic.rb rename to lib/github/ldap/member_search/classic.rb index 81a5601..68a860b 100644 --- a/lib/github/ldap/members/classic.rb +++ b/lib/github/ldap/member_search/classic.rb @@ -1,6 +1,6 @@ module GitHub class Ldap - module Members + module MemberSearch # Look up group members using the existing `Group#members` and # `Group#subgroups` API. class Classic diff --git a/lib/github/ldap/members/recursive.rb b/lib/github/ldap/member_search/recursive.rb similarity index 99% rename from lib/github/ldap/members/recursive.rb rename to lib/github/ldap/member_search/recursive.rb index 9b0becc..0df6a1c 100644 --- a/lib/github/ldap/members/recursive.rb +++ b/lib/github/ldap/member_search/recursive.rb @@ -1,6 +1,6 @@ module GitHub class Ldap - module Members + module MemberSearch # Look up group members recursively. # # This results in a maximum of `depth` iterations/recursions to look up diff --git a/test/members/classic_test.rb b/test/member_search/classic_test.rb similarity index 84% rename from test/members/classic_test.rb rename to test/member_search/classic_test.rb index 6c36a3f..656e12b 100644 --- a/test/members/classic_test.rb +++ b/test/member_search/classic_test.rb @@ -1,11 +1,11 @@ require_relative '../test_helper' -class GitHubLdapRecursiveMembersTest < GitHub::Ldap::Test +class GitHubLdapRecursiveMemberSearchTest < GitHub::Ldap::Test def setup @ldap = GitHub::Ldap.new(options.merge(search_domains: %w(dc=github,dc=com))) @domain = @ldap.domain("dc=github,dc=com") @entry = @domain.user?('user1') - @strategy = GitHub::Ldap::Members::Classic.new(@ldap) + @strategy = GitHub::Ldap::MemberSearch::Classic.new(@ldap) end def find_group(cn) @@ -33,7 +33,7 @@ def test_finds_posix_group_members end def test_does_not_respect_configured_depth_limit - strategy = GitHub::Ldap::Members::Classic.new(@ldap, depth: 2) + strategy = GitHub::Ldap::MemberSearch::Classic.new(@ldap, depth: 2) members = strategy.perform(find_group("n-depth-nested-group9")).map(&:dn) assert_includes members, @entry.dn end diff --git a/test/members/recursive_test.rb b/test/member_search/recursive_test.rb similarity index 84% rename from test/members/recursive_test.rb rename to test/member_search/recursive_test.rb index e743ca8..a2d388d 100644 --- a/test/members/recursive_test.rb +++ b/test/member_search/recursive_test.rb @@ -1,11 +1,11 @@ require_relative '../test_helper' -class GitHubLdapRecursiveMembersTest < GitHub::Ldap::Test +class GitHubLdapRecursiveMemberSearchTest < GitHub::Ldap::Test def setup @ldap = GitHub::Ldap.new(options.merge(search_domains: %w(dc=github,dc=com))) @domain = @ldap.domain("dc=github,dc=com") @entry = @domain.user?('user1') - @strategy = GitHub::Ldap::Members::Recursive.new(@ldap) + @strategy = GitHub::Ldap::MemberSearch::Recursive.new(@ldap) end def find_group(cn) @@ -33,7 +33,7 @@ def test_finds_posix_group_members end def test_respects_configured_depth_limit - strategy = GitHub::Ldap::Members::Recursive.new(@ldap, depth: 2) + strategy = GitHub::Ldap::MemberSearch::Recursive.new(@ldap, depth: 2) members = strategy.perform(find_group("n-depth-nested-group9")).map(&:dn) refute_includes members, @entry.dn end From e79d6321ea90e0c7b8111c2cac07546b87825687 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Wed, 3 Dec 2014 15:41:05 -0800 Subject: [PATCH 2/7] Add member_search_strategy config option --- lib/github/ldap.rb | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 40db8be..e4c8c55 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -36,6 +36,7 @@ class Ldap attr_reader :uid, :search_domains, :virtual_attributes, :membership_validator, + :member_search_strategy, :instrumentation_service # Build a new GitHub::Ldap instance @@ -92,6 +93,9 @@ def initialize(options = {}) # configure which strategy should be used to validate user membership configure_membership_validation_strategy(options[:membership_validator]) + # configure which strategy should be used for member search + configure_member_search_strategy(options[:member_search_strategy]) + # enables instrumenting queries @instrumentation_service = options[:instrumentation_service] end @@ -255,5 +259,24 @@ def configure_membership_validation_strategy(strategy = nil) :detect end end + + # Internal: Configure the member search strategy. + # + # Used by GitHub::Ldap::MemberSearch::Detect to force a specific strategy + # (instead of detecting the host capabilities and deciding at runtime). + # + # If `strategy` is not provided, or doesn't match a known strategy, + # defaults to `:detect`. Otherwise the configured strategy is selected. + # + # Returns the selected strategy Symbol. + def configure_member_search_strategy(strategy = nil) + @member_search_strategy = + case strategy.to_s + when "classic", "recursive" + strategy.to_sym + else + :detect + end + end end end From a2ea06f1976779fc5c220bb0bb1560b8cc69a758 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Wed, 3 Dec 2014 15:51:57 -0800 Subject: [PATCH 3/7] Extract re-usable capability detection logic --- lib/github/ldap.rb | 1 + lib/github/ldap/capabilities.rb | 24 +++++++++++++++++++ .../ldap/membership_validators/detect.rb | 20 ++-------------- 3 files changed, 27 insertions(+), 18 deletions(-) create mode 100644 lib/github/ldap/capabilities.rb diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index e4c8c55..dc18a44 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -9,6 +9,7 @@ class Ldap require 'github/ldap/virtual_group' require 'github/ldap/virtual_attributes' require 'github/ldap/instrumentation' + require 'github/ldap/capabilities' require 'github/ldap/member_search' require 'github/ldap/membership_validators' diff --git a/lib/github/ldap/capabilities.rb b/lib/github/ldap/capabilities.rb new file mode 100644 index 0000000..370be4b --- /dev/null +++ b/lib/github/ldap/capabilities.rb @@ -0,0 +1,24 @@ +module GitHub + class Ldap + module Capabilities + # Internal: The capability required to use the ActiveDirectory strategy. + # See: http://msdn.microsoft.com/en-us/library/cc223359.aspx. + ACTIVE_DIRECTORY_V61_R2_OID = "1.2.840.113556.1.4.2080".freeze + + # Internal: Detect whether the LDAP host is an ActiveDirectory server. + # + # See: http://msdn.microsoft.com/en-us/library/cc223359.aspx. + # + # Returns true if the host is an ActiveDirectory server, false otherwise. + def active_directory_capability? + capabilities[:supportedcapabilities].include?(ACTIVE_DIRECTORY_V61_R2_OID) + end + + # Internal: Returns the Net::LDAP::Entry object describing the LDAP + # host's capabilities (via the Root DSE). + def capabilities + ldap.capabilities + end + end + end +end diff --git a/lib/github/ldap/membership_validators/detect.rb b/lib/github/ldap/membership_validators/detect.rb index ba8c4ba..74f7f0d 100644 --- a/lib/github/ldap/membership_validators/detect.rb +++ b/lib/github/ldap/membership_validators/detect.rb @@ -7,9 +7,8 @@ module MembershipValidators # also be defined via `GitHub::Ldap#membership_validator=`. See also # `GitHub::Ldap#configure_membership_validation_strategy`. class Detect < Base - # Internal: The capability required to use the ActiveDirectory strategy. - # See: http://msdn.microsoft.com/en-us/library/cc223359.aspx. - ACTIVE_DIRECTORY_V61_R2_OID = "1.2.840.113556.1.4.2080".freeze + # Defines `active_directory_capability?` and necessary helpers. + include GitHub::Ldap::Capabilities def perform(entry) # short circuit validation if there are no groups to check against @@ -48,21 +47,6 @@ def detect_strategy def strategy_config ldap.membership_validator end - - # Internal: Detect whether the LDAP host is an ActiveDirectory server. - # - # See: http://msdn.microsoft.com/en-us/library/cc223359.aspx. - # - # Returns true if the host is an ActiveDirectory server, false otherwise. - def active_directory_capability? - capabilities[:supportedcapabilities].include?(ACTIVE_DIRECTORY_V61_R2_OID) - end - - # Internal: Returns the Net::LDAP::Entry object describing the LDAP - # host's capabilities (via the Root DSE). - def capabilities - ldap.capabilities - end end end end From 05cb39cb9b860a7cfdb0b3b521e6ee8856dc8806 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Wed, 3 Dec 2014 15:59:29 -0800 Subject: [PATCH 4/7] Add member search Detect strategy --- lib/github/ldap/member_search.rb | 1 + lib/github/ldap/member_search/detect.rb | 71 +++++++++++++++++++++++++ test/member_search/detect_test.rb | 42 +++++++++++++++ 3 files changed, 114 insertions(+) create mode 100644 lib/github/ldap/member_search/detect.rb create mode 100644 test/member_search/detect_test.rb diff --git a/lib/github/ldap/member_search.rb b/lib/github/ldap/member_search.rb index 10e0b38..fc81607 100644 --- a/lib/github/ldap/member_search.rb +++ b/lib/github/ldap/member_search.rb @@ -1,3 +1,4 @@ +require 'github/ldap/member_search/detect' require 'github/ldap/member_search/classic' require 'github/ldap/member_search/recursive' diff --git a/lib/github/ldap/member_search/detect.rb b/lib/github/ldap/member_search/detect.rb new file mode 100644 index 0000000..06cdb32 --- /dev/null +++ b/lib/github/ldap/member_search/detect.rb @@ -0,0 +1,71 @@ +module GitHub + class Ldap + module MemberSearch + # Detects the LDAP host's capabilities and determines the appropriate + # member search strategy at runtime. + # + # Currently detects for ActiveDirectory in-chain membership validation. + # + # An explicit strategy can also be defined via + # `GitHub::Ldap#member_search_strategy=`. + # + # See also `GitHub::Ldap#configure_member_search_strategy`. + class Detect + # Defines `active_directory_capability?` and necessary helpers. + include GitHub::Ldap::Capabilities + + # Internal: The GitHub::Ldap object to search domains with. + attr_reader :ldap + + # Internal: The Hash of options to pass through to the strategy. + attr_reader :options + + # Public: Instantiate a meta strategy to detect the right strategy + # to use for the search, and call that strategy, at runtime. + # + # - ldap: GitHub::Ldap object + # - options: Hash of options (passed through) + def initialize(ldap, options = {}) + @ldap = ldap + @options = options + end + + # Public: Performs search for group members via the appropriate search + # strategy detected/configured. + # + # Returns Array of Net::LDAP::Entry objects. + def perform(entry) + strategy.perform(entry) + end + + # Internal: Returns the member search strategy object. + def strategy + @strategy ||= begin + strategy = detect_strategy + strategy.new(ldap, options) + end + end + + # Internal: Find the most appropriate search strategy, either by + # configuration or by detecting the host's capabilities. + # + # Returns the strategy class. + def detect_strategy + case + when GitHub::Ldap::MemberSearch::STRATEGIES.key?(strategy_config) + GitHub::Ldap::MemberSearch::STRATEGIES[strategy_config] + when active_directory_capability? + GitHub::Ldap::MemberSearch::STRATEGIES[:active_directory] + else + GitHub::Ldap::MemberSearch::STRATEGIES[:recursive] + end + end + + # Internal: Returns the configured member search strategy Symbol. + def strategy_config + ldap.member_search_strategy + end + end + end + end +end diff --git a/test/member_search/detect_test.rb b/test/member_search/detect_test.rb new file mode 100644 index 0000000..6092cdf --- /dev/null +++ b/test/member_search/detect_test.rb @@ -0,0 +1,42 @@ +require_relative '../test_helper' + +# NOTE: Since this strategy is targeted at detecting ActiveDirectory +# capabilities, and we don't have AD setup in CI, we stub out actual queries +# and test against what AD *would* respond with. + +class GitHubLdapDetectMemberSearchTest < GitHub::Ldap::Test + include GitHub::Ldap::Capabilities + + def setup + @ldap = GitHub::Ldap.new(options.merge(search_domains: %w(dc=github,dc=com))) + @domain = @ldap.domain("dc=github,dc=com") + @entry = @domain.user?('user1') + @strategy = GitHub::Ldap::MemberSearch::Detect.new(@ldap) + end + + def test_defers_to_configured_strategy + @ldap.configure_member_search_strategy(:classic) + + assert_kind_of GitHub::Ldap::MemberSearch::Classic, @strategy.strategy + end + + def test_detects_active_directory + caps = Net::LDAP::Entry.new + caps[:supportedcapabilities] = [ACTIVE_DIRECTORY_V61_R2_OID] + + @ldap.stub :capabilities, caps do + assert_kind_of GitHub::Ldap::MemberSearch::ActiveDirectory, + @strategy.strategy + end + end + + def test_falls_back_to_recursive + caps = Net::LDAP::Entry.new + caps[:supportedcapabilities] = [] + + @ldap.stub :capabilities, caps do + assert_kind_of GitHub::Ldap::MemberSearch::Recursive, + @strategy.strategy + end + end +end From 4f774fd7202cf4bf45bbe56f3412622073db99b9 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Wed, 3 Dec 2014 16:00:41 -0800 Subject: [PATCH 5/7] Include Capabilities to reuse constant --- test/membership_validators/detect_test.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/membership_validators/detect_test.rb b/test/membership_validators/detect_test.rb index 8bf522a..34d476a 100644 --- a/test/membership_validators/detect_test.rb +++ b/test/membership_validators/detect_test.rb @@ -5,6 +5,8 @@ # and test against what AD *would* respond with. class GitHubLdapDetectMembershipValidatorsTest < GitHub::Ldap::Test + include GitHub::Ldap::Capabilities + def setup @ldap = GitHub::Ldap.new(options.merge(search_domains: %w(dc=github,dc=com))) @domain = @ldap.domain("dc=github,dc=com") @@ -26,8 +28,7 @@ def test_defers_to_configured_strategy def test_detects_active_directory caps = Net::LDAP::Entry.new - caps[:supportedcapabilities] = - [GitHub::Ldap::MembershipValidators::Detect::ACTIVE_DIRECTORY_V61_R2_OID] + caps[:supportedcapabilities] = [ACTIVE_DIRECTORY_V61_R2_OID] validator = make_validator(%w(group)) @ldap.stub :capabilities, caps do From d4d705daa4f02f721f8d2aab523cf6600d8cb613 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Wed, 3 Dec 2014 17:32:01 -0800 Subject: [PATCH 6/7] Add ActiveDirectory member search strategy --- lib/github/ldap/member_search.rb | 6 +- .../ldap/member_search/active_directory.rb | 70 +++++++++++++++++ test/member_search/active_directory_test.rb | 77 +++++++++++++++++++ 3 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 lib/github/ldap/member_search/active_directory.rb create mode 100644 test/member_search/active_directory_test.rb diff --git a/lib/github/ldap/member_search.rb b/lib/github/ldap/member_search.rb index fc81607..b3965a5 100644 --- a/lib/github/ldap/member_search.rb +++ b/lib/github/ldap/member_search.rb @@ -1,6 +1,7 @@ require 'github/ldap/member_search/detect' require 'github/ldap/member_search/classic' require 'github/ldap/member_search/recursive' +require 'github/ldap/member_search/active_directory' module GitHub class Ldap @@ -15,8 +16,9 @@ class Ldap module MemberSearch # Internal: Mapping of strategy name to class. STRATEGIES = { - :classic => GitHub::Ldap::MemberSearch::Classic, - :recursive => GitHub::Ldap::MemberSearch::Recursive + :classic => GitHub::Ldap::MemberSearch::Classic, + :recursive => GitHub::Ldap::MemberSearch::Recursive, + :active_directory => GitHub::Ldap::MemberSearch::ActiveDirectory } end end diff --git a/lib/github/ldap/member_search/active_directory.rb b/lib/github/ldap/member_search/active_directory.rb new file mode 100644 index 0000000..6245012 --- /dev/null +++ b/lib/github/ldap/member_search/active_directory.rb @@ -0,0 +1,70 @@ +module GitHub + class Ldap + module MemberSearch + # Look up group members using the ActiveDirectory "in chain" matching rule. + # + # The 1.2.840.113556.1.4.1941 matching rule (LDAP_MATCHING_RULE_IN_CHAIN) + # "walks the chain of ancestry in objects all the way to the root until + # it finds a match". + # Source: http://msdn.microsoft.com/en-us/library/aa746475(v=vs.85).aspx + # + # This means we have an efficient method of searching for group members, + # even in nested groups, performed on the server side. + class ActiveDirectory + OID = "1.2.840.113556.1.4.1941" + + # Internal: The default attributes to query for. + # NOTE: We technically don't need any by default, but if we left this + # empty, we'd be querying for *all* attributes which is less ideal. + DEFAULT_ATTRS = %w(objectClass) + + # Internal: The GitHub::Ldap object to search domains with. + attr_reader :ldap + + # Internal: The attributes to search for. + attr_reader :attrs + + # Public: Instantiate new search strategy. + # + # - ldap: GitHub::Ldap object + # - options: Hash of options + def initialize(ldap, options = {}) + @ldap = ldap + @options = options + @attrs = Array(options[:attrs]).concat DEFAULT_ATTRS + end + + # Public: Performs search for group members, including groups and + # members of subgroups, using ActiveDirectory's "in chain" matching + # rule. + # + # Returns Array of Net::LDAP::Entry objects. + def perform(group) + filter = member_of_in_chain_filter(group) + + # search for all members of the group, including subgroups, by + # searching "in chain". + domains.each_with_object([]) do |domain, members| + members.concat domain.search(filter: filter, attributes: attrs) + end + end + + # Internal: Constructs a member filter using the "in chain" + # extended matching rule afforded by ActiveDirectory. + # + # Returns a Net::LDAP::Filter object. + def member_of_in_chain_filter(entry) + Net::LDAP::Filter.ex("memberOf:#{OID}", entry.dn) + end + + # Internal: Domains to search through. + # + # Returns an Array of GitHub::Ldap::Domain objects. + def domains + @domains ||= ldap.search_domains.map { |base| ldap.domain(base) } + end + private :domains + end + end + end +end diff --git a/test/member_search/active_directory_test.rb b/test/member_search/active_directory_test.rb new file mode 100644 index 0000000..e3f367a --- /dev/null +++ b/test/member_search/active_directory_test.rb @@ -0,0 +1,77 @@ +require_relative '../test_helper' + +class GitHubLdapActiveDirectoryMemberSearchStubbedTest < GitHub::Ldap::Test + # Only run when AD integration tests aren't run + def run(*) + self.class.test_env != "activedirectory" ? super : self + end + + def find_group(cn) + @domain.groups([cn]).first + end + + def setup + @ldap = GitHub::Ldap.new(options.merge(search_domains: %w(dc=github,dc=com))) + @domain = @ldap.domain("dc=github,dc=com") + @entry = @domain.user?('user1') + @strategy = GitHub::Ldap::MemberSearch::ActiveDirectory.new(@ldap) + end + + def test_finds_group_members + members = + @ldap.stub :search, [@entry] do + @strategy.perform(find_group("nested-group1")).map(&:dn) + end + assert_includes members, @entry.dn + end + + def test_finds_nested_group_members + members = + @ldap.stub :search, [@entry] do + @strategy.perform(find_group("n-depth-nested-group1")).map(&:dn) + end + assert_includes members, @entry.dn + end + + def test_finds_deeply_nested_group_members + members = + @ldap.stub :search, [@entry] do + @strategy.perform(find_group("n-depth-nested-group9")).map(&:dn) + end + assert_includes members, @entry.dn + end +end + +# See test/support/vm/activedirectory/README.md for details +class GitHubLdapActiveDirectoryMemberSearchIntegrationTest < GitHub::Ldap::Test + # Only run this test suite if ActiveDirectory is configured + def run(*) + self.class.test_env == "activedirectory" ? super : self + end + + def find_group(cn) + @domain.groups([cn]).first + end + + def setup + @ldap = GitHub::Ldap.new(options) + @domain = @ldap.domain(options[:search_domains]) + @entry = @domain.user?('user1') + @strategy = GitHub::Ldap::MemberSearch::ActiveDirectory.new(@ldap) + end + + def test_finds_group_members + members = @strategy.perform(find_group("nested-group1")).map(&:dn) + assert_includes members, @entry.dn + end + + def test_finds_nested_group_members + members = @strategy.perform(find_group("n-depth-nested-group1")).map(&:dn) + assert_includes members, @entry.dn + end + + def test_finds_deeply_nested_group_members + members = @strategy.perform(find_group("n-depth-nested-group9")).map(&:dn) + assert_includes members, @entry.dn + end +end From a9b86ef83737943d16df960353169ad03d1b2da5 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Wed, 3 Dec 2014 17:41:21 -0800 Subject: [PATCH 7/7] Extract common behaviors for MemberSearch strategies --- lib/github/ldap/member_search.rb | 1 + .../ldap/member_search/active_directory.rb | 20 +++-------- lib/github/ldap/member_search/base.rb | 34 +++++++++++++++++++ lib/github/ldap/member_search/classic.rb | 14 +------- lib/github/ldap/member_search/recursive.rb | 22 ++++-------- 5 files changed, 47 insertions(+), 44 deletions(-) create mode 100644 lib/github/ldap/member_search/base.rb diff --git a/lib/github/ldap/member_search.rb b/lib/github/ldap/member_search.rb index b3965a5..6269638 100644 --- a/lib/github/ldap/member_search.rb +++ b/lib/github/ldap/member_search.rb @@ -1,3 +1,4 @@ +require 'github/ldap/member_search/base' require 'github/ldap/member_search/detect' require 'github/ldap/member_search/classic' require 'github/ldap/member_search/recursive' diff --git a/lib/github/ldap/member_search/active_directory.rb b/lib/github/ldap/member_search/active_directory.rb index 6245012..f78085a 100644 --- a/lib/github/ldap/member_search/active_directory.rb +++ b/lib/github/ldap/member_search/active_directory.rb @@ -10,7 +10,7 @@ module MemberSearch # # This means we have an efficient method of searching for group members, # even in nested groups, performed on the server side. - class ActiveDirectory + class ActiveDirectory < Base OID = "1.2.840.113556.1.4.1941" # Internal: The default attributes to query for. @@ -18,9 +18,6 @@ class ActiveDirectory # empty, we'd be querying for *all* attributes which is less ideal. DEFAULT_ATTRS = %w(objectClass) - # Internal: The GitHub::Ldap object to search domains with. - attr_reader :ldap - # Internal: The attributes to search for. attr_reader :attrs @@ -28,10 +25,11 @@ class ActiveDirectory # # - ldap: GitHub::Ldap object # - options: Hash of options + # + # NOTE: This overrides default behavior to configure attrs`. def initialize(ldap, options = {}) - @ldap = ldap - @options = options - @attrs = Array(options[:attrs]).concat DEFAULT_ATTRS + super + @attrs = Array(options[:attrs]).concat DEFAULT_ATTRS end # Public: Performs search for group members, including groups and @@ -56,14 +54,6 @@ def perform(group) def member_of_in_chain_filter(entry) Net::LDAP::Filter.ex("memberOf:#{OID}", entry.dn) end - - # Internal: Domains to search through. - # - # Returns an Array of GitHub::Ldap::Domain objects. - def domains - @domains ||= ldap.search_domains.map { |base| ldap.domain(base) } - end - private :domains end end end diff --git a/lib/github/ldap/member_search/base.rb b/lib/github/ldap/member_search/base.rb new file mode 100644 index 0000000..e3491f1 --- /dev/null +++ b/lib/github/ldap/member_search/base.rb @@ -0,0 +1,34 @@ +module GitHub + class Ldap + module MemberSearch + class Base + + # Internal: The GitHub::Ldap object to search domains with. + attr_reader :ldap + + # Public: Instantiate new search strategy. + # + # - ldap: GitHub::Ldap object + # - options: Hash of options + def initialize(ldap, options = {}) + @ldap = ldap + @options = options + end + + # Public: Abstract: Performs search for group members. + # + # Returns Array of Net::LDAP::Entry objects. + # def perform(entry) + # end + + # Internal: Domains to search through. + # + # Returns an Array of GitHub::Ldap::Domain objects. + def domains + @domains ||= ldap.search_domains.map { |base| ldap.domain(base) } + end + private :domains + end + end + end +end diff --git a/lib/github/ldap/member_search/classic.rb b/lib/github/ldap/member_search/classic.rb index 68a860b..47bb7a1 100644 --- a/lib/github/ldap/member_search/classic.rb +++ b/lib/github/ldap/member_search/classic.rb @@ -3,19 +3,7 @@ class Ldap module MemberSearch # Look up group members using the existing `Group#members` and # `Group#subgroups` API. - class Classic - # Internal: The GitHub::Ldap object to search domains with. - attr_reader :ldap - - # Public: Instantiate new search strategy. - # - # - ldap: GitHub::Ldap object - # - options: Hash of options (unused) - def initialize(ldap, options = {}) - @ldap = ldap - @options = options - end - + class Classic < Base # Public: Performs search for group members, including groups and # members of subgroups recursively. # diff --git a/lib/github/ldap/member_search/recursive.rb b/lib/github/ldap/member_search/recursive.rb index 0df6a1c..5fe2489 100644 --- a/lib/github/ldap/member_search/recursive.rb +++ b/lib/github/ldap/member_search/recursive.rb @@ -5,15 +5,12 @@ module MemberSearch # # This results in a maximum of `depth` iterations/recursions to look up # members of a group and its subgroups. - class Recursive + class Recursive < Base include Filter DEFAULT_MAX_DEPTH = 9 DEFAULT_ATTRS = %w(member uniqueMember memberUid) - # Internal: The GitHub::Ldap object to search domains with. - attr_reader :ldap - # Internal: The maximum depth to search for members. attr_reader :depth @@ -24,11 +21,12 @@ class Recursive # # - ldap: GitHub::Ldap object # - options: Hash of options + # + # NOTE: This overrides default behavior to configure `depth` and `attrs`. def initialize(ldap, options = {}) - @ldap = ldap - @options = options - @depth = options[:depth] || DEFAULT_MAX_DEPTH - @attrs = Array(options[:attrs]).concat DEFAULT_ATTRS + super + @depth = options[:depth] || DEFAULT_MAX_DEPTH + @attrs = Array(options[:attrs]).concat DEFAULT_ATTRS end # Public: Performs search for group members, including groups and @@ -129,14 +127,6 @@ def member_uids(entry) entry["memberUid"] end private :member_uids - - # Internal: Domains to search through. - # - # Returns an Array of GitHub::Ldap::Domain objects. - def domains - @domains ||= ldap.search_domains.map { |base| ldap.domain(base) } - end - private :domains end end end