net-ssh 4.0.0.beta3 → 4.0.0.beta4

Sign up to get free protection for your applications and to get access to all the features.
@@ -49,8 +49,7 @@ module Net; module SSH; module Proxy
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
51
  def open(host, port, connection_options)
52
- socket = Socket.tcp(proxy_host, proxy_port, nil, nil,
53
- connect_timeout: connection_options[:timeout])
52
+ socket = establish_connection(connection_options[:timeout])
54
53
  socket.write "CONNECT #{host}:#{port} HTTP/1.0\r\n"
55
54
 
56
55
  if options[:user]
@@ -68,7 +67,12 @@ module Net; module SSH; module Proxy
68
67
  raise ConnectError, resp.inspect
69
68
  end
70
69
 
71
- private
70
+ protected
71
+
72
+ def establish_connection(connect_timeout)
73
+ Socket.tcp(proxy_host, proxy_port, nil, nil,
74
+ connect_timeout: connect_timeout)
75
+ end
72
76
 
73
77
  def parse_response(socket)
74
78
  version, code, reason = socket.gets.chomp.split(/ /, 3)
@@ -89,7 +93,6 @@ module Net; module SSH; module Proxy
89
93
  :headers => headers,
90
94
  :body => body }
91
95
  end
92
-
93
96
  end
94
97
 
95
98
  end; end; end
@@ -0,0 +1,49 @@
1
+ require 'socket'
2
+ require 'openssl'
3
+ require 'net/ssh/proxy/errors'
4
+ require 'net/ssh/proxy/http'
5
+
6
+ module Net; module SSH; module Proxy
7
+
8
+ # A specialization of the HTTP proxy which encrypts the whole connection
9
+ # using OpenSSL. This has the advantage that proxy authentication
10
+ # information is not sent in plaintext.
11
+ class HTTPS < HTTP
12
+
13
+ # Create a new socket factory that tunnels via the given host and
14
+ # port. The +options+ parameter is a hash of additional settings that
15
+ # can be used to tweak this proxy connection. In addition to the options
16
+ # taken by Net::SSH::Proxy::HTTP it supports:
17
+ #
18
+ # * :ssl_context => the SSL configuration to use for the connection
19
+ def initialize(proxy_host, proxy_port=80, options={})
20
+ @ssl_context = options.delete(:ssl_context) ||
21
+ OpenSSL::SSL::SSLContext.new
22
+ super(proxy_host, proxy_port, options)
23
+ end
24
+
25
+ protected
26
+
27
+ # Shim to make OpenSSL::SSL::SSLSocket behave like a regular TCPSocket
28
+ # for all intents and purposes of Net::SSH::BufferedIo
29
+ module SSLSocketCompatibility
30
+ def self.extended(object) #:nodoc:
31
+ object.define_singleton_method(:recv, object.method(:sysread))
32
+ object.sync_close = true
33
+ end
34
+
35
+ def send(data, _opts)
36
+ syswrite(data)
37
+ end
38
+ end
39
+
40
+ def establish_connection(connect_timeout)
41
+ plain_socket = super(connect_timeout)
42
+ OpenSSL::SSL::SSLSocket.new(plain_socket, @ssl_context).tap do |socket|
43
+ socket.extend(SSLSocketCompatibility)
44
+ socket.connect
45
+ end
46
+ end
47
+ end
48
+
49
+ end; end; end
data/lib/net/ssh/test.rb CHANGED
@@ -50,7 +50,7 @@ module Net; module SSH
50
50
  # If a block is given, yields the script for the test socket (#socket).
51
51
  # Otherwise, simply returns the socket's script. See Net::SSH::Test::Script.
52
52
  def story
53
- yield socket.script if block_given?
53
+ Net::SSH::Test::Extensions::IO.with_test_extension { yield socket.script if block_given? }
54
54
  return socket.script
55
55
  end
56
56
 
@@ -81,7 +81,7 @@ module Net; module SSH
81
81
  # the block passed to this assertion.
82
82
  def assert_scripted
83
83
  raise "there is no script to be processed" if socket.script.events.empty?
84
- yield
84
+ Net::SSH::Test::Extensions::IO.with_test_extension { yield }
85
85
  assert socket.script.events.empty?, "there should not be any remaining scripted events, but there are still #{socket.script.events.length} pending"
86
86
  end
87
87
  end
@@ -113,6 +113,22 @@ module Net; module SSH; module Test
113
113
  base.extend(ClassMethods)
114
114
  end
115
115
 
116
+ @extension_enabled = false
117
+
118
+ def self.with_test_extension(&block)
119
+ orig_value = @extension_enabled
120
+ @extension_enabled = true
121
+ begin
122
+ yield
123
+ ensure
124
+ @extension_enabled = orig_value
125
+ end
126
+ end
127
+
128
+ def self.extension_enabled?
129
+ @extension_enabled
130
+ end
131
+
116
132
  module ClassMethods
117
133
  def self.extended(obj) #:nodoc:
118
134
  class <<obj
@@ -125,6 +141,7 @@ module Net; module SSH; module Test
125
141
  # writers, and errors arrays are either nil, or contain only objects
126
142
  # that mix in Net::SSH::Test::Extensions::BufferedIo.
127
143
  def select_for_test(readers=nil, writers=nil, errors=nil, wait=nil)
144
+ return select_for_real(readers, writers, errors, wait) unless Net::SSH::Test::Extensions::IO.extension_enabled?
128
145
  ready_readers = Array(readers).select { |r| r.select_for_read? }
129
146
  ready_writers = Array(writers).select { |r| r.select_for_write? }
130
147
  ready_errors = Array(errors).select { |r| r.select_for_error? }
@@ -12,12 +12,10 @@ module Net::SSH::Transport
12
12
  @counter_len = orig.block_size
13
13
  orig.encrypt
14
14
  orig.padding = 0
15
- }
16
-
17
- class <<orig
18
- alias :_update :update
19
- private :_update
20
- undef :update
15
+
16
+ singleton_class.send(:alias_method, :_update, :update)
17
+ singleton_class.send(:private, :_update)
18
+ singleton_class.send(:undef_method, :update)
21
19
 
22
20
  def iv
23
21
  @counter
@@ -73,13 +71,12 @@ module Net::SSH::Transport
73
71
  s
74
72
  end
75
73
 
76
- private
77
-
78
74
  def xor!(s1, s2)
79
75
  s = []
80
76
  s1.unpack('Q*').zip(s2.unpack('Q*')) {|a,b| s.push(a^b) }
81
77
  s.pack('Q*')
82
78
  end
79
+ singleton_class.send(:private, :xor!)
83
80
 
84
81
  def increment_counter!
85
82
  c = @counter_len
@@ -89,7 +86,8 @@ module Net::SSH::Transport
89
86
  end
90
87
  end
91
88
  end
92
- end
89
+ singleton_class.send(:private, :increment_counter!)
90
+ }
93
91
  end
94
92
  end
95
93
  end
@@ -53,9 +53,9 @@ module Net; module SSH
53
53
  # The tiny component of this version of the Net::SSH library
54
54
  TINY = 0
55
55
 
56
- # The prerelease component of this version of the Net::SSH library
56
+ # The prerelease component of this version of the Net::SSH library
57
57
  # nil allowed
58
- PRE = "beta3"
58
+ PRE = "beta4"
59
59
 
60
60
  # The current version of the Net::SSH library as a Version instance
61
61
  CURRENT = new(*[MAJOR, MINOR, TINY, PRE].compact)
data/net-ssh.gemspec CHANGED
@@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
22
22
  "LICENSE.txt",
23
23
  "README.rdoc"
24
24
  ]
25
-
25
+
26
26
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
27
27
  spec.bindir = "exe"
28
28
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
@@ -31,7 +31,7 @@ Gem::Specification.new do |spec|
31
31
  unless ENV['NET_SSH_NO_RBNACL']
32
32
  spec.add_development_dependency("rbnacl-libsodium", "~> 1.0.10")
33
33
  spec.add_development_dependency("rbnacl", "~> 3.4.0")
34
- spec.add_development_dependency("bcrypt_pbkdf", "~> 1.0.0.alpha1") unless RUBY_PLATFORM == "java"
34
+ spec.add_development_dependency("bcrypt_pbkdf", "~> 1.0.0") unless RUBY_PLATFORM == "java"
35
35
  end
36
36
 
37
37
  spec.add_development_dependency "bundler", "~> 1.11"
@@ -39,7 +39,6 @@ Gem::Specification.new do |spec|
39
39
  spec.add_development_dependency "minitest", "~> 5.0"
40
40
  spec.add_development_dependency "rubocop", "~> 0.39.0"
41
41
  spec.add_development_dependency "mocha", ">= 1.1.0"
42
- spec.add_development_dependency("byebug") if RUBY_ENGINE == "ruby"
43
42
 
44
- spec.add_dependency('jruby-pageant', '>= 1.1.1') if RUBY_PLATFORM == 'jruby'
43
+ spec.add_dependency('jruby-pageant', '>= 1.1.1') if RUBY_ENGINE == 'jruby'
45
44
  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: 4.0.0.beta3
4
+ version: 4.0.0.beta4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jamis Buck
@@ -31,7 +31,7 @@ cert_chain:
31
31
  s/ZUKye79ELwFYKJOhjW5g725OL3hy+llhEleytwKRwgXFQBPTC4f5UkdxZVVWGH
32
32
  e2C9M1m/2odPZo8h
33
33
  -----END CERTIFICATE-----
34
- date: 2016-08-14 00:00:00.000000000 Z
34
+ date: 2016-11-25 00:00:00.000000000 Z
35
35
  dependencies:
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rbnacl-libsodium
@@ -67,14 +67,14 @@ dependencies:
67
67
  requirements:
68
68
  - - "~>"
69
69
  - !ruby/object:Gem::Version
70
- version: 1.0.0.alpha1
70
+ version: 1.0.0
71
71
  type: :development
72
72
  prerelease: false
73
73
  version_requirements: !ruby/object:Gem::Requirement
74
74
  requirements:
75
75
  - - "~>"
76
76
  - !ruby/object:Gem::Version
77
- version: 1.0.0.alpha1
77
+ version: 1.0.0
78
78
  - !ruby/object:Gem::Dependency
79
79
  name: bundler
80
80
  requirement: !ruby/object:Gem::Requirement
@@ -145,20 +145,6 @@ dependencies:
145
145
  - - ">="
146
146
  - !ruby/object:Gem::Version
147
147
  version: 1.1.0
148
- - !ruby/object:Gem::Dependency
149
- name: byebug
150
- requirement: !ruby/object:Gem::Requirement
151
- requirements:
152
- - - ">="
153
- - !ruby/object:Gem::Version
154
- version: '0'
155
- type: :development
156
- prerelease: false
157
- version_requirements: !ruby/object:Gem::Requirement
158
- requirements:
159
- - - ">="
160
- - !ruby/object:Gem::Version
161
- version: '0'
162
148
  description: 'Net::SSH: a pure-Ruby implementation of the SSH2 client protocol. It
163
149
  allows you to write programs that invoke and interact with processes on remote servers,
164
150
  via SSH2.'
@@ -178,6 +164,7 @@ files:
178
164
  - Gemfile
179
165
  - Gemfile.norbnacl
180
166
  - Gemfile.norbnacl.lock
167
+ - ISSUE_TEMPLATE.md
181
168
  - LICENSE.txt
182
169
  - Manifest
183
170
  - README.rdoc
@@ -186,8 +173,6 @@ files:
186
173
  - appveyor.yml
187
174
  - lib/net/ssh.rb
188
175
  - lib/net/ssh/authentication/agent.rb
189
- - lib/net/ssh/authentication/agent/java_pageant.rb
190
- - lib/net/ssh/authentication/agent/socket.rb
191
176
  - lib/net/ssh/authentication/constants.rb
192
177
  - lib/net/ssh/authentication/ed25519.rb
193
178
  - lib/net/ssh/authentication/ed25519_loader.rb
@@ -218,6 +203,7 @@ files:
218
203
  - lib/net/ssh/proxy/command.rb
219
204
  - lib/net/ssh/proxy/errors.rb
220
205
  - lib/net/ssh/proxy/http.rb
206
+ - lib/net/ssh/proxy/https.rb
221
207
  - lib/net/ssh/proxy/socks4.rb
222
208
  - lib/net/ssh/proxy/socks5.rb
223
209
  - lib/net/ssh/ruby_compat.rb
@@ -291,8 +277,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
291
277
  version: 1.3.1
292
278
  requirements: []
293
279
  rubyforge_project:
294
- rubygems_version: 2.4.6
280
+ rubygems_version: 2.5.1
295
281
  signing_key:
296
282
  specification_version: 4
297
283
  summary: 'Net::SSH: a pure-Ruby implementation of the SSH2 client protocol.'
298
284
  test_files: []
285
+ has_rdoc:
metadata.gz.sig CHANGED
Binary file
@@ -1,85 +0,0 @@
1
- require 'jruby_pageant'
2
-
3
- module Net; module SSH; module Authentication
4
-
5
- # This class implements an agent for JRuby + Pageant.
6
- #
7
- # Written by Artūras Šlajus <arturas.slajus@gmail.com>
8
- class Agent
9
- include Loggable
10
- include JRubyPageant
11
-
12
- # A simple module for extending keys, to allow blobs and comments to be
13
- # specified for them.
14
- module Key
15
- # :blob is used by OpenSSL::PKey::RSA#to_blob
16
- attr_accessor :java_blob
17
- attr_accessor :comment
18
- end
19
-
20
- # Instantiates a new agent object, connects to a running SSH agent,
21
- # negotiates the agent protocol version, and returns the agent object.
22
- def self.connect(logger=nil, agent_socket_factory)
23
- agent = new(logger)
24
- agent.connect!
25
- agent
26
- end
27
-
28
- # Creates a new Agent object, using the optional logger instance to
29
- # report status.
30
- def initialize(logger=nil)
31
- self.logger = logger
32
- end
33
-
34
- # Connect to the agent process using the socket factory and socket name
35
- # given by the attribute writers. If the agent on the other end of the
36
- # socket reports that it is an SSH2-compatible agent, this will fail
37
- # (it only supports the ssh-agent distributed by OpenSSH).
38
- def connect!
39
- debug { "connecting to Pageant ssh-agent (via java connector)" }
40
- @agent_proxy = JRubyPageant.create
41
- unless @agent_proxy.is_running
42
- raise AgentNotAvailable, "Pageant is not running!"
43
- end
44
- debug { "connection to Pageant ssh-agent (via java connector) succeeded" }
45
- rescue AgentProxyException => e
46
- error { "could not connect to Pageant ssh-agent (via java connector)" }
47
- raise AgentNotAvailable, e.message, e.backtrace
48
- end
49
-
50
- # Return an array of all identities (public keys) known to the agent.
51
- # Each key returned is augmented with a +comment+ property which is set
52
- # to the comment returned by the agent for that key.
53
- def identities
54
- debug { "getting identities from Pageant" }
55
- @agent_proxy.get_identities.map do |identity|
56
- blob = identity.get_blob
57
- key = Buffer.new(String.from_java_bytes(blob)).read_key
58
- key.extend(Key)
59
- key.java_blob = blob
60
- key.comment = String.from_java_bytes(identity.get_comment)
61
- key
62
- end
63
- rescue AgentProxyException => e
64
- raise AgentError, "Cannot get identities: #{e.message}", e.backtrace
65
- end
66
-
67
- # Simulate agent close. This agent reference is no longer able to
68
- # query the agent.
69
- def close
70
- @agent_proxy = nil
71
- end
72
-
73
- # Using the agent and the given public key, sign the given data. The
74
- # signature is returned in SSH2 format.
75
- def sign(key, data)
76
- signed = @agent_proxy.sign(key.java_blob, data.to_java_bytes)
77
- String.from_java_bytes(signed)
78
- rescue AgentProxyException => e
79
- raise AgentError,
80
- "agent could not sign data with requested identity: #{e.message}",
81
- e.backtrace
82
- end
83
- end
84
-
85
- end; end; end
@@ -1,178 +0,0 @@
1
- require 'net/ssh/transport/server_version'
2
-
3
- # Only load pageant on Windows
4
- if Net::SSH::Authentication::PLATFORM == :win32
5
- require 'net/ssh/authentication/pageant'
6
- end
7
-
8
- module Net; module SSH; module Authentication
9
-
10
- # This class implements a simple client for the ssh-agent protocol. It
11
- # does not implement any specific protocol, but instead copies the
12
- # behavior of the ssh-agent functions in the OpenSSH library (3.8).
13
- #
14
- # This means that although it behaves like a SSH1 client, it also has
15
- # some SSH2 functionality (like signing data).
16
- class Agent
17
- include Loggable
18
-
19
- # A simple module for extending keys, to allow comments to be specified
20
- # for them.
21
- module Comment
22
- attr_accessor :comment
23
- end
24
-
25
- SSH2_AGENT_REQUEST_VERSION = 1
26
- SSH2_AGENT_REQUEST_IDENTITIES = 11
27
- SSH2_AGENT_IDENTITIES_ANSWER = 12
28
- SSH2_AGENT_SIGN_REQUEST = 13
29
- SSH2_AGENT_SIGN_RESPONSE = 14
30
- SSH2_AGENT_FAILURE = 30
31
- SSH2_AGENT_VERSION_RESPONSE = 103
32
-
33
- SSH_COM_AGENT2_FAILURE = 102
34
-
35
- SSH_AGENT_REQUEST_RSA_IDENTITIES = 1
36
- SSH_AGENT_RSA_IDENTITIES_ANSWER1 = 2
37
- SSH_AGENT_RSA_IDENTITIES_ANSWER2 = 5
38
- SSH_AGENT_FAILURE = 5
39
-
40
- # The underlying socket being used to communicate with the SSH agent.
41
- attr_reader :socket
42
-
43
- # Instantiates a new agent object, connects to a running SSH agent,
44
- # negotiates the agent protocol version, and returns the agent object.
45
- def self.connect(logger=nil, agent_socket_factory = nil)
46
- agent = new(logger)
47
- agent.connect!(agent_socket_factory)
48
- agent.negotiate!
49
- agent
50
- end
51
-
52
- # Creates a new Agent object, using the optional logger instance to
53
- # report status.
54
- def initialize(logger=nil)
55
- self.logger = logger
56
- end
57
-
58
- # Connect to the agent process using the socket factory and socket name
59
- # given by the attribute writers. If the agent on the other end of the
60
- # socket reports that it is an SSH2-compatible agent, this will fail
61
- # (it only supports the ssh-agent distributed by OpenSSH).
62
- def connect!(agent_socket_factory = nil)
63
- begin
64
- debug { "connecting to ssh-agent" }
65
- @socket = agent_socket_factory.nil? ? socket_class.open(ENV['SSH_AUTH_SOCK']) : agent_socket_factory.call
66
- rescue
67
- error { "could not connect to ssh-agent" }
68
- raise AgentNotAvailable, $!.message
69
- end
70
- end
71
-
72
- # Attempts to negotiate the SSH agent protocol version. Raises an error
73
- # if the version could not be negotiated successfully.
74
- def negotiate!
75
- # determine what type of agent we're communicating with
76
- type, body = send_and_wait(SSH2_AGENT_REQUEST_VERSION, :string, Transport::ServerVersion::PROTO_VERSION)
77
-
78
- if type == SSH2_AGENT_VERSION_RESPONSE
79
- raise AgentNotAvailable, "SSH2 agents are not yet supported"
80
- elsif type == SSH2_AGENT_FAILURE
81
- debug { "Unexpected response type==#{type}, this will be ignored" }
82
- elsif type != SSH_AGENT_RSA_IDENTITIES_ANSWER1 && type != SSH_AGENT_RSA_IDENTITIES_ANSWER2
83
- raise AgentNotAvailable, "unknown response from agent: #{type}, #{body.to_s.inspect}"
84
- end
85
- end
86
-
87
- # Return an array of all identities (public keys) known to the agent.
88
- # Each key returned is augmented with a +comment+ property which is set
89
- # to the comment returned by the agent for that key.
90
- def identities
91
- type, body = send_and_wait(SSH2_AGENT_REQUEST_IDENTITIES)
92
- raise AgentError, "could not get identity count" if agent_failed(type)
93
- raise AgentError, "bad authentication reply: #{type}" if type != SSH2_AGENT_IDENTITIES_ANSWER
94
-
95
- identities = []
96
- body.read_long.times do
97
- key_str = body.read_string
98
- comment_str = body.read_string
99
- begin
100
- key = Buffer.new(key_str).read_key
101
- key.extend(Comment)
102
- key.comment = comment_str
103
- identities.push key
104
- rescue NotImplementedError => e
105
- error { "ignoring unimplemented key:#{e.message} #{comment_str}" }
106
- end
107
- end
108
-
109
- return identities
110
- end
111
-
112
- # Closes this socket. This agent reference is no longer able to
113
- # query the agent.
114
- def close
115
- @socket.close
116
- end
117
-
118
- # Using the agent and the given public key, sign the given data. The
119
- # signature is returned in SSH2 format.
120
- def sign(key, data)
121
- type, reply = send_and_wait(SSH2_AGENT_SIGN_REQUEST, :string, Buffer.from(:key, key), :string, data, :long, 0)
122
-
123
- if agent_failed(type)
124
- raise AgentError, "agent could not sign data with requested identity"
125
- elsif type != SSH2_AGENT_SIGN_RESPONSE
126
- raise AgentError, "bad authentication response #{type}"
127
- end
128
-
129
- return reply.read_string
130
- end
131
-
132
- private
133
-
134
- # Returns the agent socket factory to use.
135
- def socket_class
136
- if Net::SSH::Authentication::PLATFORM == :win32
137
- Pageant::Socket
138
- else
139
- UNIXSocket
140
- end
141
- end
142
-
143
- # Send a new packet of the given type, with the associated data.
144
- def send_packet(type, *args)
145
- buffer = Buffer.from(*args)
146
- data = [buffer.length + 1, type.to_i, buffer.to_s].pack("NCA*")
147
- debug { "sending agent request #{type} len #{buffer.length}" }
148
- @socket.send data, 0
149
- end
150
-
151
- # Read the next packet from the agent. This will return a two-part
152
- # tuple consisting of the packet type, and the packet's body (which
153
- # is returned as a Net::SSH::Buffer).
154
- def read_packet
155
- buffer = Net::SSH::Buffer.new(@socket.read(4))
156
- buffer.append(@socket.read(buffer.read_long))
157
- type = buffer.read_byte
158
- debug { "received agent packet #{type} len #{buffer.length-4}" }
159
- return type, buffer
160
- end
161
-
162
- # Send the given packet and return the subsequent reply from the agent.
163
- # (See #send_packet and #read_packet).
164
- def send_and_wait(type, *args)
165
- send_packet(type, *args)
166
- read_packet
167
- end
168
-
169
- # Returns +true+ if the parameter indicates a "failure" response from
170
- # the agent, and +false+ otherwise.
171
- def agent_failed(type)
172
- type == SSH_AGENT_FAILURE ||
173
- type == SSH2_AGENT_FAILURE ||
174
- type == SSH_COM_AGENT2_FAILURE
175
- end
176
- end
177
-
178
- end; end; end