sonixlabs-net-ssh 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.rdoc +262 -0
- data/Manifest +121 -0
- data/README.rdoc +184 -0
- data/Rakefile +86 -0
- data/Rudyfile +96 -0
- data/THANKS.rdoc +19 -0
- data/lib/net/ssh.rb +223 -0
- data/lib/net/ssh/authentication/agent.rb +179 -0
- data/lib/net/ssh/authentication/constants.rb +18 -0
- data/lib/net/ssh/authentication/key_manager.rb +253 -0
- data/lib/net/ssh/authentication/methods/abstract.rb +60 -0
- data/lib/net/ssh/authentication/methods/hostbased.rb +75 -0
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +70 -0
- data/lib/net/ssh/authentication/methods/password.rb +43 -0
- data/lib/net/ssh/authentication/methods/publickey.rb +96 -0
- data/lib/net/ssh/authentication/pageant.rb +264 -0
- data/lib/net/ssh/authentication/session.rb +146 -0
- data/lib/net/ssh/buffer.rb +340 -0
- data/lib/net/ssh/buffered_io.rb +198 -0
- data/lib/net/ssh/config.rb +207 -0
- data/lib/net/ssh/connection/channel.rb +630 -0
- data/lib/net/ssh/connection/constants.rb +33 -0
- data/lib/net/ssh/connection/session.rb +597 -0
- data/lib/net/ssh/connection/term.rb +178 -0
- data/lib/net/ssh/errors.rb +88 -0
- data/lib/net/ssh/key_factory.rb +102 -0
- data/lib/net/ssh/known_hosts.rb +129 -0
- data/lib/net/ssh/loggable.rb +61 -0
- data/lib/net/ssh/packet.rb +102 -0
- data/lib/net/ssh/prompt.rb +93 -0
- data/lib/net/ssh/proxy/command.rb +75 -0
- data/lib/net/ssh/proxy/errors.rb +14 -0
- data/lib/net/ssh/proxy/http.rb +94 -0
- data/lib/net/ssh/proxy/socks4.rb +70 -0
- data/lib/net/ssh/proxy/socks5.rb +142 -0
- data/lib/net/ssh/ruby_compat.rb +43 -0
- data/lib/net/ssh/service/forward.rb +298 -0
- data/lib/net/ssh/test.rb +89 -0
- data/lib/net/ssh/test/channel.rb +129 -0
- data/lib/net/ssh/test/extensions.rb +152 -0
- data/lib/net/ssh/test/kex.rb +44 -0
- data/lib/net/ssh/test/local_packet.rb +51 -0
- data/lib/net/ssh/test/packet.rb +81 -0
- data/lib/net/ssh/test/remote_packet.rb +38 -0
- data/lib/net/ssh/test/script.rb +157 -0
- data/lib/net/ssh/test/socket.rb +64 -0
- data/lib/net/ssh/transport/algorithms.rb +386 -0
- data/lib/net/ssh/transport/cipher_factory.rb +79 -0
- data/lib/net/ssh/transport/constants.rb +30 -0
- data/lib/net/ssh/transport/hmac.rb +42 -0
- data/lib/net/ssh/transport/hmac/abstract.rb +79 -0
- data/lib/net/ssh/transport/hmac/md5.rb +12 -0
- data/lib/net/ssh/transport/hmac/md5_96.rb +11 -0
- data/lib/net/ssh/transport/hmac/none.rb +15 -0
- data/lib/net/ssh/transport/hmac/sha1.rb +13 -0
- data/lib/net/ssh/transport/hmac/sha1_96.rb +11 -0
- data/lib/net/ssh/transport/hmac/sha2_256.rb +15 -0
- data/lib/net/ssh/transport/hmac/sha2_256_96.rb +13 -0
- data/lib/net/ssh/transport/hmac/sha2_512.rb +14 -0
- data/lib/net/ssh/transport/hmac/sha2_512_96.rb +13 -0
- data/lib/net/ssh/transport/identity_cipher.rb +55 -0
- data/lib/net/ssh/transport/kex.rb +17 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +208 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +80 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +15 -0
- data/lib/net/ssh/transport/key_expander.rb +26 -0
- data/lib/net/ssh/transport/openssl.rb +127 -0
- data/lib/net/ssh/transport/packet_stream.rb +235 -0
- data/lib/net/ssh/transport/server_version.rb +71 -0
- data/lib/net/ssh/transport/session.rb +278 -0
- data/lib/net/ssh/transport/state.rb +206 -0
- data/lib/net/ssh/verifiers/lenient.rb +30 -0
- data/lib/net/ssh/verifiers/null.rb +12 -0
- data/lib/net/ssh/verifiers/strict.rb +53 -0
- data/lib/net/ssh/version.rb +62 -0
- data/lib/sonixlabs-net-ssh.rb +1 -0
- data/net-ssh.gemspec +145 -0
- data/setup.rb +1585 -0
- data/support/arcfour_check.rb +20 -0
- data/support/ssh_tunnel_bug.rb +65 -0
- data/test/authentication/methods/common.rb +28 -0
- data/test/authentication/methods/test_abstract.rb +51 -0
- data/test/authentication/methods/test_hostbased.rb +114 -0
- data/test/authentication/methods/test_keyboard_interactive.rb +100 -0
- data/test/authentication/methods/test_password.rb +52 -0
- data/test/authentication/methods/test_publickey.rb +148 -0
- data/test/authentication/test_agent.rb +205 -0
- data/test/authentication/test_key_manager.rb +171 -0
- data/test/authentication/test_session.rb +106 -0
- data/test/common.rb +107 -0
- data/test/configs/eqsign +3 -0
- data/test/configs/exact_match +8 -0
- data/test/configs/host_plus +10 -0
- data/test/configs/multihost +4 -0
- data/test/configs/wild_cards +14 -0
- data/test/connection/test_channel.rb +467 -0
- data/test/connection/test_session.rb +488 -0
- data/test/test_all.rb +9 -0
- data/test/test_buffer.rb +336 -0
- data/test/test_buffered_io.rb +63 -0
- data/test/test_config.rb +120 -0
- data/test/test_key_factory.rb +79 -0
- data/test/transport/hmac/test_md5.rb +39 -0
- data/test/transport/hmac/test_md5_96.rb +25 -0
- data/test/transport/hmac/test_none.rb +34 -0
- data/test/transport/hmac/test_sha1.rb +34 -0
- data/test/transport/hmac/test_sha1_96.rb +25 -0
- data/test/transport/hmac/test_sha2_256.rb +35 -0
- data/test/transport/hmac/test_sha2_256_96.rb +25 -0
- data/test/transport/hmac/test_sha2_512.rb +35 -0
- data/test/transport/hmac/test_sha2_512_96.rb +25 -0
- data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +146 -0
- data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +92 -0
- data/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb +33 -0
- data/test/transport/test_algorithms.rb +308 -0
- data/test/transport/test_cipher_factory.rb +213 -0
- data/test/transport/test_hmac.rb +34 -0
- data/test/transport/test_identity_cipher.rb +40 -0
- data/test/transport/test_packet_stream.rb +736 -0
- data/test/transport/test_server_version.rb +78 -0
- data/test/transport/test_session.rb +315 -0
- data/test/transport/test_state.rb +179 -0
- metadata +178 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
|
|
2
|
+
require 'net/ssh'
|
|
3
|
+
|
|
4
|
+
# ARCFOUR CHECK
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# $ ruby support/arcfour_check.rb
|
|
8
|
+
#
|
|
9
|
+
# Expected Output:
|
|
10
|
+
# arcfour128: [16, 8] OpenSSL::Cipher::Cipher
|
|
11
|
+
# arcfour256: [32, 8] OpenSSL::Cipher::Cipher
|
|
12
|
+
# arcfour512: [64, 8] OpenSSL::Cipher::Cipher
|
|
13
|
+
|
|
14
|
+
[['arcfour128', 16], ['arcfour256', 32], ['arcfour512', 64]].each do |cipher|
|
|
15
|
+
print "#{cipher[0]}: "
|
|
16
|
+
a = Net::SSH::Transport::CipherFactory.get_lengths(cipher[0])
|
|
17
|
+
b = Net::SSH::Transport::CipherFactory.get(cipher[0], :key => ([].fill('x', 0, cipher[1]).join))
|
|
18
|
+
puts "#{a} #{b.class}"
|
|
19
|
+
end
|
|
20
|
+
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/ruby
|
|
2
|
+
|
|
3
|
+
# SSH TUNNEL CONNECTION BUG
|
|
4
|
+
# from: http://net-ssh.lighthouseapp.com/projects/36253/tickets/7-an-existing-connection-was-forcibly-closed-by-the-remote-host#ticket-7-3
|
|
5
|
+
#
|
|
6
|
+
# Steps to reproduce:
|
|
7
|
+
#
|
|
8
|
+
# * Start HTTP Proxy
|
|
9
|
+
# * If running debian in EC2:
|
|
10
|
+
# * apt-get install squid
|
|
11
|
+
# * Add the following to /etc/squid/squid.conf:
|
|
12
|
+
# acl localnet src 1.2.3.0/255.255.255.0
|
|
13
|
+
# http_access allow localnet
|
|
14
|
+
# icp_access allow localnet
|
|
15
|
+
# visible_hostname netsshtest
|
|
16
|
+
# * Start squid squid -N -d 1 -D
|
|
17
|
+
# * Run this script
|
|
18
|
+
# * Configure browser proxy to use localhost with LOCAL_PORT.
|
|
19
|
+
# * Load any page, wait for it to load fully. If the page loads
|
|
20
|
+
# correctly, move on. If not, something needs to be corrected.
|
|
21
|
+
# * Refresh the page several times. This should cause this
|
|
22
|
+
# script to failed with the error: "closed stream". You may
|
|
23
|
+
# need to try a few times.
|
|
24
|
+
#
|
|
25
|
+
|
|
26
|
+
require 'highline/import'
|
|
27
|
+
require 'net/ssh'
|
|
28
|
+
|
|
29
|
+
LOCAL_PORT = 8080
|
|
30
|
+
PROXY_PORT = 3128
|
|
31
|
+
|
|
32
|
+
host, user = *ARGV
|
|
33
|
+
abort "Usage: #{$0} host user" unless ARGV.size == 2
|
|
34
|
+
|
|
35
|
+
puts "Connecting to #{user}@#{host}..."
|
|
36
|
+
pass = ask("Password: ") { |q| q.echo = "*" }
|
|
37
|
+
puts "Configure your browser proxy to localhost:#{LOCAL_PORT}"
|
|
38
|
+
|
|
39
|
+
begin
|
|
40
|
+
session = Net::SSH.start(host, user, :password => pass)
|
|
41
|
+
session.forward.local(LOCAL_PORT, host, PROXY_PORT)
|
|
42
|
+
session.loop{true}
|
|
43
|
+
rescue => e
|
|
44
|
+
puts e.message
|
|
45
|
+
puts e.backtrace
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
__END__
|
|
50
|
+
|
|
51
|
+
$ ruby support/ssh_tunnel.rb host user
|
|
52
|
+
Connecting to user@host...
|
|
53
|
+
Password: ******
|
|
54
|
+
Configure your browser proxy to localhost:8080
|
|
55
|
+
closed stream
|
|
56
|
+
/usr/local/lib/ruby/gems/1.9.1/gems/net-ssh-2.0.15/lib/net/ssh/buffered_io.rb:99:in `send'
|
|
57
|
+
/usr/local/lib/ruby/gems/1.9.1/gems/net-ssh-2.0.15/lib/net/ssh/buffered_io.rb:99:in `send_pending'
|
|
58
|
+
/usr/local/lib/ruby/gems/1.9.1/gems/net-ssh-2.0.15/lib/net/ssh/connection/session.rb:236:in `block in postprocess'
|
|
59
|
+
/usr/local/lib/ruby/gems/1.9.1/gems/net-ssh-2.0.15/lib/net/ssh/connection/session.rb:235:in `each'
|
|
60
|
+
/usr/local/lib/ruby/gems/1.9.1/gems/net-ssh-2.0.15/lib/net/ssh/connection/session.rb:235:in `postprocess'
|
|
61
|
+
/usr/local/lib/ruby/gems/1.9.1/gems/net-ssh-2.0.15/lib/net/ssh/connection/session.rb:203:in `process'
|
|
62
|
+
/usr/local/lib/ruby/gems/1.9.1/gems/net-ssh-2.0.15/lib/net/ssh/connection/session.rb:161:in `block in loop'
|
|
63
|
+
/usr/local/lib/ruby/gems/1.9.1/gems/net-ssh-2.0.15/lib/net/ssh/connection/session.rb:161:in `loop'
|
|
64
|
+
/usr/local/lib/ruby/gems/1.9.1/gems/net-ssh-2.0.15/lib/net/ssh/connection/session.rb:161:in `loop'
|
|
65
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Authentication; module Methods
|
|
2
|
+
|
|
3
|
+
module Common
|
|
4
|
+
include Net::SSH::Authentication::Constants
|
|
5
|
+
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def socket(options={})
|
|
9
|
+
@socket ||= stub("socket", :client_name => "me.ssh.test")
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def transport(options={})
|
|
13
|
+
@transport ||= MockTransport.new(options.merge(:socket => socket))
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def session(options={})
|
|
17
|
+
@session ||= begin
|
|
18
|
+
sess = stub("auth-session", :logger => nil, :transport => transport(options))
|
|
19
|
+
def sess.next_message
|
|
20
|
+
transport.next_message
|
|
21
|
+
end
|
|
22
|
+
sess
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end; end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require 'common'
|
|
2
|
+
require 'authentication/methods/common'
|
|
3
|
+
require 'net/ssh/authentication/methods/abstract'
|
|
4
|
+
|
|
5
|
+
module Authentication; module Methods
|
|
6
|
+
|
|
7
|
+
class TestAbstract < Test::Unit::TestCase
|
|
8
|
+
include Common
|
|
9
|
+
|
|
10
|
+
def test_constructor_should_set_defaults
|
|
11
|
+
assert_nil subject.key_manager
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_constructor_should_honor_options
|
|
15
|
+
assert_equal :manager, subject(:key_manager => :manager).key_manager
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def test_session_id_should_query_session_id_from_key_exchange
|
|
19
|
+
transport.stubs(:algorithms).returns(stub("algorithms", :session_id => "abcxyz123"))
|
|
20
|
+
assert_equal "abcxyz123", subject.session_id
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_send_message_should_delegate_to_transport
|
|
24
|
+
transport.expects(:send_message).with("abcxyz123")
|
|
25
|
+
subject.send_message("abcxyz123")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def test_userauth_request_should_build_well_formed_userauth_packet
|
|
29
|
+
packet = subject.userauth_request("jamis", "ssh-connection", "password")
|
|
30
|
+
assert_equal "\062\0\0\0\005jamis\0\0\0\016ssh-connection\0\0\0\010password", packet.to_s
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_userauth_request_should_translate_extra_booleans_onto_end
|
|
34
|
+
packet = subject.userauth_request("jamis", "ssh-connection", "password", true, false)
|
|
35
|
+
assert_equal "\062\0\0\0\005jamis\0\0\0\016ssh-connection\0\0\0\010password\1\0", packet.to_s
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def test_userauth_request_should_translate_extra_strings_onto_end
|
|
39
|
+
packet = subject.userauth_request("jamis", "ssh-connection", "password", "foo", "bar")
|
|
40
|
+
assert_equal "\062\0\0\0\005jamis\0\0\0\016ssh-connection\0\0\0\010password\0\0\0\3foo\0\0\0\3bar", packet.to_s
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def subject(options={})
|
|
46
|
+
@subject ||= Net::SSH::Authentication::Methods::Abstract.new(session(options), options)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end; end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
require 'common'
|
|
2
|
+
require 'net/ssh/authentication/methods/hostbased'
|
|
3
|
+
require 'authentication/methods/common'
|
|
4
|
+
|
|
5
|
+
module Authentication; module Methods
|
|
6
|
+
|
|
7
|
+
class TestHostbased < Test::Unit::TestCase
|
|
8
|
+
include Common
|
|
9
|
+
|
|
10
|
+
def test_authenticate_should_return_false_when_no_key_manager_has_been_set
|
|
11
|
+
assert_equal false, subject(:key_manager => nil).authenticate("ssh-connection", "jamis")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_authenticate_should_return_false_when_key_manager_has_no_keys
|
|
15
|
+
assert_equal false, subject(:keys => []).authenticate("ssh-connection", "jamis")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def test_authenticate_should_return_false_if_no_keys_can_authenticate
|
|
19
|
+
ENV.stubs(:[]).with('USER').returns(nil)
|
|
20
|
+
key_manager.expects(:sign).with(&signature_parameters(keys.first)).returns("sig-one")
|
|
21
|
+
key_manager.expects(:sign).with(&signature_parameters(keys.last)).returns("sig-two")
|
|
22
|
+
|
|
23
|
+
transport.expect do |t, packet|
|
|
24
|
+
assert_equal USERAUTH_REQUEST, packet.type
|
|
25
|
+
assert verify_userauth_request_packet(packet, keys.first)
|
|
26
|
+
assert_equal "sig-one", packet.read_string
|
|
27
|
+
t.return(USERAUTH_FAILURE, :string, "hostbased,password")
|
|
28
|
+
|
|
29
|
+
t.expect do |t2, packet2|
|
|
30
|
+
assert_equal USERAUTH_REQUEST, packet2.type
|
|
31
|
+
assert verify_userauth_request_packet(packet2, keys.last)
|
|
32
|
+
assert_equal "sig-two", packet2.read_string
|
|
33
|
+
t2.return(USERAUTH_FAILURE, :string, "hostbased,password")
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
assert_equal false, subject.authenticate("ssh-connection", "jamis")
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def test_authenticate_should_return_true_if_any_key_can_authenticate
|
|
41
|
+
ENV.stubs(:[]).with('USER').returns(nil)
|
|
42
|
+
key_manager.expects(:sign).with(&signature_parameters(keys.first)).returns("sig-one")
|
|
43
|
+
|
|
44
|
+
transport.expect do |t, packet|
|
|
45
|
+
assert_equal USERAUTH_REQUEST, packet.type
|
|
46
|
+
assert verify_userauth_request_packet(packet, keys.first)
|
|
47
|
+
assert_equal "sig-one", packet.read_string
|
|
48
|
+
t.return(USERAUTH_SUCCESS)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
assert subject.authenticate("ssh-connection", "jamis")
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
def signature_parameters(key)
|
|
57
|
+
Proc.new do |given_key, data|
|
|
58
|
+
next false unless given_key.to_blob == key.to_blob
|
|
59
|
+
buffer = Net::SSH::Buffer.new(data)
|
|
60
|
+
buffer.read_string == "abcxyz123" && # session-id
|
|
61
|
+
buffer.read_byte == USERAUTH_REQUEST && # type
|
|
62
|
+
verify_userauth_request_packet(buffer, key)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def verify_userauth_request_packet(packet, key)
|
|
67
|
+
packet.read_string == "jamis" && # user-name
|
|
68
|
+
packet.read_string == "ssh-connection" && # next service
|
|
69
|
+
packet.read_string == "hostbased" && # auth-method
|
|
70
|
+
packet.read_string == key.ssh_type && # key type
|
|
71
|
+
packet.read_buffer.read_key.to_blob == key.to_blob && # key
|
|
72
|
+
packet.read_string == "me.ssh.test." && # client hostname
|
|
73
|
+
packet.read_string == "jamis" # client username
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
@@keys = nil
|
|
77
|
+
def keys
|
|
78
|
+
@@keys ||= [OpenSSL::PKey::RSA.new(512), OpenSSL::PKey::DSA.new(512)]
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def key_manager(options={})
|
|
82
|
+
@key_manager ||= begin
|
|
83
|
+
manager = stub("key_manager")
|
|
84
|
+
manager.stubs(:each_identity).multiple_yields(*(options[:keys] || keys))
|
|
85
|
+
manager
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def subject(options={})
|
|
90
|
+
options[:key_manager] = key_manager(options) unless options.key?(:key_manager)
|
|
91
|
+
@subject ||= Net::SSH::Authentication::Methods::Hostbased.new(session(options), options)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def socket(options={})
|
|
95
|
+
@socket ||= stub("socket", :client_name => "me.ssh.test")
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def transport(options={})
|
|
99
|
+
@transport ||= MockTransport.new(options.merge(:socket => socket))
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def session(options={})
|
|
103
|
+
@session ||= begin
|
|
104
|
+
sess = stub("auth-session", :logger => nil, :transport => transport(options))
|
|
105
|
+
def sess.next_message
|
|
106
|
+
transport.next_message
|
|
107
|
+
end
|
|
108
|
+
sess
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
end; end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
require 'common'
|
|
2
|
+
require 'net/ssh/authentication/methods/keyboard_interactive'
|
|
3
|
+
require 'authentication/methods/common'
|
|
4
|
+
|
|
5
|
+
module Authentication; module Methods
|
|
6
|
+
|
|
7
|
+
class TestKeyboardInteractive < Test::Unit::TestCase
|
|
8
|
+
include Common
|
|
9
|
+
|
|
10
|
+
USERAUTH_INFO_REQUEST = 60
|
|
11
|
+
USERAUTH_INFO_RESPONSE = 61
|
|
12
|
+
|
|
13
|
+
def test_authenticate_should_raise_if_keyboard_interactive_disallowed
|
|
14
|
+
transport.expect do |t,packet|
|
|
15
|
+
assert_equal USERAUTH_REQUEST, packet.type
|
|
16
|
+
assert_equal "jamis", packet.read_string
|
|
17
|
+
assert_equal "ssh-connection", packet.read_string
|
|
18
|
+
assert_equal "keyboard-interactive", packet.read_string
|
|
19
|
+
assert_equal "", packet.read_string # language tags
|
|
20
|
+
assert_equal "", packet.read_string # submethods
|
|
21
|
+
|
|
22
|
+
t.return(USERAUTH_FAILURE, :string, "password")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
assert_raises Net::SSH::Authentication::DisallowedMethod do
|
|
26
|
+
subject.authenticate("ssh-connection", "jamis")
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_authenticate_should_be_false_if_given_password_is_not_accepted
|
|
31
|
+
transport.expect do |t,packet|
|
|
32
|
+
assert_equal USERAUTH_REQUEST, packet.type
|
|
33
|
+
t.return(USERAUTH_INFO_REQUEST, :string, "", :string, "", :string, "", :long, 1, :string, "Password:", :bool, false)
|
|
34
|
+
t.expect do |t2,packet2|
|
|
35
|
+
assert_equal USERAUTH_INFO_RESPONSE, packet2.type
|
|
36
|
+
assert_equal 1, packet2.read_long
|
|
37
|
+
assert_equal "the-password", packet2.read_string
|
|
38
|
+
t2.return(USERAUTH_FAILURE, :string, "keyboard-interactive")
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
assert_equal false, subject.authenticate("ssh-connection", "jamis", "the-password")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def test_authenticate_should_be_true_if_given_password_is_accepted
|
|
46
|
+
transport.expect do |t,packet|
|
|
47
|
+
assert_equal USERAUTH_REQUEST, packet.type
|
|
48
|
+
t.return(USERAUTH_INFO_REQUEST, :string, "", :string, "", :string, "", :long, 1, :string, "Password:", :bool, false)
|
|
49
|
+
t.expect do |t2,packet2|
|
|
50
|
+
assert_equal USERAUTH_INFO_RESPONSE, packet2.type
|
|
51
|
+
t2.return(USERAUTH_SUCCESS)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
assert subject.authenticate("ssh-connection", "jamis", "the-password")
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def test_authenticate_should_duplicate_password_as_needed_to_fill_request
|
|
59
|
+
transport.expect do |t,packet|
|
|
60
|
+
assert_equal USERAUTH_REQUEST, packet.type
|
|
61
|
+
t.return(USERAUTH_INFO_REQUEST, :string, "", :string, "", :string, "", :long, 2, :string, "Password:", :bool, false, :string, "Again:", :bool, false)
|
|
62
|
+
t.expect do |t2,packet2|
|
|
63
|
+
assert_equal USERAUTH_INFO_RESPONSE, packet2.type
|
|
64
|
+
assert_equal 2, packet2.read_long
|
|
65
|
+
assert_equal "the-password", packet2.read_string
|
|
66
|
+
assert_equal "the-password", packet2.read_string
|
|
67
|
+
t2.return(USERAUTH_SUCCESS)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
assert subject.authenticate("ssh-connection", "jamis", "the-password")
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def test_authenticate_should_prompt_for_input_when_password_is_not_given
|
|
75
|
+
subject.expects(:prompt).with("Name:", true).returns("name")
|
|
76
|
+
subject.expects(:prompt).with("Password:", false).returns("password")
|
|
77
|
+
|
|
78
|
+
transport.expect do |t,packet|
|
|
79
|
+
assert_equal USERAUTH_REQUEST, packet.type
|
|
80
|
+
t.return(USERAUTH_INFO_REQUEST, :string, "", :string, "", :string, "", :long, 2, :string, "Name:", :bool, true, :string, "Password:", :bool, false)
|
|
81
|
+
t.expect do |t2,packet2|
|
|
82
|
+
assert_equal USERAUTH_INFO_RESPONSE, packet2.type
|
|
83
|
+
assert_equal 2, packet2.read_long
|
|
84
|
+
assert_equal "name", packet2.read_string
|
|
85
|
+
assert_equal "password", packet2.read_string
|
|
86
|
+
t2.return(USERAUTH_SUCCESS)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
assert subject.authenticate("ssh-connection", "jamis", nil)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
|
|
95
|
+
def subject(options={})
|
|
96
|
+
@subject ||= Net::SSH::Authentication::Methods::KeyboardInteractive.new(session(options), options)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
end; end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
require 'common'
|
|
2
|
+
require 'net/ssh/authentication/methods/password'
|
|
3
|
+
require 'authentication/methods/common'
|
|
4
|
+
|
|
5
|
+
module Authentication; module Methods
|
|
6
|
+
|
|
7
|
+
class TestPassword < Test::Unit::TestCase
|
|
8
|
+
include Common
|
|
9
|
+
|
|
10
|
+
def test_authenticate_should_raise_if_password_disallowed
|
|
11
|
+
transport.expect do |t,packet|
|
|
12
|
+
assert_equal USERAUTH_REQUEST, packet.type
|
|
13
|
+
assert_equal "jamis", packet.read_string
|
|
14
|
+
assert_equal "ssh-connection", packet.read_string
|
|
15
|
+
assert_equal "password", packet.read_string
|
|
16
|
+
assert_equal false, packet.read_bool
|
|
17
|
+
assert_equal "the-password", packet.read_string
|
|
18
|
+
|
|
19
|
+
t.return(USERAUTH_FAILURE, :string, "publickey")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
assert_raises Net::SSH::Authentication::DisallowedMethod do
|
|
23
|
+
subject.authenticate("ssh-connection", "jamis", "the-password")
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def test_authenticate_when_password_is_acceptible_should_return_true
|
|
28
|
+
transport.expect do |t,packet|
|
|
29
|
+
assert_equal USERAUTH_REQUEST, packet.type
|
|
30
|
+
t.return(USERAUTH_SUCCESS)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
assert subject.authenticate("ssh-connection", "jamis", "the-password")
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def test_authenticate_should_return_false_if_password_change_request_is_received
|
|
37
|
+
transport.expect do |t,packet|
|
|
38
|
+
assert_equal USERAUTH_REQUEST, packet.type
|
|
39
|
+
t.return(USERAUTH_PASSWD_CHANGEREQ, :string, "Change your password:", :string, "")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
assert !subject.authenticate("ssh-connection", "jamis", "the-password")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def subject(options={})
|
|
48
|
+
@subject ||= Net::SSH::Authentication::Methods::Password.new(session(options), options)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end; end
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
require 'common'
|
|
2
|
+
require 'net/ssh/authentication/methods/publickey'
|
|
3
|
+
require 'authentication/methods/common'
|
|
4
|
+
|
|
5
|
+
module Authentication; module Methods
|
|
6
|
+
|
|
7
|
+
class TestPublickey < Test::Unit::TestCase
|
|
8
|
+
include Common
|
|
9
|
+
|
|
10
|
+
def test_authenticate_should_return_false_when_no_key_manager_has_been_set
|
|
11
|
+
assert_equal false, subject(:key_manager => nil).authenticate("ssh-connection", "jamis")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_authenticate_should_return_false_when_key_manager_has_no_keys
|
|
15
|
+
assert_equal false, subject(:keys => []).authenticate("ssh-connection", "jamis")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def test_authenticate_should_return_false_if_no_keys_can_authenticate
|
|
19
|
+
transport.expect do |t, packet|
|
|
20
|
+
assert_equal USERAUTH_REQUEST, packet.type
|
|
21
|
+
assert verify_userauth_request_packet(packet, keys.first, false)
|
|
22
|
+
t.return(USERAUTH_FAILURE, :string, "hostbased,password")
|
|
23
|
+
|
|
24
|
+
t.expect do |t2, packet2|
|
|
25
|
+
assert_equal USERAUTH_REQUEST, packet2.type
|
|
26
|
+
assert verify_userauth_request_packet(packet2, keys.last, false)
|
|
27
|
+
t2.return(USERAUTH_FAILURE, :string, "hostbased,password")
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
assert_equal false, subject.authenticate("ssh-connection", "jamis")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def test_authenticate_should_raise_if_publickey_disallowed
|
|
35
|
+
key_manager.expects(:sign).with(&signature_parameters(keys.first)).returns("sig-one")
|
|
36
|
+
|
|
37
|
+
transport.expect do |t, packet|
|
|
38
|
+
assert_equal USERAUTH_REQUEST, packet.type
|
|
39
|
+
assert verify_userauth_request_packet(packet, keys.first, false)
|
|
40
|
+
t.return(USERAUTH_PK_OK, :string, keys.first.ssh_type, :string, Net::SSH::Buffer.from(:key, keys.first))
|
|
41
|
+
|
|
42
|
+
t.expect do |t2,packet2|
|
|
43
|
+
assert_equal USERAUTH_REQUEST, packet2.type
|
|
44
|
+
assert verify_userauth_request_packet(packet2, keys.first, true)
|
|
45
|
+
assert_equal "sig-one", packet2.read_string
|
|
46
|
+
t2.return(USERAUTH_FAILURE, :string, "hostbased,password")
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
assert_raises Net::SSH::Authentication::DisallowedMethod do
|
|
51
|
+
subject.authenticate("ssh-connection", "jamis")
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def test_authenticate_should_return_false_if_signature_exchange_fails
|
|
56
|
+
key_manager.expects(:sign).with(&signature_parameters(keys.first)).returns("sig-one")
|
|
57
|
+
key_manager.expects(:sign).with(&signature_parameters(keys.last)).returns("sig-two")
|
|
58
|
+
|
|
59
|
+
transport.expect do |t, packet|
|
|
60
|
+
assert_equal USERAUTH_REQUEST, packet.type
|
|
61
|
+
assert verify_userauth_request_packet(packet, keys.first, false)
|
|
62
|
+
t.return(USERAUTH_PK_OK, :string, keys.first.ssh_type, :string, Net::SSH::Buffer.from(:key, keys.first))
|
|
63
|
+
|
|
64
|
+
t.expect do |t2,packet2|
|
|
65
|
+
assert_equal USERAUTH_REQUEST, packet2.type
|
|
66
|
+
assert verify_userauth_request_packet(packet2, keys.first, true)
|
|
67
|
+
assert_equal "sig-one", packet2.read_string
|
|
68
|
+
t2.return(USERAUTH_FAILURE, :string, "publickey")
|
|
69
|
+
|
|
70
|
+
t2.expect do |t3, packet3|
|
|
71
|
+
assert_equal USERAUTH_REQUEST, packet3.type
|
|
72
|
+
assert verify_userauth_request_packet(packet3, keys.last, false)
|
|
73
|
+
t3.return(USERAUTH_PK_OK, :string, keys.last.ssh_type, :string, Net::SSH::Buffer.from(:key, keys.last))
|
|
74
|
+
|
|
75
|
+
t3.expect do |t4,packet4|
|
|
76
|
+
assert_equal USERAUTH_REQUEST, packet4.type
|
|
77
|
+
assert verify_userauth_request_packet(packet4, keys.last, true)
|
|
78
|
+
assert_equal "sig-two", packet4.read_string
|
|
79
|
+
t4.return(USERAUTH_FAILURE, :string, "publickey")
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
assert !subject.authenticate("ssh-connection", "jamis")
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def test_authenticate_should_return_true_if_any_key_can_authenticate
|
|
89
|
+
key_manager.expects(:sign).with(&signature_parameters(keys.first)).returns("sig-one")
|
|
90
|
+
|
|
91
|
+
transport.expect do |t, packet|
|
|
92
|
+
assert_equal USERAUTH_REQUEST, packet.type
|
|
93
|
+
assert verify_userauth_request_packet(packet, keys.first, false)
|
|
94
|
+
t.return(USERAUTH_PK_OK, :string, keys.first.ssh_type, :string, Net::SSH::Buffer.from(:key, keys.first))
|
|
95
|
+
|
|
96
|
+
t.expect do |t2,packet2|
|
|
97
|
+
assert_equal USERAUTH_REQUEST, packet2.type
|
|
98
|
+
assert verify_userauth_request_packet(packet2, keys.first, true)
|
|
99
|
+
assert_equal "sig-one", packet2.read_string
|
|
100
|
+
t2.return(USERAUTH_SUCCESS)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
assert subject.authenticate("ssh-connection", "jamis")
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
private
|
|
108
|
+
|
|
109
|
+
def signature_parameters(key)
|
|
110
|
+
Proc.new do |given_key, data|
|
|
111
|
+
next false unless given_key.to_blob == key.to_blob
|
|
112
|
+
buffer = Net::SSH::Buffer.new(data)
|
|
113
|
+
buffer.read_string == "abcxyz123" && # session-id
|
|
114
|
+
buffer.read_byte == USERAUTH_REQUEST && # type
|
|
115
|
+
verify_userauth_request_packet(buffer, key, true)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def verify_userauth_request_packet(packet, key, has_sig)
|
|
120
|
+
packet.read_string == "jamis" && # user-name
|
|
121
|
+
packet.read_string == "ssh-connection" && # next service
|
|
122
|
+
packet.read_string == "publickey" && # auth-method
|
|
123
|
+
packet.read_bool == has_sig && # whether a signature is appended
|
|
124
|
+
packet.read_string == key.ssh_type && # ssh key type
|
|
125
|
+
packet.read_buffer.read_key.to_blob == key.to_blob # key
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
@@keys = nil
|
|
129
|
+
def keys
|
|
130
|
+
@@keys ||= [OpenSSL::PKey::RSA.new(512), OpenSSL::PKey::DSA.new(512)]
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def key_manager(options={})
|
|
134
|
+
@key_manager ||= begin
|
|
135
|
+
manager = stub("key_manager")
|
|
136
|
+
manager.stubs(:each_identity).multiple_yields(*(options[:keys] || keys))
|
|
137
|
+
manager
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def subject(options={})
|
|
142
|
+
options[:key_manager] = key_manager(options) unless options.key?(:key_manager)
|
|
143
|
+
@subject ||= Net::SSH::Authentication::Methods::Publickey.new(session(options), options)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
end; end
|