From 0e04583da578286a435b167f7d7676d69dd8dd07 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Fri, 5 Dec 2014 13:59:53 -0800 Subject: [PATCH 1/5] Move requires to the top --- lib/github/ldap.rb | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index dc18a44..41d98dc 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -1,18 +1,19 @@ +require 'net/ldap' +require 'forwardable' + +require 'github/ldap/filter' +require 'github/ldap/domain' +require 'github/ldap/group' +require 'github/ldap/posix_group' +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' + module GitHub class Ldap - require 'net/ldap' - require 'forwardable' - require 'github/ldap/filter' - require 'github/ldap/domain' - require 'github/ldap/group' - require 'github/ldap/posix_group' - 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' - include Instrumentation extend Forwardable From cb8f4918b364b1fa41e713d74a115ac791b4352f Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Fri, 5 Dec 2014 14:57:49 -0800 Subject: [PATCH 2/5] Remove Detect meta-strategy, inline config/detection --- lib/github/ldap.rb | 72 +++++++++++++++---- lib/github/ldap/capabilities.rb | 24 ------- lib/github/ldap/member_search.rb | 22 ------ lib/github/ldap/member_search/detect.rb | 71 ------------------ lib/github/ldap/membership_validators.rb | 22 ------ .../ldap/membership_validators/detect.rb | 53 -------------- 6 files changed, 57 insertions(+), 207 deletions(-) delete mode 100644 lib/github/ldap/capabilities.rb delete mode 100644 lib/github/ldap/member_search/detect.rb delete mode 100644 lib/github/ldap/membership_validators/detect.rb diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 41d98dc..d9c547c 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -18,6 +18,10 @@ class Ldap extend Forwardable + # 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 + # Utility method to get the last operation result with a human friendly message. # # Returns an OpenStruct with `code` and `message`. @@ -92,11 +96,8 @@ def initialize(options = {}) # when a base is not explicitly provided. @search_domains = Array(options[:search_domains]) - # 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]) + # configure both the membership validator and the member search strategies + configure_search_strategy(options[:search_strategy]) # enables instrumenting queries @instrumentation_service = options[:instrumentation_service] @@ -243,6 +244,19 @@ def configure_virtual_attributes(attributes) end end + # Internal: Configure the member search and membership validation strategies. + # + # TODO: Inline the logic in these two methods here. + # + # Returns nothing. + def configure_search_strategy(strategy = nil) + # configure which strategy should be used to validate user membership + configure_membership_validation_strategy(strategy) + + # configure which strategy should be used for member search + configure_member_search_strategy(strategy) + end + # Internal: Configure the membership validation strategy. # # Used by GitHub::Ldap::MembershipValidators::Detect to force a specific @@ -251,14 +265,23 @@ def configure_virtual_attributes(attributes) # If `strategy` is not provided, or doesn't match a known strategy, # defaults to `:detect`. Otherwise the configured strategy is selected. # - # Returns the selected membership validator strategy Symbol. + # Returns the membership validator strategy Class. def configure_membership_validation_strategy(strategy = nil) @membership_validator = case strategy.to_s - when "classic", "recursive", "active_directory" - strategy.to_sym + when "classic" + GitHub::Ldap::MembershipValidators::Classic + when "recursive" + GitHub::Ldap::MembershipValidators::Recursive + when "active_directory" + GitHub::Ldap::MembershipValidators::ActiveDirectory else - :detect + # fallback to detection, defaulting to recursive strategy + if active_directory_capability? + GitHub::Ldap::MembershipValidators::ActiveDirectory + else + GitHub::Ldap::MembershipValidators::Recursive + end end end @@ -273,12 +296,31 @@ def configure_membership_validation_strategy(strategy = nil) # 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 + case strategy.to_s + when "classic" + GitHub::Ldap::MemberSearch::Classic + when "recursive" + GitHub::Ldap::MemberSearch::Recursive + when "active_directory" + GitHub::Ldap::MemberSearch::ActiveDirectory + else + # fallback to detection, defaulting to recursive strategy + if active_directory_capability? + GitHub::Ldap::MemberSearch::ActiveDirectory + else + GitHub::Ldap::MemberSearch::Recursive + end + end + 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 + private :active_directory_capability? end end diff --git a/lib/github/ldap/capabilities.rb b/lib/github/ldap/capabilities.rb deleted file mode 100644 index 370be4b..0000000 --- a/lib/github/ldap/capabilities.rb +++ /dev/null @@ -1,24 +0,0 @@ -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/member_search.rb b/lib/github/ldap/member_search.rb index 6269638..d051268 100644 --- a/lib/github/ldap/member_search.rb +++ b/lib/github/ldap/member_search.rb @@ -1,26 +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' require 'github/ldap/member_search/active_directory' - -module GitHub - class Ldap - # Provides various strategies for member lookup. - # - # For example: - # - # group = domain.groups(%w(Engineering)).first - # strategy = GitHub::Ldap::MemberSearch::Recursive.new(ldap) - # strategy.perform(group) #=> [#] - # - module MemberSearch - # Internal: Mapping of strategy name to class. - STRATEGIES = { - :classic => GitHub::Ldap::MemberSearch::Classic, - :recursive => GitHub::Ldap::MemberSearch::Recursive, - :active_directory => GitHub::Ldap::MemberSearch::ActiveDirectory - } - end - end -end diff --git a/lib/github/ldap/member_search/detect.rb b/lib/github/ldap/member_search/detect.rb deleted file mode 100644 index 06cdb32..0000000 --- a/lib/github/ldap/member_search/detect.rb +++ /dev/null @@ -1,71 +0,0 @@ -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/lib/github/ldap/membership_validators.rb b/lib/github/ldap/membership_validators.rb index 1135a2d..c629a37 100644 --- a/lib/github/ldap/membership_validators.rb +++ b/lib/github/ldap/membership_validators.rb @@ -1,26 +1,4 @@ require 'github/ldap/membership_validators/base' -require 'github/ldap/membership_validators/detect' require 'github/ldap/membership_validators/classic' require 'github/ldap/membership_validators/recursive' require 'github/ldap/membership_validators/active_directory' - -module GitHub - class Ldap - # Provides various strategies for validating membership. - # - # For example: - # - # groups = domain.groups(%w(Engineering)) - # validator = GitHub::Ldap::MembershipValidators::Classic.new(ldap, groups) - # validator.perform(entry) #=> true - # - module MembershipValidators - # Internal: Mapping of strategy name to class. - STRATEGIES = { - :classic => GitHub::Ldap::MembershipValidators::Classic, - :recursive => GitHub::Ldap::MembershipValidators::Recursive, - :active_directory => GitHub::Ldap::MembershipValidators::ActiveDirectory - } - end - end -end diff --git a/lib/github/ldap/membership_validators/detect.rb b/lib/github/ldap/membership_validators/detect.rb deleted file mode 100644 index 74f7f0d..0000000 --- a/lib/github/ldap/membership_validators/detect.rb +++ /dev/null @@ -1,53 +0,0 @@ -module GitHub - class Ldap - module MembershipValidators - # Detects the LDAP host's capabilities and determines the appropriate - # membership validation strategy at runtime. Currently detects for - # ActiveDirectory in-chain membership validation. An explicit strategy can - # also be defined via `GitHub::Ldap#membership_validator=`. See also - # `GitHub::Ldap#configure_membership_validation_strategy`. - class Detect < Base - # 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 - return true if groups.empty? - - strategy.perform(entry) - end - - # Internal: Returns the membership validation strategy object. - def strategy - @strategy ||= begin - strategy = detect_strategy - strategy.new(ldap, groups) - end - end - - # Internal: Detects LDAP host's capabilities and chooses the best - # strategy for the host. - # - # If the strategy has been set explicitly, skips detection and uses the - # configured strategy instead. - # - # Returns the strategy class. - def detect_strategy - case - when GitHub::Ldap::MembershipValidators::STRATEGIES.key?(strategy_config) - GitHub::Ldap::MembershipValidators::STRATEGIES[strategy_config] - when active_directory_capability? - GitHub::Ldap::MembershipValidators::STRATEGIES[:active_directory] - else - GitHub::Ldap::MembershipValidators::STRATEGIES[:recursive] - end - end - - # Internal: Returns the configured membership validator strategy Symbol. - def strategy_config - ldap.membership_validator - end - end - end - end -end From d7b83cd312ce817ccb2c6a3aa5fd650085415e55 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Fri, 5 Dec 2014 15:01:32 -0800 Subject: [PATCH 3/5] Capabilities module was removed --- lib/github/ldap.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index d9c547c..8c46cd1 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -8,7 +8,6 @@ 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' From 42ffdb659cdff72d6e61817ac93ecb62e78359b8 Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Fri, 5 Dec 2014 18:45:22 -0800 Subject: [PATCH 4/5] Test search strategy config, detection, defaults --- test/ldap_test.rb | 45 +++++++++++++------- test/member_search/detect_test.rb | 42 ------------------- test/membership_validators/detect_test.rb | 50 ----------------------- 3 files changed, 31 insertions(+), 106 deletions(-) delete mode 100644 test/member_search/detect_test.rb delete mode 100644 test/membership_validators/detect_test.rb diff --git a/test/ldap_test.rb b/test/ldap_test.rb index 6d4d5fb..48511d8 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -73,28 +73,45 @@ def test_instruments_search assert_equal "dc=github,dc=com", payload[:base] end - def test_membership_validator_default - assert_equal :detect, @ldap.membership_validator + def test_search_strategy_defaults + assert_equal GitHub::Ldap::MembershipValidators::Recursive, @ldap.membership_validator + assert_equal GitHub::Ldap::MemberSearch::Recursive, @ldap.member_search_strategy end - def test_membership_validator_configured_to_classic_strategy - @ldap.configure_membership_validation_strategy :classic - assert_equal :classic, @ldap.membership_validator + def test_search_strategy_detects_active_directory + caps = Net::LDAP::Entry.new + caps[:supportedcapabilities] = [GitHub::Ldap::ACTIVE_DIRECTORY_V61_R2_OID] + + @ldap.stub :capabilities, caps do + @ldap.configure_search_strategy :detect + + assert_equal GitHub::Ldap::MembershipValidators::ActiveDirectory, @ldap.membership_validator + assert_equal GitHub::Ldap::MemberSearch::ActiveDirectory, @ldap.member_search_strategy + end + end + + def test_search_strategy_configured_to_classic + @ldap.configure_search_strategy :classic + assert_equal GitHub::Ldap::MembershipValidators::Classic, @ldap.membership_validator + assert_equal GitHub::Ldap::MemberSearch::Classic, @ldap.member_search_strategy end - def test_membership_validator_configured_to_recursive_strategy - @ldap.configure_membership_validation_strategy :recursive - assert_equal :recursive, @ldap.membership_validator + def test_search_strategy_configured_to_recursive + @ldap.configure_search_strategy :recursive + assert_equal GitHub::Ldap::MembershipValidators::Recursive, @ldap.membership_validator + assert_equal GitHub::Ldap::MemberSearch::Recursive, @ldap.member_search_strategy end - def test_membership_validator_configured_to_active_directory_strategy - @ldap.configure_membership_validation_strategy :active_directory - assert_equal :active_directory, @ldap.membership_validator + def test_search_strategy_configured_to_active_directory + @ldap.configure_search_strategy :active_directory + assert_equal GitHub::Ldap::MembershipValidators::ActiveDirectory, @ldap.membership_validator + assert_equal GitHub::Ldap::MemberSearch::ActiveDirectory, @ldap.member_search_strategy end - def test_membership_validator_misconfigured_to_unrecognized_strategy_falls_back_to_default - @ldap.configure_membership_validation_strategy :unknown - assert_equal :detect, @ldap.membership_validator + def test_search_strategy_misconfigured_to_unrecognized_strategy_falls_back_to_default + @ldap.configure_search_strategy :unknown + assert_equal GitHub::Ldap::MembershipValidators::Recursive, @ldap.membership_validator + assert_equal GitHub::Ldap::MemberSearch::Recursive, @ldap.member_search_strategy end def test_capabilities diff --git a/test/member_search/detect_test.rb b/test/member_search/detect_test.rb deleted file mode 100644 index 6092cdf..0000000 --- a/test/member_search/detect_test.rb +++ /dev/null @@ -1,42 +0,0 @@ -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 diff --git a/test/membership_validators/detect_test.rb b/test/membership_validators/detect_test.rb deleted file mode 100644 index 34d476a..0000000 --- a/test/membership_validators/detect_test.rb +++ /dev/null @@ -1,50 +0,0 @@ -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 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") - @entry = @domain.user?('user1') - @validator = GitHub::Ldap::MembershipValidators::Detect - end - - def make_validator(groups) - groups = @domain.groups(groups) - @validator.new(@ldap, groups) - end - - def test_defers_to_configured_strategy - @ldap.configure_membership_validation_strategy(:classic) - validator = make_validator(%w(group)) - - assert_kind_of GitHub::Ldap::MembershipValidators::Classic, validator.strategy - end - - def test_detects_active_directory - caps = Net::LDAP::Entry.new - caps[:supportedcapabilities] = [ACTIVE_DIRECTORY_V61_R2_OID] - - validator = make_validator(%w(group)) - @ldap.stub :capabilities, caps do - assert_kind_of GitHub::Ldap::MembershipValidators::ActiveDirectory, - validator.strategy - end - end - - def test_falls_back_to_recursive - caps = Net::LDAP::Entry.new - caps[:supportedcapabilities] = [] - - validator = make_validator(%w(group)) - @ldap.stub :capabilities, caps do - assert_kind_of GitHub::Ldap::MembershipValidators::Recursive, - validator.strategy - end - end -end From a62ca6c716ab73e5e6dae96bf21d02bc1e289bba Mon Sep 17 00:00:00 2001 From: Matt Todd Date: Fri, 5 Dec 2014 19:00:31 -0800 Subject: [PATCH 5/5] Fix config method doco --- lib/github/ldap.rb | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 8c46cd1..ebdfddc 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -258,11 +258,8 @@ def configure_search_strategy(strategy = nil) # Internal: Configure the membership validation strategy. # - # Used by GitHub::Ldap::MembershipValidators::Detect to force a specific - # strategy (instead of detecting 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. + # If no known strategy is provided, detects ActiveDirectory capabilities or + # falls back to the Recursive strategy by default. # # Returns the membership validator strategy Class. def configure_membership_validation_strategy(strategy = nil) @@ -286,13 +283,11 @@ def configure_membership_validation_strategy(strategy = nil) # 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. + # If no known strategy is provided, detects ActiveDirectory capabilities or + # falls back to the Recursive strategy by default. # - # Returns the selected strategy Symbol. + # Returns the selected strategy Class. def configure_member_search_strategy(strategy = nil) @member_search_strategy = case strategy.to_s