diff options
| -rw-r--r-- | CHANGELOG.rdoc | 6 | ||||
| -rw-r--r-- | lib/net/ssh.rb | 1 | ||||
| -rw-r--r-- | lib/net/ssh/authentication/key_manager.rb | 2 | ||||
| -rw-r--r-- | lib/net/ssh/authentication/methods/hostbased.rb | 4 | ||||
| -rw-r--r-- | lib/net/ssh/authentication/methods/keyboard_interactive.rb | 4 | ||||
| -rw-r--r-- | lib/net/ssh/authentication/methods/password.rb | 4 | ||||
| -rw-r--r-- | lib/net/ssh/authentication/methods/publickey.rb | 4 | ||||
| -rw-r--r-- | lib/net/ssh/authentication/session.rb | 19 | ||||
| -rw-r--r-- | test/authentication/methods/test_keyboard_interactive.rb | 10 | ||||
| -rw-r--r-- | test/authentication/methods/test_password.rb | 6 | ||||
| -rw-r--r-- | test/authentication/methods/test_publickey.rb | 25 | ||||
| -rw-r--r-- | test/authentication/test_key_manager.rb | 18 | ||||
| -rw-r--r-- | test/authentication/test_session.rb | 13 |
13 files changed, 97 insertions, 19 deletions
diff --git a/CHANGELOG.rdoc b/CHANGELOG.rdoc index 2a18292..5a87cda 100644 --- a/CHANGELOG.rdoc +++ b/CHANGELOG.rdoc @@ -1,4 +1,10 @@ +=== 2.1.1 / 1 Mar 2011 + +* Fix for Net::SSH Continues to attempt authentication when notified it is not allowed [Eric Hodel] + (see: http://net-ssh.lighthouseapp.com/projects/36253-net-ssh/tickets/26) +* Fix for transport won't be closed if authentication fails [Patrick Marchi] + === 2.1 / 19 Jan 2011 diff --git a/lib/net/ssh.rb b/lib/net/ssh.rb index acc23a7..9f03a98 100644 --- a/lib/net/ssh.rb +++ b/lib/net/ssh.rb @@ -193,6 +193,7 @@ module Net return connection end else + transport.closed raise AuthenticationFailed, user end end diff --git a/lib/net/ssh/authentication/key_manager.rb b/lib/net/ssh/authentication/key_manager.rb index c96e18c..7a0692f 100644 --- a/lib/net/ssh/authentication/key_manager.rb +++ b/lib/net/ssh/authentication/key_manager.rb @@ -135,7 +135,7 @@ module Net if info[:key].nil? && info[:from] == :file begin info[:key] = KeyFactory.load_private_key(info[:file], options[:passphrase]) - rescue Exception => e + rescue Exception, OpenSSL::OpenSSLError => e raise KeyManagerError, "the given identity is known, but the private key could not be loaded: #{e.class} (#{e.message})" end end diff --git a/lib/net/ssh/authentication/methods/hostbased.rb b/lib/net/ssh/authentication/methods/hostbased.rb index 43c3eac..610b64e 100644 --- a/lib/net/ssh/authentication/methods/hostbased.rb +++ b/lib/net/ssh/authentication/methods/hostbased.rb @@ -51,6 +51,10 @@ module Net return true when USERAUTH_FAILURE info { "hostbased failed (#{identity.fingerprint})" } + + raise Net::SSH::Authentication::DisallowedMethod unless + message[:authentications].split(/,/).include? 'hostbased' + return false else raise Net::SSH::Exception, "unexpected server response to USERAUTH_REQUEST: #{message.type} (#{message.inspect})" diff --git a/lib/net/ssh/authentication/methods/keyboard_interactive.rb b/lib/net/ssh/authentication/methods/keyboard_interactive.rb index 1ab2459..bf17e4d 100644 --- a/lib/net/ssh/authentication/methods/keyboard_interactive.rb +++ b/lib/net/ssh/authentication/methods/keyboard_interactive.rb @@ -27,6 +27,10 @@ module Net return true when USERAUTH_FAILURE debug { "keyboard-interactive failed" } + + raise Net::SSH::Authentication::DisallowedMethod unless + message[:authentications].split(/,/).include? 'keyboard-interactive' + return false when USERAUTH_INFO_REQUEST name = message.read_string diff --git a/lib/net/ssh/authentication/methods/password.rb b/lib/net/ssh/authentication/methods/password.rb index 9b1c095..ad1eed7 100644 --- a/lib/net/ssh/authentication/methods/password.rb +++ b/lib/net/ssh/authentication/methods/password.rb @@ -23,6 +23,10 @@ module Net return true when USERAUTH_FAILURE debug { "password failed" } + + raise Net::SSH::Authentication::DisallowedMethod unless + message[:authentications].split(/,/).include? 'password' + return false when USERAUTH_PASSWD_CHANGEREQ debug { "password change request received, failing" } diff --git a/lib/net/ssh/authentication/methods/publickey.rb b/lib/net/ssh/authentication/methods/publickey.rb index b453def..d06af5c 100644 --- a/lib/net/ssh/authentication/methods/publickey.rb +++ b/lib/net/ssh/authentication/methods/publickey.rb @@ -70,6 +70,10 @@ module Net return true when USERAUTH_FAILURE debug { "publickey failed (#{identity.fingerprint})" } + + raise Net::SSH::Authentication::DisallowedMethod unless + message[:authentications].split(/,/).include? 'publickey' + return false else raise Net::SSH::Exception, diff --git a/lib/net/ssh/authentication/session.rb b/lib/net/ssh/authentication/session.rb index 8e7d3df..180ae46 100644 --- a/lib/net/ssh/authentication/session.rb +++ b/lib/net/ssh/authentication/session.rb @@ -9,6 +9,10 @@ require 'net/ssh/authentication/methods/keyboard_interactive' module Net; module SSH; module Authentication + # Raised if the current authentication method is not allowed + class DisallowedMethod < Net::SSH::Exception + end + # Represents an authentication session. It manages the authentication of # a user over an established connection (the "transport" object, see # Net::SSH::Transport::Session). @@ -59,13 +63,16 @@ module Net; module SSH; module Authentication attempted = [] @auth_methods.each do |name| - next unless @allowed_auth_methods.include?(name) - attempted << name + begin + next unless @allowed_auth_methods.include?(name) + attempted << name - debug { "trying #{name}" } - method = Methods.const_get(name.split(/\W+/).map { |p| p.capitalize }.join).new(self, :key_manager => key_manager) + debug { "trying #{name}" } + method = Methods.const_get(name.split(/\W+/).map { |p| p.capitalize }.join).new(self, :key_manager => key_manager) - return true if method.authenticate(next_service, username, password) + return true if method.authenticate(next_service, username, password) + rescue Net::SSH::Authentication::DisallowedMethod + end end error { "all authorization methods failed (tried #{attempted.join(', ')})" } @@ -131,4 +138,4 @@ module Net; module SSH; module Authentication Array(options[:key_data]) end end -end; end; end
\ No newline at end of file +end; end; end diff --git a/test/authentication/methods/test_keyboard_interactive.rb b/test/authentication/methods/test_keyboard_interactive.rb index b092263..2ea1a15 100644 --- a/test/authentication/methods/test_keyboard_interactive.rb +++ b/test/authentication/methods/test_keyboard_interactive.rb @@ -10,7 +10,7 @@ module Authentication; module Methods USERAUTH_INFO_REQUEST = 60 USERAUTH_INFO_RESPONSE = 61 - def test_authenticate_should_be_false_when_server_does_not_support_this_method + def test_authenticate_should_raise_if_keyboard_interactive_disallowed transport.expect do |t,packet| assert_equal USERAUTH_REQUEST, packet.type assert_equal "jamis", packet.read_string @@ -22,7 +22,9 @@ module Authentication; module Methods t.return(USERAUTH_FAILURE, :string, "password") end - assert_equal false, subject.authenticate("ssh-connection", "jamis") + assert_raises Net::SSH::Authentication::DisallowedMethod do + subject.authenticate("ssh-connection", "jamis") + end end def test_authenticate_should_be_false_if_given_password_is_not_accepted @@ -33,7 +35,7 @@ module Authentication; module Methods assert_equal USERAUTH_INFO_RESPONSE, packet2.type assert_equal 1, packet2.read_long assert_equal "the-password", packet2.read_string - t2.return(USERAUTH_FAILURE, :string, "publickey") + t2.return(USERAUTH_FAILURE, :string, "keyboard-interactive") end end @@ -95,4 +97,4 @@ module Authentication; module Methods end end -end; end
\ No newline at end of file +end; end diff --git a/test/authentication/methods/test_password.rb b/test/authentication/methods/test_password.rb index 52f4196..4ba8207 100644 --- a/test/authentication/methods/test_password.rb +++ b/test/authentication/methods/test_password.rb @@ -7,7 +7,7 @@ module Authentication; module Methods class TestPassword < Test::Unit::TestCase include Common - def test_authenticate_when_password_is_unacceptible_should_return_false + def test_authenticate_should_raise_if_password_disallowed transport.expect do |t,packet| assert_equal USERAUTH_REQUEST, packet.type assert_equal "jamis", packet.read_string @@ -19,7 +19,9 @@ module Authentication; module Methods t.return(USERAUTH_FAILURE, :string, "publickey") end - assert !subject.authenticate("ssh-connection", "jamis", "the-password") + assert_raises Net::SSH::Authentication::DisallowedMethod do + subject.authenticate("ssh-connection", "jamis", "the-password") + end end def test_authenticate_when_password_is_acceptible_should_return_true diff --git a/test/authentication/methods/test_publickey.rb b/test/authentication/methods/test_publickey.rb index 94d7e3e..b475cf2 100644 --- a/test/authentication/methods/test_publickey.rb +++ b/test/authentication/methods/test_publickey.rb @@ -31,6 +31,27 @@ module Authentication; module Methods assert_equal false, subject.authenticate("ssh-connection", "jamis") end + def test_authenticate_should_raise_if_publickey_disallowed + key_manager.expects(:sign).with(&signature_parameters(keys.first)).returns("sig-one") + + transport.expect do |t, packet| + assert_equal USERAUTH_REQUEST, packet.type + assert verify_userauth_request_packet(packet, keys.first, false) + t.return(USERAUTH_PK_OK, :string, keys.first.ssh_type, :string, Net::SSH::Buffer.from(:key, keys.first)) + + t.expect do |t2,packet2| + assert_equal USERAUTH_REQUEST, packet2.type + assert verify_userauth_request_packet(packet2, keys.first, true) + assert_equal "sig-one", packet2.read_string + t2.return(USERAUTH_FAILURE, :string, "hostbased,password") + end + end + + assert_raises Net::SSH::Authentication::DisallowedMethod do + subject.authenticate("ssh-connection", "jamis") + end + end + def test_authenticate_should_return_false_if_signature_exchange_fails key_manager.expects(:sign).with(&signature_parameters(keys.first)).returns("sig-one") key_manager.expects(:sign).with(&signature_parameters(keys.last)).returns("sig-two") @@ -44,7 +65,7 @@ module Authentication; module Methods assert_equal USERAUTH_REQUEST, packet2.type assert verify_userauth_request_packet(packet2, keys.first, true) assert_equal "sig-one", packet2.read_string - t2.return(USERAUTH_FAILURE, :string, "hostbased,password") + t2.return(USERAUTH_FAILURE, :string, "publickey") t2.expect do |t3, packet3| assert_equal USERAUTH_REQUEST, packet3.type @@ -55,7 +76,7 @@ module Authentication; module Methods assert_equal USERAUTH_REQUEST, packet4.type assert verify_userauth_request_packet(packet4, keys.last, true) assert_equal "sig-two", packet4.read_string - t4.return(USERAUTH_FAILURE, :string, "hostbased,password") + t4.return(USERAUTH_FAILURE, :string, "publickey") end end end diff --git a/test/authentication/test_key_manager.rb b/test/authentication/test_key_manager.rb index ad171ac..3e8c9b0 100644 --- a/test/authentication/test_key_manager.rb +++ b/test/authentication/test_key_manager.rb @@ -32,7 +32,7 @@ module Authentication manager.stubs(:agent).returns(nil) stub_file_key "/first", rsa - stub_file_key "/second", dsa + stub_file_key "/second", dsa identities = [] manager.each_identity { |identity| identities << identity } @@ -40,7 +40,7 @@ module Authentication assert_equal 2, identities.length assert_equal rsa.to_blob, identities.first.to_blob assert_equal dsa.to_blob, identities.last.to_blob - + assert_equal({:from => :file, :file => "/first", :key => rsa}, manager.known_identities[rsa]) assert_equal({:from => :file, :file => "/second", :key => dsa}, manager.known_identities[dsa]) end @@ -82,15 +82,25 @@ module Authentication def test_sign_with_file_originated_key_should_load_private_key_and_sign_with_it manager.stubs(:agent).returns(nil) - stub_file_key "/first", rsa(512), true + stub_file_key "/first", rsa(512) rsa.expects(:ssh_do_sign).with("hello, world").returns("abcxyz123") manager.each_identity { |identity| } # preload the known_identities assert_equal "\0\0\0\assh-rsa\0\0\0\011abcxyz123", manager.sign(rsa, "hello, world") end + def test_sign_with_file_originated_key_should_raise_key_manager_error_if_unloadable + manager.known_identities[rsa] = { :from => :file, :file => "/first" } + + Net::SSH::KeyFactory.expects(:load_private_key).raises(OpenSSL::PKey::RSAError) + + assert_raises Net::SSH::Authentication::KeyManagerError do + manager.sign(rsa, "hello, world") + end + end + private - def stub_file_key(name, key, also_private=false) + def stub_file_key(name, key) manager.add(name) File.expects(:readable?).with(name).returns(true) File.expects(:readable?).with(name + ".pub").returns(false) diff --git a/test/authentication/test_session.rb b/test/authentication/test_session.rb index 4cc9bd5..46145fa 100644 --- a/test/authentication/test_session.rb +++ b/test/authentication/test_session.rb @@ -12,6 +12,19 @@ module Authentication assert_equal session.auth_methods, session.allowed_auth_methods end + def test_authenticate_should_continue_if_method_disallowed + transport.expect do |t, packet| + assert_equal SERVICE_REQUEST, packet.type + assert_equal "ssh-userauth", packet.read_string + t.return(SERVICE_ACCEPT) + 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) + + assert session.authenticate("next service", "username", "password") + end + def test_authenticate_should_raise_error_if_service_request_fails transport.expect do |t, packet| assert_equal SERVICE_REQUEST, packet.type |
