diff options
author | Delano Mandelbaum <delano@solutious.com> | 2014-09-30 17:18:39 -0700 |
---|---|---|
committer | Delano Mandelbaum <delano@solutious.com> | 2014-09-30 17:18:39 -0700 |
commit | 25ac6987c922c462af0611f2e570f2c971879143 (patch) | |
tree | 745cc27f9f23d2d1498c695fb7eb25c46df357e0 | |
parent | 2c10a94e81d9f6f0cbf38c8e8c023d5ece9e334b (diff) | |
parent | 85c91e87dd5a1c34cf34f381274e26df02b91c79 (diff) | |
download | net-ssh-25ac6987c922c462af0611f2e570f2c971879143.tar.gz |
Merge pull request #187 from mfazekas/password_auth_ask
Password auth will ask for password up to number_of_password_prompts tim...
-rw-r--r-- | lib/net/ssh/authentication/methods/password.rb | 45 | ||||
-rw-r--r-- | lib/net/ssh/config.rb | 3 | ||||
-rw-r--r-- | test/authentication/methods/test_password.rb | 43 | ||||
-rw-r--r-- | test/test_config.rb | 4 |
4 files changed, 84 insertions, 11 deletions
diff --git a/lib/net/ssh/authentication/methods/password.rb b/lib/net/ssh/authentication/methods/password.rb index ad1eed7..6c4f174 100644 --- a/lib/net/ssh/authentication/methods/password.rb +++ b/lib/net/ssh/authentication/methods/password.rb @@ -1,4 +1,5 @@ require 'net/ssh/errors' +require 'net/ssh/prompt' require 'net/ssh/authentication/methods/abstract' module Net @@ -8,25 +9,36 @@ module Net # Implements the "password" SSH authentication method. class Password < Abstract + include Prompt + # Attempt to authenticate the given user for the given service. If - # the password parameter is nil, this will never do anything except - # return false. + # the password parameter is nil, this will ask for password def authenticate(next_service, username, password=nil) - return false unless password + retries = 0 + max_retries = get_max_retries + return false if !password && max_retries == 0 - send_message(userauth_request(username, next_service, "password", false, password)) - message = session.next_message + begin + password_to_send = password || ask_password(username) - case message.type - when USERAUTH_SUCCESS - debug { "password succeeded" } - return true - when USERAUTH_FAILURE + send_message(userauth_request(username, next_service, "password", false, password_to_send)) + message = session.next_message + retries += 1 + + if message.type == USERAUTH_FAILURE debug { "password failed" } raise Net::SSH::Authentication::DisallowedMethod unless message[:authentications].split(/,/).include? 'password' + password = nil + end + end until (message.type != USERAUTH_FAILURE || retries >= max_retries) + case message.type + when USERAUTH_SUCCESS + debug { "password succeeded" } + return true + when USERAUTH_FAILURE return false when USERAUTH_PASSWD_CHANGEREQ debug { "password change request received, failing" } @@ -35,6 +47,19 @@ module Net raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})" end end + + private + + NUMBER_OF_PASSWORD_PROMPTS = 3 + + def ask_password(username) + echo = false + prompt("#{username}@#{session.transport.host}'s password:", echo) + end + + def get_max_retries + (session.transport.options||{})[:number_of_password_prompts] || NUMBER_OF_PASSWORD_PROMPTS + end end end diff --git a/lib/net/ssh/config.rb b/lib/net/ssh/config.rb index e2590a9..0622472 100644 --- a/lib/net/ssh/config.rb +++ b/lib/net/ssh/config.rb @@ -31,6 +31,7 @@ module Net; module SSH # * RekeyLimit => :rekey_limit # * User => :user # * UserKnownHostsFile => :user_known_hosts_file + # * NumberOfPasswordPrompts => :number_of_password_prompts # # Note that you will never need to use this class directly--you can control # whether the OpenSSH configuration files are read by passing the :config @@ -219,6 +220,8 @@ module Net; module SSH when 'sendenv' multi_send_env = value.to_s.split(/\s+/) hash[:send_env] = multi_send_env.map { |e| Regexp.new pattern2regex(e).source, false } + when 'numberofpasswordprompts' + hash[:number_of_password_prompts] = value.to_i end hash end diff --git a/test/authentication/methods/test_password.rb b/test/authentication/methods/test_password.rb index 4ba8207..3448b5a 100644 --- a/test/authentication/methods/test_password.rb +++ b/test/authentication/methods/test_password.rb @@ -1,7 +1,9 @@ require 'common' require 'net/ssh/authentication/methods/password' +require 'net/ssh/authentication/session' require 'authentication/methods/common' + module Authentication; module Methods class TestPassword < Test::Unit::TestCase @@ -24,6 +26,47 @@ module Authentication; module Methods end end + def test_authenticate_ask_for_password_for_second_time_when_password_is_incorrect + transport.expect do |t,packet| + assert_equal USERAUTH_REQUEST, packet.type + assert_equal "jamis", packet.read_string + assert_equal "ssh-connection", packet.read_string + assert_equal "password", packet.read_string + assert_equal false, packet.read_bool + assert_equal "the-password", packet.read_string + t.return(USERAUTH_FAILURE, :string, "publickey,password") + + t.expect do |t2, packet2| + assert_equal USERAUTH_REQUEST, packet2.type + assert_equal "jamis", packet2.read_string + assert_equal "ssh-connection", packet2.read_string + assert_equal "password", packet2.read_string + assert_equal false, packet2.read_bool + assert_equal "the-password-2", packet2.read_string + t.return(USERAUTH_SUCCESS) + end + end + + subject.expects(:prompt).with("jamis@'s password:", false).returns("the-password-2") + subject.authenticate("ssh-connection", "jamis", "the-password") + end + + def test_authenticate_ask_for_password_if_not_given + transport.expect do |t,packet| + assert_equal USERAUTH_REQUEST, packet.type + assert_equal "bill", packet.read_string + assert_equal "ssh-connection", packet.read_string + assert_equal "password", packet.read_string + assert_equal false, packet.read_bool + assert_equal "good-password", packet.read_string + t.return(USERAUTH_SUCCESS) + end + + transport.instance_eval { @host='testhost' } + subject.expects(:prompt).with("bill@testhost's password:", false).returns("good-password") + subject.authenticate("ssh-connection", "bill", nil) + end + def test_authenticate_when_password_is_acceptible_should_return_true transport.expect do |t,packet| assert_equal USERAUTH_REQUEST, packet.type diff --git a/test/test_config.rb b/test/test_config.rb index 623281e..9b3eeb8 100644 --- a/test/test_config.rb +++ b/test/test_config.rb @@ -93,7 +93,8 @@ class TestConfig < Test::Unit::TestCase 'port' => 1234, 'pubkeyauthentication' => true, 'rekeylimit' => 1024, - 'sendenv' => "LC_*" + 'sendenv' => "LC_*", + 'numberofpasswordprompts' => '123' } net_ssh = Net::SSH::Config.translate(open_ssh) @@ -111,6 +112,7 @@ class TestConfig < Test::Unit::TestCase assert_equal 1024, net_ssh[:rekey_limit] assert_equal "127.0.0.1", net_ssh[:bind_address] assert_equal [/^LC_.*$/], net_ssh[:send_env] + assert_equal 123, net_ssh[:number_of_password_prompts] end def test_translate_should_turn_off_authentication_methods |