ddollar-net-ssh 2.0.1
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 +42 -0
- data/Manifest +101 -0
- data/README.rdoc +110 -0
- data/Rakefile +26 -0
- data/THANKS.rdoc +16 -0
- data/lib/net/ssh.rb +199 -0
- data/lib/net/ssh/authentication/agent.rb +175 -0
- data/lib/net/ssh/authentication/constants.rb +18 -0
- data/lib/net/ssh/authentication/key_manager.rb +169 -0
- data/lib/net/ssh/authentication/methods/abstract.rb +60 -0
- data/lib/net/ssh/authentication/methods/hostbased.rb +71 -0
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +66 -0
- data/lib/net/ssh/authentication/methods/password.rb +39 -0
- data/lib/net/ssh/authentication/methods/publickey.rb +92 -0
- data/lib/net/ssh/authentication/pageant.rb +176 -0
- data/lib/net/ssh/authentication/session.rb +127 -0
- data/lib/net/ssh/buffer.rb +339 -0
- data/lib/net/ssh/buffered_io.rb +149 -0
- data/lib/net/ssh/config.rb +173 -0
- data/lib/net/ssh/connection/channel.rb +625 -0
- data/lib/net/ssh/connection/constants.rb +33 -0
- data/lib/net/ssh/connection/session.rb +569 -0
- data/lib/net/ssh/connection/term.rb +178 -0
- data/lib/net/ssh/errors.rb +85 -0
- data/lib/net/ssh/key_factory.rb +85 -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/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 +128 -0
- data/lib/net/ssh/service/forward.rb +267 -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 +59 -0
- data/lib/net/ssh/transport/algorithms.rb +384 -0
- data/lib/net/ssh/transport/cipher_factory.rb +72 -0
- data/lib/net/ssh/transport/constants.rb +30 -0
- data/lib/net/ssh/transport/hmac.rb +31 -0
- data/lib/net/ssh/transport/hmac/abstract.rb +48 -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/identity_cipher.rb +40 -0
- data/lib/net/ssh/transport/kex.rb +13 -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 +77 -0
- data/lib/net/ssh/transport/openssl.rb +128 -0
- data/lib/net/ssh/transport/packet_stream.rb +230 -0
- data/lib/net/ssh/transport/server_version.rb +61 -0
- data/lib/net/ssh/transport/session.rb +262 -0
- data/lib/net/ssh/transport/state.rb +170 -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 +60 -0
- data/net-ssh.gemspec +56 -0
- data/setup.rb +1585 -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 +108 -0
- data/test/authentication/methods/test_keyboard_interactive.rb +98 -0
- data/test/authentication/methods/test_password.rb +50 -0
- data/test/authentication/methods/test_publickey.rb +123 -0
- data/test/authentication/test_agent.rb +205 -0
- data/test/authentication/test_key_manager.rb +100 -0
- data/test/authentication/test_session.rb +93 -0
- data/test/common.rb +106 -0
- data/test/configs/exact_match +8 -0
- data/test/configs/wild_cards +14 -0
- data/test/connection/test_channel.rb +452 -0
- data/test/connection/test_session.rb +483 -0
- data/test/test_all.rb +6 -0
- data/test/test_buffer.rb +336 -0
- data/test/test_buffered_io.rb +63 -0
- data/test/test_config.rb +78 -0
- data/test/test_key_factory.rb +67 -0
- data/test/transport/hmac/test_md5.rb +34 -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/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/test_algorithms.rb +302 -0
- data/test/transport/test_cipher_factory.rb +163 -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 +433 -0
- data/test/transport/test_server_version.rb +55 -0
- data/test/transport/test_session.rb +312 -0
- data/test/transport/test_state.rb +173 -0
- metadata +222 -0
@@ -0,0 +1,205 @@
|
|
1
|
+
require 'common'
|
2
|
+
require 'net/ssh/authentication/agent'
|
3
|
+
|
4
|
+
module Authentication
|
5
|
+
|
6
|
+
class TestAgent < Test::Unit::TestCase
|
7
|
+
|
8
|
+
SSH2_AGENT_REQUEST_VERSION = 1
|
9
|
+
SSH2_AGENT_REQUEST_IDENTITIES = 11
|
10
|
+
SSH2_AGENT_IDENTITIES_ANSWER = 12
|
11
|
+
SSH2_AGENT_SIGN_REQUEST = 13
|
12
|
+
SSH2_AGENT_SIGN_RESPONSE = 14
|
13
|
+
SSH2_AGENT_FAILURE = 30
|
14
|
+
SSH2_AGENT_VERSION_RESPONSE = 103
|
15
|
+
|
16
|
+
SSH_COM_AGENT2_FAILURE = 102
|
17
|
+
|
18
|
+
SSH_AGENT_REQUEST_RSA_IDENTITIES = 1
|
19
|
+
SSH_AGENT_RSA_IDENTITIES_ANSWER = 2
|
20
|
+
SSH_AGENT_FAILURE = 5
|
21
|
+
|
22
|
+
def setup
|
23
|
+
@original, ENV['SSH_AUTH_SOCK'] = ENV['SSH_AUTH_SOCK'], "/path/to/ssh.agent.sock"
|
24
|
+
end
|
25
|
+
|
26
|
+
def teardown
|
27
|
+
ENV['SSH_AUTH_SOCK'] = @original
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_connect_should_use_agent_factory_to_determine_connection_type
|
31
|
+
factory.expects(:open).with("/path/to/ssh.agent.sock").returns(socket)
|
32
|
+
agent(false).connect!
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_connect_should_raise_error_if_connection_could_not_be_established
|
36
|
+
factory.expects(:open).raises(SocketError)
|
37
|
+
assert_raises(Net::SSH::Authentication::AgentNotAvailable) { agent(false).connect! }
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_negotiate_should_raise_error_if_ssh2_agent_response_recieved
|
41
|
+
socket.expect do |s, type, buffer|
|
42
|
+
assert_equal SSH2_AGENT_REQUEST_VERSION, type
|
43
|
+
assert_equal Net::SSH::Transport::ServerVersion::PROTO_VERSION, buffer.read_string
|
44
|
+
s.return(SSH2_AGENT_VERSION_RESPONSE)
|
45
|
+
end
|
46
|
+
assert_raises(NotImplementedError) { agent.negotiate! }
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_negotiate_should_raise_error_if_response_was_unexpected
|
50
|
+
socket.expect do |s, type, buffer|
|
51
|
+
assert_equal SSH2_AGENT_REQUEST_VERSION, type
|
52
|
+
s.return(255)
|
53
|
+
end
|
54
|
+
assert_raises(Net::SSH::Authentication::AgentError) { agent.negotiate! }
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_negotiate_should_be_successful_with_expected_response
|
58
|
+
socket.expect do |s, type, buffer|
|
59
|
+
assert_equal SSH2_AGENT_REQUEST_VERSION, type
|
60
|
+
s.return(SSH_AGENT_RSA_IDENTITIES_ANSWER)
|
61
|
+
end
|
62
|
+
assert_nothing_raised { agent(:connect).negotiate! }
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_identities_should_fail_if_SSH_AGENT_FAILURE_recieved
|
66
|
+
socket.expect do |s, type, buffer|
|
67
|
+
assert_equal SSH2_AGENT_REQUEST_IDENTITIES, type
|
68
|
+
s.return(SSH_AGENT_FAILURE)
|
69
|
+
end
|
70
|
+
assert_raises(Net::SSH::Authentication::AgentError) { agent.identities }
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_identities_should_fail_if_SSH2_AGENT_FAILURE_recieved
|
74
|
+
socket.expect do |s, type, buffer|
|
75
|
+
assert_equal SSH2_AGENT_REQUEST_IDENTITIES, type
|
76
|
+
s.return(SSH2_AGENT_FAILURE)
|
77
|
+
end
|
78
|
+
assert_raises(Net::SSH::Authentication::AgentError) { agent.identities }
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_identities_should_fail_if_SSH_COM_AGENT2_FAILURE_recieved
|
82
|
+
socket.expect do |s, type, buffer|
|
83
|
+
assert_equal SSH2_AGENT_REQUEST_IDENTITIES, type
|
84
|
+
s.return(SSH_COM_AGENT2_FAILURE)
|
85
|
+
end
|
86
|
+
assert_raises(Net::SSH::Authentication::AgentError) { agent.identities }
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_identities_should_fail_if_response_is_not_SSH2_AGENT_IDENTITIES_ANSWER
|
90
|
+
socket.expect do |s, type, buffer|
|
91
|
+
assert_equal SSH2_AGENT_REQUEST_IDENTITIES, type
|
92
|
+
s.return(255)
|
93
|
+
end
|
94
|
+
assert_raises(Net::SSH::Authentication::AgentError) { agent.identities }
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_identities_should_augment_identities_with_comment_field
|
98
|
+
key1 = key
|
99
|
+
key2 = OpenSSL::PKey::DSA.new(32)
|
100
|
+
|
101
|
+
socket.expect do |s, type, buffer|
|
102
|
+
assert_equal SSH2_AGENT_REQUEST_IDENTITIES, type
|
103
|
+
s.return(SSH2_AGENT_IDENTITIES_ANSWER, :long, 2, :string, Net::SSH::Buffer.from(:key, key1), :string, "My favorite key", :string, Net::SSH::Buffer.from(:key, key2), :string, "Okay, but not the best")
|
104
|
+
end
|
105
|
+
|
106
|
+
result = agent.identities
|
107
|
+
assert_equal key1.to_blob, result.first.to_blob
|
108
|
+
assert_equal key2.to_blob, result.last.to_blob
|
109
|
+
assert_equal "My favorite key", result.first.comment
|
110
|
+
assert_equal "Okay, but not the best", result.last.comment
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_close_should_close_socket
|
114
|
+
socket.expects(:close)
|
115
|
+
agent.close
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_sign_should_fail_if_response_is_SSH_AGENT_FAILURE
|
119
|
+
socket.expect { |s,| s.return(SSH_AGENT_FAILURE) }
|
120
|
+
assert_raises(Net::SSH::Authentication::AgentError) { agent.sign(key, "hello world") }
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_sign_should_fail_if_response_is_SSH2_AGENT_FAILURE
|
124
|
+
socket.expect { |s,| s.return(SSH2_AGENT_FAILURE) }
|
125
|
+
assert_raises(Net::SSH::Authentication::AgentError) { agent.sign(key, "hello world") }
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_sign_should_fail_if_response_is_SSH_COM_AGENT2_FAILURE
|
129
|
+
socket.expect { |s,| s.return(SSH_COM_AGENT2_FAILURE) }
|
130
|
+
assert_raises(Net::SSH::Authentication::AgentError) { agent.sign(key, "hello world") }
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_sign_should_fail_if_response_is_not_SSH2_AGENT_SIGN_RESPONSE
|
134
|
+
socket.expect { |s,| s.return(255) }
|
135
|
+
assert_raises(Net::SSH::Authentication::AgentError) { agent.sign(key, "hello world") }
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_sign_should_return_signed_data_from_agent
|
139
|
+
socket.expect do |s,type,buffer|
|
140
|
+
assert_equal SSH2_AGENT_SIGN_REQUEST, type
|
141
|
+
assert_equal key.to_blob, Net::SSH::Buffer.new(buffer.read_string).read_key.to_blob
|
142
|
+
assert_equal "hello world", buffer.read_string
|
143
|
+
assert_equal 0, buffer.read_long
|
144
|
+
|
145
|
+
s.return(SSH2_AGENT_SIGN_RESPONSE, :string, "abcxyz123")
|
146
|
+
end
|
147
|
+
|
148
|
+
assert_equal "abcxyz123", agent.sign(key, "hello world")
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
class MockSocket
|
154
|
+
def initialize
|
155
|
+
@expectation = nil
|
156
|
+
@buffer = Net::SSH::Buffer.new
|
157
|
+
end
|
158
|
+
|
159
|
+
def expect(&block)
|
160
|
+
@expectation = block
|
161
|
+
end
|
162
|
+
|
163
|
+
def return(type, *args)
|
164
|
+
data = Net::SSH::Buffer.from(*args)
|
165
|
+
@buffer.append([data.length+1, type, data.to_s].pack("NCA*"))
|
166
|
+
end
|
167
|
+
|
168
|
+
def send(data, flags)
|
169
|
+
raise "got #{data.inspect} but no packet was expected" unless @expectation
|
170
|
+
buffer = Net::SSH::Buffer.new(data)
|
171
|
+
buffer.read_long # skip the length
|
172
|
+
type = buffer.read_byte
|
173
|
+
@expectation.call(self, type, buffer)
|
174
|
+
@expectation = nil
|
175
|
+
end
|
176
|
+
|
177
|
+
def read(length)
|
178
|
+
@buffer.read(length)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def key
|
183
|
+
@key ||= OpenSSL::PKey::RSA.new(32)
|
184
|
+
end
|
185
|
+
|
186
|
+
def socket
|
187
|
+
@socket ||= MockSocket.new
|
188
|
+
end
|
189
|
+
|
190
|
+
def factory
|
191
|
+
@factory ||= stub("socket factory", :open => socket)
|
192
|
+
end
|
193
|
+
|
194
|
+
def agent(auto=:connect)
|
195
|
+
@agent ||= begin
|
196
|
+
agent = Net::SSH::Authentication::Agent.new
|
197
|
+
agent.stubs(:agent_socket_factory).returns(factory)
|
198
|
+
agent.connect! if auto == :connect
|
199
|
+
agent
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'common'
|
2
|
+
require 'net/ssh/authentication/key_manager'
|
3
|
+
|
4
|
+
module Authentication
|
5
|
+
|
6
|
+
class TestKeyManager < Test::Unit::TestCase
|
7
|
+
def test_key_files_and_known_identities_are_empty_by_default
|
8
|
+
assert manager.key_files.empty?
|
9
|
+
assert manager.known_identities.empty?
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_assume_agent_is_available_by_default
|
13
|
+
assert manager.use_agent?
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_add_ensures_list_is_unique
|
17
|
+
manager.add "/first"
|
18
|
+
manager.add "/second"
|
19
|
+
manager.add "/third"
|
20
|
+
manager.add "/second"
|
21
|
+
assert_equal %w(/first /second /third), manager.key_files
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_use_agent_should_be_set_to_false_if_agent_could_not_be_found
|
25
|
+
Net::SSH::Authentication::Agent.expects(:connect).raises(Net::SSH::Authentication::AgentNotAvailable)
|
26
|
+
assert manager.use_agent?
|
27
|
+
assert_nil manager.agent
|
28
|
+
assert !manager.use_agent?
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_identities_should_load_from_key_files
|
32
|
+
manager.stubs(:agent).returns(nil)
|
33
|
+
|
34
|
+
stub_file_key "/first", rsa
|
35
|
+
stub_file_key "/second", dsa
|
36
|
+
|
37
|
+
identities = manager.identities
|
38
|
+
assert_equal 2, identities.length
|
39
|
+
assert_equal rsa.to_blob, identities.first.to_blob
|
40
|
+
assert_equal dsa.to_blob, identities.last.to_blob
|
41
|
+
|
42
|
+
assert_equal({:from => :file, :file => "/first"}, manager.known_identities[rsa])
|
43
|
+
assert_equal({:from => :file, :file => "/second"}, manager.known_identities[dsa])
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_identities_should_load_from_agent
|
47
|
+
manager.stubs(:agent).returns(agent)
|
48
|
+
identities = manager.identities
|
49
|
+
|
50
|
+
assert_equal 2, identities.length
|
51
|
+
assert_equal rsa.to_blob, identities.first.to_blob
|
52
|
+
assert_equal dsa.to_blob, identities.last.to_blob
|
53
|
+
|
54
|
+
assert_equal({:from => :agent}, manager.known_identities[rsa])
|
55
|
+
assert_equal({:from => :agent}, manager.known_identities[dsa])
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_sign_with_agent_originated_key_should_request_signature_from_agent
|
59
|
+
manager.stubs(:agent).returns(agent)
|
60
|
+
manager.identities
|
61
|
+
agent.expects(:sign).with(rsa, "hello, world").returns("abcxyz123")
|
62
|
+
assert_equal "abcxyz123", manager.sign(rsa, "hello, world")
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_sign_with_file_originated_key_should_load_private_key_and_sign_with_it
|
66
|
+
manager.stubs(:agent).returns(nil)
|
67
|
+
stub_file_key "/first", rsa(512), true
|
68
|
+
rsa.expects(:ssh_do_sign).with("hello, world").returns("abcxyz123")
|
69
|
+
manager.identities
|
70
|
+
assert_equal "\0\0\0\assh-rsa\0\0\0\011abcxyz123", manager.sign(rsa, "hello, world")
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def stub_file_key(name, key, also_private=false)
|
76
|
+
manager.add(name)
|
77
|
+
File.expects(:readable?).returns(true)
|
78
|
+
Net::SSH::KeyFactory.expects(:load_public_key).with("#{name}.pub").returns(key)
|
79
|
+
Net::SSH::KeyFactory.expects(:load_private_key).with(name, nil).returns(key) if also_private
|
80
|
+
end
|
81
|
+
|
82
|
+
def rsa(size=32)
|
83
|
+
@rsa ||= OpenSSL::PKey::RSA.new(size)
|
84
|
+
end
|
85
|
+
|
86
|
+
def dsa
|
87
|
+
@dsa ||= OpenSSL::PKey::DSA.new(32)
|
88
|
+
end
|
89
|
+
|
90
|
+
def agent
|
91
|
+
@agent ||= stub("agent", :identities => [rsa, dsa])
|
92
|
+
end
|
93
|
+
|
94
|
+
def manager
|
95
|
+
@manager ||= Net::SSH::Authentication::KeyManager.new(nil)
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'common'
|
2
|
+
require 'net/ssh/authentication/session'
|
3
|
+
|
4
|
+
module Authentication
|
5
|
+
|
6
|
+
class TestSession < Test::Unit::TestCase
|
7
|
+
include Net::SSH::Transport::Constants
|
8
|
+
include Net::SSH::Authentication::Constants
|
9
|
+
|
10
|
+
def test_constructor_should_set_defaults
|
11
|
+
assert_equal %w(publickey hostbased password keyboard-interactive), session.auth_methods
|
12
|
+
assert_equal session.auth_methods, session.allowed_auth_methods
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_authenticate_should_raise_error_if_service_request_fails
|
16
|
+
transport.expect do |t, packet|
|
17
|
+
assert_equal SERVICE_REQUEST, packet.type
|
18
|
+
assert_equal "ssh-userauth", packet.read_string
|
19
|
+
t.return(255)
|
20
|
+
end
|
21
|
+
|
22
|
+
assert_raises(Net::SSH::Exception) { session.authenticate("next service", "username", "password") }
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_authenticate_should_return_false_if_all_auth_methods_fail
|
26
|
+
transport.expect do |t, packet|
|
27
|
+
assert_equal SERVICE_REQUEST, packet.type
|
28
|
+
assert_equal "ssh-userauth", packet.read_string
|
29
|
+
t.return(SERVICE_ACCEPT)
|
30
|
+
end
|
31
|
+
|
32
|
+
Net::SSH::Authentication::Methods::Publickey.any_instance.expects(:authenticate).with("next service", "username", "password").returns(false)
|
33
|
+
Net::SSH::Authentication::Methods::Hostbased.any_instance.expects(:authenticate).with("next service", "username", "password").returns(false)
|
34
|
+
Net::SSH::Authentication::Methods::Password.any_instance.expects(:authenticate).with("next service", "username", "password").returns(false)
|
35
|
+
Net::SSH::Authentication::Methods::KeyboardInteractive.any_instance.expects(:authenticate).with("next service", "username", "password").returns(false)
|
36
|
+
|
37
|
+
assert_equal false, session.authenticate("next service", "username", "password")
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_next_message_should_silently_handle_USERAUTH_BANNER_packets
|
41
|
+
transport.return(USERAUTH_BANNER, :string, "Howdy, folks!")
|
42
|
+
transport.return(SERVICE_ACCEPT)
|
43
|
+
assert_equal SERVICE_ACCEPT, session.next_message.type
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_next_message_should_understand_USERAUTH_FAILURE
|
47
|
+
transport.return(USERAUTH_FAILURE, :string, "a,b,c", :bool, false)
|
48
|
+
packet = session.next_message
|
49
|
+
assert_equal USERAUTH_FAILURE, packet.type
|
50
|
+
assert_equal %w(a b c), session.allowed_auth_methods
|
51
|
+
end
|
52
|
+
|
53
|
+
(60..79).each do |type|
|
54
|
+
define_method("test_next_message_should_return_packets_of_type_#{type}") do
|
55
|
+
transport.return(type)
|
56
|
+
assert_equal type, session.next_message.type
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_next_message_should_understand_USERAUTH_SUCCESS
|
61
|
+
transport.return(USERAUTH_SUCCESS)
|
62
|
+
assert !transport.hints[:authenticated]
|
63
|
+
assert_equal USERAUTH_SUCCESS, session.next_message.type
|
64
|
+
assert transport.hints[:authenticated]
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_next_message_should_raise_error_on_unrecognized_packet_types
|
68
|
+
transport.return(1)
|
69
|
+
assert_raises(Net::SSH::Exception) { session.next_message }
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_expect_message_should_raise_exception_if_next_packet_is_not_expected_type
|
73
|
+
transport.return(SERVICE_ACCEPT)
|
74
|
+
assert_raises(Net::SSH::Exception) { session.expect_message(USERAUTH_BANNER) }
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_expect_message_should_return_packet_if_next_packet_is_expected_type
|
78
|
+
transport.return(SERVICE_ACCEPT)
|
79
|
+
assert_equal SERVICE_ACCEPT, session.expect_message(SERVICE_ACCEPT).type
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def session(options={})
|
85
|
+
@session ||= Net::SSH::Authentication::Session.new(transport(options), options)
|
86
|
+
end
|
87
|
+
|
88
|
+
def transport(options={})
|
89
|
+
@transport ||= MockTransport.new(options)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
data/test/common.rb
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
|
2
|
+
require 'test/unit'
|
3
|
+
require 'mocha'
|
4
|
+
require 'net/ssh/buffer'
|
5
|
+
require 'net/ssh/config'
|
6
|
+
require 'net/ssh/loggable'
|
7
|
+
require 'net/ssh/packet'
|
8
|
+
require 'net/ssh/transport/session'
|
9
|
+
require 'ostruct'
|
10
|
+
|
11
|
+
# clear the default files out so that tests don't get confused by existing
|
12
|
+
# SSH config files.
|
13
|
+
$original_config_default_files = Net::SSH::Config.default_files.dup
|
14
|
+
Net::SSH::Config.default_files.clear
|
15
|
+
|
16
|
+
def P(*args)
|
17
|
+
Net::SSH::Packet.new(Net::SSH::Buffer.from(*args))
|
18
|
+
end
|
19
|
+
|
20
|
+
class MockTransport < Net::SSH::Transport::Session
|
21
|
+
class BlockVerifier
|
22
|
+
def initialize(block)
|
23
|
+
@block = block
|
24
|
+
end
|
25
|
+
|
26
|
+
def verify(data)
|
27
|
+
@block.call(data)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
attr_reader :host_key_verifier
|
32
|
+
attr_accessor :host_as_string
|
33
|
+
attr_accessor :server_version
|
34
|
+
|
35
|
+
attr_reader :client_options
|
36
|
+
attr_reader :server_options
|
37
|
+
attr_reader :hints, :queue
|
38
|
+
|
39
|
+
attr_accessor :mock_enqueue
|
40
|
+
|
41
|
+
def initialize(options={})
|
42
|
+
self.logger = options[:logger]
|
43
|
+
self.host_as_string = "net.ssh.test,127.0.0.1"
|
44
|
+
self.server_version = OpenStruct.new(:version => "SSH-2.0-Ruby/Net::SSH::Test")
|
45
|
+
@expectation = nil
|
46
|
+
@queue = []
|
47
|
+
@hints = {}
|
48
|
+
@socket = options[:socket]
|
49
|
+
@algorithms = OpenStruct.new(:session_id => "abcxyz123")
|
50
|
+
verifier { |data| true }
|
51
|
+
end
|
52
|
+
|
53
|
+
def send_message(message)
|
54
|
+
buffer = Net::SSH::Buffer.new(message.to_s)
|
55
|
+
if @expectation.nil?
|
56
|
+
raise "got #{message.to_s.inspect} but was not expecting anything"
|
57
|
+
else
|
58
|
+
block, @expectation = @expectation, nil
|
59
|
+
block.call(self, Net::SSH::Packet.new(buffer))
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def enqueue_message(message)
|
64
|
+
if mock_enqueue
|
65
|
+
send_message(message)
|
66
|
+
else
|
67
|
+
super
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def poll_message
|
72
|
+
@queue.shift
|
73
|
+
end
|
74
|
+
|
75
|
+
def next_message
|
76
|
+
@queue.shift or raise "expected a message from the server but nothing was ready to send"
|
77
|
+
end
|
78
|
+
|
79
|
+
def return(type, *args)
|
80
|
+
@queue << P(:byte, type, *args)
|
81
|
+
end
|
82
|
+
|
83
|
+
def expect(&block)
|
84
|
+
@expectation = block
|
85
|
+
end
|
86
|
+
|
87
|
+
def expect!
|
88
|
+
expect {}
|
89
|
+
end
|
90
|
+
|
91
|
+
def verifier(&block)
|
92
|
+
@host_key_verifier = BlockVerifier.new(block)
|
93
|
+
end
|
94
|
+
|
95
|
+
def configure_client(options)
|
96
|
+
@client_options = options
|
97
|
+
end
|
98
|
+
|
99
|
+
def configure_server(options)
|
100
|
+
@server_options = options
|
101
|
+
end
|
102
|
+
|
103
|
+
def hint(name, value=true)
|
104
|
+
@hints[name] = value
|
105
|
+
end
|
106
|
+
end
|