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 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
require 'net/ssh/buffer'
require 'net/ssh/errors'
require 'net/ssh/authentication/methods/abstract'
module Net
module SSH
module Authentication
module Methods
# Implements the "publickey" SSH authentication method.
class Publickey < Abstract
# Attempts to perform public-key authentication for the given
# username, trying each identity known to the key manager. If any of
# them succeed, returns +true+, otherwise returns +false+. This
# requires the presence of a key manager.
def authenticate(next_service, username, password=nil)
return false unless key_manager
key_manager.each_identity do |identity|
return true if authenticate_with(identity, next_service, username)
end
return false
end
private
# Builds a packet that contains the request formatted for sending
# a public-key request to the server.
def build_request(pub_key, username, next_service, alg, has_sig)
blob = Net::SSH::Buffer.new
blob.write_key pub_key
userauth_request(username, next_service, "publickey", has_sig,
alg, blob.to_s)
end
# Builds and sends a request formatted for a public-key
# authentication request.
def send_request(pub_key, username, next_service, alg, signature = nil)
msg = build_request(pub_key, username, next_service, alg,
!signature.nil?)
msg.write_string(signature) if signature
send_message(msg)
end
def authenticate_with_alg(identity, next_service, username, alg, sig_alg = nil)
debug { "trying publickey (#{identity.fingerprint})" }
send_request(identity, username, next_service, alg)
message = session.next_message
case message.type
when USERAUTH_PK_OK
buffer = build_request(identity, username, next_service, alg,
true)
sig_data = Net::SSH::Buffer.new
sig_data.write_string(session_id)
sig_data.append(buffer.to_s)
sig_blob = key_manager.sign(identity, sig_data, sig_alg)
send_request(identity, username, next_service, alg, sig_blob.to_s)
message = session.next_message
case message.type
when USERAUTH_SUCCESS
debug { "publickey succeeded (#{identity.fingerprint})" }
return true
when USERAUTH_FAILURE
debug { "publickey failed (#{identity.fingerprint})" }
raise Net::SSH::Authentication::DisallowedMethod unless
message[:authentications].split(/,/).include? 'publickey'
return false
else
raise Net::SSH::Exception,
"unexpected server response to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
end
when USERAUTH_FAILURE
return false
when USERAUTH_SUCCESS
return true
else
raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
end
end
# Attempts to perform public-key authentication for the given
# username, with the given identity (public key). Returns +true+ if
# successful, or +false+ otherwise.
def authenticate_with(identity, next_service, username)
type = identity.ssh_type
if type == "ssh-rsa"
pubkey_algorithms.each do |pk_alg|
case pk_alg
when "rsa-sha2-512", "rsa-sha2-256", "ssh-rsa"
if authenticate_with_alg(identity, next_service, username, pk_alg, pk_alg)
# success
return true
end
end
end
elsif type == "ssh-rsa-cert-v01@openssh.com"
pubkey_algorithms.each do |pk_alg|
case pk_alg
when "rsa-sha2-512-cert-v01@openssh.com"
if authenticate_with_alg(identity, next_service, username, pk_alg, "rsa-sha2-512")
# success
return true
end
when "rsa-sha2-256-cert-v01@openssh.com"
if authenticate_with_alg(identity, next_service, username, pk_alg, "rsa-sha2-256")
# success
return true
end
when "ssh-rsa-cert-v01@openssh.com"
if authenticate_with_alg(identity, next_service, username, pk_alg)
# success
return true
end
end
end
elsif authenticate_with_alg(identity, next_service, username, type)
# success
return true
end
# failure
return false
end
end
end
end
end
end
|