forked from capistrano/capistrano
/
ssh.rb
61 lines (53 loc) · 2.16 KB
/
ssh.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
require 'net/ssh'
module Capistrano
unless ENV['SKIP_VERSION_CHECK']
require 'capistrano/version'
require 'net/ssh/version'
ssh_version = [Net::SSH::Version::MAJOR, Net::SSH::Version::MINOR, Net::SSH::Version::TINY]
if !Version.check(Version::SSH_REQUIRED, ssh_version)
raise "You have Net::SSH #{ssh_version.join(".")}, but you need at least #{Version::SSH_REQUIRED.join(".")}"
end
end
# A helper class for dealing with SSH connections.
class SSH
# Patch an accessor onto an SSH connection so that we can record the "real"
# host behind the connection. This is useful because the gateway returns
# connections whose "host" is 127.0.0.1, instead of the host on the other
# side of the tunnel.
module RealHost #:nodoc:
def self.apply_to(connection, host)
connection.extend(RealHost)
connection.real_host = host
connection
end
attr_accessor :real_host
end
# The default port for SSH.
DEFAULT_PORT = 22
# An abstraction to make it possible to connect to the server via public key
# without prompting for the password. If the public key authentication fails
# this will fall back to password authentication.
#
# +server+ must be an instance of ServerDefinition.
#
# If a block is given, the new session is yielded to it, otherwise the new
# session is returned.
def self.connect(server, options={}, &block)
methods = [ %w(publickey hostbased), %w(password keyboard-interactive) ]
password_value = nil
begin
ssh_options = { :username => (server.user || options[:user]),
:password => password_value,
:port => (server.port || options[:port] || DEFAULT_PORT),
:auth_methods => methods.shift }
ssh_options.update(options[:ssh_options]) if options[:ssh_options]
connection = Net::SSH.start(server.host, ssh_options, &block)
RealHost.apply_to(connection, server.host)
rescue Net::SSH::AuthenticationFailed
raise if methods.empty?
password_value = options[:password]
retry
end
end
end
end