From 090e02fe60d022ed9b38e985754adc1f6f02ee40 Mon Sep 17 00:00:00 2001 From: Jesse Sanford Date: Fri, 17 Jan 2014 15:43:13 -0800 Subject: added default that match openssh ssh_config defaults --- lib/net/ssh/authentication/session.rb | 2 +- lib/net/ssh/config.rb | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/net/ssh/authentication/session.rb b/lib/net/ssh/authentication/session.rb index b8650d5..c63bf41 100644 --- a/lib/net/ssh/authentication/session.rb +++ b/lib/net/ssh/authentication/session.rb @@ -42,7 +42,7 @@ module Net; module SSH; module Authentication self.logger = transport.logger @transport = transport - @auth_methods = options[:auth_methods] || %w(none publickey hostbased password keyboard-interactive) + @auth_methods = options[:auth_methods] || Net::SSH::Config.default_auth_methods @options = options @allowed_auth_methods = @auth_methods diff --git a/lib/net/ssh/config.rb b/lib/net/ssh/config.rb index b0acf30..27c69ff 100644 --- a/lib/net/ssh/config.rb +++ b/lib/net/ssh/config.rb @@ -35,12 +35,17 @@ module Net; module SSH class Config class << self @@default_files = %w(~/.ssh/config /etc/ssh_config /etc/ssh/ssh_config) + @@default_auth_methods = %w(none publickey hostbased password keyboard-interactive) # Returns an array of locations of OpenSSH configuration files # to parse by default. def default_files @@default_files end + + def default_auth_methods + @@default_auth_methods + end # Loads the configuration data for the given +host+ from all of the # given +files+ (defaulting to the list of files returned by @@ -56,7 +61,7 @@ module Net; module SSH # ones. Returns a hash containing the OpenSSH options. (See # #translate for how to convert the OpenSSH options into Net::SSH # options.) - def load(path, host, settings={}) + def load(path, host, settings={:auth_methods=>default_auth_methods}) file = File.expand_path(path) return settings unless File.readable?(file) @@ -138,7 +143,6 @@ module Net; module SSH hash[:global_known_hosts_file] = value when 'hostbasedauthentication' then if value - hash[:auth_methods] ||= [] hash[:auth_methods] << "hostbased" end when 'hostkeyalgorithms' then @@ -152,9 +156,8 @@ module Net; module SSH when 'macs' then hash[:hmac] = value.split(/,/) when 'passwordauthentication' - if value - hash[:auth_methods] ||= [] - hash[:auth_methods] << "password" + unless value + hash[:auth_methods] = hash[:auth_methods].delete('password') end when 'port' hash[:port] = value @@ -165,10 +168,9 @@ module Net; module SSH require 'net/ssh/proxy/command' hash[:proxy] = Net::SSH::Proxy::Command.new(value) end - when 'pubkeyauthentication' - if value - hash[:auth_methods] ||= [] - hash[:auth_methods] << "publickey" + when 'pubkeyauthentication' + unless value + hash[:auth_methods] = hash[:auth_methods].delete('publickey') end when 'rekeylimit' hash[:rekey_limit] = interpret_size(value) -- cgit v1.2.1 From 7e29297a33423f1301ee6511e4b6c9073d528c63 Mon Sep 17 00:00:00 2001 From: Jesse Sanford Date: Fri, 17 Jan 2014 15:55:18 -0800 Subject: added commenting --- lib/net/ssh/config.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/net/ssh/config.rb b/lib/net/ssh/config.rb index 27c69ff..22f81ed 100644 --- a/lib/net/ssh/config.rb +++ b/lib/net/ssh/config.rb @@ -35,7 +35,11 @@ module Net; module SSH class Config class << self @@default_files = %w(~/.ssh/config /etc/ssh_config /etc/ssh/ssh_config) - @@default_auth_methods = %w(none publickey hostbased password keyboard-interactive) + # The following defaults follow the openssh client ssh_config defaults. + # http://lwn.net/Articles/544640/ + # "hostbased" is off and "none" is not supported but we allow it since + # it's used by some clients to query the server for allowed auth methods + @@default_auth_methods = %w(none publickey password keyboard-interactive) # Returns an array of locations of OpenSSH configuration files # to parse by default. @@ -61,7 +65,9 @@ module Net; module SSH # ones. Returns a hash containing the OpenSSH options. (See # #translate for how to convert the OpenSSH options into Net::SSH # options.) - def load(path, host, settings={:auth_methods=>default_auth_methods}) + def load(path, host, settings) + settings[:auth_methods] ||= default_auth_methods + file = File.expand_path(path) return settings unless File.readable?(file) -- cgit v1.2.1 From 2f27a580add330ecac22b8e9d168a1400972e244 Mon Sep 17 00:00:00 2001 From: Jesse Sanford Date: Fri, 17 Jan 2014 16:39:02 -0800 Subject: fixed issue with array munging --- lib/net/ssh/config.rb | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/net/ssh/config.rb b/lib/net/ssh/config.rb index 22f81ed..0a2e76e 100644 --- a/lib/net/ssh/config.rb +++ b/lib/net/ssh/config.rb @@ -56,7 +56,11 @@ module Net; module SSH # #default_files), translates the resulting hash into the options # recognized by Net::SSH, and returns them. def for(host, files=default_files) - translate(files.inject({}) { |settings, file| load(file, host, settings) }) + hash = translate(files.inject({}) { |settings, file| + load(file, host, settings) + }) + puts "FINAL AUTH METHODS: #{hash[:auth_methods]}" + return hash end # Load the OpenSSH configuration settings in the given +file+ for the @@ -129,7 +133,11 @@ module Net; module SSH # +settings+ hash must have Strings for keys, all downcased, and # the returned hash will have Symbols for keys. def translate(settings) + puts "SETTINGS AUTH METHODS: #{settings[:auth_methods]}" + settings.inject({}) do |hash, (key, value)| + hash[:auth_methods] ||= settings[:auth_methods] + puts "CONSIDERING AUTH METHODS: #{hash[:auth_methods]}" case key when 'bindaddress' then hash[:bind_address] = value @@ -163,7 +171,7 @@ module Net; module SSH hash[:hmac] = value.split(/,/) when 'passwordauthentication' unless value - hash[:auth_methods] = hash[:auth_methods].delete('password') + hash[:auth_methods].delete('password') end when 'port' hash[:port] = value @@ -176,7 +184,7 @@ module Net; module SSH end when 'pubkeyauthentication' unless value - hash[:auth_methods] = hash[:auth_methods].delete('publickey') + hash[:auth_methods].delete('publickey') end when 'rekeylimit' hash[:rekey_limit] = interpret_size(value) -- cgit v1.2.1 From 82e6cd36e1ac8efa7f17190ee974da882ab996b0 Mon Sep 17 00:00:00 2001 From: Jesse Sanford Date: Sat, 18 Jan 2014 09:21:17 -0800 Subject: removed debug messages --- lib/net/ssh/config.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/net/ssh/config.rb b/lib/net/ssh/config.rb index 0a2e76e..821b574 100644 --- a/lib/net/ssh/config.rb +++ b/lib/net/ssh/config.rb @@ -59,8 +59,6 @@ module Net; module SSH hash = translate(files.inject({}) { |settings, file| load(file, host, settings) }) - puts "FINAL AUTH METHODS: #{hash[:auth_methods]}" - return hash end # Load the OpenSSH configuration settings in the given +file+ for the @@ -133,11 +131,8 @@ module Net; module SSH # +settings+ hash must have Strings for keys, all downcased, and # the returned hash will have Symbols for keys. def translate(settings) - puts "SETTINGS AUTH METHODS: #{settings[:auth_methods]}" - settings.inject({}) do |hash, (key, value)| hash[:auth_methods] ||= settings[:auth_methods] - puts "CONSIDERING AUTH METHODS: #{hash[:auth_methods]}" case key when 'bindaddress' then hash[:bind_address] = value -- cgit v1.2.1 From 404e795f470099789d144f593cd0be2cf3ecfd0a Mon Sep 17 00:00:00 2001 From: Jesse Sanford Date: Tue, 21 Jan 2014 15:01:00 -0800 Subject: updated tests to match the default of not allowing hostbased auth --- test/authentication/test_session.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/authentication/test_session.rb b/test/authentication/test_session.rb index ab233da..0cd9727 100644 --- a/test/authentication/test_session.rb +++ b/test/authentication/test_session.rb @@ -8,7 +8,7 @@ module Authentication include Net::SSH::Authentication::Constants def test_constructor_should_set_defaults - assert_equal %w(none publickey hostbased password keyboard-interactive), session.auth_methods + assert_equal %w(none publickey password keyboard-interactive), session.auth_methods assert_equal session.auth_methods, session.allowed_auth_methods end @@ -44,7 +44,6 @@ module Authentication end Net::SSH::Authentication::Methods::Publickey.any_instance.expects(:authenticate).with("next service", "username", "password").returns(false) - Net::SSH::Authentication::Methods::Hostbased.any_instance.expects(:authenticate).with("next service", "username", "password").returns(false) Net::SSH::Authentication::Methods::Password.any_instance.expects(:authenticate).with("next service", "username", "password").returns(false) Net::SSH::Authentication::Methods::KeyboardInteractive.any_instance.expects(:authenticate).with("next service", "username", "password").returns(false) Net::SSH::Authentication::Methods::None.any_instance.expects(:authenticate).with("next service", "username", "password").returns(false) -- cgit v1.2.1 From 45a2b0cc17936c4cc593c8e5df5c4ca603b6730a Mon Sep 17 00:00:00 2001 From: liggitt Date: Wed, 29 Jan 2014 16:32:41 -0500 Subject: Restore empty hash behavior for loading nonexistent files Let auth methods be added or removed, and ensure there are no duplicates Clone default auth methods to avoid modifying defaults Add support for ChallengeResponseAuthentication keyboard-interactive --- lib/net/ssh/config.rb | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/lib/net/ssh/config.rb b/lib/net/ssh/config.rb index 821b574..fab681b 100644 --- a/lib/net/ssh/config.rb +++ b/lib/net/ssh/config.rb @@ -8,6 +8,7 @@ module Net; module SSH # # Only a subset of OpenSSH configuration options are understood: # + # * ChallengeResponseAuthentication => maps to the :auth_methods option # * Ciphers => maps to the :encryption option # * Compression => :compression # * CompressionLevel => :compression_level @@ -25,6 +26,7 @@ module Net; module SSH # * Port => :port # * PreferredAuthentications => maps to the :auth_methods option # * ProxyCommand => maps to the :proxy option + # * PubKeyAuthentication => maps to the :auth_methods option # * RekeyLimit => :rekey_limit # * User => :user # * UserKnownHostsFile => :user_known_hosts_file @@ -67,11 +69,11 @@ module Net; module SSH # ones. Returns a hash containing the OpenSSH options. (See # #translate for how to convert the OpenSSH options into Net::SSH # options.) - def load(path, host, settings) - settings[:auth_methods] ||= default_auth_methods - + def load(path, host, settings={}) file = File.expand_path(path) return settings unless File.readable?(file) + + settings[:auth_methods] ||= default_auth_methods.clone globals = {} matched_host = nil @@ -132,7 +134,7 @@ module Net; module SSH # the returned hash will have Symbols for keys. def translate(settings) settings.inject({}) do |hash, (key, value)| - hash[:auth_methods] ||= settings[:auth_methods] + hash[:auth_methods] ||= settings[:auth_methods] || default_auth_methods.clone case key when 'bindaddress' then hash[:bind_address] = value @@ -152,7 +154,9 @@ module Net; module SSH hash[:global_known_hosts_file] = value when 'hostbasedauthentication' then if value - hash[:auth_methods] << "hostbased" + (hash[:auth_methods] << "hostbased").uniq! + else + hash[:auth_methods].delete("hostbased") end when 'hostkeyalgorithms' then hash[:host_key] = value.split(/,/) @@ -165,9 +169,17 @@ module Net; module SSH when 'macs' then hash[:hmac] = value.split(/,/) when 'passwordauthentication' - unless value + if value + (hash[:auth_methods] << 'password').uniq! + else hash[:auth_methods].delete('password') end + when 'challengeresponseauthentication' + if value + (hash[:auth_methods] << 'keyboard-interactive').uniq! + else + hash[:auth_methods].delete('keyboard-interactive') + end when 'port' hash[:port] = value when 'preferredauthentications' @@ -178,7 +190,9 @@ module Net; module SSH hash[:proxy] = Net::SSH::Proxy::Command.new(value) end when 'pubkeyauthentication' - unless value + if value + (hash[:auth_methods] << 'publickey').uniq! + else hash[:auth_methods].delete('publickey') end when 'rekeylimit' -- cgit v1.2.1 From 523d4d66ed34624b24a085cc44629eab9e157183 Mon Sep 17 00:00:00 2001 From: liggitt Date: Wed, 29 Jan 2014 16:34:31 -0500 Subject: Fix session test to work with new default auth_methods --- test/authentication/test_session.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/authentication/test_session.rb b/test/authentication/test_session.rb index 0cd9727..ab29640 100644 --- a/test/authentication/test_session.rb +++ b/test/authentication/test_session.rb @@ -20,7 +20,7 @@ module Authentication end Net::SSH::Authentication::Methods::Publickey.any_instance.expects(:authenticate).with("next service", "username", "password").raises(Net::SSH::Authentication::DisallowedMethod) - Net::SSH::Authentication::Methods::Hostbased.any_instance.expects(:authenticate).with("next service", "username", "password").returns(true) + Net::SSH::Authentication::Methods::Password.any_instance.expects(:authenticate).with("next service", "username", "password").returns(true) Net::SSH::Authentication::Methods::None.any_instance.expects(:authenticate).with("next service", "username", "password").returns(false) assert session.authenticate("next service", "username", "password") -- cgit v1.2.1 From b22e8db93dc7b8b88c6f5343b0abcfcaf663daa5 Mon Sep 17 00:00:00 2001 From: liggitt Date: Wed, 29 Jan 2014 16:35:09 -0500 Subject: Add config tests for auth parsing --- test/configs/auth_off | 4 ++++ test/configs/auth_on | 4 ++++ test/configs/empty | 0 test/test_config.rb | 38 +++++++++++++++++++++++++++++++++++++- 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 test/configs/auth_off create mode 100644 test/configs/auth_on create mode 100644 test/configs/empty diff --git a/test/configs/auth_off b/test/configs/auth_off new file mode 100644 index 0000000..6b1b6ef --- /dev/null +++ b/test/configs/auth_off @@ -0,0 +1,4 @@ +HostBasedAuthentication no +PasswordAuthentication no +PubKeyAuthentication no +ChallengeResponseAuthentication no \ No newline at end of file diff --git a/test/configs/auth_on b/test/configs/auth_on new file mode 100644 index 0000000..97d20bc --- /dev/null +++ b/test/configs/auth_on @@ -0,0 +1,4 @@ +HostBasedAuthentication yes +PasswordAuthentication yes +PubKeyAuthentication yes +ChallengeResponseAuthentication yes \ No newline at end of file diff --git a/test/configs/empty b/test/configs/empty new file mode 100644 index 0000000..e69de29 diff --git a/test/test_config.rb b/test/test_config.rb index e9961ad..cb462de 100644 --- a/test/test_config.rb +++ b/test/test_config.rb @@ -97,7 +97,7 @@ class TestConfig < Test::Unit::TestCase assert_equal 6, net_ssh[:compression_level] assert_equal 100, net_ssh[:timeout] assert_equal true, net_ssh[:forward_agent] - assert_equal %w(hostbased password publickey), net_ssh[:auth_methods].sort + assert_equal %w(hostbased keyboard-interactive none password publickey), net_ssh[:auth_methods].sort assert_equal %w(d e f), net_ssh[:host_key] assert_equal %w(g h i), net_ssh[:keys] assert_equal %w(j k l), net_ssh[:hmac] @@ -106,6 +106,42 @@ class TestConfig < Test::Unit::TestCase assert_equal "127.0.0.1", net_ssh[:bind_address] assert_equal [/^LC_.*$/], net_ssh[:send_env] end + + def test_translate_should_turn_off_authentication_methods + open_ssh = { + 'hostbasedauthentication' => false, + 'passwordauthentication' => false, + 'pubkeyauthentication' => false, + 'challengeresponseauthentication' => false + } + + net_ssh = Net::SSH::Config.translate(open_ssh) + + assert_equal %w(none), net_ssh[:auth_methods].sort + end + + def test_translate_should_turn_on_authentication_methods + open_ssh = { + 'hostbasedauthentication' => true, + 'passwordauthentication' => true, + 'pubkeyauthentication' => true, + 'challengeresponseauthentication' => true + } + + net_ssh = Net::SSH::Config.translate(open_ssh) + + assert_equal %w(hostbased keyboard-interactive none password publickey), net_ssh[:auth_methods].sort + end + + def test_for_should_turn_off_authentication_methods + config = Net::SSH::Config.for("test.host", [config(:empty), config(:auth_off), config(:auth_on)]) + assert_equal %w(none), config[:auth_methods].sort + end + + def test_for_should_turn_on_authentication_methods + config = Net::SSH::Config.for("test.host", [config(:empty), config(:auth_on), config(:auth_off)]) + assert_equal %w(hostbased keyboard-interactive none password publickey), config[:auth_methods].sort + end def test_load_with_plus_sign_hosts config = Net::SSH::Config.load(config(:host_plus), "test.host") -- cgit v1.2.1