net-ssh 3.2.0.rc2 → 7.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +2 -2
- data/.dockerignore +6 -0
- data/.github/config/rubocop_linter_action.yml +4 -0
- data/.github/workflows/ci-with-docker.yml +44 -0
- data/.github/workflows/ci.yml +87 -0
- data/.github/workflows/rubocop.yml +16 -0
- data/.gitignore +13 -0
- data/.rubocop.yml +22 -0
- data/.rubocop_todo.yml +1081 -0
- data/CHANGES.txt +228 -7
- data/Dockerfile +27 -0
- data/Dockerfile.openssl3 +17 -0
- data/Gemfile +13 -0
- data/Gemfile.noed25519 +12 -0
- data/ISSUE_TEMPLATE.md +30 -0
- data/Manifest +4 -5
- data/README.md +297 -0
- data/Rakefile +125 -74
- data/SECURITY.md +4 -0
- data/appveyor.yml +58 -0
- data/docker-compose.yml +23 -0
- data/lib/net/ssh/authentication/agent.rb +279 -18
- data/lib/net/ssh/authentication/certificate.rb +183 -0
- data/lib/net/ssh/authentication/constants.rb +17 -15
- data/lib/net/ssh/authentication/ed25519.rb +186 -0
- data/lib/net/ssh/authentication/ed25519_loader.rb +31 -0
- data/lib/net/ssh/authentication/key_manager.rb +86 -39
- data/lib/net/ssh/authentication/methods/abstract.rb +67 -48
- data/lib/net/ssh/authentication/methods/hostbased.rb +34 -37
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +13 -13
- data/lib/net/ssh/authentication/methods/none.rb +16 -19
- data/lib/net/ssh/authentication/methods/password.rb +27 -17
- data/lib/net/ssh/authentication/methods/publickey.rb +96 -55
- data/lib/net/ssh/authentication/pageant.rb +471 -367
- data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
- data/lib/net/ssh/authentication/session.rb +131 -121
- data/lib/net/ssh/buffer.rb +399 -300
- data/lib/net/ssh/buffered_io.rb +154 -150
- data/lib/net/ssh/config.rb +308 -185
- data/lib/net/ssh/connection/channel.rb +635 -613
- data/lib/net/ssh/connection/constants.rb +29 -29
- data/lib/net/ssh/connection/event_loop.rb +123 -0
- data/lib/net/ssh/connection/keepalive.rb +55 -51
- data/lib/net/ssh/connection/session.rb +620 -551
- data/lib/net/ssh/connection/term.rb +125 -123
- data/lib/net/ssh/errors.rb +101 -99
- data/lib/net/ssh/key_factory.rb +197 -105
- data/lib/net/ssh/known_hosts.rb +214 -127
- data/lib/net/ssh/loggable.rb +50 -49
- data/lib/net/ssh/packet.rb +83 -79
- data/lib/net/ssh/prompt.rb +50 -81
- data/lib/net/ssh/proxy/command.rb +105 -90
- data/lib/net/ssh/proxy/errors.rb +12 -10
- data/lib/net/ssh/proxy/http.rb +82 -79
- data/lib/net/ssh/proxy/https.rb +50 -0
- data/lib/net/ssh/proxy/jump.rb +54 -0
- data/lib/net/ssh/proxy/socks4.rb +2 -6
- data/lib/net/ssh/proxy/socks5.rb +14 -17
- data/lib/net/ssh/service/forward.rb +370 -317
- data/lib/net/ssh/test/channel.rb +145 -136
- data/lib/net/ssh/test/extensions.rb +131 -110
- data/lib/net/ssh/test/kex.rb +34 -32
- data/lib/net/ssh/test/local_packet.rb +46 -44
- data/lib/net/ssh/test/packet.rb +89 -70
- data/lib/net/ssh/test/remote_packet.rb +32 -30
- data/lib/net/ssh/test/script.rb +156 -142
- data/lib/net/ssh/test/socket.rb +49 -48
- data/lib/net/ssh/test.rb +82 -77
- data/lib/net/ssh/transport/algorithms.rb +441 -360
- data/lib/net/ssh/transport/cipher_factory.rb +96 -98
- data/lib/net/ssh/transport/constants.rb +32 -24
- data/lib/net/ssh/transport/ctr.rb +42 -22
- data/lib/net/ssh/transport/hmac/abstract.rb +81 -63
- data/lib/net/ssh/transport/hmac/md5.rb +0 -2
- data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
- data/lib/net/ssh/transport/hmac/none.rb +0 -2
- data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
- data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
- data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
- data/lib/net/ssh/transport/hmac/sha2_256.rb +7 -11
- data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
- data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
- data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
- data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
- data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
- data/lib/net/ssh/transport/hmac.rb +14 -12
- data/lib/net/ssh/transport/identity_cipher.rb +54 -52
- data/lib/net/ssh/transport/kex/abstract.rb +130 -0
- data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
- data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
- data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +33 -40
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +119 -213
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +53 -61
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +36 -90
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +18 -10
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +18 -10
- data/lib/net/ssh/transport/kex.rb +15 -12
- data/lib/net/ssh/transport/key_expander.rb +24 -20
- data/lib/net/ssh/transport/openssl.rb +161 -124
- data/lib/net/ssh/transport/packet_stream.rb +225 -185
- data/lib/net/ssh/transport/server_version.rb +55 -56
- data/lib/net/ssh/transport/session.rb +306 -255
- data/lib/net/ssh/transport/state.rb +178 -176
- data/lib/net/ssh/verifiers/accept_new.rb +33 -0
- data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +33 -0
- data/lib/net/ssh/verifiers/always.rb +58 -0
- data/lib/net/ssh/verifiers/never.rb +19 -0
- data/lib/net/ssh/version.rb +55 -53
- data/lib/net/ssh.rb +110 -47
- data/net-ssh-public_cert.pem +18 -18
- data/net-ssh.gemspec +36 -205
- data/support/ssh_tunnel_bug.rb +5 -5
- data.tar.gz.sig +0 -0
- metadata +153 -118
- metadata.gz.sig +0 -0
- data/.travis.yml +0 -18
- data/README.rdoc +0 -182
- data/lib/net/ssh/authentication/agent/java_pageant.rb +0 -85
- data/lib/net/ssh/authentication/agent/socket.rb +0 -178
- data/lib/net/ssh/ruby_compat.rb +0 -46
- data/lib/net/ssh/verifiers/lenient.rb +0 -30
- data/lib/net/ssh/verifiers/null.rb +0 -12
- data/lib/net/ssh/verifiers/secure.rb +0 -52
- data/lib/net/ssh/verifiers/strict.rb +0 -24
- data/setup.rb +0 -1585
- data/support/arcfour_check.rb +0 -20
- data/test/README.txt +0 -18
- data/test/authentication/methods/common.rb +0 -28
- data/test/authentication/methods/test_abstract.rb +0 -51
- data/test/authentication/methods/test_hostbased.rb +0 -114
- data/test/authentication/methods/test_keyboard_interactive.rb +0 -121
- data/test/authentication/methods/test_none.rb +0 -41
- data/test/authentication/methods/test_password.rb +0 -95
- data/test/authentication/methods/test_publickey.rb +0 -148
- data/test/authentication/test_agent.rb +0 -232
- data/test/authentication/test_key_manager.rb +0 -240
- data/test/authentication/test_session.rb +0 -107
- data/test/common.rb +0 -125
- data/test/configs/auth_off +0 -5
- data/test/configs/auth_on +0 -4
- data/test/configs/empty +0 -0
- data/test/configs/eqsign +0 -3
- data/test/configs/exact_match +0 -8
- data/test/configs/host_plus +0 -10
- data/test/configs/multihost +0 -4
- data/test/configs/negative_match +0 -6
- data/test/configs/nohost +0 -19
- data/test/configs/numeric_host +0 -4
- data/test/configs/proxy_remote_user +0 -2
- data/test/configs/send_env +0 -2
- data/test/configs/substitutes +0 -8
- data/test/configs/wild_cards +0 -14
- data/test/connection/test_channel.rb +0 -487
- data/test/connection/test_session.rb +0 -564
- data/test/integration/README.txt +0 -17
- data/test/integration/Vagrantfile +0 -12
- data/test/integration/common.rb +0 -63
- data/test/integration/playbook.yml +0 -56
- data/test/integration/test_forward.rb +0 -637
- data/test/integration/test_id_rsa_keys.rb +0 -96
- data/test/integration/test_proxy.rb +0 -93
- data/test/known_hosts/github +0 -1
- data/test/known_hosts/github_hash +0 -1
- data/test/manual/test_pageant.rb +0 -37
- data/test/start/test_connection.rb +0 -53
- data/test/start/test_options.rb +0 -57
- data/test/start/test_transport.rb +0 -28
- data/test/start/test_user_nil.rb +0 -27
- data/test/test_all.rb +0 -12
- data/test/test_buffer.rb +0 -433
- data/test/test_buffered_io.rb +0 -63
- data/test/test_config.rb +0 -268
- data/test/test_key_factory.rb +0 -191
- data/test/test_known_hosts.rb +0 -66
- data/test/transport/hmac/test_md5.rb +0 -41
- data/test/transport/hmac/test_md5_96.rb +0 -27
- data/test/transport/hmac/test_none.rb +0 -34
- data/test/transport/hmac/test_ripemd160.rb +0 -36
- data/test/transport/hmac/test_sha1.rb +0 -36
- data/test/transport/hmac/test_sha1_96.rb +0 -27
- data/test/transport/hmac/test_sha2_256.rb +0 -37
- data/test/transport/hmac/test_sha2_256_96.rb +0 -27
- data/test/transport/hmac/test_sha2_512.rb +0 -37
- data/test/transport/hmac/test_sha2_512_96.rb +0 -27
- data/test/transport/kex/test_diffie_hellman_group14_sha1.rb +0 -13
- data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +0 -150
- data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +0 -96
- data/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb +0 -19
- data/test/transport/kex/test_ecdh_sha2_nistp256.rb +0 -161
- data/test/transport/kex/test_ecdh_sha2_nistp384.rb +0 -38
- data/test/transport/kex/test_ecdh_sha2_nistp521.rb +0 -38
- data/test/transport/test_algorithms.rb +0 -328
- data/test/transport/test_cipher_factory.rb +0 -443
- data/test/transport/test_hmac.rb +0 -34
- data/test/transport/test_identity_cipher.rb +0 -40
- data/test/transport/test_packet_stream.rb +0 -1762
- data/test/transport/test_server_version.rb +0 -74
- data/test/transport/test_session.rb +0 -331
- data/test/transport/test_state.rb +0 -181
- data/test/verifiers/test_secure.rb +0 -40
@@ -1,564 +0,0 @@
|
|
1
|
-
require 'common'
|
2
|
-
require 'net/ssh/connection/session'
|
3
|
-
|
4
|
-
module Connection
|
5
|
-
|
6
|
-
class TestSession < Test::Unit::TestCase
|
7
|
-
include Net::SSH::Connection::Constants
|
8
|
-
|
9
|
-
def test_constructor_should_set_defaults
|
10
|
-
assert session.channels.empty?
|
11
|
-
assert session.pending_requests.empty?
|
12
|
-
assert_equal({ socket => nil }, session.listeners)
|
13
|
-
end
|
14
|
-
|
15
|
-
def test_on_open_channel_should_register_block_with_given_channel_type
|
16
|
-
flag = false
|
17
|
-
session.on_open_channel("testing") { flag = true }
|
18
|
-
assert_not_nil session.channel_open_handlers["testing"]
|
19
|
-
session.channel_open_handlers["testing"].call
|
20
|
-
assert flag, "callback should have been invoked"
|
21
|
-
end
|
22
|
-
|
23
|
-
def test_forward_should_create_and_cache_instance_of_forward_service
|
24
|
-
assert_instance_of Net::SSH::Service::Forward, session.forward
|
25
|
-
assert_equal session.forward.object_id, session.forward.object_id
|
26
|
-
end
|
27
|
-
|
28
|
-
def test_listen_to_without_callback_should_add_argument_as_listener
|
29
|
-
io = stub("io")
|
30
|
-
session.listen_to(io)
|
31
|
-
assert session.listeners.key?(io)
|
32
|
-
assert_nil session.listeners[io]
|
33
|
-
end
|
34
|
-
|
35
|
-
def test_listen_to_should_add_argument_to_listeners_list_if_block_is_given
|
36
|
-
io = stub("io", :pending_write? => true)
|
37
|
-
flag = false
|
38
|
-
session.listen_to(io) { flag = true }
|
39
|
-
assert !flag, "callback should not be invoked immediately"
|
40
|
-
assert session.listeners.key?(io)
|
41
|
-
session.listeners[io].call
|
42
|
-
assert flag, "callback should have been invoked"
|
43
|
-
end
|
44
|
-
|
45
|
-
def test_stop_listening_to_should_remove_argument_from_listeners
|
46
|
-
io = stub("io", :pending_write? => true)
|
47
|
-
|
48
|
-
session.listen_to(io)
|
49
|
-
assert session.listeners.key?(io)
|
50
|
-
|
51
|
-
session.stop_listening_to(io)
|
52
|
-
assert !session.listeners.key?(io)
|
53
|
-
end
|
54
|
-
|
55
|
-
def test_send_message_should_enqueue_message_at_transport_layer
|
56
|
-
packet = P(:byte, REQUEST_SUCCESS)
|
57
|
-
session.send_message(packet)
|
58
|
-
assert_equal packet.to_s, socket.write_buffer
|
59
|
-
end
|
60
|
-
|
61
|
-
def test_open_channel_defaults_should_use_session_channel
|
62
|
-
flag = false
|
63
|
-
channel = session.open_channel { flag = true }
|
64
|
-
assert !flag, "callback should not be invoked immediately"
|
65
|
-
channel.do_open_confirmation(1,2,3)
|
66
|
-
assert flag, "callback should have been invoked"
|
67
|
-
assert_equal "session", channel.type
|
68
|
-
assert_equal 0, channel.local_id
|
69
|
-
assert_equal channel, session.channels[channel.local_id]
|
70
|
-
|
71
|
-
packet = P(:byte, CHANNEL_OPEN, :string, "session", :long, channel.local_id,
|
72
|
-
:long, channel.local_maximum_window_size, :long, channel.local_maximum_packet_size)
|
73
|
-
assert_equal packet.to_s, socket.write_buffer
|
74
|
-
end
|
75
|
-
|
76
|
-
def test_open_channel_with_type_should_use_type
|
77
|
-
channel = session.open_channel("direct-tcpip")
|
78
|
-
assert_equal "direct-tcpip", channel.type
|
79
|
-
packet = P(:byte, CHANNEL_OPEN, :string, "direct-tcpip", :long, channel.local_id,
|
80
|
-
:long, channel.local_maximum_window_size, :long, channel.local_maximum_packet_size)
|
81
|
-
assert_equal packet.to_s, socket.write_buffer
|
82
|
-
end
|
83
|
-
|
84
|
-
def test_open_channel_with_extras_should_append_extras_to_packet
|
85
|
-
channel = session.open_channel("direct-tcpip", :string, "other.host", :long, 1234)
|
86
|
-
packet = P(:byte, CHANNEL_OPEN, :string, "direct-tcpip", :long, channel.local_id,
|
87
|
-
:long, channel.local_maximum_window_size, :long, channel.local_maximum_packet_size,
|
88
|
-
:string, "other.host", :long, 1234)
|
89
|
-
assert_equal packet.to_s, socket.write_buffer
|
90
|
-
end
|
91
|
-
|
92
|
-
def test_send_global_request_without_callback_should_not_expect_reply
|
93
|
-
packet = P(:byte, GLOBAL_REQUEST, :string, "testing", :bool, false)
|
94
|
-
session.send_global_request("testing")
|
95
|
-
assert_equal packet.to_s, socket.write_buffer
|
96
|
-
assert session.pending_requests.empty?
|
97
|
-
end
|
98
|
-
|
99
|
-
def test_send_global_request_with_callback_should_expect_reply
|
100
|
-
packet = P(:byte, GLOBAL_REQUEST, :string, "testing", :bool, true)
|
101
|
-
proc = Proc.new {}
|
102
|
-
session.send_global_request("testing", &proc)
|
103
|
-
assert_equal packet.to_s, socket.write_buffer
|
104
|
-
assert_equal [proc], session.pending_requests
|
105
|
-
end
|
106
|
-
|
107
|
-
def test_send_global_request_with_extras_should_append_extras_to_packet
|
108
|
-
packet = P(:byte, GLOBAL_REQUEST, :string, "testing", :bool, false, :string, "other.host", :long, 1234)
|
109
|
-
session.send_global_request("testing", :string, "other.host", :long, 1234)
|
110
|
-
assert_equal packet.to_s, socket.write_buffer
|
111
|
-
end
|
112
|
-
|
113
|
-
def test_process_should_exit_immediately_if_block_is_false
|
114
|
-
session.channels[0] = stub("channel", :closing? => false)
|
115
|
-
session.channels[0].expects(:process).never
|
116
|
-
process_times(0)
|
117
|
-
end
|
118
|
-
|
119
|
-
def test_process_should_exit_after_processing_if_block_is_true_then_false
|
120
|
-
session.channels[0] = stub("channel", :local_closed? => false)
|
121
|
-
session.channels[0].expects(:process)
|
122
|
-
IO.expects(:select).never
|
123
|
-
process_times(2)
|
124
|
-
end
|
125
|
-
|
126
|
-
def test_process_should_not_process_channels_that_are_closing
|
127
|
-
session.channels[0] = stub("channel", :local_closed? => true)
|
128
|
-
session.channels[0].expects(:process).never
|
129
|
-
IO.expects(:select).never
|
130
|
-
process_times(2)
|
131
|
-
end
|
132
|
-
|
133
|
-
def test_global_request_packets_should_be_silently_handled_if_no_handler_exists_for_them
|
134
|
-
transport.return(GLOBAL_REQUEST, :string, "testing", :bool, false)
|
135
|
-
process_times(2)
|
136
|
-
assert transport.queue.empty?
|
137
|
-
assert !socket.pending_write?
|
138
|
-
end
|
139
|
-
|
140
|
-
def test_global_request_packets_should_be_auto_replied_to_even_if_no_handler_exists
|
141
|
-
transport.return(GLOBAL_REQUEST, :string, "testing", :bool, true)
|
142
|
-
process_times(2)
|
143
|
-
assert_equal P(:byte, REQUEST_FAILURE).to_s, socket.write_buffer
|
144
|
-
end
|
145
|
-
|
146
|
-
def test_global_request_handler_should_not_trigger_auto_reply_if_no_reply_is_wanted
|
147
|
-
flag = false
|
148
|
-
session.on_global_request("testing") { flag = true }
|
149
|
-
assert !flag, "callback should not be invoked yet"
|
150
|
-
transport.return(GLOBAL_REQUEST, :string, "testing", :bool, false)
|
151
|
-
process_times(2)
|
152
|
-
assert transport.queue.empty?
|
153
|
-
assert !socket.pending_write?
|
154
|
-
assert flag, "callback should have been invoked"
|
155
|
-
end
|
156
|
-
|
157
|
-
def test_global_request_handler_returning_true_should_trigger_success_auto_reply
|
158
|
-
flag = false
|
159
|
-
session.on_global_request("testing") { flag = true }
|
160
|
-
transport.return(GLOBAL_REQUEST, :string, "testing", :bool, true)
|
161
|
-
process_times(2)
|
162
|
-
assert_equal P(:byte, REQUEST_SUCCESS).to_s, socket.write_buffer
|
163
|
-
assert flag
|
164
|
-
end
|
165
|
-
|
166
|
-
def test_global_request_handler_returning_false_should_trigger_failure_auto_reply
|
167
|
-
flag = false
|
168
|
-
session.on_global_request("testing") { flag = true; false }
|
169
|
-
transport.return(GLOBAL_REQUEST, :string, "testing", :bool, true)
|
170
|
-
process_times(2)
|
171
|
-
assert_equal P(:byte, REQUEST_FAILURE).to_s, socket.write_buffer
|
172
|
-
assert flag
|
173
|
-
end
|
174
|
-
|
175
|
-
def test_global_request_handler_returning_sent_should_not_trigger_auto_reply
|
176
|
-
flag = false
|
177
|
-
session.on_global_request("testing") { flag = true; :sent }
|
178
|
-
transport.return(GLOBAL_REQUEST, :string, "testing", :bool, true)
|
179
|
-
process_times(2)
|
180
|
-
assert !socket.pending_write?
|
181
|
-
assert flag
|
182
|
-
end
|
183
|
-
|
184
|
-
def test_global_request_handler_returning_other_value_should_raise_error
|
185
|
-
transport.expects(:closed?).at_least_once.returns(false)
|
186
|
-
session.on_global_request("testing") { "bug" }
|
187
|
-
transport.return(GLOBAL_REQUEST, :string, "testing", :bool, true)
|
188
|
-
assert_raises(RuntimeError) { process_times(2) }
|
189
|
-
end
|
190
|
-
|
191
|
-
def test_request_success_packets_should_invoke_next_pending_request_with_true
|
192
|
-
result = nil
|
193
|
-
session.pending_requests << Proc.new { |*args| result = args }
|
194
|
-
transport.return(REQUEST_SUCCESS)
|
195
|
-
process_times(2)
|
196
|
-
assert_equal [true, P(:byte, REQUEST_SUCCESS)], result
|
197
|
-
assert session.pending_requests.empty?
|
198
|
-
end
|
199
|
-
|
200
|
-
def test_request_failure_packets_should_invoke_next_pending_request_with_false
|
201
|
-
result = nil
|
202
|
-
session.pending_requests << Proc.new { |*args| result = args }
|
203
|
-
transport.return(REQUEST_FAILURE)
|
204
|
-
process_times(2)
|
205
|
-
assert_equal [false, P(:byte, REQUEST_FAILURE)], result
|
206
|
-
assert session.pending_requests.empty?
|
207
|
-
end
|
208
|
-
|
209
|
-
def test_channel_open_packet_without_corresponding_channel_open_handler_should_result_in_channel_open_failure
|
210
|
-
transport.return(CHANNEL_OPEN, :string, "auth-agent", :long, 14, :long, 0x20000, :long, 0x10000)
|
211
|
-
process_times(2)
|
212
|
-
assert_equal P(:byte, CHANNEL_OPEN_FAILURE, :long, 14, :long, 3, :string, "unknown channel type auth-agent", :string, "").to_s, socket.write_buffer
|
213
|
-
end
|
214
|
-
|
215
|
-
def test_channel_open_packet_with_corresponding_handler_should_result_in_channel_open_failure_when_handler_returns_an_error
|
216
|
-
transport.return(CHANNEL_OPEN, :string, "auth-agent", :long, 14, :long, 0x20000, :long, 0x10000)
|
217
|
-
session.on_open_channel "auth-agent" do |s, ch, p|
|
218
|
-
raise Net::SSH::ChannelOpenFailed.new(1234, "we iz in ur channelz!")
|
219
|
-
end
|
220
|
-
process_times(2)
|
221
|
-
assert_equal P(:byte, CHANNEL_OPEN_FAILURE, :long, 14, :long, 1234, :string, "we iz in ur channelz!", :string, "").to_s, socket.write_buffer
|
222
|
-
end
|
223
|
-
|
224
|
-
def test_channel_open_packet_with_corresponding_handler_should_result_in_channel_open_confirmation_when_handler_succeeds
|
225
|
-
transport.return(CHANNEL_OPEN, :string, "auth-agent", :long, 14, :long, 0x20001, :long, 0x10001)
|
226
|
-
result = nil
|
227
|
-
session.on_open_channel("auth-agent") { |*args| result = args }
|
228
|
-
process_times(2)
|
229
|
-
assert_equal P(:byte, CHANNEL_OPEN_CONFIRMATION, :long, 14, :long, 0, :long, 0x20000, :long, 0x8000).to_s, socket.write_buffer
|
230
|
-
assert_not_nil(ch = session.channels[0])
|
231
|
-
assert_equal [session, ch, P(:byte, CHANNEL_OPEN, :string, "auth-agent", :long, 14, :long, 0x20001, :long, 0x10001)], result
|
232
|
-
assert_equal 0, ch.local_id
|
233
|
-
assert_equal 14, ch.remote_id
|
234
|
-
assert_equal 0x20001, ch.remote_maximum_window_size
|
235
|
-
assert_equal 0x10001, ch.remote_maximum_packet_size
|
236
|
-
assert_equal 0x20000, ch.local_maximum_window_size
|
237
|
-
assert_equal 0x8000, ch.local_maximum_packet_size
|
238
|
-
assert_equal "auth-agent", ch.type
|
239
|
-
end
|
240
|
-
|
241
|
-
def test_channel_open_failure_should_remove_channel_and_tell_channel_that_open_failed
|
242
|
-
session.channels[1] = stub("channel")
|
243
|
-
session.channels[1].expects(:do_open_failed).with(1234, "some reason")
|
244
|
-
transport.return(CHANNEL_OPEN_FAILURE, :long, 1, :long, 1234, :string, "some reason", :string, "lang tag")
|
245
|
-
process_times(2)
|
246
|
-
assert session.channels.empty?
|
247
|
-
end
|
248
|
-
|
249
|
-
def test_channel_open_confirmation_packet_should_be_routed_to_corresponding_channel
|
250
|
-
channel_at(14).expects(:do_open_confirmation).with(1234, 0x20001, 0x10001)
|
251
|
-
transport.return(CHANNEL_OPEN_CONFIRMATION, :long, 14, :long, 1234, :long, 0x20001, :long, 0x10001)
|
252
|
-
process_times(2)
|
253
|
-
end
|
254
|
-
|
255
|
-
def test_channel_window_adjust_packet_should_be_routed_to_corresponding_channel
|
256
|
-
channel_at(14).expects(:do_window_adjust).with(5000)
|
257
|
-
transport.return(CHANNEL_WINDOW_ADJUST, :long, 14, :long, 5000)
|
258
|
-
process_times(2)
|
259
|
-
end
|
260
|
-
|
261
|
-
def test_channel_request_for_nonexistant_channel_should_be_ignored
|
262
|
-
transport.return(CHANNEL_REQUEST, :long, 14, :string, "testing", :bool, false)
|
263
|
-
assert_nothing_raised { process_times(2) }
|
264
|
-
end
|
265
|
-
|
266
|
-
def test_channel_request_packet_should_be_routed_to_corresponding_channel
|
267
|
-
channel_at(14).expects(:do_request).with("testing", false, Net::SSH::Buffer.new)
|
268
|
-
transport.return(CHANNEL_REQUEST, :long, 14, :string, "testing", :bool, false)
|
269
|
-
process_times(2)
|
270
|
-
end
|
271
|
-
|
272
|
-
def test_channel_data_packet_should_be_routed_to_corresponding_channel
|
273
|
-
channel_at(14).expects(:do_data).with("bring it on down")
|
274
|
-
transport.return(CHANNEL_DATA, :long, 14, :string, "bring it on down")
|
275
|
-
process_times(2)
|
276
|
-
end
|
277
|
-
|
278
|
-
def test_channel_extended_data_packet_should_be_routed_to_corresponding_channel
|
279
|
-
channel_at(14).expects(:do_extended_data).with(1, "bring it on down")
|
280
|
-
transport.return(CHANNEL_EXTENDED_DATA, :long, 14, :long, 1, :string, "bring it on down")
|
281
|
-
process_times(2)
|
282
|
-
end
|
283
|
-
|
284
|
-
def test_channel_eof_packet_should_be_routed_to_corresponding_channel
|
285
|
-
channel_at(14).expects(:do_eof).with()
|
286
|
-
transport.return(CHANNEL_EOF, :long, 14)
|
287
|
-
process_times(2)
|
288
|
-
end
|
289
|
-
|
290
|
-
def test_channel_success_packet_should_be_routed_to_corresponding_channel
|
291
|
-
channel_at(14).expects(:do_success).with()
|
292
|
-
transport.return(CHANNEL_SUCCESS, :long, 14)
|
293
|
-
process_times(2)
|
294
|
-
end
|
295
|
-
|
296
|
-
def test_channel_failure_packet_should_be_routed_to_corresponding_channel
|
297
|
-
channel_at(14).expects(:do_failure).with()
|
298
|
-
transport.return(CHANNEL_FAILURE, :long, 14)
|
299
|
-
process_times(2)
|
300
|
-
end
|
301
|
-
|
302
|
-
def test_channel_close_packet_should_be_routed_to_corresponding_channel_and_channel_should_be_closed_and_removed
|
303
|
-
session.channels[14] = stub("channel") do
|
304
|
-
# this simulates the case where we closed the channel first, sent
|
305
|
-
# CHANNEL_CLOSE to server and are waiting for server's response.
|
306
|
-
expects(:local_closed?).returns(true)
|
307
|
-
expects(:do_close)
|
308
|
-
expects(:close).with()
|
309
|
-
expects(:remote_closed!).with()
|
310
|
-
expects(:remote_closed?).with().returns(true)
|
311
|
-
expects(:local_id).returns(14)
|
312
|
-
end
|
313
|
-
|
314
|
-
transport.return(CHANNEL_CLOSE, :long, 14)
|
315
|
-
process_times(2)
|
316
|
-
assert session.channels.empty?
|
317
|
-
end
|
318
|
-
|
319
|
-
def test_multiple_pending_dispatches_should_be_dispatched_together
|
320
|
-
channel_at(14).expects(:do_eof).with()
|
321
|
-
session.channels[14].expects(:do_success).with()
|
322
|
-
transport.return(CHANNEL_SUCCESS, :long, 14)
|
323
|
-
transport.return(CHANNEL_EOF, :long, 14)
|
324
|
-
process_times(2)
|
325
|
-
end
|
326
|
-
|
327
|
-
def test_writers_without_pending_writes_should_not_be_considered_for_select
|
328
|
-
IO.expects(:select).with([socket],[],nil,nil).returns([[],[],[]])
|
329
|
-
session.process
|
330
|
-
end
|
331
|
-
|
332
|
-
def test_writers_with_pending_writes_should_be_considered_for_select
|
333
|
-
socket.enqueue("laksdjflasdkf")
|
334
|
-
IO.expects(:select).with([socket],[socket],nil,nil).returns([[],[],[]])
|
335
|
-
session.process
|
336
|
-
end
|
337
|
-
|
338
|
-
def test_ready_readers_should_be_filled
|
339
|
-
socket.expects(:recv).returns("this is some data")
|
340
|
-
IO.expects(:select).with([socket],[],nil,nil).returns([[socket],[],[]])
|
341
|
-
session.process
|
342
|
-
assert_equal [socket], session.listeners.keys
|
343
|
-
end
|
344
|
-
|
345
|
-
def test_ready_readers_that_cant_be_filled_should_be_removed
|
346
|
-
socket.expects(:recv).returns("")
|
347
|
-
socket.expects(:close)
|
348
|
-
IO.expects(:select).with([socket],[],nil,nil).returns([[socket],[],[]])
|
349
|
-
session.process
|
350
|
-
assert session.listeners.empty?
|
351
|
-
end
|
352
|
-
|
353
|
-
def test_ready_readers_that_are_registered_with_a_block_should_call_block_instead_of_fill
|
354
|
-
io = stub("io", :pending_write? => false)
|
355
|
-
flag = false
|
356
|
-
session.stop_listening_to(socket) # so that we only have to test the presence of a single IO object
|
357
|
-
session.listen_to(io) { flag = true }
|
358
|
-
IO.expects(:select).with([io],[],nil,nil).returns([[io],[],[]])
|
359
|
-
session.process
|
360
|
-
assert flag, "callback should have been invoked"
|
361
|
-
end
|
362
|
-
|
363
|
-
def test_ready_writers_should_call_send_pending
|
364
|
-
socket.enqueue("laksdjflasdkf")
|
365
|
-
socket.expects(:send).with("laksdjflasdkf", 0).returns(13)
|
366
|
-
IO.expects(:select).with([socket],[socket],nil,nil).returns([[],[socket],[]])
|
367
|
-
session.process
|
368
|
-
end
|
369
|
-
|
370
|
-
def test_process_should_call_rekey_as_needed
|
371
|
-
transport.expects(:rekey_as_needed)
|
372
|
-
IO.expects(:select).with([socket],[],nil,nil).returns([[],[],[]])
|
373
|
-
session.process
|
374
|
-
end
|
375
|
-
|
376
|
-
def test_process_should_call_enqueue_message_if_io_select_timed_out
|
377
|
-
timeout = Net::SSH::Connection::Session::DEFAULT_IO_SELECT_TIMEOUT
|
378
|
-
options = { :keepalive => true }
|
379
|
-
expected_packet = P(:byte, Net::SSH::Packet::GLOBAL_REQUEST, :string, "keepalive@openssh.com", :bool, true)
|
380
|
-
IO.stubs(:select).with([socket],[],nil,timeout).returns(nil)
|
381
|
-
transport.expects(:enqueue_message).with{ |msg| msg.content == expected_packet.content }
|
382
|
-
session(options).process
|
383
|
-
end
|
384
|
-
|
385
|
-
def test_process_should_raise_if_keepalives_not_answered
|
386
|
-
timeout = Net::SSH::Connection::Session::DEFAULT_IO_SELECT_TIMEOUT
|
387
|
-
options = { :keepalive => true, :keepalive_interval => 300, :keepalive_maxcount => 3 }
|
388
|
-
expected_packet = P(:byte, Net::SSH::Packet::GLOBAL_REQUEST, :string, "keepalive@openssh.com", :bool, true)
|
389
|
-
[1,2,3].each do |i|
|
390
|
-
Time.stubs(:now).returns(Time.at(i*300))
|
391
|
-
IO.stubs(:select).with([socket],[],nil,timeout).returns(nil)
|
392
|
-
transport.expects(:enqueue_message).with{ |msg| msg.content == expected_packet.content }
|
393
|
-
session(options).process
|
394
|
-
end
|
395
|
-
|
396
|
-
Time.stubs(:now).returns(Time.at(4*300))
|
397
|
-
IO.stubs(:select).with([socket],[],nil,timeout).returns(nil)
|
398
|
-
transport.expects(:enqueue_message).with{ |msg| msg.content == expected_packet.content }
|
399
|
-
assert_raises(Net::SSH::Timeout) { session(options).process }
|
400
|
-
end
|
401
|
-
|
402
|
-
def test_process_should_not_call_enqueue_message_unless_io_select_timed_out
|
403
|
-
timeout = Net::SSH::Connection::Session::DEFAULT_IO_SELECT_TIMEOUT
|
404
|
-
options = { :keepalive => true }
|
405
|
-
IO.stubs(:select).with([socket],[],nil,timeout).returns([[],[],[]])
|
406
|
-
transport.expects(:enqueue_message).never
|
407
|
-
session(options).process
|
408
|
-
end
|
409
|
-
|
410
|
-
def test_process_should_not_call_enqueue_message_unless_keepalive_interval_not_go_on
|
411
|
-
timeout = 10
|
412
|
-
options = { :keepalive => true, :keepalive_interval => timeout }
|
413
|
-
Time.stubs(:now).returns(Time.at(0), Time.at(9), Time.at(timeout))
|
414
|
-
IO.stubs(:select).with([socket],[],nil,timeout).returns(nil)
|
415
|
-
transport.expects(:enqueue_message).times(2)
|
416
|
-
3.times { session(options).process }
|
417
|
-
end
|
418
|
-
|
419
|
-
def test_process_should_call_io_select_with_nil_as_last_arg_if_keepalive_disabled
|
420
|
-
IO.expects(:select).with([socket],[],nil,nil).returns([[],[],[]])
|
421
|
-
session.process
|
422
|
-
end
|
423
|
-
|
424
|
-
def test_process_should_call_io_select_with_interval_as_last_arg_if_keepalive_interval_passed
|
425
|
-
timeout = 10
|
426
|
-
options = { :keepalive => true, :keepalive_interval => timeout }
|
427
|
-
IO.expects(:select).with([socket],[],nil,timeout).returns([[],[],[]])
|
428
|
-
session(options).process
|
429
|
-
end
|
430
|
-
|
431
|
-
def test_process_should_call_io_select_with_wait_if_provided_and_minimum
|
432
|
-
timeout = 10
|
433
|
-
wait = 5
|
434
|
-
options = { :keepalive => true, :keepalive_interval => timeout }
|
435
|
-
IO.expects(:select).with([socket],[],nil,wait).returns([[],[],[]])
|
436
|
-
session(options).process(wait)
|
437
|
-
end
|
438
|
-
|
439
|
-
def test_loop_should_call_process_until_process_returns_false
|
440
|
-
IO.stubs(:select).with([socket],[],nil,nil).returns([[],[],[]])
|
441
|
-
session.expects(:process).with(nil).times(4).returns(true,true,true,false).yields
|
442
|
-
n = 0
|
443
|
-
session.loop { n += 1 }
|
444
|
-
assert_equal 4, n
|
445
|
-
end
|
446
|
-
|
447
|
-
def test_exec_should_open_channel_and_configure_default_callbacks
|
448
|
-
prep_exec("ls", :stdout, "data packet", :stderr, "extended data packet")
|
449
|
-
|
450
|
-
call = :first
|
451
|
-
session.exec "ls" do |channel, type, data|
|
452
|
-
if call == :first
|
453
|
-
assert_equal :stdout, type
|
454
|
-
assert_equal "data packet", data
|
455
|
-
call = :second
|
456
|
-
elsif call == :second
|
457
|
-
assert_equal :stderr, type
|
458
|
-
assert_equal "extended data packet", data
|
459
|
-
call = :third
|
460
|
-
else
|
461
|
-
flunk "should never get here, call == #{call.inspect}"
|
462
|
-
end
|
463
|
-
end
|
464
|
-
|
465
|
-
session.loop
|
466
|
-
assert_equal :third, call
|
467
|
-
end
|
468
|
-
|
469
|
-
def test_exec_without_block_should_use_print_to_display_result
|
470
|
-
prep_exec("ls", :stdout, "data packet", :stderr, "extended data packet")
|
471
|
-
$stdout.expects(:print).with("data packet")
|
472
|
-
$stderr.expects(:print).with("extended data packet")
|
473
|
-
|
474
|
-
session.exec "ls"
|
475
|
-
session.loop
|
476
|
-
end
|
477
|
-
|
478
|
-
def test_exec_bang_should_block_until_command_finishes
|
479
|
-
prep_exec("ls", :stdout, "some data")
|
480
|
-
called = false
|
481
|
-
session.exec! "ls" do |channel, type, data|
|
482
|
-
called = true
|
483
|
-
assert_equal :stdout, type
|
484
|
-
assert_equal "some data", data
|
485
|
-
end
|
486
|
-
assert called
|
487
|
-
end
|
488
|
-
|
489
|
-
def test_exec_bang_without_block_should_return_data_as_string
|
490
|
-
prep_exec("ls", :stdout, "some data")
|
491
|
-
assert_equal "some data", session.exec!("ls")
|
492
|
-
end
|
493
|
-
|
494
|
-
def test_exec_bang_without_block_should_return_empty_string_for_empty_command_output
|
495
|
-
prep_exec('ls', :stdout, '')
|
496
|
-
assert_equal "", session.exec!('ls')
|
497
|
-
end
|
498
|
-
|
499
|
-
private
|
500
|
-
|
501
|
-
def prep_exec(command, *data)
|
502
|
-
transport.mock_enqueue = true
|
503
|
-
transport.expect do |t, p|
|
504
|
-
assert_equal CHANNEL_OPEN, p.type
|
505
|
-
t.return(CHANNEL_OPEN_CONFIRMATION, :long, p[:remote_id], :long, 0, :long, 0x20000, :long, 0x10000)
|
506
|
-
t.expect do |t2, p2|
|
507
|
-
assert_equal CHANNEL_REQUEST, p2.type
|
508
|
-
assert_equal "exec", p2[:request]
|
509
|
-
assert_equal true, p2[:want_reply]
|
510
|
-
assert_equal "ls", p2.read_string
|
511
|
-
|
512
|
-
t2.return(CHANNEL_SUCCESS, :long, p[:remote_id])
|
513
|
-
|
514
|
-
data.each_slice(2) do |type, datum|
|
515
|
-
next if datum.empty?
|
516
|
-
if type == :stdout
|
517
|
-
t2.return(CHANNEL_DATA, :long, p[:remote_id], :string, datum)
|
518
|
-
else
|
519
|
-
t2.return(CHANNEL_EXTENDED_DATA, :long, p[:remote_id], :long, 1, :string, datum)
|
520
|
-
end
|
521
|
-
end
|
522
|
-
|
523
|
-
t2.return(CHANNEL_CLOSE, :long, p[:remote_id])
|
524
|
-
t2.expect { |t3,p3| assert_equal CHANNEL_CLOSE, p3.type }
|
525
|
-
end
|
526
|
-
end
|
527
|
-
end
|
528
|
-
|
529
|
-
module MockSocket
|
530
|
-
# so that we can easily test the contents that were enqueued, without
|
531
|
-
# worrying about all the packet stream overhead
|
532
|
-
def enqueue_packet(message)
|
533
|
-
enqueue(message.to_s)
|
534
|
-
end
|
535
|
-
end
|
536
|
-
|
537
|
-
def socket
|
538
|
-
@socket ||= begin
|
539
|
-
socket ||= Object.new
|
540
|
-
socket.extend(Net::SSH::Transport::PacketStream)
|
541
|
-
socket.extend(MockSocket)
|
542
|
-
socket
|
543
|
-
end
|
544
|
-
end
|
545
|
-
|
546
|
-
def channel_at(local_id)
|
547
|
-
session.channels[local_id] = stub("channel", :process => true, :local_closed? => false)
|
548
|
-
end
|
549
|
-
|
550
|
-
def transport(options={})
|
551
|
-
@transport ||= MockTransport.new(options.merge(:socket => socket))
|
552
|
-
end
|
553
|
-
|
554
|
-
def session(options={})
|
555
|
-
@session ||= Net::SSH::Connection::Session.new(transport, options)
|
556
|
-
end
|
557
|
-
|
558
|
-
def process_times(n)
|
559
|
-
i = 0
|
560
|
-
session.process { (i += 1) < n }
|
561
|
-
end
|
562
|
-
end
|
563
|
-
|
564
|
-
end
|
data/test/integration/README.txt
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
# Integration tests with vagrant
|
2
|
-
|
3
|
-
Requirements:
|
4
|
-
|
5
|
-
* Vagrant (https://www.vagrantup.com/)
|
6
|
-
* Ansible (http://docs.ansible.com/intro_installation.html)
|
7
|
-
|
8
|
-
Setup:
|
9
|
-
|
10
|
-
ansible-galaxy install rvm_io.rvm1-ruby
|
11
|
-
vagrant up ; vagrant ssh
|
12
|
-
rake test
|
13
|
-
|
14
|
-
# TODO
|
15
|
-
|
16
|
-
* get it running on ci (probalby needs docker)
|
17
|
-
* could not get gem install jeweler to work
|
@@ -1,12 +0,0 @@
|
|
1
|
-
VAGRANTFILE_API_VERSION = "2"
|
2
|
-
|
3
|
-
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
4
|
-
config.vm.box = "ubuntu/trusty64"
|
5
|
-
config.vm.provision "ansible" do |ansible|
|
6
|
-
ansible.playbook = "./playbook.yml"
|
7
|
-
ansible.sudo = true
|
8
|
-
ansible.verbose ='vvvv'
|
9
|
-
end
|
10
|
-
|
11
|
-
config.vm.synced_folder "../..", "/net-ssh"
|
12
|
-
end
|
data/test/integration/common.rb
DELETED
@@ -1,63 +0,0 @@
|
|
1
|
-
$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../../lib"
|
2
|
-
gem "test-unit" # http://rubyforge.org/pipermail/test-unit-tracker/2009-July/000075.html
|
3
|
-
gem 'mocha'
|
4
|
-
require 'test/unit'
|
5
|
-
require 'mocha/setup'
|
6
|
-
require 'pty'
|
7
|
-
require 'expect'
|
8
|
-
|
9
|
-
module IntegrationTestHelpers
|
10
|
-
def sh command
|
11
|
-
puts "$ #{command}"
|
12
|
-
res = system(command)
|
13
|
-
status = $?
|
14
|
-
raise "Command: #{command} failed:#{status.exitstatus}" unless res
|
15
|
-
end
|
16
|
-
|
17
|
-
def tmpdir(&block)
|
18
|
-
Dir.mktmpdir do |dir|
|
19
|
-
yield(dir)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def set_authorized_key(user,pubkey)
|
24
|
-
authorized_key = "/home/#{user}/.ssh/authorized_keys"
|
25
|
-
sh "sudo cp #{pubkey} #{authorized_key}"
|
26
|
-
sh "sudo chown #{user} #{authorized_key}"
|
27
|
-
sh "sudo chmod 0744 #{authorized_key}"
|
28
|
-
end
|
29
|
-
|
30
|
-
def with_agent(&block)
|
31
|
-
puts "/usr/bin/ssh-agent -c"
|
32
|
-
agent_out = `/usr/bin/ssh-agent -c`
|
33
|
-
agent_out.split("\n").each do |line|
|
34
|
-
if line =~ /setenv (\S+) (\S+);/
|
35
|
-
ENV[$1] = $2
|
36
|
-
puts "ENV[#{$1}]=#{$2}"
|
37
|
-
end
|
38
|
-
end
|
39
|
-
begin
|
40
|
-
yield
|
41
|
-
ensure
|
42
|
-
sh "/usr/bin/ssh-agent -k"
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def ssh_add(key,password)
|
47
|
-
command = "ssh-add #{key}"
|
48
|
-
status = nil
|
49
|
-
PTY.spawn(command) do |reader, writer, pid|
|
50
|
-
begin
|
51
|
-
reader.expect(/Enter passphrase for .*:/) { |data| puts data }
|
52
|
-
writer.puts(password)
|
53
|
-
until reader.eof? do
|
54
|
-
puts reader.readline
|
55
|
-
end
|
56
|
-
rescue Errno::EIO => e
|
57
|
-
end
|
58
|
-
pid, status = Process.wait2 pid
|
59
|
-
end
|
60
|
-
raise "Command: #{command} failed:#{status.exitstatus}" unless status
|
61
|
-
status.exitstatus
|
62
|
-
end
|
63
|
-
end
|