ddollar-net-ssh 2.0.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.
Files changed (103) hide show
  1. data/CHANGELOG.rdoc +42 -0
  2. data/Manifest +101 -0
  3. data/README.rdoc +110 -0
  4. data/Rakefile +26 -0
  5. data/THANKS.rdoc +16 -0
  6. data/lib/net/ssh.rb +199 -0
  7. data/lib/net/ssh/authentication/agent.rb +175 -0
  8. data/lib/net/ssh/authentication/constants.rb +18 -0
  9. data/lib/net/ssh/authentication/key_manager.rb +169 -0
  10. data/lib/net/ssh/authentication/methods/abstract.rb +60 -0
  11. data/lib/net/ssh/authentication/methods/hostbased.rb +71 -0
  12. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +66 -0
  13. data/lib/net/ssh/authentication/methods/password.rb +39 -0
  14. data/lib/net/ssh/authentication/methods/publickey.rb +92 -0
  15. data/lib/net/ssh/authentication/pageant.rb +176 -0
  16. data/lib/net/ssh/authentication/session.rb +127 -0
  17. data/lib/net/ssh/buffer.rb +339 -0
  18. data/lib/net/ssh/buffered_io.rb +149 -0
  19. data/lib/net/ssh/config.rb +173 -0
  20. data/lib/net/ssh/connection/channel.rb +625 -0
  21. data/lib/net/ssh/connection/constants.rb +33 -0
  22. data/lib/net/ssh/connection/session.rb +569 -0
  23. data/lib/net/ssh/connection/term.rb +178 -0
  24. data/lib/net/ssh/errors.rb +85 -0
  25. data/lib/net/ssh/key_factory.rb +85 -0
  26. data/lib/net/ssh/known_hosts.rb +129 -0
  27. data/lib/net/ssh/loggable.rb +61 -0
  28. data/lib/net/ssh/packet.rb +102 -0
  29. data/lib/net/ssh/prompt.rb +93 -0
  30. data/lib/net/ssh/proxy/errors.rb +14 -0
  31. data/lib/net/ssh/proxy/http.rb +94 -0
  32. data/lib/net/ssh/proxy/socks4.rb +70 -0
  33. data/lib/net/ssh/proxy/socks5.rb +128 -0
  34. data/lib/net/ssh/service/forward.rb +267 -0
  35. data/lib/net/ssh/test.rb +89 -0
  36. data/lib/net/ssh/test/channel.rb +129 -0
  37. data/lib/net/ssh/test/extensions.rb +152 -0
  38. data/lib/net/ssh/test/kex.rb +44 -0
  39. data/lib/net/ssh/test/local_packet.rb +51 -0
  40. data/lib/net/ssh/test/packet.rb +81 -0
  41. data/lib/net/ssh/test/remote_packet.rb +38 -0
  42. data/lib/net/ssh/test/script.rb +157 -0
  43. data/lib/net/ssh/test/socket.rb +59 -0
  44. data/lib/net/ssh/transport/algorithms.rb +384 -0
  45. data/lib/net/ssh/transport/cipher_factory.rb +72 -0
  46. data/lib/net/ssh/transport/constants.rb +30 -0
  47. data/lib/net/ssh/transport/hmac.rb +31 -0
  48. data/lib/net/ssh/transport/hmac/abstract.rb +48 -0
  49. data/lib/net/ssh/transport/hmac/md5.rb +12 -0
  50. data/lib/net/ssh/transport/hmac/md5_96.rb +11 -0
  51. data/lib/net/ssh/transport/hmac/none.rb +15 -0
  52. data/lib/net/ssh/transport/hmac/sha1.rb +13 -0
  53. data/lib/net/ssh/transport/hmac/sha1_96.rb +11 -0
  54. data/lib/net/ssh/transport/identity_cipher.rb +40 -0
  55. data/lib/net/ssh/transport/kex.rb +13 -0
  56. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +208 -0
  57. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +77 -0
  58. data/lib/net/ssh/transport/openssl.rb +128 -0
  59. data/lib/net/ssh/transport/packet_stream.rb +230 -0
  60. data/lib/net/ssh/transport/server_version.rb +61 -0
  61. data/lib/net/ssh/transport/session.rb +262 -0
  62. data/lib/net/ssh/transport/state.rb +170 -0
  63. data/lib/net/ssh/verifiers/lenient.rb +30 -0
  64. data/lib/net/ssh/verifiers/null.rb +12 -0
  65. data/lib/net/ssh/verifiers/strict.rb +53 -0
  66. data/lib/net/ssh/version.rb +60 -0
  67. data/net-ssh.gemspec +56 -0
  68. data/setup.rb +1585 -0
  69. data/test/authentication/methods/common.rb +28 -0
  70. data/test/authentication/methods/test_abstract.rb +51 -0
  71. data/test/authentication/methods/test_hostbased.rb +108 -0
  72. data/test/authentication/methods/test_keyboard_interactive.rb +98 -0
  73. data/test/authentication/methods/test_password.rb +50 -0
  74. data/test/authentication/methods/test_publickey.rb +123 -0
  75. data/test/authentication/test_agent.rb +205 -0
  76. data/test/authentication/test_key_manager.rb +100 -0
  77. data/test/authentication/test_session.rb +93 -0
  78. data/test/common.rb +106 -0
  79. data/test/configs/exact_match +8 -0
  80. data/test/configs/wild_cards +14 -0
  81. data/test/connection/test_channel.rb +452 -0
  82. data/test/connection/test_session.rb +483 -0
  83. data/test/test_all.rb +6 -0
  84. data/test/test_buffer.rb +336 -0
  85. data/test/test_buffered_io.rb +63 -0
  86. data/test/test_config.rb +78 -0
  87. data/test/test_key_factory.rb +67 -0
  88. data/test/transport/hmac/test_md5.rb +34 -0
  89. data/test/transport/hmac/test_md5_96.rb +25 -0
  90. data/test/transport/hmac/test_none.rb +34 -0
  91. data/test/transport/hmac/test_sha1.rb +34 -0
  92. data/test/transport/hmac/test_sha1_96.rb +25 -0
  93. data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +146 -0
  94. data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +92 -0
  95. data/test/transport/test_algorithms.rb +302 -0
  96. data/test/transport/test_cipher_factory.rb +163 -0
  97. data/test/transport/test_hmac.rb +34 -0
  98. data/test/transport/test_identity_cipher.rb +40 -0
  99. data/test/transport/test_packet_stream.rb +433 -0
  100. data/test/transport/test_server_version.rb +55 -0
  101. data/test/transport/test_session.rb +312 -0
  102. data/test/transport/test_state.rb +173 -0
  103. metadata +222 -0
@@ -0,0 +1,175 @@
1
+ require 'net/ssh/buffer'
2
+ require 'net/ssh/errors'
3
+ require 'net/ssh/loggable'
4
+ require 'net/ssh/transport/server_version'
5
+
6
+ require 'net/ssh/authentication/pageant' if File::ALT_SEPARATOR
7
+
8
+ module Net; module SSH; module Authentication
9
+
10
+ # A trivial exception class for representing agent-specific errors.
11
+ class AgentError < Net::SSH::Exception; end
12
+
13
+ # An exception for indicating that the SSH agent is not available.
14
+ class AgentNotAvailable < AgentError; end
15
+
16
+ # This class implements a simple client for the ssh-agent protocol. It
17
+ # does not implement any specific protocol, but instead copies the
18
+ # behavior of the ssh-agent functions in the OpenSSH library (3.8).
19
+ #
20
+ # This means that although it behaves like a SSH1 client, it also has
21
+ # some SSH2 functionality (like signing data).
22
+ class Agent
23
+ include Loggable
24
+
25
+ # A simple module for extending keys, to allow comments to be specified
26
+ # for them.
27
+ module Comment
28
+ attr_accessor :comment
29
+ end
30
+
31
+ SSH2_AGENT_REQUEST_VERSION = 1
32
+ SSH2_AGENT_REQUEST_IDENTITIES = 11
33
+ SSH2_AGENT_IDENTITIES_ANSWER = 12
34
+ SSH2_AGENT_SIGN_REQUEST = 13
35
+ SSH2_AGENT_SIGN_RESPONSE = 14
36
+ SSH2_AGENT_FAILURE = 30
37
+ SSH2_AGENT_VERSION_RESPONSE = 103
38
+
39
+ SSH_COM_AGENT2_FAILURE = 102
40
+
41
+ SSH_AGENT_REQUEST_RSA_IDENTITIES = 1
42
+ SSH_AGENT_RSA_IDENTITIES_ANSWER = 2
43
+ SSH_AGENT_FAILURE = 5
44
+
45
+ # The underlying socket being used to communicate with the SSH agent.
46
+ attr_reader :socket
47
+
48
+ # Instantiates a new agent object, connects to a running SSH agent,
49
+ # negotiates the agent protocol version, and returns the agent object.
50
+ def self.connect(logger=nil)
51
+ agent = new(logger)
52
+ agent.connect!
53
+ agent.negotiate!
54
+ agent
55
+ end
56
+
57
+ # Creates a new Agent object, using the optional logger instance to
58
+ # report status.
59
+ def initialize(logger=nil)
60
+ self.logger = logger
61
+ end
62
+
63
+ # Connect to the agent process using the socket factory and socket name
64
+ # given by the attribute writers. If the agent on the other end of the
65
+ # socket reports that it is an SSH2-compatible agent, this will fail
66
+ # (it only supports the ssh-agent distributed by OpenSSH).
67
+ def connect!
68
+ begin
69
+ debug { "connecting to ssh-agent" }
70
+ @socket = agent_socket_factory.open(ENV['SSH_AUTH_SOCK'])
71
+ rescue
72
+ error { "could not connect to ssh-agent" }
73
+ raise AgentNotAvailable, $!.message
74
+ end
75
+ end
76
+
77
+ # Attempts to negotiate the SSH agent protocol version. Raises an error
78
+ # if the version could not be negotiated successfully.
79
+ def negotiate!
80
+ # determine what type of agent we're communicating with
81
+ type, body = send_and_wait(SSH2_AGENT_REQUEST_VERSION, :string, Transport::ServerVersion::PROTO_VERSION)
82
+
83
+ if type == SSH2_AGENT_VERSION_RESPONSE
84
+ raise NotImplementedError, "SSH2 agents are not yet supported"
85
+ elsif type != SSH_AGENT_RSA_IDENTITIES_ANSWER
86
+ raise AgentError, "unknown response from agent: #{type}, #{body.to_s.inspect}"
87
+ end
88
+ end
89
+
90
+ # Return an array of all identities (public keys) known to the agent.
91
+ # Each key returned is augmented with a +comment+ property which is set
92
+ # to the comment returned by the agent for that key.
93
+ def identities
94
+ type, body = send_and_wait(SSH2_AGENT_REQUEST_IDENTITIES)
95
+ raise AgentError, "could not get identity count" if agent_failed(type)
96
+ raise AgentError, "bad authentication reply: #{type}" if type != SSH2_AGENT_IDENTITIES_ANSWER
97
+
98
+ identities = []
99
+ body.read_long.times do
100
+ key = Buffer.new(body.read_string).read_key
101
+ key.extend(Comment)
102
+ key.comment = body.read_string
103
+ identities.push key
104
+ end
105
+
106
+ return identities
107
+ end
108
+
109
+ # Closes this socket. This agent reference is no longer able to
110
+ # query the agent.
111
+ def close
112
+ @socket.close
113
+ end
114
+
115
+ # Using the agent and the given public key, sign the given data. The
116
+ # signature is returned in SSH2 format.
117
+ def sign(key, data)
118
+ type, reply = send_and_wait(SSH2_AGENT_SIGN_REQUEST, :string, Buffer.from(:key, key), :string, data, :long, 0)
119
+
120
+ if agent_failed(type)
121
+ raise AgentError, "agent could not sign data with requested identity"
122
+ elsif type != SSH2_AGENT_SIGN_RESPONSE
123
+ raise AgentError, "bad authentication response #{type}"
124
+ end
125
+
126
+ return reply.read_string
127
+ end
128
+
129
+ private
130
+
131
+ # Returns the agent socket factory to use.
132
+ def agent_socket_factory
133
+ if File::ALT_SEPARATOR
134
+ Pageant::Socket
135
+ else
136
+ UNIXSocket
137
+ end
138
+ end
139
+
140
+ # Send a new packet of the given type, with the associated data.
141
+ def send_packet(type, *args)
142
+ buffer = Buffer.from(*args)
143
+ data = [buffer.length + 1, type.to_i, buffer.to_s].pack("NCA*")
144
+ debug { "sending agent request #{type} len #{buffer.length}" }
145
+ @socket.send data, 0
146
+ end
147
+
148
+ # Read the next packet from the agent. This will return a two-part
149
+ # tuple consisting of the packet type, and the packet's body (which
150
+ # is returned as a Net::SSH::Buffer).
151
+ def read_packet
152
+ buffer = Net::SSH::Buffer.new(@socket.read(4))
153
+ buffer.append(@socket.read(buffer.read_long))
154
+ type = buffer.read_byte
155
+ debug { "received agent packet #{type} len #{buffer.length-4}" }
156
+ return type, buffer
157
+ end
158
+
159
+ # Send the given packet and return the subsequent reply from the agent.
160
+ # (See #send_packet and #read_packet).
161
+ def send_and_wait(type, *args)
162
+ send_packet(type, *args)
163
+ read_packet
164
+ end
165
+
166
+ # Returns +true+ if the parameter indicates a "failure" response from
167
+ # the agent, and +false+ otherwise.
168
+ def agent_failed(type)
169
+ type == SSH_AGENT_FAILURE ||
170
+ type == SSH2_AGENT_FAILURE ||
171
+ type == SSH_COM_AGENT2_FAILURE
172
+ end
173
+ end
174
+
175
+ end; end; end
@@ -0,0 +1,18 @@
1
+ module Net; module SSH; module Authentication
2
+
3
+ # Describes the constants used by the Net::SSH::Authentication components
4
+ # of the Net::SSH library. Individual authentication method implemenations
5
+ # may define yet more constants that are specific to their implementation.
6
+ module Constants
7
+ USERAUTH_REQUEST = 50
8
+ USERAUTH_FAILURE = 51
9
+ USERAUTH_SUCCESS = 52
10
+ USERAUTH_BANNER = 53
11
+
12
+ USERAUTH_PASSWD_CHANGEREQ = 60
13
+ USERAUTH_PK_OK = 60
14
+
15
+ USERAUTH_METHOD_RANGE = 60..79
16
+ end
17
+
18
+ end; end; end
@@ -0,0 +1,169 @@
1
+ require 'net/ssh/errors'
2
+ require 'net/ssh/key_factory'
3
+ require 'net/ssh/loggable'
4
+ require 'net/ssh/authentication/agent'
5
+
6
+ module Net
7
+ module SSH
8
+ module Authentication
9
+
10
+ # A trivial exception class used to report errors in the key manager.
11
+ class KeyManagerError < Net::SSH::Exception; end
12
+
13
+ # This class encapsulates all operations done by clients on a user's
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
16
+ # keys) that are available from the KeyManager, and then use
17
+ # the KeyManager to do various private key operations using those
18
+ # identities.
19
+ #
20
+ # The KeyManager also uses the Agent class to encapsulate the
21
+ # ssh-agent. Thus, from a client's perspective it is completely
22
+ # hidden whether an identity comes from the ssh-agent or from a file
23
+ # on disk.
24
+ class KeyManager
25
+ include Loggable
26
+
27
+ # The list of user key files that will be examined
28
+ attr_reader :key_files
29
+
30
+ # The map of loaded identities
31
+ attr_reader :known_identities
32
+
33
+ # The map of options that were passed to the key-manager
34
+ attr_reader :options
35
+
36
+ # Create a new KeyManager. By default, the manager will
37
+ # use the ssh-agent (if it is running).
38
+ def initialize(logger, options={})
39
+ self.logger = logger
40
+ @key_files = []
41
+ @use_agent = true
42
+ @known_identities = {}
43
+ @agent = nil
44
+ @options = options
45
+ end
46
+
47
+ # Clear all knowledge of any loaded user keys. This also clears the list
48
+ # of default identity files that are to be loaded, thus making it
49
+ # appropriate to use if a client wishes to NOT use the default identity
50
+ # files.
51
+ def clear!
52
+ key_files.clear
53
+ known_identities.clear
54
+ self
55
+ end
56
+
57
+ # Add the given key_file to the list of key files that will be used.
58
+ def add(key_file)
59
+ key_files.push(File.expand_path(key_file)).uniq!
60
+ self
61
+ end
62
+
63
+ # This is used as a hint to the KeyManager indicating that the agent
64
+ # connection is no longer needed. Any other open resources may be closed
65
+ # at this time.
66
+ #
67
+ # Calling this does NOT indicate that the KeyManager will no longer
68
+ # be used. Identities may still be requested and operations done on
69
+ # loaded identities, in which case, the agent will be automatically
70
+ # reconnected. This method simply allows the client connection to be
71
+ # closed when it will not be used in the immediate future.
72
+ def finish
73
+ @agent.close if @agent
74
+ @agent = nil
75
+ end
76
+
77
+ # Returns an array of identities (public keys) known to this manager.
78
+ # The origin of the identities may be from files on disk or from an
79
+ # ssh-agent. Note that identities from an ssh-agent are always listed
80
+ # first in the array, with other identities coming after.
81
+ def identities
82
+ identities = []
83
+
84
+ if agent
85
+ agent.identities.each do |key|
86
+ identities.push key
87
+ known_identities[key] = { :from => :agent }
88
+ end
89
+ end
90
+
91
+ key_files.each do |file|
92
+ if File.readable?(file)
93
+ begin
94
+ public_key_file = file + '.pub'
95
+ next unless File.exists?(public_key_file)
96
+
97
+ key = KeyFactory.load_public_key(public_key_file)
98
+ identities.push key
99
+ known_identities[key] = { :from => :file, :file => file }
100
+ rescue Exception => e
101
+ error { "could not load public key file `#{file}.pub': #{e.class} (#{e.message})" }
102
+ end
103
+ end
104
+ end
105
+
106
+ identities
107
+ end
108
+
109
+ # Sign the given data, using the corresponding private key of the given
110
+ # identity. If the identity was originally obtained from an ssh-agent,
111
+ # then the ssh-agent will be used to sign the data, otherwise the
112
+ # private key for the identity will be loaded from disk (if it hasn't
113
+ # been loaded already) and will then be used to sign the data.
114
+ #
115
+ # Regardless of the identity's origin or who does the signing, this
116
+ # will always return the signature in an SSH2-specified "signature
117
+ # blob" format.
118
+ def sign(identity, data)
119
+ info = known_identities[identity] or raise KeyManagerError, "the given identity is unknown to the key manager"
120
+
121
+ if info[:key].nil? && info[:from] == :file
122
+ begin
123
+ info[:key] = KeyFactory.load_private_key(info[:file], options[:passphrase])
124
+ rescue Exception => e
125
+ raise KeyManagerError, "the given identity is known, but the private key could not be loaded: #{e.class} (#{e.message})"
126
+ end
127
+ end
128
+
129
+ if info[:key]
130
+ return Net::SSH::Buffer.from(:string, identity.ssh_type,
131
+ :string, info[:key].ssh_do_sign(data.to_s)).to_s
132
+ end
133
+
134
+ if info[:from] == :agent
135
+ raise KeyManagerError, "the agent is no longer available" unless agent
136
+ return agent.sign(identity, data.to_s)
137
+ end
138
+
139
+ raise KeyManagerError, "[BUG] can't determine identity origin (#{info.inspect})"
140
+ end
141
+
142
+ # Identifies whether the ssh-agent will be used or not.
143
+ def use_agent?
144
+ @use_agent
145
+ end
146
+
147
+ # Toggles whether the ssh-agent will be used or not. If true, an
148
+ # attempt will be made to use the ssh-agent. If false, any existing
149
+ # connection to an agent is closed and the agent will not be used.
150
+ def use_agent=(use_agent)
151
+ finish if !use_agent
152
+ @use_agent = use_agent
153
+ end
154
+
155
+ # Returns an Agent instance to use for communicating with an SSH
156
+ # agent process. Returns nil if use of an SSH agent has been disabled,
157
+ # or if the agent is otherwise not available.
158
+ def agent
159
+ return unless use_agent?
160
+ @agent ||= Agent.connect(logger)
161
+ rescue AgentNotAvailable
162
+ @use_agent = false
163
+ nil
164
+ end
165
+ end
166
+
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,60 @@
1
+ require 'net/ssh/buffer'
2
+ require 'net/ssh/errors'
3
+ require 'net/ssh/loggable'
4
+ require 'net/ssh/authentication/constants'
5
+
6
+ module Net; module SSH; module Authentication; module Methods
7
+
8
+ # The base class of all user authentication methods. It provides a few
9
+ # bits of common functionality.
10
+ class Abstract
11
+ include Constants, Loggable
12
+
13
+ # The authentication session object
14
+ attr_reader :session
15
+
16
+ # The key manager object. Not all authentication methods will require
17
+ # this.
18
+ attr_reader :key_manager
19
+
20
+ # Instantiates a new authentication method.
21
+ def initialize(session, options={})
22
+ @session = session
23
+ @key_manager = options[:key_manager]
24
+ @options = options
25
+ self.logger = session.logger
26
+ end
27
+
28
+ # Returns the session-id, as generated during the first key exchange of
29
+ # an SSH connection.
30
+ def session_id
31
+ session.transport.algorithms.session_id
32
+ end
33
+
34
+ # Sends a message via the underlying transport layer abstraction. This
35
+ # will block until the message is completely sent.
36
+ def send_message(msg)
37
+ session.transport.send_message(msg)
38
+ end
39
+
40
+ # Creates a new USERAUTH_REQUEST packet. The extra arguments on the end
41
+ # must be either boolean values or strings, and are tacked onto the end
42
+ # of the packet. The new packet is returned, ready for sending.
43
+ def userauth_request(username, next_service, auth_method, *others)
44
+ buffer = Net::SSH::Buffer.from(:byte, USERAUTH_REQUEST,
45
+ :string, username, :string, next_service, :string, auth_method)
46
+
47
+ others.each do |value|
48
+ case value
49
+ when true, false then buffer.write_bool(value)
50
+ when String then buffer.write_string(value)
51
+ else raise ArgumentError, "don't know how to write #{value.inspect}"
52
+ end
53
+ end
54
+
55
+ buffer
56
+ end
57
+
58
+ end
59
+
60
+ end; end; end; end
@@ -0,0 +1,71 @@
1
+ require 'net/ssh/authentication/methods/abstract'
2
+
3
+ module Net
4
+ module SSH
5
+ module Authentication
6
+ module Methods
7
+
8
+ # Implements the host-based SSH authentication method.
9
+ class Hostbased < Abstract
10
+ include Constants
11
+
12
+ # Attempts to perform host-based authorization of the user by trying
13
+ # all known keys.
14
+ def authenticate(next_service, username, password=nil)
15
+ return false unless key_manager
16
+
17
+ key_manager.identities.each do |identity|
18
+ return true if authenticate_with(identity, next_service,
19
+ username, key_manager)
20
+ end
21
+
22
+ return false
23
+ end
24
+
25
+ private
26
+
27
+ # Returns the hostname as reported by the underlying socket.
28
+ def hostname
29
+ session.transport.socket.client_name
30
+ end
31
+
32
+ # Attempts to perform host-based authentication of the user, using
33
+ # the given host identity (key).
34
+ def authenticate_with(identity, next_service, username, key_manager)
35
+ debug { "trying hostbased (#{identity.fingerprint})" }
36
+ client_username = ENV['USER'] || username
37
+
38
+ req = build_request(identity, next_service, username, "#{hostname}.", client_username)
39
+ sig_data = Buffer.from(:string, session_id, :raw, req)
40
+
41
+ sig = key_manager.sign(identity, sig_data.to_s)
42
+
43
+ message = Buffer.from(:raw, req, :string, sig)
44
+
45
+ send_message(message)
46
+ message = session.next_message
47
+
48
+ case message.type
49
+ when USERAUTH_SUCCESS
50
+ info { "hostbased succeeded (#{identity.fingerprint})" }
51
+ return true
52
+ when USERAUTH_FAILURE
53
+ info { "hostbased failed (#{identity.fingerprint})" }
54
+ return false
55
+ else
56
+ raise Net::SSH::Exception, "unexpected server response to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
57
+ end
58
+ end
59
+
60
+ # Build the "core" hostbased request string.
61
+ def build_request(identity, next_service, username, hostname, client_username)
62
+ userauth_request(username, next_service, "hostbased", identity.ssh_type,
63
+ Buffer.from(:key, identity).to_s, hostname, client_username).to_s
64
+ end
65
+
66
+ end
67
+
68
+ end
69
+ end
70
+ end
71
+ end