net-ssh 2.2.0 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,9 @@
1
1
 
2
+ === 2.2.1 / 24 Aug 2011
3
+
4
+ * Do not prompt any passphrases before trying all identities from agent. [musybite]
5
+ (see: http://net-ssh.lighthouseapp.com/projects/36253-net-ssh/tickets/30)
6
+
2
7
  === 2.2.0 / 16 Aug 2011
3
8
 
4
9
  * Add support for forward a local UNIX domain socket to a remote TCP socket. [Mark Imbriaco]
@@ -95,12 +95,14 @@ module Net
95
95
  # from ssh-agent will be ignored unless it present in key_files or
96
96
  # key_data.
97
97
  def each_identity
98
- user_identities = load_identities_from_files + load_identities_from_data
98
+ prepared_identities = prepare_identities_from_files + prepare_identities_from_data
99
+
100
+ user_identities = load_identities(prepared_identities, false)
99
101
 
100
102
  if agent
101
103
  agent.identities.each do |key|
102
104
  corresponding_user_identity = user_identities.detect { |identity|
103
- identity[:public_key].to_pem == key.to_pem
105
+ identity[:public_key] && identity[:public_key].to_pem == key.to_pem
104
106
  }
105
107
  user_identities.delete(corresponding_user_identity) if corresponding_user_identity
106
108
 
@@ -111,6 +113,8 @@ module Net
111
113
  end
112
114
  end
113
115
 
116
+ user_identities = load_identities(user_identities, true)
117
+
114
118
  user_identities.each do |identity|
115
119
  key = identity.delete(:public_key)
116
120
  known_identities[key] = identity
@@ -134,7 +138,7 @@ module Net
134
138
 
135
139
  if info[:key].nil? && info[:from] == :file
136
140
  begin
137
- info[:key] = KeyFactory.load_private_key(info[:file], options[:passphrase])
141
+ info[:key] = KeyFactory.load_private_key(info[:file], options[:passphrase], true)
138
142
  rescue Exception, OpenSSL::OpenSSLError => e
139
143
  raise KeyManagerError, "the given identity is known, but the private key could not be loaded: #{e.class} (#{e.message})"
140
144
  end
@@ -179,37 +183,67 @@ module Net
179
183
 
180
184
  private
181
185
 
182
- # Extracts identities from user key_files, preserving their order and sources.
183
- def load_identities_from_files
186
+ # Prepares identities from user key_files for loading, preserving their order and sources.
187
+ def prepare_identities_from_files
184
188
  key_files.map do |file|
185
189
  public_key_file = file + ".pub"
186
190
  if File.readable?(public_key_file)
187
- begin
188
- key = KeyFactory.load_public_key(public_key_file)
189
- { :public_key => key, :from => :file, :file => file }
190
- rescue Exception => e
191
- error { "could not load public key file `#{public_key_file}': #{e.class} (#{e.message})" }
192
- nil
193
- end
191
+ { :load_from => :pubkey_file, :file => file }
194
192
  elsif File.readable?(file)
195
- begin
196
- private_key = KeyFactory.load_private_key(file, options[:passphrase])
193
+ { :load_from => :privkey_file, :file => file }
194
+ end
195
+ end.compact
196
+ end
197
+
198
+ # Prepared identities from user key_data, preserving their order and sources.
199
+ def prepare_identities_from_data
200
+ key_data.map do |data|
201
+ { :load_from => :data, :data => data }
202
+ end
203
+ end
204
+
205
+ # Load prepared identities. Private key decryption errors ignored if passphrase was not prompted.
206
+ def load_identities(identities, ask_passphrase)
207
+ identities.map do |identity|
208
+ begin
209
+ case identity[:load_from]
210
+ when :pubkey_file
211
+ key = KeyFactory.load_public_key(identity[:file] + ".pub")
212
+ { :public_key => key, :from => :file, :file => identity[:file] }
213
+ when :privkey_file
214
+ private_key = KeyFactory.load_private_key(identity[:file], options[:passphrase], ask_passphrase)
197
215
  key = private_key.send(:public_key)
198
- { :public_key => key, :from => :file, :file => file, :key => private_key }
199
- rescue Exception => e
200
- error { "could not load private key file `#{file}': #{e.class} (#{e.message})" }
216
+ { :public_key => key, :from => :file, :file => identity[:file], :key => private_key }
217
+ when :data
218
+ private_key = KeyFactory.load_data_private_key(identity[:data], options[:passphrase], ask_passphrase)
219
+ key = private_key.send(:public_key)
220
+ { :public_key => key, :from => :key_data, :data => identity[:data], :key => private_key }
221
+ else
222
+ identity
223
+ end
224
+
225
+ rescue OpenSSL::PKey::RSAError, OpenSSL::PKey::DSAError => e
226
+ if ask_passphrase
227
+ process_identity_loading_error(identity, e)
201
228
  nil
229
+ else
230
+ identity
202
231
  end
232
+ rescue Exception => e
233
+ process_identity_loading_error(identity, e)
234
+ nil
203
235
  end
204
236
  end.compact
205
237
  end
206
238
 
207
- # Extraccts identities from user key_data, preserving their order and sources.
208
- def load_identities_from_data
209
- key_data.map do |data|
210
- private_key = KeyFactory.load_data_private_key(data)
211
- key = private_key.send(:public_key)
212
- { :public_key => key, :from => :key_data, :data => data, :key => private_key }
239
+ def process_identity_loading_error(identity, e)
240
+ case identity[:load_from]
241
+ when :pubkey_file
242
+ error { "could not load public key file `#{identity[:file]}': #{e.class} (#{e.message})" }
243
+ when :privkey_file
244
+ error { "could not load private key file `#{identity[:file]}': #{e.class} (#{e.message})" }
245
+ else
246
+ raise e
213
247
  end
214
248
  end
215
249
 
@@ -34,9 +34,9 @@ module Net; module SSH
34
34
  # appropriately. The new key is returned. If the key itself is
35
35
  # encrypted (requiring a passphrase to use), the user will be
36
36
  # prompted to enter their password unless passphrase works.
37
- def load_private_key(filename, passphrase=nil)
37
+ def load_private_key(filename, passphrase=nil, ask_passphrase=true)
38
38
  data = File.read(File.expand_path(filename))
39
- load_data_private_key(data, passphrase, filename)
39
+ load_data_private_key(data, passphrase, ask_passphrase, filename)
40
40
  end
41
41
 
42
42
  # Loads a private key. It will correctly determine
@@ -44,7 +44,7 @@ module Net; module SSH
44
44
  # appropriately. The new key is returned. If the key itself is
45
45
  # encrypted (requiring a passphrase to use), the user will be
46
46
  # prompted to enter their password unless passphrase works.
47
- def load_data_private_key(data, passphrase=nil, filename="")
47
+ def load_data_private_key(data, passphrase=nil, ask_passphrase=true, filename="")
48
48
  if data.match(/-----BEGIN DSA PRIVATE KEY-----/)
49
49
  key_type = OpenSSL::PKey::DSA
50
50
  elsif data.match(/-----BEGIN RSA PRIVATE KEY-----/)
@@ -61,7 +61,7 @@ module Net; module SSH
61
61
  begin
62
62
  return key_type.new(data, passphrase || 'invalid')
63
63
  rescue OpenSSL::PKey::RSAError, OpenSSL::PKey::DSAError => e
64
- if encrypted_key
64
+ if encrypted_key && ask_passphrase
65
65
  tries += 1
66
66
  if tries <= 3
67
67
  passphrase = prompt("Enter passphrase for #{filename}:", false)
@@ -51,7 +51,7 @@ module Net; module SSH
51
51
  MINOR = 2
52
52
 
53
53
  # The tiny component of this version of the Net::SSH library
54
- TINY = 0
54
+ TINY = 1
55
55
 
56
56
  # The current version of the Net::SSH library as a Version instance
57
57
  CURRENT = new(MAJOR, MINOR, TINY)
@@ -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.2.0"
4
+ s.version = "2.2.1"
5
5
  s.summary = "Net::SSH: a pure-Ruby implementation of the SSH2 client protocol."
6
6
  s.description = s.summary
7
7
  s.authors = ["Jamis Buck", "Delano Mandelbaum"]
@@ -31,8 +31,8 @@ module Authentication
31
31
  def test_each_identity_should_load_from_key_files
32
32
  manager.stubs(:agent).returns(nil)
33
33
 
34
- stub_file_key "/first", rsa
35
- stub_file_key "/second", dsa
34
+ stub_file_private_key "/first", rsa
35
+ stub_file_private_key "/second", dsa
36
36
 
37
37
  identities = []
38
38
  manager.each_identity { |identity| identities << identity }
@@ -62,7 +62,7 @@ module Authentication
62
62
  def test_only_identities_with_key_files_should_load_from_agent_of_keys_only_set
63
63
  manager(:keys_only => true).stubs(:agent).returns(agent)
64
64
 
65
- stub_file_key "/first", rsa
65
+ stub_file_private_key "/first", rsa
66
66
 
67
67
  identities = []
68
68
  manager.each_identity { |identity| identities << identity }
@@ -73,6 +73,22 @@ module Authentication
73
73
  assert_equal({:from => :agent}, manager.known_identities[rsa])
74
74
  end
75
75
 
76
+ def test_identities_without_public_key_files_should_not_be_touched_if_identity_loaded_from_agent
77
+ manager.stubs(:agent).returns(agent)
78
+
79
+ stub_file_public_key "/first", rsa
80
+ stub_file_private_key "/second", dsa, :passphrase => :should_not_be_asked
81
+
82
+ identities = []
83
+ manager.each_identity do |identity|
84
+ identities << identity
85
+ break if manager.known_identities[identity][:from] == :agent
86
+ end
87
+
88
+ assert_equal 1, identities.length
89
+ assert_equal rsa.to_blob, identities.first.to_blob
90
+ end
91
+
76
92
  def test_sign_with_agent_originated_key_should_request_signature_from_agent
77
93
  manager.stubs(:agent).returns(agent)
78
94
  manager.each_identity { |identity| } # preload the known_identities
@@ -82,7 +98,7 @@ module Authentication
82
98
 
83
99
  def test_sign_with_file_originated_key_should_load_private_key_and_sign_with_it
84
100
  manager.stubs(:agent).returns(nil)
85
- stub_file_key "/first", rsa(512)
101
+ stub_file_private_key "/first", rsa(512)
86
102
  rsa.expects(:ssh_do_sign).with("hello, world").returns("abcxyz123")
87
103
  manager.each_identity { |identity| } # preload the known_identities
88
104
  assert_equal "\0\0\0\assh-rsa\0\0\0\011abcxyz123", manager.sign(rsa, "hello, world")
@@ -100,12 +116,31 @@ module Authentication
100
116
 
101
117
  private
102
118
 
103
- def stub_file_key(name, key)
119
+ def stub_file_private_key(name, key, options = {})
104
120
  manager.add(name)
105
- File.expects(:readable?).with(name).returns(true)
106
- File.expects(:readable?).with(name + ".pub").returns(false)
107
- Net::SSH::KeyFactory.expects(:load_private_key).with(name, nil).returns(key).at_least_once
108
- key.expects(:public_key).returns(key)
121
+ File.stubs(:readable?).with(name).returns(true)
122
+ File.stubs(:readable?).with(name + ".pub").returns(false)
123
+
124
+ case options.fetch(:passphrase, :indifferently)
125
+ when :should_be_asked
126
+ Net::SSH::KeyFactory.expects(:load_private_key).with(name, nil, false).raises(OpenSSL::PKey::RSAError).at_least_once
127
+ Net::SSH::KeyFactory.expects(:load_private_key).with(name, nil, true).returns(key).at_least_once
128
+ when :should_not_be_asked
129
+ Net::SSH::KeyFactory.expects(:load_private_key).with(name, nil, false).raises(OpenSSL::PKey::RSAError).at_least_once
130
+ Net::SSH::KeyFactory.expects(:load_private_key).with(name, nil, true).never
131
+ else # :indifferently
132
+ Net::SSH::KeyFactory.expects(:load_private_key).with(name, nil, any_of(true, false)).returns(key).at_least_once
133
+ end
134
+
135
+ key.stubs(:public_key).returns(key)
136
+ end
137
+
138
+ def stub_file_public_key(name, key)
139
+ manager.add(name)
140
+ File.stubs(:readable?).with(name).returns(false)
141
+ File.stubs(:readable?).with(name + ".pub").returns(true)
142
+
143
+ Net::SSH::KeyFactory.expects(:load_public_key).with(name + ".pub").returns(key).at_least_once
109
144
  end
110
145
 
111
146
  def rsa(size=512)
@@ -40,6 +40,12 @@ class TestKeyFactory < Test::Unit::TestCase
40
40
  assert_raises(OpenSSL::PKey::RSAError) { Net::SSH::KeyFactory.load_private_key("/key-file") }
41
41
  end
42
42
 
43
+ def test_load_encrypted_private_key_should_raise_exception_without_asking_passphrase
44
+ File.expects(:read).with("/key-file").returns(encrypted(rsa_key, "password"))
45
+ Net::SSH::KeyFactory.expects(:prompt).never
46
+ assert_raises(OpenSSL::PKey::RSAError) { Net::SSH::KeyFactory.load_private_key("/key-file", nil, false) }
47
+ end
48
+
43
49
  def test_load_public_rsa_key_should_return_key
44
50
  File.expects(:read).with("/key-file").returns(public(rsa_key))
45
51
  assert_equal rsa_key.to_blob, Net::SSH::KeyFactory.load_public_key("/key-file").to_blob
@@ -66,4 +72,4 @@ class TestKeyFactory < Test::Unit::TestCase
66
72
  result << [Net::SSH::Buffer.from(:key, key).to_s].pack("m*").strip.tr("\n\r\t ", "")
67
73
  result << " joe@host.test"
68
74
  end
69
- end
75
+ end
@@ -146,7 +146,7 @@ module Transport
146
146
  def test_allow_when_not_pending_should_be_true_for_all_packets
147
147
  (0..255).each do |type|
148
148
  packet = stub("packet", :type => type)
149
- assert algorithms.allow?(packet), type
149
+ assert algorithms.allow?(packet), type.to_s
150
150
  end
151
151
  end
152
152
 
@@ -299,4 +299,4 @@ module Transport
299
299
  end
300
300
  end
301
301
 
302
- end
302
+ end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: net-ssh
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 2.2.0
5
+ version: 2.2.1
6
6
  platform: ruby
7
7
  authors:
8
8
  - Jamis Buck
@@ -11,7 +11,7 @@ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
13
 
14
- date: 2011-08-17 00:00:00 -04:00
14
+ date: 2011-08-24 00:00:00 -04:00
15
15
  default_executable:
16
16
  dependencies: []
17
17