net-ssh 2.7.0 → 2.8.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/CHANGES.txt +17 -0
- data/THANKS.txt +25 -0
- data/lib/net/ssh.rb +6 -4
- data/lib/net/ssh/authentication/agent/socket.rb +3 -3
- data/lib/net/ssh/authentication/key_manager.rb +7 -7
- data/lib/net/ssh/authentication/pageant.rb +35 -51
- data/lib/net/ssh/authentication/session.rb +2 -1
- data/lib/net/ssh/buffer.rb +2 -2
- data/lib/net/ssh/config.rb +33 -8
- data/lib/net/ssh/key_factory.rb +7 -1
- data/lib/net/ssh/proxy/command.rb +8 -1
- data/lib/net/ssh/proxy/http.rb +1 -1
- data/lib/net/ssh/proxy/socks4.rb +1 -1
- data/lib/net/ssh/proxy/socks5.rb +2 -2
- data/lib/net/ssh/service/forward.rb +42 -7
- data/lib/net/ssh/transport/session.rb +7 -1
- data/lib/net/ssh/version.rb +1 -1
- data/net-ssh.gemspec +7 -3
- data/test/authentication/test_agent.rb +6 -6
- data/test/authentication/test_key_manager.rb +7 -3
- data/test/authentication/test_session.rb +2 -3
- data/test/configs/auth_off +4 -0
- data/test/configs/auth_on +4 -0
- data/test/configs/empty +0 -0
- data/test/manual/test_forward.rb +27 -14
- data/test/start/test_connection.rb +53 -0
- data/test/test_config.rb +37 -1
- data/test/test_key_factory.rb +20 -2
- metadata +7 -3
data/CHANGES.txt
CHANGED
@@ -1,5 +1,22 @@
|
|
1
1
|
|
2
2
|
|
3
|
+
=== 2.8.0 / 01 Feb 2014
|
4
|
+
|
5
|
+
* Handle ssh-rsa and ssh-dss certificate files [bobveznat]
|
6
|
+
* Correctly interpret /etc/ssh_config Authentication settings based on openssh /etc/ssh_config system defaults [therealjessesanford, liggitt]
|
7
|
+
* Fixed pageant support for Windows [jarredholman]
|
8
|
+
* Support %r in ProxyCommand configuration in ssh_config files as defined in OpenSSH [yugui]
|
9
|
+
* Don't use ssh-agent if :keys_only is true [SFEley]
|
10
|
+
* Fix the bug in keys with comments [bobtfish]
|
11
|
+
* Add a failing tests for options in pub keys [bobtfish]
|
12
|
+
* Assert that the return value from ssh block is returned [carlhoerberg]
|
13
|
+
* Don't close the connection it's already closed [carlhoerberg]
|
14
|
+
* Ensure the connection closes even on exception [carlhoerberg]
|
15
|
+
* Make the authentication error message more useful [deric]
|
16
|
+
* Fix "ConnectionError" typo in lib/net/ssh/proxy/socks5.rb [mirakui]
|
17
|
+
* Allow KeyManager to recover from incompatible agents [ecki, delano]
|
18
|
+
* Fix for "Authentication Method determination can pick up a class from the root namespace" [dave.sieh]
|
19
|
+
|
3
20
|
=== 2.7.0 / 11 Sep 2013
|
4
21
|
|
5
22
|
* Fix for 'Could not parse PKey: no start line' error on private keys with passphrases (issue #101) [metametaclass]
|
data/THANKS.txt
CHANGED
@@ -19,6 +19,30 @@ Chris Andrews <chris@nodnol.org> and Lee Jensen <lee@outerim.com>
|
|
19
19
|
Hiroshi Nakamura
|
20
20
|
* fixed errors with JRuby tests
|
21
21
|
|
22
|
+
bobveznat
|
23
|
+
therealjessesanford
|
24
|
+
liggitt
|
25
|
+
jarredholman
|
26
|
+
yugui
|
27
|
+
SFEley
|
28
|
+
bobtfish
|
29
|
+
carlhoerberg
|
30
|
+
deric
|
31
|
+
mirakui
|
32
|
+
ecki
|
33
|
+
Dave Sieh
|
34
|
+
metametaclass
|
35
|
+
fnordfish
|
36
|
+
krishicks
|
37
|
+
noric
|
38
|
+
GabKlein
|
39
|
+
Josh Kalderimis
|
40
|
+
voxik
|
41
|
+
Olipro
|
42
|
+
jansegre
|
43
|
+
priteau
|
44
|
+
jordimassaguerpla
|
45
|
+
Kenichi Kamiya
|
22
46
|
Andreas Wolff
|
23
47
|
mhuffnagle
|
24
48
|
ohrite
|
@@ -83,3 +107,4 @@ watsonian
|
|
83
107
|
Grant Hutchins
|
84
108
|
Michael Schubert
|
85
109
|
mtrudel
|
110
|
+
Aurélien Derouineau
|
data/lib/net/ssh.rb
CHANGED
@@ -204,15 +204,17 @@ module Net
|
|
204
204
|
if auth.authenticate("ssh-connection", user, options[:password])
|
205
205
|
connection = Connection::Session.new(transport, options)
|
206
206
|
if block_given?
|
207
|
-
|
208
|
-
|
209
|
-
|
207
|
+
begin
|
208
|
+
yield connection
|
209
|
+
ensure
|
210
|
+
connection.close unless connection.closed?
|
211
|
+
end
|
210
212
|
else
|
211
213
|
return connection
|
212
214
|
end
|
213
215
|
else
|
214
216
|
transport.close
|
215
|
-
raise AuthenticationFailed, user
|
217
|
+
raise AuthenticationFailed, "Authentication failed for user #{user}@#{host}"
|
216
218
|
end
|
217
219
|
end
|
218
220
|
|
@@ -76,9 +76,9 @@ module Net; module SSH; module Authentication
|
|
76
76
|
type, body = send_and_wait(SSH2_AGENT_REQUEST_VERSION, :string, Transport::ServerVersion::PROTO_VERSION)
|
77
77
|
|
78
78
|
if type == SSH2_AGENT_VERSION_RESPONSE
|
79
|
-
raise
|
79
|
+
raise AgentNotAvailable, "SSH2 agents are not yet supported"
|
80
80
|
elsif type != SSH_AGENT_RSA_IDENTITIES_ANSWER1 && type != SSH_AGENT_RSA_IDENTITIES_ANSWER2
|
81
|
-
raise
|
81
|
+
raise AgentNotAvailable, "unknown response from agent: #{type}, #{body.to_s.inspect}"
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
@@ -126,7 +126,7 @@ module Net; module SSH; module Authentication
|
|
126
126
|
# Returns the agent socket factory to use.
|
127
127
|
def agent_socket_factory
|
128
128
|
if Net::SSH::Authentication::PLATFORM == :win32
|
129
|
-
Pageant::
|
129
|
+
Pageant::Socket
|
130
130
|
else
|
131
131
|
UNIXSocket
|
132
132
|
end
|
@@ -12,7 +12,7 @@ module Net
|
|
12
12
|
|
13
13
|
# This class encapsulates all operations done by clients on a user's
|
14
14
|
# private keys. In practice, the client should never need a reference
|
15
|
-
# to a private key; instead, they grab a list of "identities" (public
|
15
|
+
# to a private key; instead, they grab a list of "identities" (public
|
16
16
|
# keys) that are available from the KeyManager, and then use
|
17
17
|
# the KeyManager to do various private key operations using those
|
18
18
|
# identities.
|
@@ -37,12 +37,13 @@ module Net
|
|
37
37
|
attr_reader :options
|
38
38
|
|
39
39
|
# Create a new KeyManager. By default, the manager will
|
40
|
-
# use the ssh-agent
|
40
|
+
# use the ssh-agent if it is running and the `:keys_only` option
|
41
|
+
# is not true.
|
41
42
|
def initialize(logger, options={})
|
42
43
|
self.logger = logger
|
43
44
|
@key_files = []
|
44
45
|
@key_data = []
|
45
|
-
@use_agent =
|
46
|
+
@use_agent = !options[:keys_only]
|
46
47
|
@known_identities = {}
|
47
48
|
@agent = nil
|
48
49
|
@options = options
|
@@ -91,9 +92,8 @@ module Net
|
|
91
92
|
# ssh-agent. Note that identities from an ssh-agent are always listed
|
92
93
|
# first in the array, with other identities coming after.
|
93
94
|
#
|
94
|
-
# If key manager was created with :keys_only option,
|
95
|
-
# from ssh-agent will be
|
96
|
-
# key_data.
|
95
|
+
# If key manager was created with :keys_only option, no identities
|
96
|
+
# from ssh-agent will be loaded.
|
97
97
|
def each_identity
|
98
98
|
prepared_identities = prepare_identities_from_files + prepare_identities_from_data
|
99
99
|
|
@@ -139,7 +139,7 @@ module Net
|
|
139
139
|
if info[:key].nil? && info[:from] == :file
|
140
140
|
begin
|
141
141
|
info[:key] = KeyFactory.load_private_key(info[:file], options[:passphrase], true)
|
142
|
-
rescue Exception, OpenSSL::OpenSSLError => e
|
142
|
+
rescue Exception, OpenSSL::OpenSSLError => e
|
143
143
|
raise KeyManagerError, "the given identity is known, but the private key could not be loaded: #{e.class} (#{e.message})"
|
144
144
|
end
|
145
145
|
end
|
@@ -110,21 +110,49 @@ module Net; module SSH; module Authentication
|
|
110
110
|
"pageant process not running"
|
111
111
|
end
|
112
112
|
|
113
|
-
@
|
114
|
-
@
|
113
|
+
@input_buffer = Net::SSH::Buffer.new
|
114
|
+
@output_buffer = Net::SSH::Buffer.new
|
115
115
|
end
|
116
116
|
|
117
117
|
# Forwards the data to #send_query, ignoring any arguments after
|
118
|
-
# the first.
|
118
|
+
# the first.
|
119
119
|
def send(data, *args)
|
120
|
-
@
|
121
|
-
|
120
|
+
@input_buffer.append(data)
|
121
|
+
|
122
|
+
ret = data.length
|
123
|
+
|
124
|
+
while true
|
125
|
+
return ret if @input_buffer.length < 4
|
126
|
+
msg_length = @input_buffer.read_long + 4
|
127
|
+
@input_buffer.reset!
|
128
|
+
|
129
|
+
return ret if @input_buffer.length < msg_length
|
130
|
+
msg = @input_buffer.read!(msg_length)
|
131
|
+
@output_buffer.append(send_query(msg))
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# Reads +n+ bytes from the cached result of the last query. If +n+
|
136
|
+
# is +nil+, returns all remaining data from the last query.
|
137
|
+
def read(n = nil)
|
138
|
+
@output_buffer.read(n)
|
122
139
|
end
|
123
140
|
|
141
|
+
def close
|
142
|
+
end
|
143
|
+
|
144
|
+
def send_query(query)
|
145
|
+
if RUBY_VERSION < "1.9"
|
146
|
+
send_query_18(query)
|
147
|
+
else
|
148
|
+
send_query_19(query)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
124
152
|
# Packages the given query string and sends it to the pageant
|
125
153
|
# process via the Windows messaging subsystem. The result is
|
126
154
|
# cached, to be returned piece-wise when #read is called.
|
127
|
-
def
|
155
|
+
def send_query_18(query)
|
128
156
|
res = nil
|
129
157
|
filemap = 0
|
130
158
|
ptr = nil
|
@@ -165,43 +193,10 @@ module Net; module SSH; module Authentication
|
|
165
193
|
Win.closeHandle(filemap) if filemap != 0
|
166
194
|
end
|
167
195
|
|
168
|
-
# Conceptually close the socket. This doesn't really do anthing
|
169
|
-
# significant, but merely complies with the Socket interface.
|
170
|
-
def close
|
171
|
-
@res = nil
|
172
|
-
@pos = 0
|
173
|
-
end
|
174
|
-
|
175
|
-
# Conceptually asks if the socket is closed. As with #close,
|
176
|
-
# this doesn't really do anything significant, but merely
|
177
|
-
# complies with the Socket interface.
|
178
|
-
def closed?
|
179
|
-
@res.nil? && @pos.zero?
|
180
|
-
end
|
181
|
-
|
182
|
-
# Reads +n+ bytes from the cached result of the last query. If +n+
|
183
|
-
# is +nil+, returns all remaining data from the last query.
|
184
|
-
def read(n = nil)
|
185
|
-
return nil unless @res
|
186
|
-
if n.nil?
|
187
|
-
start, @pos = @pos, @res.size
|
188
|
-
return @res[start..-1]
|
189
|
-
else
|
190
|
-
start, @pos = @pos, @pos + n
|
191
|
-
return @res[start, n]
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
|
-
end
|
196
|
-
|
197
|
-
# Socket changes for Ruby 1.9
|
198
|
-
# Functionality is the same as Ruby 1.8 but it includes the new calls to
|
199
|
-
# the DL module as well as other pointer transformations
|
200
|
-
class Socket19 < Socket
|
201
196
|
# Packages the given query string and sends it to the pageant
|
202
197
|
# process via the Windows messaging subsystem. The result is
|
203
198
|
# cached, to be returned piece-wise when #read is called.
|
204
|
-
def
|
199
|
+
def send_query_19(query)
|
205
200
|
res = nil
|
206
201
|
filemap = 0
|
207
202
|
ptr = nil
|
@@ -244,17 +239,6 @@ module Net; module SSH; module Authentication
|
|
244
239
|
Win.CloseHandle(filemap) if filemap != 0
|
245
240
|
end
|
246
241
|
end
|
247
|
-
|
248
|
-
# Selects which socket to use depending on the ruby version
|
249
|
-
# This is needed due changes in the DL module.
|
250
|
-
def self.socket_factory
|
251
|
-
if RUBY_VERSION < "1.9"
|
252
|
-
Socket
|
253
|
-
else
|
254
|
-
Socket19
|
255
|
-
end
|
256
|
-
end
|
257
|
-
|
258
242
|
end
|
259
243
|
|
260
244
|
end; end; end
|
@@ -2,6 +2,7 @@ require 'net/ssh/loggable'
|
|
2
2
|
require 'net/ssh/transport/constants'
|
3
3
|
require 'net/ssh/authentication/constants'
|
4
4
|
require 'net/ssh/authentication/key_manager'
|
5
|
+
require 'net/ssh/authentication/methods/none'
|
5
6
|
require 'net/ssh/authentication/methods/publickey'
|
6
7
|
require 'net/ssh/authentication/methods/hostbased'
|
7
8
|
require 'net/ssh/authentication/methods/password'
|
@@ -41,7 +42,7 @@ module Net; module SSH; module Authentication
|
|
41
42
|
self.logger = transport.logger
|
42
43
|
@transport = transport
|
43
44
|
|
44
|
-
@auth_methods = options[:auth_methods] ||
|
45
|
+
@auth_methods = options[:auth_methods] || Net::SSH::Config.default_auth_methods
|
45
46
|
@options = options
|
46
47
|
|
47
48
|
@allowed_auth_methods = @auth_methods
|
data/lib/net/ssh/buffer.rb
CHANGED
@@ -243,14 +243,14 @@ module Net; module SSH
|
|
243
243
|
# a key. Only RSA, DSA, and ECDSA keys are supported.
|
244
244
|
def read_keyblob(type)
|
245
245
|
case type
|
246
|
-
when
|
246
|
+
when /^ssh-dss(-cert-v01@openssh\.com)?$/
|
247
247
|
key = OpenSSL::PKey::DSA.new
|
248
248
|
key.p = read_bignum
|
249
249
|
key.q = read_bignum
|
250
250
|
key.g = read_bignum
|
251
251
|
key.pub_key = read_bignum
|
252
252
|
|
253
|
-
when
|
253
|
+
when /^ssh-rsa(-cert-v01@openssh\.com)?$/
|
254
254
|
key = OpenSSL::PKey::RSA.new
|
255
255
|
key.e = read_bignum
|
256
256
|
key.n = read_bignum
|
data/lib/net/ssh/config.rb
CHANGED
@@ -8,6 +8,7 @@ module Net; module SSH
|
|
8
8
|
#
|
9
9
|
# Only a subset of OpenSSH configuration options are understood:
|
10
10
|
#
|
11
|
+
# * ChallengeResponseAuthentication => maps to the :auth_methods option
|
11
12
|
# * Ciphers => maps to the :encryption option
|
12
13
|
# * Compression => :compression
|
13
14
|
# * CompressionLevel => :compression_level
|
@@ -25,6 +26,7 @@ module Net; module SSH
|
|
25
26
|
# * Port => :port
|
26
27
|
# * PreferredAuthentications => maps to the :auth_methods option
|
27
28
|
# * ProxyCommand => maps to the :proxy option
|
29
|
+
# * PubKeyAuthentication => maps to the :auth_methods option
|
28
30
|
# * RekeyLimit => :rekey_limit
|
29
31
|
# * User => :user
|
30
32
|
# * UserKnownHostsFile => :user_known_hosts_file
|
@@ -35,19 +37,30 @@ module Net; module SSH
|
|
35
37
|
class Config
|
36
38
|
class << self
|
37
39
|
@@default_files = %w(~/.ssh/config /etc/ssh_config /etc/ssh/ssh_config)
|
40
|
+
# The following defaults follow the openssh client ssh_config defaults.
|
41
|
+
# http://lwn.net/Articles/544640/
|
42
|
+
# "hostbased" is off and "none" is not supported but we allow it since
|
43
|
+
# it's used by some clients to query the server for allowed auth methods
|
44
|
+
@@default_auth_methods = %w(none publickey password keyboard-interactive)
|
38
45
|
|
39
46
|
# Returns an array of locations of OpenSSH configuration files
|
40
47
|
# to parse by default.
|
41
48
|
def default_files
|
42
49
|
@@default_files
|
43
50
|
end
|
51
|
+
|
52
|
+
def default_auth_methods
|
53
|
+
@@default_auth_methods
|
54
|
+
end
|
44
55
|
|
45
56
|
# Loads the configuration data for the given +host+ from all of the
|
46
57
|
# given +files+ (defaulting to the list of files returned by
|
47
58
|
# #default_files), translates the resulting hash into the options
|
48
59
|
# recognized by Net::SSH, and returns them.
|
49
60
|
def for(host, files=default_files)
|
50
|
-
translate(files.inject({}) { |settings, file|
|
61
|
+
hash = translate(files.inject({}) { |settings, file|
|
62
|
+
load(file, host, settings)
|
63
|
+
})
|
51
64
|
end
|
52
65
|
|
53
66
|
# Load the OpenSSH configuration settings in the given +file+ for the
|
@@ -59,6 +72,8 @@ module Net; module SSH
|
|
59
72
|
def load(path, host, settings={})
|
60
73
|
file = File.expand_path(path)
|
61
74
|
return settings unless File.readable?(file)
|
75
|
+
|
76
|
+
settings[:auth_methods] ||= default_auth_methods.clone
|
62
77
|
|
63
78
|
globals = {}
|
64
79
|
matched_host = nil
|
@@ -119,6 +134,7 @@ module Net; module SSH
|
|
119
134
|
# the returned hash will have Symbols for keys.
|
120
135
|
def translate(settings)
|
121
136
|
settings.inject({}) do |hash, (key, value)|
|
137
|
+
hash[:auth_methods] ||= settings[:auth_methods] || default_auth_methods.clone
|
122
138
|
case key
|
123
139
|
when 'bindaddress' then
|
124
140
|
hash[:bind_address] = value
|
@@ -138,8 +154,9 @@ module Net; module SSH
|
|
138
154
|
hash[:global_known_hosts_file] = value
|
139
155
|
when 'hostbasedauthentication' then
|
140
156
|
if value
|
141
|
-
hash[:auth_methods]
|
142
|
-
|
157
|
+
(hash[:auth_methods] << "hostbased").uniq!
|
158
|
+
else
|
159
|
+
hash[:auth_methods].delete("hostbased")
|
143
160
|
end
|
144
161
|
when 'hostkeyalgorithms' then
|
145
162
|
hash[:host_key] = value.split(/,/)
|
@@ -153,8 +170,15 @@ module Net; module SSH
|
|
153
170
|
hash[:hmac] = value.split(/,/)
|
154
171
|
when 'passwordauthentication'
|
155
172
|
if value
|
156
|
-
hash[:auth_methods]
|
157
|
-
|
173
|
+
(hash[:auth_methods] << 'password').uniq!
|
174
|
+
else
|
175
|
+
hash[:auth_methods].delete('password')
|
176
|
+
end
|
177
|
+
when 'challengeresponseauthentication'
|
178
|
+
if value
|
179
|
+
(hash[:auth_methods] << 'keyboard-interactive').uniq!
|
180
|
+
else
|
181
|
+
hash[:auth_methods].delete('keyboard-interactive')
|
158
182
|
end
|
159
183
|
when 'port'
|
160
184
|
hash[:port] = value
|
@@ -165,10 +189,11 @@ module Net; module SSH
|
|
165
189
|
require 'net/ssh/proxy/command'
|
166
190
|
hash[:proxy] = Net::SSH::Proxy::Command.new(value)
|
167
191
|
end
|
168
|
-
|
192
|
+
when 'pubkeyauthentication'
|
169
193
|
if value
|
170
|
-
hash[:auth_methods]
|
171
|
-
|
194
|
+
(hash[:auth_methods] << 'publickey').uniq!
|
195
|
+
else
|
196
|
+
hash[:auth_methods].delete('publickey')
|
172
197
|
end
|
173
198
|
when 'rekeylimit'
|
174
199
|
hash[:rekey_limit] = interpret_size(value)
|
data/lib/net/ssh/key_factory.rb
CHANGED
@@ -105,7 +105,13 @@ module Net; module SSH
|
|
105
105
|
# the file describes an RSA or DSA key, and will load it
|
106
106
|
# appropriately. The new public key is returned.
|
107
107
|
def load_data_public_key(data, filename="")
|
108
|
-
|
108
|
+
fields = data.split(/ /)
|
109
|
+
|
110
|
+
blob = nil
|
111
|
+
begin
|
112
|
+
blob = fields.shift
|
113
|
+
end while !blob.nil? && !/^(ssh-(rsa|dss)|ecdsa-sha2-nistp\d+)$/.match(blob)
|
114
|
+
blob = fields.shift
|
109
115
|
|
110
116
|
raise Net::SSH::Exception, "public key at #{filename} is not valid" if blob.nil?
|
111
117
|
|
@@ -33,13 +33,20 @@ module Net; module SSH; module Proxy
|
|
33
33
|
|
34
34
|
# Return a new socket connected to the given host and port via the
|
35
35
|
# proxy that was requested when the socket factory was instantiated.
|
36
|
-
def open(host, port)
|
36
|
+
def open(host, port, connection_options = nil)
|
37
37
|
command_line = @command_line_template.gsub(/%(.)/) {
|
38
38
|
case $1
|
39
39
|
when 'h'
|
40
40
|
host
|
41
41
|
when 'p'
|
42
42
|
port.to_s
|
43
|
+
when 'r'
|
44
|
+
remote_user = connection_options && connection_options[:remote_user]
|
45
|
+
if remote_user
|
46
|
+
remote_user
|
47
|
+
else
|
48
|
+
raise ArgumentError, "remote user name not available"
|
49
|
+
end
|
43
50
|
when '%'
|
44
51
|
'%'
|
45
52
|
else
|
data/lib/net/ssh/proxy/http.rb
CHANGED
@@ -48,7 +48,7 @@ module Net; module SSH; module Proxy
|
|
48
48
|
|
49
49
|
# Return a new socket connected to the given host and port via the
|
50
50
|
# proxy that was requested when the socket factory was instantiated.
|
51
|
-
def open(host, port)
|
51
|
+
def open(host, port, connection_options = nil)
|
52
52
|
socket = TCPSocket.new(proxy_host, proxy_port)
|
53
53
|
socket.write "CONNECT #{host}:#{port} HTTP/1.0\r\n"
|
54
54
|
|
data/lib/net/ssh/proxy/socks4.rb
CHANGED
@@ -47,7 +47,7 @@ module Net
|
|
47
47
|
|
48
48
|
# Return a new socket connected to the given host and port via the
|
49
49
|
# proxy that was requested when the socket factory was instantiated.
|
50
|
-
def open(host, port)
|
50
|
+
def open(host, port, connection_options)
|
51
51
|
socket = TCPSocket.new(proxy_host, proxy_port)
|
52
52
|
ip_addr = IPAddr.new(Resolv.getaddress(host))
|
53
53
|
|
data/lib/net/ssh/proxy/socks5.rb
CHANGED
@@ -62,7 +62,7 @@ module Net
|
|
62
62
|
|
63
63
|
# Return a new socket connected to the given host and port via the
|
64
64
|
# proxy that was requested when the socket factory was instantiated.
|
65
|
-
def open(host, port)
|
65
|
+
def open(host, port, connection_options = nil)
|
66
66
|
socket = TCPSocket.new(proxy_host, proxy_port)
|
67
67
|
|
68
68
|
methods = [METHOD_NO_AUTH]
|
@@ -108,7 +108,7 @@ module Net
|
|
108
108
|
ipv6addr hostname = socket.recv(16)
|
109
109
|
else
|
110
110
|
socket.close
|
111
|
-
raise
|
111
|
+
raise ConnectError, "Illegal response type"
|
112
112
|
end
|
113
113
|
portnum = socket.recv(2)
|
114
114
|
|
@@ -47,8 +47,12 @@ module Net; module SSH; module Service
|
|
47
47
|
# If three arguments are given, it is as if the local bind address is
|
48
48
|
# "127.0.0.1", and the rest are applied as above.
|
49
49
|
#
|
50
|
+
# To request an ephemeral port on the remote server, provide 0 (zero) for
|
51
|
+
# the port number. In all cases, this method will return the port that
|
52
|
+
# has been assigned.
|
53
|
+
#
|
50
54
|
# ssh.forward.local(1234, "www.capify.org", 80)
|
51
|
-
# ssh.forward.local("0.0.0.0",
|
55
|
+
# assigned_port = ssh.forward.local("0.0.0.0", 0, "www.capify.org", 80)
|
52
56
|
def local(*args)
|
53
57
|
if args.length < 3 || args.length > 4
|
54
58
|
raise ArgumentError, "expected 3 or 4 parameters, got #{args.length}"
|
@@ -69,6 +73,7 @@ module Net; module SSH; module Service
|
|
69
73
|
end
|
70
74
|
end
|
71
75
|
|
76
|
+
local_port = socket.addr[1] if local_port == 0 # ephemeral port was requested
|
72
77
|
remote_host = args.shift
|
73
78
|
remote_port = args.shift.to_i
|
74
79
|
|
@@ -89,6 +94,8 @@ module Net; module SSH; module Service
|
|
89
94
|
channel[:socket].close
|
90
95
|
end
|
91
96
|
end
|
97
|
+
|
98
|
+
local_port
|
92
99
|
end
|
93
100
|
|
94
101
|
# Terminates an active local forwarded port. If no such forwarded port
|
@@ -120,15 +127,21 @@ module Net; module SSH; module Service
|
|
120
127
|
# forwarded immediately. If the remote server is not able to begin the
|
121
128
|
# listener for this request, an exception will be raised asynchronously.
|
122
129
|
#
|
123
|
-
#
|
124
|
-
#
|
125
|
-
#
|
130
|
+
# To request an ephemeral port on the remote server, provide 0 (zero) for
|
131
|
+
# the port number. The assigned port will show up in the # #active_remotes
|
132
|
+
# list.
|
126
133
|
#
|
127
|
-
#
|
128
|
-
#
|
134
|
+
# If you want to block until the port is active, you could do something
|
135
|
+
# like this:
|
136
|
+
#
|
137
|
+
# old_active_remotes = ssh.forward.active_remotes
|
138
|
+
# ssh.forward.remote(80, "www.google.com", 0, "0.0.0.0")
|
139
|
+
# ssh.loop { !(ssh.forward.active_remotes.length > old_active_remotes.length) }
|
140
|
+
# assigned_port = (ssh.forward.active_remotes - old_active_remotes).first[0]
|
129
141
|
def remote(port, host, remote_port, remote_host="127.0.0.1")
|
130
142
|
session.send_global_request("tcpip-forward", :string, remote_host, :long, remote_port) do |success, response|
|
131
143
|
if success
|
144
|
+
remote_port = response.read_long if remote_port == 0
|
132
145
|
debug { "remote forward from remote #{remote_host}:#{remote_port} to #{host}:#{port} established" }
|
133
146
|
@remote_forwarded_ports[[remote_port, remote_host]] = Remote.new(host, port)
|
134
147
|
else
|
@@ -257,6 +270,24 @@ module Net; module SSH; module Service
|
|
257
270
|
end
|
258
271
|
end
|
259
272
|
|
273
|
+
# not a real socket, so use a simpler behaviour
|
274
|
+
def prepare_simple_client(client, channel, type)
|
275
|
+
channel[:socket] = client
|
276
|
+
|
277
|
+
channel.on_data do |ch, data|
|
278
|
+
ch.debug { "data:#{data.length} on #{type} forwarded channel" }
|
279
|
+
ch[:socket].send(data)
|
280
|
+
end
|
281
|
+
|
282
|
+
channel.on_process do |ch|
|
283
|
+
data = ch[:socket].read(8192)
|
284
|
+
if data
|
285
|
+
ch.debug { "read #{data.length} bytes from client, sending over #{type} forwarded connection" }
|
286
|
+
ch.send_data(data)
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
260
291
|
# The callback used when a new "forwarded-tcpip" channel is requested
|
261
292
|
# by the server. This will open a new socket to the host/port specified
|
262
293
|
# when the forwarded connection was first requested.
|
@@ -287,7 +318,11 @@ module Net; module SSH; module Service
|
|
287
318
|
|
288
319
|
begin
|
289
320
|
agent = Authentication::Agent.connect(logger)
|
290
|
-
|
321
|
+
if (agent.socket.is_a? ::IO)
|
322
|
+
prepare_client(agent.socket, channel, :agent)
|
323
|
+
else
|
324
|
+
prepare_simple_client(agent.socket, channel, :agent)
|
325
|
+
end
|
291
326
|
rescue Exception => e
|
292
327
|
error { "attempted to connect to agent but failed: #{e.class.name} (#{e.message})" }
|
293
328
|
raise Net::SSH::ChannelOpenFailed.new(2, "could not connect to authentication agent")
|
@@ -64,7 +64,13 @@ module Net; module SSH; module Transport
|
|
64
64
|
|
65
65
|
debug { "establishing connection to #{@host}:#{@port}" }
|
66
66
|
factory = options[:proxy] || TCPSocket
|
67
|
-
@socket = timeout(options[:timeout] || 0) {
|
67
|
+
@socket = timeout(options[:timeout] || 0) {
|
68
|
+
case
|
69
|
+
when options[:proxy] then factory.open(@host, @port, options)
|
70
|
+
when @bind_address.nil? then factory.open(@host, @port)
|
71
|
+
else factory.open(@host, @port, @bind_address)
|
72
|
+
end
|
73
|
+
}
|
68
74
|
@socket.extend(PacketStream)
|
69
75
|
@socket.logger = @logger
|
70
76
|
|
data/lib/net/ssh/version.rb
CHANGED
data/net-ssh.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "net-ssh"
|
8
|
-
s.version = "2.
|
8
|
+
s.version = "2.8.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Jamis Buck", "Delano Mandelbaum"]
|
12
|
-
s.date = "
|
12
|
+
s.date = "2014-02-01"
|
13
13
|
s.description = "Net::SSH: a pure-Ruby implementation of the SSH2 client protocol. It allows you to write programs that invoke and interact with processes on remote servers, via SSH2."
|
14
14
|
s.email = "net-ssh@solutious.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -120,6 +120,9 @@ Gem::Specification.new do |s|
|
|
120
120
|
"test/authentication/test_key_manager.rb",
|
121
121
|
"test/authentication/test_session.rb",
|
122
122
|
"test/common.rb",
|
123
|
+
"test/configs/auth_off",
|
124
|
+
"test/configs/auth_on",
|
125
|
+
"test/configs/empty",
|
123
126
|
"test/configs/eqsign",
|
124
127
|
"test/configs/exact_match",
|
125
128
|
"test/configs/host_plus",
|
@@ -133,6 +136,7 @@ Gem::Specification.new do |s|
|
|
133
136
|
"test/connection/test_session.rb",
|
134
137
|
"test/known_hosts/github",
|
135
138
|
"test/manual/test_forward.rb",
|
139
|
+
"test/start/test_connection.rb",
|
136
140
|
"test/start/test_options.rb",
|
137
141
|
"test/start/test_transport.rb",
|
138
142
|
"test/test_all.rb",
|
@@ -171,7 +175,7 @@ Gem::Specification.new do |s|
|
|
171
175
|
s.licenses = ["MIT"]
|
172
176
|
s.require_paths = ["lib"]
|
173
177
|
s.rubyforge_project = "net-ssh"
|
174
|
-
s.rubygems_version = "1.8.
|
178
|
+
s.rubygems_version = "1.8.23"
|
175
179
|
s.summary = "Net::SSH: a pure-Ruby implementation of the SSH2 client protocol."
|
176
180
|
|
177
181
|
if s.respond_to? :specification_version then
|
@@ -43,7 +43,7 @@ module Authentication
|
|
43
43
|
assert_equal Net::SSH::Transport::ServerVersion::PROTO_VERSION, buffer.read_string
|
44
44
|
s.return(SSH2_AGENT_VERSION_RESPONSE)
|
45
45
|
end
|
46
|
-
assert_raises(
|
46
|
+
assert_raises(Net::SSH::Authentication::AgentNotAvailable) { agent.negotiate! }
|
47
47
|
end
|
48
48
|
|
49
49
|
def test_negotiate_should_raise_error_if_response_was_unexpected
|
@@ -51,7 +51,7 @@ module Authentication
|
|
51
51
|
assert_equal SSH2_AGENT_REQUEST_VERSION, type
|
52
52
|
s.return(255)
|
53
53
|
end
|
54
|
-
assert_raises(Net::SSH::Authentication::
|
54
|
+
assert_raises(Net::SSH::Authentication::AgentNotAvailable) { agent.negotiate! }
|
55
55
|
end
|
56
56
|
|
57
57
|
def test_negotiate_should_be_successful_with_expected_response
|
@@ -65,7 +65,7 @@ module Authentication
|
|
65
65
|
def test_identities_should_fail_if_SSH_AGENT_FAILURE_recieved
|
66
66
|
socket.expect do |s, type, buffer|
|
67
67
|
assert_equal SSH2_AGENT_REQUEST_IDENTITIES, type
|
68
|
-
s.return(SSH_AGENT_FAILURE)
|
68
|
+
s.return(SSH_AGENT_FAILURE)
|
69
69
|
end
|
70
70
|
assert_raises(Net::SSH::Authentication::AgentError) { agent.identities }
|
71
71
|
end
|
@@ -73,7 +73,7 @@ module Authentication
|
|
73
73
|
def test_identities_should_fail_if_SSH2_AGENT_FAILURE_recieved
|
74
74
|
socket.expect do |s, type, buffer|
|
75
75
|
assert_equal SSH2_AGENT_REQUEST_IDENTITIES, type
|
76
|
-
s.return(SSH2_AGENT_FAILURE)
|
76
|
+
s.return(SSH2_AGENT_FAILURE)
|
77
77
|
end
|
78
78
|
assert_raises(Net::SSH::Authentication::AgentError) { agent.identities }
|
79
79
|
end
|
@@ -81,7 +81,7 @@ module Authentication
|
|
81
81
|
def test_identities_should_fail_if_SSH_COM_AGENT2_FAILURE_recieved
|
82
82
|
socket.expect do |s, type, buffer|
|
83
83
|
assert_equal SSH2_AGENT_REQUEST_IDENTITIES, type
|
84
|
-
s.return(SSH_COM_AGENT2_FAILURE)
|
84
|
+
s.return(SSH_COM_AGENT2_FAILURE)
|
85
85
|
end
|
86
86
|
assert_raises(Net::SSH::Authentication::AgentError) { agent.identities }
|
87
87
|
end
|
@@ -202,4 +202,4 @@ module Authentication
|
|
202
202
|
|
203
203
|
end
|
204
204
|
|
205
|
-
end
|
205
|
+
end
|
@@ -18,7 +18,7 @@ module Authentication
|
|
18
18
|
manager.add "/second"
|
19
19
|
manager.add "/third"
|
20
20
|
manager.add "/second"
|
21
|
-
|
21
|
+
assert_equal 3, manager.key_files.length
|
22
22
|
final_files = manager.key_files.map {|item| item.split('/').last}
|
23
23
|
assert_equal %w(first second third), final_files
|
24
24
|
end
|
@@ -30,12 +30,16 @@ module Authentication
|
|
30
30
|
assert !manager.use_agent?
|
31
31
|
end
|
32
32
|
|
33
|
+
def test_use_agent_is_false_if_keys_only
|
34
|
+
assert !manager(:keys_only => true).use_agent?
|
35
|
+
end
|
36
|
+
|
33
37
|
def test_each_identity_should_load_from_key_files
|
34
38
|
manager.stubs(:agent).returns(nil)
|
35
39
|
first = File.expand_path("/first")
|
36
40
|
second = File.expand_path("/second")
|
37
41
|
stub_file_private_key first, rsa
|
38
|
-
stub_file_private_key second, dsa
|
42
|
+
stub_file_private_key second, dsa
|
39
43
|
|
40
44
|
identities = []
|
41
45
|
manager.each_identity { |identity| identities << identity }
|
@@ -43,7 +47,7 @@ module Authentication
|
|
43
47
|
assert_equal 2, identities.length
|
44
48
|
assert_equal rsa.to_blob, identities.first.to_blob
|
45
49
|
assert_equal dsa.to_blob, identities.last.to_blob
|
46
|
-
|
50
|
+
|
47
51
|
assert_equal({:from => :file, :file => first, :key => rsa}, manager.known_identities[rsa])
|
48
52
|
assert_equal({:from => :file, :file => second, :key => dsa}, manager.known_identities[dsa])
|
49
53
|
end
|
@@ -8,7 +8,7 @@ module Authentication
|
|
8
8
|
include Net::SSH::Authentication::Constants
|
9
9
|
|
10
10
|
def test_constructor_should_set_defaults
|
11
|
-
assert_equal %w(none publickey
|
11
|
+
assert_equal %w(none publickey password keyboard-interactive), session.auth_methods
|
12
12
|
assert_equal session.auth_methods, session.allowed_auth_methods
|
13
13
|
end
|
14
14
|
|
@@ -20,7 +20,7 @@ module Authentication
|
|
20
20
|
end
|
21
21
|
|
22
22
|
Net::SSH::Authentication::Methods::Publickey.any_instance.expects(:authenticate).with("next service", "username", "password").raises(Net::SSH::Authentication::DisallowedMethod)
|
23
|
-
Net::SSH::Authentication::Methods::
|
23
|
+
Net::SSH::Authentication::Methods::Password.any_instance.expects(:authenticate).with("next service", "username", "password").returns(true)
|
24
24
|
Net::SSH::Authentication::Methods::None.any_instance.expects(:authenticate).with("next service", "username", "password").returns(false)
|
25
25
|
|
26
26
|
assert session.authenticate("next service", "username", "password")
|
@@ -44,7 +44,6 @@ module Authentication
|
|
44
44
|
end
|
45
45
|
|
46
46
|
Net::SSH::Authentication::Methods::Publickey.any_instance.expects(:authenticate).with("next service", "username", "password").returns(false)
|
47
|
-
Net::SSH::Authentication::Methods::Hostbased.any_instance.expects(:authenticate).with("next service", "username", "password").returns(false)
|
48
47
|
Net::SSH::Authentication::Methods::Password.any_instance.expects(:authenticate).with("next service", "username", "password").returns(false)
|
49
48
|
Net::SSH::Authentication::Methods::KeyboardInteractive.any_instance.expects(:authenticate).with("next service", "username", "password").returns(false)
|
50
49
|
Net::SSH::Authentication::Methods::None.any_instance.expects(:authenticate).with("next service", "username", "password").returns(false)
|
data/test/configs/empty
ADDED
File without changes
|
data/test/manual/test_forward.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# $ ruby -Ilib -Itest -rrubygems test/test_forward.rb
|
1
|
+
# $ ruby -Ilib -Itest -rrubygems test/manual/test_forward.rb
|
2
2
|
|
3
3
|
# Tests for the following patch:
|
4
4
|
#
|
@@ -30,14 +30,6 @@ class TestForward < Test::Unit::TestCase
|
|
30
30
|
[localhost ,ENV['USER'], {:keys => "~/.ssh/id_rsa", :verbose => :debug}]
|
31
31
|
end
|
32
32
|
|
33
|
-
def find_free_port
|
34
|
-
server = TCPServer.open(0)
|
35
|
-
server.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR,true)
|
36
|
-
port = server.addr[1]
|
37
|
-
server.close
|
38
|
-
port
|
39
|
-
end
|
40
|
-
|
41
33
|
def start_server_sending_lot_of_data(exceptions)
|
42
34
|
server = TCPServer.open(0)
|
43
35
|
Thread.start do
|
@@ -77,12 +69,34 @@ class TestForward < Test::Unit::TestCase
|
|
77
69
|
return server
|
78
70
|
end
|
79
71
|
|
72
|
+
def test_local_ephemeral_port_should_work_correctly
|
73
|
+
session = Net::SSH.start(*ssh_start_params)
|
74
|
+
|
75
|
+
assert_nothing_raised do
|
76
|
+
assigned_port = session.forward.local(0, localhost, 22)
|
77
|
+
assert_not_nil assigned_port
|
78
|
+
assert_operator assigned_port, :>, 0
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_remote_ephemeral_port_should_work_correctly
|
83
|
+
session = Net::SSH.start(*ssh_start_params)
|
84
|
+
|
85
|
+
assert_nothing_raised do
|
86
|
+
session.forward.remote(22, localhost, 0, localhost)
|
87
|
+
session.loop { !(session.forward.active_remotes.length > 0) }
|
88
|
+
assigned_port = session.forward.active_remotes.first[0]
|
89
|
+
assert_not_nil assigned_port
|
90
|
+
assert_operator assigned_port, :>, 0
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
80
94
|
def test_loop_should_not_abort_when_local_side_of_forward_is_closed
|
81
95
|
session = Net::SSH.start(*ssh_start_params)
|
82
96
|
server_exc = Queue.new
|
83
97
|
server = start_server_sending_lot_of_data(server_exc)
|
84
98
|
remote_port = server.addr[1]
|
85
|
-
local_port =
|
99
|
+
local_port = 0 # request ephemeral port
|
86
100
|
session.forward.local(local_port, localhost, remote_port)
|
87
101
|
client_done = Queue.new
|
88
102
|
Thread.start do
|
@@ -104,7 +118,7 @@ class TestForward < Test::Unit::TestCase
|
|
104
118
|
server_exc = Queue.new
|
105
119
|
server = start_server_sending_lot_of_data(server_exc)
|
106
120
|
remote_port = server.addr[1]
|
107
|
-
local_port =
|
121
|
+
local_port = 0 # request ephemeral port
|
108
122
|
session.forward.local(local_port, localhost, remote_port)
|
109
123
|
client_done = Queue.new
|
110
124
|
Thread.start do
|
@@ -163,7 +177,7 @@ class TestForward < Test::Unit::TestCase
|
|
163
177
|
session = Net::SSH.start(*ssh_start_params)
|
164
178
|
server = start_server_closing_soon
|
165
179
|
remote_port = server.addr[1]
|
166
|
-
local_port =
|
180
|
+
local_port = 0 # request ephemeral port
|
167
181
|
session.forward.local(local_port, localhost, remote_port)
|
168
182
|
client_done = Queue.new
|
169
183
|
Thread.start do
|
@@ -203,8 +217,7 @@ class TestForward < Test::Unit::TestCase
|
|
203
217
|
client_exception = Queue.new
|
204
218
|
client_data = Queue.new
|
205
219
|
remote_port = server.addr[1]
|
206
|
-
local_port =
|
207
|
-
session.forward.local(local_port, localhost, remote_port)
|
220
|
+
local_port = session.forward.local(0, localhost, remote_port)
|
208
221
|
Thread.start do
|
209
222
|
begin
|
210
223
|
client = TCPSocket.new(localhost, local_port)
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'common'
|
2
|
+
require 'net/ssh'
|
3
|
+
|
4
|
+
module NetSSH
|
5
|
+
class TestConnection < Test::Unit::TestCase
|
6
|
+
attr_reader :connection_session
|
7
|
+
|
8
|
+
def setup
|
9
|
+
authentication_session = mock('authentication_session')
|
10
|
+
authentication_session.stubs(:authenticate).returns(true)
|
11
|
+
Net::SSH::Authentication::Session.stubs(:new).returns(authentication_session)
|
12
|
+
Net::SSH::Transport::Session.stubs(:new).returns(mock('transport_session'))
|
13
|
+
@connection_session = mock('connection_session')
|
14
|
+
Net::SSH::Connection::Session.expects(:new => connection_session)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_close_connection_on_exception
|
18
|
+
@connection_session.expects(:closed?).returns(false)
|
19
|
+
@connection_session.expects(:close).once
|
20
|
+
|
21
|
+
begin
|
22
|
+
Net::SSH.start('localhost', 'testuser') { raise "error" }
|
23
|
+
rescue RuntimeError
|
24
|
+
# We aren't interested in the exception
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_close_connection_on_exception_only_if_still_open
|
29
|
+
conn_open = states('conn').starts_as(true)
|
30
|
+
@connection_session.expects(:close).then(conn_open.is(false)).once
|
31
|
+
@connection_session.expects(:closed?).when(conn_open.is(false)).returns(true)
|
32
|
+
|
33
|
+
begin
|
34
|
+
Net::SSH.start('localhost', 'testuser') do |ssh|
|
35
|
+
ssh.close
|
36
|
+
raise "error"
|
37
|
+
end
|
38
|
+
rescue RuntimeError
|
39
|
+
# We aren't interested in the exception
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_return_value_is_returned
|
44
|
+
@connection_session.expects(:closed?).returns(false)
|
45
|
+
@connection_session.expects(:close).once
|
46
|
+
|
47
|
+
val = 1
|
48
|
+
retval = Net::SSH.start('localhost', 'testuser') { val }
|
49
|
+
assert_equal(val, retval)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
data/test/test_config.rb
CHANGED
@@ -97,7 +97,7 @@ class TestConfig < Test::Unit::TestCase
|
|
97
97
|
assert_equal 6, net_ssh[:compression_level]
|
98
98
|
assert_equal 100, net_ssh[:timeout]
|
99
99
|
assert_equal true, net_ssh[:forward_agent]
|
100
|
-
assert_equal %w(hostbased password publickey), net_ssh[:auth_methods].sort
|
100
|
+
assert_equal %w(hostbased keyboard-interactive none password publickey), net_ssh[:auth_methods].sort
|
101
101
|
assert_equal %w(d e f), net_ssh[:host_key]
|
102
102
|
assert_equal %w(g h i), net_ssh[:keys]
|
103
103
|
assert_equal %w(j k l), net_ssh[:hmac]
|
@@ -106,6 +106,42 @@ class TestConfig < Test::Unit::TestCase
|
|
106
106
|
assert_equal "127.0.0.1", net_ssh[:bind_address]
|
107
107
|
assert_equal [/^LC_.*$/], net_ssh[:send_env]
|
108
108
|
end
|
109
|
+
|
110
|
+
def test_translate_should_turn_off_authentication_methods
|
111
|
+
open_ssh = {
|
112
|
+
'hostbasedauthentication' => false,
|
113
|
+
'passwordauthentication' => false,
|
114
|
+
'pubkeyauthentication' => false,
|
115
|
+
'challengeresponseauthentication' => false
|
116
|
+
}
|
117
|
+
|
118
|
+
net_ssh = Net::SSH::Config.translate(open_ssh)
|
119
|
+
|
120
|
+
assert_equal %w(none), net_ssh[:auth_methods].sort
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_translate_should_turn_on_authentication_methods
|
124
|
+
open_ssh = {
|
125
|
+
'hostbasedauthentication' => true,
|
126
|
+
'passwordauthentication' => true,
|
127
|
+
'pubkeyauthentication' => true,
|
128
|
+
'challengeresponseauthentication' => true
|
129
|
+
}
|
130
|
+
|
131
|
+
net_ssh = Net::SSH::Config.translate(open_ssh)
|
132
|
+
|
133
|
+
assert_equal %w(hostbased keyboard-interactive none password publickey), net_ssh[:auth_methods].sort
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_for_should_turn_off_authentication_methods
|
137
|
+
config = Net::SSH::Config.for("test.host", [config(:empty), config(:auth_off), config(:auth_on)])
|
138
|
+
assert_equal %w(none), config[:auth_methods].sort
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_for_should_turn_on_authentication_methods
|
142
|
+
config = Net::SSH::Config.for("test.host", [config(:empty), config(:auth_on), config(:auth_off)])
|
143
|
+
assert_equal %w(hostbased keyboard-interactive none password publickey), config[:auth_methods].sort
|
144
|
+
end
|
109
145
|
|
110
146
|
def test_load_with_plus_sign_hosts
|
111
147
|
config = Net::SSH::Config.load(config(:host_plus), "test.host")
|
data/test/test_key_factory.rb
CHANGED
@@ -65,6 +65,20 @@ class TestKeyFactory < Test::Unit::TestCase
|
|
65
65
|
assert_equal rsa_key.to_blob, Net::SSH::KeyFactory.load_public_key(@key_file).to_blob
|
66
66
|
end
|
67
67
|
|
68
|
+
def test_load_public_rsa_key_with_comment_should_return_key
|
69
|
+
File.expects(:read).with(@key_file).returns(public(rsa_key) + " key_comment")
|
70
|
+
assert_equal rsa_key.to_blob, Net::SSH::KeyFactory.load_public_key(@key_file).to_blob
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_load_public_rsa_key_with_options_should_return_key
|
74
|
+
File.expects(:read).with(@key_file).returns(public(rsa_key, 'environment="FOO=bar"'))
|
75
|
+
assert_equal rsa_key.to_blob, Net::SSH::KeyFactory.load_public_key(@key_file).to_blob
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_load_public_rsa_key_with_options_and_comment_should_return_key
|
79
|
+
File.expects(:read).with(@key_file).returns(public(rsa_key, 'environment="FOO=bar"') + " key_comment")
|
80
|
+
assert_equal rsa_key.to_blob, Net::SSH::KeyFactory.load_public_key(@key_file).to_blob
|
81
|
+
end
|
68
82
|
if defined?(OpenSSL::PKey::EC)
|
69
83
|
def test_load_unencrypted_private_ecdsa_sha2_nistp256_key_should_return_key
|
70
84
|
File.expects(:read).with("/key-file").returns(ecdsa_sha2_nistp256_key.to_pem)
|
@@ -165,8 +179,12 @@ WEKt5v3QsUEgVrzkM4K9UbI=
|
|
165
179
|
key.export(OpenSSL::Cipher::Cipher.new("des-ede3-cbc"), password)
|
166
180
|
end
|
167
181
|
|
168
|
-
def public(key)
|
169
|
-
result = "
|
182
|
+
def public(key, args = nil)
|
183
|
+
result = ""
|
184
|
+
if !args.nil?
|
185
|
+
result << "#{args} "
|
186
|
+
end
|
187
|
+
result << "#{key.ssh_type} "
|
170
188
|
result << [Net::SSH::Buffer.from(:key, key).to_s].pack("m*").strip.tr("\n\r\t ", "")
|
171
189
|
result << " joe@host.test"
|
172
190
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: net-ssh
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.8.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2014-02-01 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: test-unit
|
@@ -157,6 +157,9 @@ files:
|
|
157
157
|
- test/authentication/test_key_manager.rb
|
158
158
|
- test/authentication/test_session.rb
|
159
159
|
- test/common.rb
|
160
|
+
- test/configs/auth_off
|
161
|
+
- test/configs/auth_on
|
162
|
+
- test/configs/empty
|
160
163
|
- test/configs/eqsign
|
161
164
|
- test/configs/exact_match
|
162
165
|
- test/configs/host_plus
|
@@ -170,6 +173,7 @@ files:
|
|
170
173
|
- test/connection/test_session.rb
|
171
174
|
- test/known_hosts/github
|
172
175
|
- test/manual/test_forward.rb
|
176
|
+
- test/start/test_connection.rb
|
173
177
|
- test/start/test_options.rb
|
174
178
|
- test/start/test_transport.rb
|
175
179
|
- test/test_all.rb
|
@@ -224,7 +228,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
224
228
|
version: '0'
|
225
229
|
requirements: []
|
226
230
|
rubyforge_project: net-ssh
|
227
|
-
rubygems_version: 1.8.
|
231
|
+
rubygems_version: 1.8.23
|
228
232
|
signing_key:
|
229
233
|
specification_version: 3
|
230
234
|
summary: ! 'Net::SSH: a pure-Ruby implementation of the SSH2 client protocol.'
|