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
|
require 'net/ssh/prompt'
require 'net/ssh/authentication/methods/abstract'
module Net
module SSH
module Authentication
module Methods
# Implements the "keyboard-interactive" SSH authentication method.
class KeyboardInteractive < Abstract
USERAUTH_INFO_REQUEST = 60
USERAUTH_INFO_RESPONSE = 61
# Attempt to authenticate the given user for the given service.
def authenticate(next_service, username, password = nil)
debug { "trying keyboard-interactive" }
send_message(userauth_request(username, next_service, "keyboard-interactive", "", ""))
prompter = nil
loop do
message = session.next_message
case message.type
when USERAUTH_SUCCESS
debug { "keyboard-interactive succeeded" }
prompter.success if prompter
return true
when USERAUTH_FAILURE
debug { "keyboard-interactive failed" }
raise Net::SSH::Authentication::DisallowedMethod unless
message[:authentications].split(/,/).include? 'keyboard-interactive'
return false unless interactive?
password = nil
debug { "retrying keyboard-interactive" }
send_message(userauth_request(username, next_service, "keyboard-interactive", "", ""))
when USERAUTH_INFO_REQUEST
name = message.read_string
instruction = message.read_string
debug { "keyboard-interactive info request" }
if password.nil? && interactive? && prompter.nil?
prompter = prompt.start(type: 'keyboard-interactive', name: name, instruction: instruction)
end
_ = message.read_string # lang_tag
responses = []
message.read_long.times do
text = message.read_string
echo = message.read_bool
password_to_send = password || (prompter && prompter.ask(text, echo))
responses << password_to_send
end
# if the password failed the first time around, don't try
# and use it on subsequent requests.
password = nil
msg = Buffer.from(:byte, USERAUTH_INFO_RESPONSE, :long, responses.length, :string, responses)
send_message(msg)
else
raise Net::SSH::Exception, "unexpected reply in keyboard interactive: #{message.type} (#{message.inspect})"
end
end
end
def interactive?
options = session.transport.options || {}
!options[:non_interactive]
end
end
end
end
end
end
|