net-ssh 2.5.2 → 2.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +9 -0
- data/Manifest +1 -0
- data/README.rdoc +1 -1
- data/Rakefile +7 -11
- data/lib/net/ssh.rb +2 -2
- data/lib/net/ssh/authentication/session.rb +1 -1
- data/lib/net/ssh/buffer.rb +1 -1
- data/lib/net/ssh/errors.rb +19 -7
- data/lib/net/ssh/key_factory.rb +24 -11
- data/lib/net/ssh/service/forward.rb +1 -1
- data/lib/net/ssh/transport/packet_stream.rb +3 -3
- data/lib/net/ssh/transport/session.rb +6 -2
- data/lib/net/ssh/verifiers/secure.rb +54 -0
- data/lib/net/ssh/verifiers/strict.rb +7 -36
- data/lib/net/ssh/version.rb +2 -2
- data/net-ssh.gemspec +6 -7
- data/test/authentication/test_session.rb +4 -2
- data/test/manual/test_forward.rb +2 -2
- data/test/test_buffer.rb +5 -0
- data/test/test_key_factory.rb +54 -2
- data/test/transport/test_packet_stream.rb +8 -0
- data/test/transport/test_session.rb +5 -1
- metadata +38 -31
data/CHANGELOG.rdoc
CHANGED
@@ -1,4 +1,13 @@
|
|
1
1
|
|
2
|
+
=== 2.6.0 / 19 Sep 2012
|
3
|
+
|
4
|
+
* Use OpenSSL::PKey.read to read arbitrary private key. [nagachika]
|
5
|
+
* Check availability of UNIXSocket and UNIXServer for Windows [Nobuhiro IMAI]
|
6
|
+
* Bump version to 2.5.3 and depend on newer jruby-pageant version for Java 1.5 compat. [arturaz]
|
7
|
+
* Implementation of the "none"-authentication method [dubspeed]
|
8
|
+
* Add class for stricter host key verification [Andy Brody]
|
9
|
+
|
10
|
+
|
2
11
|
=== 2.5.2 / 25 May 2012
|
3
12
|
|
4
13
|
* Fix for Net::SSH::KnownHosts::SUPPORTED_TYPE [Marco Sandrini]
|
data/Manifest
CHANGED
data/README.rdoc
CHANGED
data/Rakefile
CHANGED
@@ -1,14 +1,10 @@
|
|
1
1
|
require 'rubygems'
|
2
|
+
require 'rubygems/package_task'
|
2
3
|
require 'rake/clean'
|
3
|
-
require 'rake/gempackagetask'
|
4
4
|
require 'fileutils'
|
5
5
|
include FileUtils
|
6
6
|
|
7
|
-
|
8
|
-
require 'hanna/rdoctask'
|
9
|
-
rescue LoadError
|
10
|
-
require 'rdoc/task'
|
11
|
-
end
|
7
|
+
require 'rdoc/task'
|
12
8
|
|
13
9
|
|
14
10
|
task :default => :package
|
@@ -39,7 +35,7 @@ version = @spec.version
|
|
39
35
|
|
40
36
|
# INSTALL =============================================================
|
41
37
|
|
42
|
-
|
38
|
+
Gem::PackageTask.new(@spec) do |p|
|
43
39
|
p.need_tar = true if RUBY_PLATFORM !~ /mswin/
|
44
40
|
end
|
45
41
|
|
@@ -74,15 +70,15 @@ end
|
|
74
70
|
|
75
71
|
# RUBY DOCS TASK ==================================
|
76
72
|
|
77
|
-
|
73
|
+
RDoc::Task.new do |t|
|
74
|
+
# this only works with RDoc 3.1 or greater
|
75
|
+
t.generator = 'hanna' # gem install hanna-nouveau
|
78
76
|
t.rdoc_dir = 'doc'
|
79
77
|
t.title = @spec.summary
|
80
|
-
t.
|
81
|
-
t.options << '--charset' << 'utf-8'
|
78
|
+
t.main = README
|
82
79
|
t.rdoc_files.include(README)
|
83
80
|
t.rdoc_files.include(CHANGES)
|
84
81
|
t.rdoc_files.include(THANKS)
|
85
82
|
t.rdoc_files.include(LICENSE)
|
86
83
|
t.rdoc_files.include('lib/**/*.rb')
|
87
84
|
end
|
88
|
-
|
data/lib/net/ssh.rb
CHANGED
@@ -133,8 +133,8 @@ module Net
|
|
133
133
|
# option is intended for situations where ssh-agent offers many different
|
134
134
|
# identites.
|
135
135
|
# * :logger => the logger instance to use when logging
|
136
|
-
# * :paranoid => either true,
|
137
|
-
# host-key verification should be
|
136
|
+
# * :paranoid => either false, true, :very, or :secure specifying how
|
137
|
+
# strict host-key verification should be (in increasing order here)
|
138
138
|
# * :passphrase => the passphrase to use when loading a private key (default
|
139
139
|
# is +nil+, for no passphrase)
|
140
140
|
# * :password => the password to use to login
|
@@ -41,7 +41,7 @@ module Net; module SSH; module Authentication
|
|
41
41
|
self.logger = transport.logger
|
42
42
|
@transport = transport
|
43
43
|
|
44
|
-
@auth_methods = options[:auth_methods] || %w(publickey hostbased password keyboard-interactive)
|
44
|
+
@auth_methods = options[:auth_methods] || %w(none publickey hostbased password keyboard-interactive)
|
45
45
|
@options = options
|
46
46
|
|
47
47
|
@allowed_auth_methods = @auth_methods
|
data/lib/net/ssh/buffer.rb
CHANGED
data/lib/net/ssh/errors.rb
CHANGED
@@ -35,12 +35,10 @@ module Net; module SSH
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
|
42
|
-
# method on the exception, and then retry.
|
43
|
-
class HostKeyMismatch < Exception
|
38
|
+
# Base class for host key exceptions. When rescuing this exception, you can
|
39
|
+
# inspect the key fingerprint and, if you want to proceed anyway, simply call
|
40
|
+
# the remember_host! method on the exception, and then retry.
|
41
|
+
class HostKeyError < Exception
|
44
42
|
# the callback to use when #remember_host! is called
|
45
43
|
attr_writer :callback #:nodoc:
|
46
44
|
|
@@ -85,4 +83,18 @@ module Net; module SSH
|
|
85
83
|
@callback.call
|
86
84
|
end
|
87
85
|
end
|
88
|
-
|
86
|
+
|
87
|
+
# Raised when the cached key for a particular host does not match the
|
88
|
+
# key given by the host, which can be indicative of a man-in-the-middle
|
89
|
+
# attack. When rescuing this exception, you can inspect the key fingerprint
|
90
|
+
# and, if you want to proceed anyway, simply call the remember_host!
|
91
|
+
# method on the exception, and then retry.
|
92
|
+
class HostKeyMismatch < HostKeyError; end
|
93
|
+
|
94
|
+
# Raised when there is no cached key for a particular host, which probably
|
95
|
+
# means that the host has simply not been seen before.
|
96
|
+
# When rescuing this exception, you can inspect the key fingerprint and, if
|
97
|
+
# you want to proceed anyway, simply call the remember_host! method on the
|
98
|
+
# exception, and then retry.
|
99
|
+
class HostKeyUnknown < HostKeyError; end
|
100
|
+
end; end
|
data/lib/net/ssh/key_factory.rb
CHANGED
@@ -48,24 +48,37 @@ module Net; module SSH
|
|
48
48
|
# encrypted (requiring a passphrase to use), the user will be
|
49
49
|
# prompted to enter their password unless passphrase works.
|
50
50
|
def load_data_private_key(data, passphrase=nil, ask_passphrase=true, filename="")
|
51
|
-
if
|
52
|
-
|
53
|
-
|
54
|
-
key_type = OpenSSL::PKey::RSA
|
55
|
-
elsif data.match(/-----BEGIN EC PRIVATE KEY-----/) && defined?(OpenSSL::PKey::EC)
|
56
|
-
key_type = OpenSSL::PKey::EC
|
57
|
-
elsif data.match(/-----BEGIN (.*) PRIVATE KEY-----/)
|
58
|
-
raise OpenSSL::PKey::PKeyError, "not a supported key type '#{$1}'"
|
51
|
+
if OpenSSL::PKey.respond_to?(:read)
|
52
|
+
pkey_read = true
|
53
|
+
error_class = ArgumentError
|
59
54
|
else
|
60
|
-
|
55
|
+
pkey_read = false
|
56
|
+
if data.match(/-----BEGIN DSA PRIVATE KEY-----/)
|
57
|
+
key_type = OpenSSL::PKey::DSA
|
58
|
+
error_class = OpenSSL::PKey::DSAError
|
59
|
+
elsif data.match(/-----BEGIN RSA PRIVATE KEY-----/)
|
60
|
+
key_type = OpenSSL::PKey::RSA
|
61
|
+
error_class = OpenSSL::PKey::RSAError
|
62
|
+
elsif data.match(/-----BEGIN EC PRIVATE KEY-----/) && defined?(OpenSSL::PKey::EC)
|
63
|
+
key_type = OpenSSL::PKey::EC
|
64
|
+
error_class = OpenSSL::PKey::RCError
|
65
|
+
elsif data.match(/-----BEGIN (.+) PRIVATE KEY-----/)
|
66
|
+
raise OpenSSL::PKey::PKeyError, "not a supported key type '#{$1}'"
|
67
|
+
else
|
68
|
+
raise OpenSSL::PKey::PKeyError, "not a private key (#{filename})"
|
69
|
+
end
|
61
70
|
end
|
62
71
|
|
63
72
|
encrypted_key = data.match(/ENCRYPTED/)
|
64
73
|
tries = 0
|
65
74
|
|
66
75
|
begin
|
67
|
-
|
68
|
-
|
76
|
+
if pkey_read
|
77
|
+
return OpenSSL::PKey.read(data, passphrase || 'invalid')
|
78
|
+
else
|
79
|
+
return key_type.new(data, passphrase || 'invalid')
|
80
|
+
end
|
81
|
+
rescue error_class
|
69
82
|
if encrypted_key && ask_passphrase
|
70
83
|
tries += 1
|
71
84
|
if tries <= 3
|
@@ -120,18 +120,18 @@ module Net; module SSH; module Transport
|
|
120
120
|
payload = client.compress(payload)
|
121
121
|
|
122
122
|
# the length of the packet, minus the padding
|
123
|
-
actual_length = 4 + payload.
|
123
|
+
actual_length = 4 + payload.bytesize + 1
|
124
124
|
|
125
125
|
# compute the padding length
|
126
126
|
padding_length = client.block_size - (actual_length % client.block_size)
|
127
127
|
padding_length += client.block_size if padding_length < 4
|
128
128
|
|
129
129
|
# compute the packet length (sans the length field itself)
|
130
|
-
packet_length = payload.
|
130
|
+
packet_length = payload.bytesize + padding_length + 1
|
131
131
|
|
132
132
|
if packet_length < 16
|
133
133
|
padding_length += client.block_size
|
134
|
-
packet_length = payload.
|
134
|
+
packet_length = payload.bytesize + padding_length + 1
|
135
135
|
end
|
136
136
|
|
137
137
|
padding = Array.new(padding_length) { rand(256) }.pack("C*")
|
@@ -9,6 +9,7 @@ require 'net/ssh/transport/constants'
|
|
9
9
|
require 'net/ssh/transport/packet_stream'
|
10
10
|
require 'net/ssh/transport/server_version'
|
11
11
|
require 'net/ssh/verifiers/null'
|
12
|
+
require 'net/ssh/verifiers/secure'
|
12
13
|
require 'net/ssh/verifiers/strict'
|
13
14
|
require 'net/ssh/verifiers/lenient'
|
14
15
|
|
@@ -255,8 +256,9 @@ module Net; module SSH; module Transport
|
|
255
256
|
# Instantiates a new host-key verification class, based on the value of
|
256
257
|
# the parameter. When true or nil, the default Lenient verifier is
|
257
258
|
# returned. If it is false, the Null verifier is returned, and if it is
|
258
|
-
# :very, the Strict verifier is returned. If the
|
259
|
-
#
|
259
|
+
# :very, the Strict verifier is returned. If it is :secure, the even more
|
260
|
+
# strict Secure verifier is returned. If the argument happens to respond
|
261
|
+
# to :verify, it is returned directly. Otherwise, an exception
|
260
262
|
# is raised.
|
261
263
|
def select_host_key_verifier(paranoid)
|
262
264
|
case paranoid
|
@@ -266,6 +268,8 @@ module Net; module SSH; module Transport
|
|
266
268
|
Net::SSH::Verifiers::Null.new
|
267
269
|
when :very then
|
268
270
|
Net::SSH::Verifiers::Strict.new
|
271
|
+
when :secure then
|
272
|
+
Net::SSH::Verifiers::Secure.new
|
269
273
|
else
|
270
274
|
if paranoid.respond_to?(:verify)
|
271
275
|
paranoid
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'net/ssh/errors'
|
2
|
+
require 'net/ssh/known_hosts'
|
3
|
+
|
4
|
+
module Net; module SSH; module Verifiers
|
5
|
+
|
6
|
+
# Does a strict host verification, looking the server up in the known
|
7
|
+
# host files to see if a key has already been seen for this server. If this
|
8
|
+
# server does not appear in any host file, an exception will be raised
|
9
|
+
# (HostKeyUnknown). This is in contrast to the "Strict" class, which will
|
10
|
+
# silently add the key to your known_hosts file. If the server does appear at
|
11
|
+
# least once, but the key given does not match any known for the server, an
|
12
|
+
# exception will be raised (HostKeyMismatch).
|
13
|
+
# Otherwise, this returns true.
|
14
|
+
class Secure
|
15
|
+
def verify(arguments)
|
16
|
+
options = arguments[:session].options
|
17
|
+
host = options[:host_key_alias] || arguments[:session].host_as_string
|
18
|
+
matches = Net::SSH::KnownHosts.search_for(host, arguments[:session].options)
|
19
|
+
|
20
|
+
# We've never seen this host before, so raise an exception.
|
21
|
+
if matches.empty?
|
22
|
+
process_cache_miss(host, arguments, HostKeyUnknown, "is unknown")
|
23
|
+
end
|
24
|
+
|
25
|
+
# If we found any matches, check to see that the key type and
|
26
|
+
# blob also match.
|
27
|
+
found = matches.any? do |key|
|
28
|
+
key.ssh_type == arguments[:key].ssh_type &&
|
29
|
+
key.to_blob == arguments[:key].to_blob
|
30
|
+
end
|
31
|
+
|
32
|
+
# If a match was found, return true. Otherwise, raise an exception
|
33
|
+
# indicating that the key was not recognized.
|
34
|
+
unless found
|
35
|
+
process_cache_miss(host, arguments, HostKeyMismatch, "does not match")
|
36
|
+
end
|
37
|
+
|
38
|
+
found
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def process_cache_miss(host, args, exc_class, message)
|
44
|
+
exception = exc_class.new("fingerprint #{args[:fingerprint]} " +
|
45
|
+
"#{message} for #{host.inspect}")
|
46
|
+
exception.data = args
|
47
|
+
exception.callback = Proc.new do
|
48
|
+
Net::SSH::KnownHosts.add(host, args[:key], args[:session].options)
|
49
|
+
end
|
50
|
+
raise exception
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end; end; end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'net/ssh/errors'
|
2
2
|
require 'net/ssh/known_hosts'
|
3
|
+
require 'net/ssh/verifiers/secure'
|
3
4
|
|
4
5
|
module Net; module SSH; module Verifiers
|
5
6
|
|
@@ -9,45 +10,15 @@ module Net; module SSH; module Verifiers
|
|
9
10
|
# server. If the server does appear at least once, but the key given does
|
10
11
|
# not match any known for the server, an exception will be raised (HostKeyMismatch).
|
11
12
|
# Otherwise, this returns true.
|
12
|
-
class Strict
|
13
|
+
class Strict < Secure
|
13
14
|
def verify(arguments)
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
# we've never seen this host before, so just automatically add the key.
|
19
|
-
# not the most secure option (since the first hit might be the one that
|
20
|
-
# is hacked), but since almost nobody actually compares the key
|
21
|
-
# fingerprint, this is a reasonable compromise between usability and
|
22
|
-
# security.
|
23
|
-
if matches.empty?
|
24
|
-
ip = arguments[:session].peer[:ip]
|
25
|
-
Net::SSH::KnownHosts.add(host, arguments[:key], arguments[:session].options)
|
15
|
+
begin
|
16
|
+
super
|
17
|
+
rescue HostKeyUnknown => err
|
18
|
+
err.remember_host!
|
26
19
|
return true
|
27
20
|
end
|
28
|
-
|
29
|
-
# If we found any matches, check to see that the key type and
|
30
|
-
# blob also match.
|
31
|
-
found = matches.any? do |key|
|
32
|
-
key.ssh_type == arguments[:key].ssh_type &&
|
33
|
-
key.to_blob == arguments[:key].to_blob
|
34
|
-
end
|
35
|
-
|
36
|
-
# If a match was found, return true. Otherwise, raise an exception
|
37
|
-
# indicating that the key was not recognized.
|
38
|
-
found || process_cache_miss(host, arguments)
|
39
21
|
end
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
def process_cache_miss(host, args)
|
44
|
-
exception = HostKeyMismatch.new("fingerprint #{args[:fingerprint]} does not match for #{host.inspect}")
|
45
|
-
exception.data = args
|
46
|
-
exception.callback = Proc.new do
|
47
|
-
Net::SSH::KnownHosts.add(host, args[:key], args[:session].options)
|
48
|
-
end
|
49
|
-
raise exception
|
50
|
-
end
|
51
22
|
end
|
52
23
|
|
53
|
-
end; end; end
|
24
|
+
end; end; end
|
data/lib/net/ssh/version.rb
CHANGED
@@ -48,10 +48,10 @@ module Net; module SSH
|
|
48
48
|
MAJOR = 2
|
49
49
|
|
50
50
|
# The minor component of this version of the Net::SSH library
|
51
|
-
MINOR =
|
51
|
+
MINOR = 6
|
52
52
|
|
53
53
|
# The tiny component of this version of the Net::SSH library
|
54
|
-
TINY =
|
54
|
+
TINY = 0
|
55
55
|
|
56
56
|
# The current version of the Net::SSH library as a Version instance
|
57
57
|
CURRENT = new(MAJOR, MINOR, TINY)
|
data/net-ssh.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
@spec = Gem::Specification.new do |s|
|
2
2
|
s.name = "net-ssh"
|
3
3
|
s.rubyforge_project = 'net-ssh'
|
4
|
-
s.version = "2.
|
4
|
+
s.version = "2.6.0"
|
5
5
|
s.summary = "Net::SSH: a pure-Ruby implementation of the SSH2 client protocol."
|
6
6
|
s.description = s.summary + " It allows you to write programs that invoke and interact with processes on remote servers, via SSH2."
|
7
7
|
s.authors = ["Jamis Buck", "Delano Mandelbaum"]
|
@@ -14,12 +14,10 @@
|
|
14
14
|
s.require_paths = %w[lib]
|
15
15
|
s.rubygems_version = '1.3.2'
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
s.add_dependency 'jruby-pageant', ">=1.0.2"
|
22
|
-
end
|
17
|
+
# This has two flavours with java one actually doing something and other
|
18
|
+
# one just raising error. This is a workaround for no ability to specify
|
19
|
+
# platform specific dependencies in gemspecs.
|
20
|
+
s.add_dependency 'jruby-pageant', ">=1.1.1"
|
23
21
|
|
24
22
|
s.executables = %w[]
|
25
23
|
|
@@ -107,6 +105,7 @@
|
|
107
105
|
lib/net/ssh/transport/state.rb
|
108
106
|
lib/net/ssh/verifiers/lenient.rb
|
109
107
|
lib/net/ssh/verifiers/null.rb
|
108
|
+
lib/net/ssh/verifiers/secure.rb
|
110
109
|
lib/net/ssh/verifiers/strict.rb
|
111
110
|
lib/net/ssh/version.rb
|
112
111
|
net-ssh.gemspec
|
@@ -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(publickey hostbased password keyboard-interactive), session.auth_methods
|
11
|
+
assert_equal %w(none publickey hostbased password keyboard-interactive), session.auth_methods
|
12
12
|
assert_equal session.auth_methods, session.allowed_auth_methods
|
13
13
|
end
|
14
14
|
|
@@ -21,6 +21,7 @@ module Authentication
|
|
21
21
|
|
22
22
|
Net::SSH::Authentication::Methods::Publickey.any_instance.expects(:authenticate).with("next service", "username", "password").raises(Net::SSH::Authentication::DisallowedMethod)
|
23
23
|
Net::SSH::Authentication::Methods::Hostbased.any_instance.expects(:authenticate).with("next service", "username", "password").returns(true)
|
24
|
+
Net::SSH::Authentication::Methods::None.any_instance.expects(:authenticate).with("next service", "username", "password").returns(false)
|
24
25
|
|
25
26
|
assert session.authenticate("next service", "username", "password")
|
26
27
|
end
|
@@ -46,7 +47,8 @@ module Authentication
|
|
46
47
|
Net::SSH::Authentication::Methods::Hostbased.any_instance.expects(:authenticate).with("next service", "username", "password").returns(false)
|
47
48
|
Net::SSH::Authentication::Methods::Password.any_instance.expects(:authenticate).with("next service", "username", "password").returns(false)
|
48
49
|
Net::SSH::Authentication::Methods::KeyboardInteractive.any_instance.expects(:authenticate).with("next service", "username", "password").returns(false)
|
49
|
-
|
50
|
+
Net::SSH::Authentication::Methods::None.any_instance.expects(:authenticate).with("next service", "username", "password").returns(false)
|
51
|
+
|
50
52
|
assert_equal false, session.authenticate("next service", "username", "password")
|
51
53
|
end
|
52
54
|
|
data/test/manual/test_forward.rb
CHANGED
@@ -128,7 +128,7 @@ class TestForward < Test::Unit::TestCase
|
|
128
128
|
tempfile.delete
|
129
129
|
yield UNIXServer.open(path)
|
130
130
|
File.delete(path)
|
131
|
-
end
|
131
|
+
end if defined?(UNIXServer)
|
132
132
|
|
133
133
|
def test_forward_local_unix_socket_to_remote_port
|
134
134
|
session = Net::SSH.start(*ssh_start_params)
|
@@ -157,7 +157,7 @@ class TestForward < Test::Unit::TestCase
|
|
157
157
|
|
158
158
|
assert_not_nil(client_data, "client should have received data")
|
159
159
|
assert(client_data.match(/item\d/), 'client should have received the string item')
|
160
|
-
end
|
160
|
+
end if defined?(UNIXSocket)
|
161
161
|
|
162
162
|
def test_loop_should_not_abort_when_server_side_of_forward_is_closed
|
163
163
|
session = Net::SSH.start(*ssh_start_params)
|
data/test/test_buffer.rb
CHANGED
@@ -29,6 +29,11 @@ class TestBuffer < Test::Unit::TestCase
|
|
29
29
|
assert_equal "\1\2\3\4\5", buffer.to_s
|
30
30
|
end
|
31
31
|
|
32
|
+
def test_from_should_measure_bytesize_of_utf_8_string_correctly
|
33
|
+
buffer = Net::SSH::Buffer.from(:string, "\u2603") # Snowman is 3 bytes
|
34
|
+
assert_equal "\0\0\0\3\u2603", buffer.to_s
|
35
|
+
end
|
36
|
+
|
32
37
|
def test_read_without_argument_should_read_to_end
|
33
38
|
buffer = new("hello world")
|
34
39
|
assert_equal "hello world", buffer.read
|
data/test/test_key_factory.rb
CHANGED
@@ -41,13 +41,23 @@ class TestKeyFactory < Test::Unit::TestCase
|
|
41
41
|
def test_load_encrypted_private_key_should_give_three_tries_for_the_password_and_then_raise_exception
|
42
42
|
File.expects(:read).with(@key_file).returns(encrypted(rsa_key, "password"))
|
43
43
|
Net::SSH::KeyFactory.expects(:prompt).times(3).with("Enter passphrase for #{@key_file}:", false).returns("passwod","passphrase","passwd")
|
44
|
-
|
44
|
+
if OpenSSL::PKey.respond_to?(:read)
|
45
|
+
error_class = ArgumentError
|
46
|
+
else
|
47
|
+
error_class = OpenSSL::PKey::RSAError
|
48
|
+
end
|
49
|
+
assert_raises(error_class) { Net::SSH::KeyFactory.load_private_key(@key_file) }
|
45
50
|
end
|
46
51
|
|
47
52
|
def test_load_encrypted_private_key_should_raise_exception_without_asking_passphrase
|
48
53
|
File.expects(:read).with(@key_file).returns(encrypted(rsa_key, "password"))
|
49
54
|
Net::SSH::KeyFactory.expects(:prompt).never
|
50
|
-
|
55
|
+
if OpenSSL::PKey.respond_to?(:read)
|
56
|
+
error_class = ArgumentError
|
57
|
+
else
|
58
|
+
error_class = OpenSSL::PKey::RSAError
|
59
|
+
end
|
60
|
+
assert_raises(error_class) { Net::SSH::KeyFactory.load_private_key(@key_file, nil, false) }
|
51
61
|
end
|
52
62
|
|
53
63
|
def test_load_public_rsa_key_should_return_key
|
@@ -83,6 +93,15 @@ class TestKeyFactory < Test::Unit::TestCase
|
|
83
93
|
end
|
84
94
|
end
|
85
95
|
|
96
|
+
def test_load_anonymous_private_key_should_return_key_or_raise_exception
|
97
|
+
File.expects(:read).with(@key_file).returns(anonymous_private_key)
|
98
|
+
if OpenSSL::PKey.respond_to?(:read)
|
99
|
+
assert_equal OpenSSL::PKey::RSA.new(anonymous_private_key).to_der, Net::SSH::KeyFactory.load_private_key(@key_file).to_der
|
100
|
+
else
|
101
|
+
assert_raises(OpenSSL::PKey::PKeyError) { Net::SSH::KeyFactory.load_private_key(@key_file) }
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
86
105
|
private
|
87
106
|
|
88
107
|
def rsa_key
|
@@ -109,6 +128,39 @@ class TestKeyFactory < Test::Unit::TestCase
|
|
109
128
|
end
|
110
129
|
end
|
111
130
|
|
131
|
+
def anonymous_private_key
|
132
|
+
@anonymous_key = <<-EOF
|
133
|
+
-----BEGIN PRIVATE KEY-----
|
134
|
+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC3id5gZ6bglJth
|
135
|
+
yli8JNaRxhsqKwwPlReEI/mplzz5IP6gWQ92LogXbdBXtHf9ZpA53BeLmtcNBEY0
|
136
|
+
Ygd7sPBhlHABS5D5///zltSSX2+L5GCEiC6dpfGsySjqymWF+SZ2PaqfZbkWLmCD
|
137
|
+
9u4ysueaHf7xbF6txGprNp69efttWxdy+vU5tno7HVxemMZQUalpShFrdAYKKXEo
|
138
|
+
cV7MtbkQjzubS14gaWGpWCXIl9uNKQeHpLKtre1Qn5Ft/zVpCHmhLQcYDuB1LAj9
|
139
|
+
7eoev4rIiOE2sfdkvKDlmFxvzq3myYH4o27WwAg9OZ5SBusn2zesKkRCBBEZ55rl
|
140
|
+
uVknOGHXAgMBAAECggEAZE0U2OxsNxkfXS6+lXswQ5PW7pF90towcsdSPgrniGIu
|
141
|
+
pKRnHbfKKbuaewOl+zZcpTIRL/rbgUKPtzrHSiJlC36aQyrvvJ/ZWV5ZJvC+vd19
|
142
|
+
nY/qob65NyrrkHwxRSjmiwGiR9/IaUXI+vUsMUqx5Ph1hawqhZ3sZlEAKR4LeDO8
|
143
|
+
M+OguG77jLaqj5/SNfi+GwyUDe85de4VfEG4S9HrMQk2Cp66rx0BqDnCLacyFQaI
|
144
|
+
R0VczMXTU52q0uETmgUr8G9A1SaRc5ZWKAfZwxJTvqdIImWC9E+CY7wm+mZD4FE6
|
145
|
+
iVzVC0ngcdEd596kTDdU2BPVMluWzLkfqIrTt/5CeQKBgQDzgRzCPNxFtai6RAIi
|
146
|
+
ekBSHqrDnrbeTaw32GVq5ACk1Zfk2I0svctz1iQ9qJ2SRINpygQhcyJKQ4r/LXi1
|
147
|
+
7Av9H/d6QV4T2AZzS4WcqBkxxRXFUfARtnKChzuCzNt9tNz4EZiv75RyQmztGZjV
|
148
|
+
i94+ZvCyqup5be4Svf4MBxin9QKBgQDA9P4nHzFWZakTMei78LGb/4Auc+r0rZp7
|
149
|
+
8xg8Z92tvrDeJjMdesdhiFrPP1qiSYHnQ81MSWpn6BycBsHZqitejQmYnYput/s4
|
150
|
+
qG+m7SrkN8WL6rijYsbB+U14VDjMlBlOgcEgjlSNU2oeS+68u+uVI/fgyXcXn4Jq
|
151
|
+
33TSWSgfGwKBgA2tRdE/G9wqfOShZ0FKfoxePpcoNfs8f5zPYbrkPYkEmjh3VU6b
|
152
|
+
Bm9mKrjv3JHXmU3608qRLe7f5lG42xvUu0OnZP4P59nTe2FEb6fB5VBfUn63wHUu
|
153
|
+
OzZLpDMPkJB59SNV0a6oFT1pr7aNhoEQDxaQL5rJcMwLOaEB3OAOEft1AoGASz7+
|
154
|
+
4Zi7b7rDPVYIMUpCqNfxT6wqovIUPWPmPqAuhXPIm0kAQ+2+VN2MtCc7m+/Ydawu
|
155
|
+
IiK7GPweNAY6kDxZH00WweolstmSYVzl9Y2lXUwWgGKvUB/T7I7g1Bzb7YOPftsA
|
156
|
+
ykZW2Kn/xwLLfdQ2oXleT82g4Jh2jmDHuMPF7qMCgYEA6QF45PvOgnrJessgmwO/
|
157
|
+
dEmkLl07PQYJPGZLaZteuWrvfMrn+AiW5aAdHzhzNaOtNy5B3T7zGUHtgxXegqgd
|
158
|
+
/QdCVCJgnZUO/zdAxkr22dDn+WEXkL4wgBVStQvvnQp9C2NJcoOExvex5PLzKWQg
|
159
|
+
WEKt5v3QsUEgVrzkM4K9UbI=
|
160
|
+
-----END PRIVATE KEY-----
|
161
|
+
EOF
|
162
|
+
end
|
163
|
+
|
112
164
|
def encrypted(key, password)
|
113
165
|
key.export(OpenSSL::Cipher::Cipher.new("des-ede3-cbc"), password)
|
114
166
|
end
|
@@ -165,6 +165,14 @@ module Transport
|
|
165
165
|
assert_equal 24, stream.write_buffer.length
|
166
166
|
end
|
167
167
|
|
168
|
+
def test_enqueue_utf_8_packet_should_ensure_packet_length_is_in_bytes_and_multiple_of_block_length
|
169
|
+
packet = Net::SSH::Buffer.from(:string, "\u2603") # Snowman is 3 bytes
|
170
|
+
stream.enqueue_packet(packet)
|
171
|
+
# When bytesize is measured wrong using length, the result is off by 2.
|
172
|
+
# With length instead of bytesize, you get 26 length buffer.
|
173
|
+
assert_equal 0, stream.write_buffer.length % 8
|
174
|
+
end
|
175
|
+
|
168
176
|
PACKETS = {
|
169
177
|
"3des-cbc" => {
|
170
178
|
"hmac-md5" => {
|
@@ -28,6 +28,10 @@ module Transport
|
|
28
28
|
assert_instance_of Net::SSH::Verifiers::Strict, session(:paranoid => :very).host_key_verifier
|
29
29
|
end
|
30
30
|
|
31
|
+
def test_paranoid_secure_uses_secure_verifier
|
32
|
+
assert_instance_of Net::SSH::Verifiers::Secure, session(:paranoid => :secure).host_key_verifier
|
33
|
+
end
|
34
|
+
|
31
35
|
def test_paranoid_false_uses_null_verifier
|
32
36
|
assert_instance_of Net::SSH::Verifiers::Null, session(:paranoid => false).host_key_verifier
|
33
37
|
end
|
@@ -312,4 +316,4 @@ module Transport
|
|
312
316
|
alias session! session
|
313
317
|
end
|
314
318
|
|
315
|
-
end
|
319
|
+
end
|
metadata
CHANGED
@@ -1,31 +1,40 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: net-ssh
|
3
|
-
version: !ruby/object:Gem::Version
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.6.0
|
4
5
|
prerelease:
|
5
|
-
version: 2.5.2
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
7
|
+
authors:
|
8
8
|
- Jamis Buck
|
9
9
|
- Delano Mandelbaum
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
13
|
+
date: 2012-09-19 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: jruby-pageant
|
17
|
+
requirement: &70132399474300 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.1.1
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *70132399474300
|
26
|
+
description: ! 'Net::SSH: a pure-Ruby implementation of the SSH2 client protocol.
|
27
|
+
It allows you to write programs that invoke and interact with processes on remote
|
28
|
+
servers, via SSH2.'
|
29
|
+
email:
|
19
30
|
- net-ssh@solutious.com
|
20
31
|
executables: []
|
21
|
-
|
22
32
|
extensions: []
|
23
|
-
|
24
|
-
extra_rdoc_files:
|
33
|
+
extra_rdoc_files:
|
25
34
|
- README.rdoc
|
26
35
|
- THANKS.rdoc
|
27
36
|
- CHANGELOG.rdoc
|
28
|
-
files:
|
37
|
+
files:
|
29
38
|
- CHANGELOG.rdoc
|
30
39
|
- Manifest
|
31
40
|
- README.rdoc
|
@@ -108,6 +117,7 @@ files:
|
|
108
117
|
- lib/net/ssh/transport/state.rb
|
109
118
|
- lib/net/ssh/verifiers/lenient.rb
|
110
119
|
- lib/net/ssh/verifiers/null.rb
|
120
|
+
- lib/net/ssh/verifiers/secure.rb
|
111
121
|
- lib/net/ssh/verifiers/strict.rb
|
112
122
|
- lib/net/ssh/version.rb
|
113
123
|
- net-ssh.gemspec
|
@@ -170,34 +180,31 @@ files:
|
|
170
180
|
- test/transport/test_state.rb
|
171
181
|
homepage: http://github.com/net-ssh/net-ssh
|
172
182
|
licenses: []
|
173
|
-
|
174
183
|
post_install_message:
|
175
|
-
rdoc_options:
|
184
|
+
rdoc_options:
|
176
185
|
- --line-numbers
|
177
186
|
- --title
|
178
|
-
-
|
187
|
+
- ! 'Net::SSH: a pure-Ruby implementation of the SSH2 client protocol.'
|
179
188
|
- --main
|
180
189
|
- README.rdoc
|
181
|
-
require_paths:
|
190
|
+
require_paths:
|
182
191
|
- lib
|
183
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
192
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
184
193
|
none: false
|
185
|
-
requirements:
|
186
|
-
- -
|
187
|
-
- !ruby/object:Gem::Version
|
188
|
-
version:
|
189
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
194
|
+
requirements:
|
195
|
+
- - ! '>='
|
196
|
+
- !ruby/object:Gem::Version
|
197
|
+
version: '0'
|
198
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
190
199
|
none: false
|
191
|
-
requirements:
|
192
|
-
- -
|
193
|
-
- !ruby/object:Gem::Version
|
194
|
-
version:
|
200
|
+
requirements:
|
201
|
+
- - ! '>='
|
202
|
+
- !ruby/object:Gem::Version
|
203
|
+
version: '0'
|
195
204
|
requirements: []
|
196
|
-
|
197
205
|
rubyforge_project: net-ssh
|
198
206
|
rubygems_version: 1.8.10
|
199
207
|
signing_key:
|
200
208
|
specification_version: 3
|
201
|
-
summary:
|
209
|
+
summary: ! 'Net::SSH: a pure-Ruby implementation of the SSH2 client protocol.'
|
202
210
|
test_files: []
|
203
|
-
|