hrr_rb_ssh 0.3.0.pre1 → 0.4.2
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.
- checksums.yaml +4 -4
- data/.gitignore +0 -3
- data/.travis.yml +1 -0
- data/README.md +208 -46
- data/demo/client.rb +71 -0
- data/demo/echo_server.rb +8 -3
- data/demo/more_flexible_auth.rb +105 -0
- data/demo/multi_step_auth.rb +99 -0
- data/demo/server.rb +10 -4
- data/demo/subsystem_echo_server.rb +8 -3
- data/hrr_rb_ssh.gemspec +6 -6
- data/lib/hrr_rb_ssh.rb +1 -1
- data/lib/hrr_rb_ssh/algorithm/publickey.rb +0 -1
- data/lib/hrr_rb_ssh/algorithm/publickey/ecdsa_sha2.rb +12 -9
- data/lib/hrr_rb_ssh/algorithm/publickey/ecdsa_sha2/ecdsa_signature_blob.rb +2 -4
- data/lib/hrr_rb_ssh/algorithm/publickey/ecdsa_sha2/public_key_blob.rb +2 -4
- data/lib/hrr_rb_ssh/algorithm/publickey/ecdsa_sha2/signature.rb +2 -4
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_dss.rb +10 -7
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_dss/public_key_blob.rb +2 -4
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_dss/signature.rb +2 -4
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_rsa.rb +9 -6
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_rsa/public_key_blob.rb +2 -4
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_rsa/signature.rb +2 -4
- data/lib/hrr_rb_ssh/authentication.rb +103 -22
- data/lib/hrr_rb_ssh/authentication/constant.rb +14 -0
- data/lib/hrr_rb_ssh/authentication/method/keyboard_interactive.rb +44 -7
- data/lib/hrr_rb_ssh/authentication/method/keyboard_interactive/context.rb +16 -9
- data/lib/hrr_rb_ssh/authentication/method/keyboard_interactive/info_request.rb +7 -6
- data/lib/hrr_rb_ssh/authentication/method/keyboard_interactive/info_response.rb +5 -2
- data/lib/hrr_rb_ssh/authentication/method/none.rb +23 -7
- data/lib/hrr_rb_ssh/authentication/method/none/context.rb +15 -7
- data/lib/hrr_rb_ssh/authentication/method/password.rb +28 -7
- data/lib/hrr_rb_ssh/authentication/method/password/context.rb +16 -7
- data/lib/hrr_rb_ssh/authentication/method/publickey.rb +63 -10
- data/lib/hrr_rb_ssh/authentication/method/publickey/algorithm.rb +0 -1
- data/lib/hrr_rb_ssh/authentication/method/publickey/algorithm/functionable.rb +32 -8
- data/lib/hrr_rb_ssh/authentication/method/publickey/algorithm/signature_blob.rb +2 -4
- data/lib/hrr_rb_ssh/authentication/method/publickey/context.rb +11 -2
- data/lib/hrr_rb_ssh/client.rb +234 -0
- data/lib/hrr_rb_ssh/codable.rb +15 -13
- data/lib/hrr_rb_ssh/compat/ruby.rb +0 -1
- data/lib/hrr_rb_ssh/connection.rb +145 -75
- data/lib/hrr_rb_ssh/connection/channel.rb +342 -109
- data/lib/hrr_rb_ssh/connection/channel/channel_type/direct_tcpip.rb +24 -19
- data/lib/hrr_rb_ssh/connection/channel/channel_type/forwarded_tcpip.rb +24 -19
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session.rb +19 -12
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/proc_chain.rb +0 -2
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/proc_chain/chain_context.rb +0 -3
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/env.rb +2 -5
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/env/context.rb +5 -4
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/exec.rb +2 -5
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/exec/context.rb +5 -4
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/pty_req.rb +2 -5
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/pty_req/context.rb +5 -4
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/shell.rb +2 -5
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/shell/context.rb +5 -4
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/subsystem.rb +2 -5
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/subsystem/context.rb +5 -4
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/window_change.rb +2 -5
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/window_change/context.rb +5 -4
- data/lib/hrr_rb_ssh/connection/global_request_handler.rb +14 -12
- data/lib/hrr_rb_ssh/connection/request_handler.rb +1 -3
- data/lib/hrr_rb_ssh/connection/request_handler/reference_env_request_handler.rb +0 -2
- data/lib/hrr_rb_ssh/connection/request_handler/reference_exec_request_handler.rb +4 -6
- data/lib/hrr_rb_ssh/connection/request_handler/reference_pty_req_request_handler.rb +10 -12
- data/lib/hrr_rb_ssh/connection/request_handler/reference_shell_request_handler.rb +4 -6
- data/lib/hrr_rb_ssh/connection/request_handler/reference_window_change_request_handler.rb +0 -2
- data/lib/hrr_rb_ssh/error/closed_authentication.rb +1 -1
- data/lib/hrr_rb_ssh/error/closed_connection.rb +1 -1
- data/lib/hrr_rb_ssh/error/closed_transport.rb +1 -1
- data/lib/hrr_rb_ssh/loggable.rb +42 -0
- data/lib/hrr_rb_ssh/message/001_ssh_msg_disconnect.rb +2 -4
- data/lib/hrr_rb_ssh/message/002_ssh_msg_ignore.rb +2 -4
- data/lib/hrr_rb_ssh/message/003_ssh_msg_unimplemented.rb +2 -4
- data/lib/hrr_rb_ssh/message/004_ssh_msg_debug.rb +2 -4
- data/lib/hrr_rb_ssh/message/005_ssh_msg_service_request.rb +2 -4
- data/lib/hrr_rb_ssh/message/006_ssh_msg_service_accept.rb +2 -4
- data/lib/hrr_rb_ssh/message/020_ssh_msg_kexinit.rb +2 -4
- data/lib/hrr_rb_ssh/message/021_ssh_msg_newkeys.rb +2 -4
- data/lib/hrr_rb_ssh/message/030_ssh_msg_kex_dh_gex_request_old.rb +2 -4
- data/lib/hrr_rb_ssh/message/030_ssh_msg_kexdh_init.rb +2 -4
- data/lib/hrr_rb_ssh/message/030_ssh_msg_kexecdh_init.rb +2 -4
- data/lib/hrr_rb_ssh/message/031_ssh_msg_kex_dh_gex_group.rb +2 -4
- data/lib/hrr_rb_ssh/message/031_ssh_msg_kexdh_reply.rb +2 -4
- data/lib/hrr_rb_ssh/message/031_ssh_msg_kexecdh_reply.rb +2 -4
- data/lib/hrr_rb_ssh/message/032_ssh_msg_kex_dh_gex_init.rb +2 -4
- data/lib/hrr_rb_ssh/message/033_ssh_msg_kex_dh_gex_reply.rb +2 -4
- data/lib/hrr_rb_ssh/message/034_ssh_msg_kex_dh_gex_request.rb +2 -4
- data/lib/hrr_rb_ssh/message/050_ssh_msg_userauth_request.rb +2 -4
- data/lib/hrr_rb_ssh/message/051_ssh_msg_userauth_failure.rb +2 -4
- data/lib/hrr_rb_ssh/message/052_ssh_msg_userauth_success.rb +2 -4
- data/lib/hrr_rb_ssh/message/060_ssh_msg_userauth_info_request.rb +2 -4
- data/lib/hrr_rb_ssh/message/060_ssh_msg_userauth_pk_ok.rb +2 -4
- data/lib/hrr_rb_ssh/message/061_ssh_msg_userauth_info_response.rb +2 -4
- data/lib/hrr_rb_ssh/message/080_ssh_msg_global_request.rb +2 -4
- data/lib/hrr_rb_ssh/message/081_ssh_msg_request_success.rb +2 -4
- data/lib/hrr_rb_ssh/message/082_ssh_msg_request_failure.rb +2 -4
- data/lib/hrr_rb_ssh/message/090_ssh_msg_channel_open.rb +2 -4
- data/lib/hrr_rb_ssh/message/091_ssh_msg_channel_open_confirmation.rb +2 -4
- data/lib/hrr_rb_ssh/message/092_ssh_msg_channel_open_failure.rb +2 -4
- data/lib/hrr_rb_ssh/message/093_ssh_msg_channel_window_adjust.rb +2 -4
- data/lib/hrr_rb_ssh/message/094_ssh_msg_channel_data.rb +2 -4
- data/lib/hrr_rb_ssh/message/095_ssh_msg_channel_extended_data.rb +2 -4
- data/lib/hrr_rb_ssh/message/096_ssh_msg_channel_eof.rb +2 -4
- data/lib/hrr_rb_ssh/message/097_ssh_msg_channel_close.rb +2 -4
- data/lib/hrr_rb_ssh/message/098_ssh_msg_channel_request.rb +3 -5
- data/lib/hrr_rb_ssh/message/099_ssh_msg_channel_success.rb +2 -4
- data/lib/hrr_rb_ssh/message/100_ssh_msg_channel_failure.rb +2 -4
- data/lib/hrr_rb_ssh/server.rb +16 -10
- data/lib/hrr_rb_ssh/transport.rb +113 -77
- data/lib/hrr_rb_ssh/transport/compression_algorithm/functionable.rb +5 -3
- data/lib/hrr_rb_ssh/transport/compression_algorithm/unfunctionable.rb +5 -3
- data/lib/hrr_rb_ssh/transport/encryption_algorithm/functionable.rb +5 -3
- data/lib/hrr_rb_ssh/transport/encryption_algorithm/unfunctionable.rb +5 -3
- data/lib/hrr_rb_ssh/transport/kex_algorithm/diffie_hellman.rb +43 -37
- data/lib/hrr_rb_ssh/transport/kex_algorithm/diffie_hellman/h0.rb +2 -4
- data/lib/hrr_rb_ssh/transport/kex_algorithm/diffie_hellman_group_exchange.rb +87 -52
- data/lib/hrr_rb_ssh/transport/kex_algorithm/diffie_hellman_group_exchange/h0.rb +2 -4
- data/lib/hrr_rb_ssh/transport/kex_algorithm/elliptic_curve_diffie_hellman.rb +43 -37
- data/lib/hrr_rb_ssh/transport/kex_algorithm/elliptic_curve_diffie_hellman/h0.rb +2 -4
- data/lib/hrr_rb_ssh/transport/mac_algorithm/functionable.rb +5 -3
- data/lib/hrr_rb_ssh/transport/mac_algorithm/unfunctionable.rb +5 -3
- data/lib/hrr_rb_ssh/transport/receiver.rb +8 -7
- data/lib/hrr_rb_ssh/transport/sender.rb +5 -3
- data/lib/hrr_rb_ssh/transport/sequence_number.rb +0 -4
- data/lib/hrr_rb_ssh/transport/server_host_key_algorithm.rb +0 -1
- data/lib/hrr_rb_ssh/transport/server_host_key_algorithm/functionable.rb +5 -3
- data/lib/hrr_rb_ssh/version.rb +1 -1
- metadata +18 -51
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519.rb +0 -61
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519/openssh_private_key.rb +0 -29
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519/openssh_private_key_content.rb +0 -26
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519/pkey.rb +0 -158
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519/public_key_blob.rb +0 -23
- data/lib/hrr_rb_ssh/algorithm/publickey/ssh_ed25519/signature.rb +0 -23
- data/lib/hrr_rb_ssh/authentication/method/publickey/algorithm/ssh_ed25519.rb +0 -21
- data/lib/hrr_rb_ssh/compat/ruby/array.rb +0 -14
- data/lib/hrr_rb_ssh/logger.rb +0 -56
- data/lib/hrr_rb_ssh/transport/server_host_key_algorithm/ssh_ed25519.rb +0 -20
@@ -8,10 +8,8 @@ module HrrRbSsh
|
|
8
8
|
module Algorithm
|
9
9
|
class Publickey
|
10
10
|
module EcdsaSha2
|
11
|
-
|
12
|
-
|
13
|
-
include Codable
|
14
|
-
end
|
11
|
+
class Signature
|
12
|
+
include Codable
|
15
13
|
DEFINITION = [
|
16
14
|
[DataType::String, :'public key algorithm name'],
|
17
15
|
[DataType::String, :'ecdsa signature blob'],
|
@@ -1,16 +1,19 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
# vim: et ts=2 sw=2
|
3
3
|
|
4
|
-
require 'hrr_rb_ssh/
|
4
|
+
require 'hrr_rb_ssh/loggable'
|
5
5
|
|
6
6
|
module HrrRbSsh
|
7
7
|
module Algorithm
|
8
8
|
class Publickey
|
9
9
|
class SshDss < Publickey
|
10
|
+
include Loggable
|
11
|
+
|
10
12
|
NAME = 'ssh-dss'
|
11
13
|
DIGEST = 'sha1'
|
12
14
|
|
13
|
-
def initialize arg
|
15
|
+
def initialize arg, logger: nil
|
16
|
+
self.logger = logger
|
14
17
|
begin
|
15
18
|
new_by_key_str arg
|
16
19
|
rescue OpenSSL::PKey::DSAError
|
@@ -23,7 +26,7 @@ module HrrRbSsh
|
|
23
26
|
end
|
24
27
|
|
25
28
|
def new_by_public_key_blob public_key_blob
|
26
|
-
public_key_blob_h = PublicKeyBlob.decode
|
29
|
+
public_key_blob_h = PublicKeyBlob.new(logger: logger).decode public_key_blob
|
27
30
|
@publickey = OpenSSL::PKey::DSA.new
|
28
31
|
if @publickey.respond_to?(:set_pqg)
|
29
32
|
@publickey.set_pqg public_key_blob_h[:'p'], public_key_blob_h[:'q'], public_key_blob_h[:'g']
|
@@ -51,24 +54,24 @@ module HrrRbSsh
|
|
51
54
|
:'g' => @publickey.g.to_i,
|
52
55
|
:'y' => @publickey.pub_key.to_i,
|
53
56
|
}
|
54
|
-
PublicKeyBlob.encode
|
57
|
+
PublicKeyBlob.new(logger: logger).encode public_key_blob_h
|
55
58
|
end
|
56
59
|
|
57
60
|
def sign signature_blob
|
58
61
|
hash = OpenSSL::Digest.digest(self.class::DIGEST, signature_blob)
|
59
62
|
sign_der = @publickey.syssign(hash)
|
60
|
-
sign_asn1 = OpenSSL::ASN1.decode
|
63
|
+
sign_asn1 = OpenSSL::ASN1.decode sign_der
|
61
64
|
sign_r = sign_asn1.value[0].value.to_s(2).rjust(20, ["00"].pack("H"))
|
62
65
|
sign_s = sign_asn1.value[1].value.to_s(2).rjust(20, ["00"].pack("H"))
|
63
66
|
signature_h = {
|
64
67
|
:'public key algorithm name' => self.class::NAME,
|
65
68
|
:'signature blob' => (sign_r + sign_s),
|
66
69
|
}
|
67
|
-
Signature.encode signature_h
|
70
|
+
Signature.new(logger: logger).encode signature_h
|
68
71
|
end
|
69
72
|
|
70
73
|
def verify signature, signature_blob
|
71
|
-
signature_h = Signature.decode signature
|
74
|
+
signature_h = Signature.new(logger: logger).decode signature
|
72
75
|
sign_r = signature_h[:'signature blob'][ 0, 20]
|
73
76
|
sign_s = signature_h[:'signature blob'][20, 20]
|
74
77
|
sign_asn1 = OpenSSL::ASN1::Sequence.new(
|
@@ -8,10 +8,8 @@ module HrrRbSsh
|
|
8
8
|
module Algorithm
|
9
9
|
class Publickey
|
10
10
|
class SshDss
|
11
|
-
|
12
|
-
|
13
|
-
include Codable
|
14
|
-
end
|
11
|
+
class PublicKeyBlob
|
12
|
+
include Codable
|
15
13
|
DEFINITION = [
|
16
14
|
[DataType::String, :'public key algorithm name'],
|
17
15
|
[DataType::Mpint, :'p'],
|
@@ -8,10 +8,8 @@ module HrrRbSsh
|
|
8
8
|
module Algorithm
|
9
9
|
class Publickey
|
10
10
|
class SshDss
|
11
|
-
|
12
|
-
|
13
|
-
include Codable
|
14
|
-
end
|
11
|
+
class Signature
|
12
|
+
include Codable
|
15
13
|
DEFINITION = [
|
16
14
|
[DataType::String, :'public key algorithm name'],
|
17
15
|
[DataType::String, :'signature blob'],
|
@@ -1,16 +1,19 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
# vim: et ts=2 sw=2
|
3
3
|
|
4
|
-
require 'hrr_rb_ssh/
|
4
|
+
require 'hrr_rb_ssh/loggable'
|
5
5
|
|
6
6
|
module HrrRbSsh
|
7
7
|
module Algorithm
|
8
8
|
class Publickey
|
9
9
|
class SshRsa < Publickey
|
10
|
+
include Loggable
|
11
|
+
|
10
12
|
NAME = 'ssh-rsa'
|
11
13
|
DIGEST = 'sha1'
|
12
14
|
|
13
|
-
def initialize arg
|
15
|
+
def initialize arg, logger: nil
|
16
|
+
self.logger = logger
|
14
17
|
begin
|
15
18
|
new_by_key_str arg
|
16
19
|
rescue OpenSSL::PKey::RSAError
|
@@ -23,7 +26,7 @@ module HrrRbSsh
|
|
23
26
|
end
|
24
27
|
|
25
28
|
def new_by_public_key_blob public_key_blob
|
26
|
-
public_key_blob_h = PublicKeyBlob.decode
|
29
|
+
public_key_blob_h = PublicKeyBlob.new(logger: logger).decode public_key_blob
|
27
30
|
@publickey = OpenSSL::PKey::RSA.new
|
28
31
|
if @publickey.respond_to?(:set_key)
|
29
32
|
@publickey.set_key public_key_blob_h[:'n'], public_key_blob_h[:'e'], nil
|
@@ -43,7 +46,7 @@ module HrrRbSsh
|
|
43
46
|
:'e' => @publickey.e.to_i,
|
44
47
|
:'n' => @publickey.n.to_i,
|
45
48
|
}
|
46
|
-
PublicKeyBlob.encode
|
49
|
+
PublicKeyBlob.new(logger: logger).encode public_key_blob_h
|
47
50
|
end
|
48
51
|
|
49
52
|
def sign signature_blob
|
@@ -51,11 +54,11 @@ module HrrRbSsh
|
|
51
54
|
:'public key algorithm name' => self.class::NAME,
|
52
55
|
:'signature blob' => @publickey.sign(self.class::DIGEST, signature_blob),
|
53
56
|
}
|
54
|
-
Signature.encode signature_h
|
57
|
+
Signature.new(logger: logger).encode signature_h
|
55
58
|
end
|
56
59
|
|
57
60
|
def verify signature, signature_blob
|
58
|
-
signature_h = Signature.decode signature
|
61
|
+
signature_h = Signature.new(logger: logger).decode signature
|
59
62
|
signature_h[:'public key algorithm name'] == self.class::NAME && @publickey.verify(self.class::DIGEST, signature_h[:'signature blob'], signature_blob)
|
60
63
|
end
|
61
64
|
end
|
@@ -8,10 +8,8 @@ module HrrRbSsh
|
|
8
8
|
module Algorithm
|
9
9
|
class Publickey
|
10
10
|
class SshRsa
|
11
|
-
|
12
|
-
|
13
|
-
include Codable
|
14
|
-
end
|
11
|
+
class PublicKeyBlob
|
12
|
+
include Codable
|
15
13
|
DEFINITION = [
|
16
14
|
[DataType::String, :'public key algorithm name'],
|
17
15
|
[DataType::Mpint, :'e'],
|
@@ -8,10 +8,8 @@ module HrrRbSsh
|
|
8
8
|
module Algorithm
|
9
9
|
class Publickey
|
10
10
|
class SshRsa
|
11
|
-
|
12
|
-
|
13
|
-
include Codable
|
14
|
-
end
|
11
|
+
class Signature
|
12
|
+
include Codable
|
15
13
|
DEFINITION = [
|
16
14
|
[DataType::String, :'public key algorithm name'],
|
17
15
|
[DataType::String, :'signature blob'],
|
@@ -1,27 +1,31 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
# vim: et ts=2 sw=2
|
3
3
|
|
4
|
-
require 'hrr_rb_ssh/
|
4
|
+
require 'hrr_rb_ssh/loggable'
|
5
5
|
require 'hrr_rb_ssh/message'
|
6
6
|
require 'hrr_rb_ssh/error/closed_authentication'
|
7
|
+
require 'hrr_rb_ssh/authentication/constant'
|
7
8
|
require 'hrr_rb_ssh/authentication/authenticator'
|
8
9
|
require 'hrr_rb_ssh/authentication/method'
|
9
10
|
|
10
11
|
module HrrRbSsh
|
11
12
|
class Authentication
|
12
|
-
|
13
|
+
include Loggable
|
14
|
+
include Constant
|
15
|
+
|
16
|
+
def initialize transport, mode, options={}, logger: nil
|
17
|
+
self.logger = logger
|
13
18
|
|
14
|
-
def initialize transport, options={}
|
15
19
|
@transport = transport
|
20
|
+
@mode = mode
|
16
21
|
@options = options
|
17
22
|
|
18
|
-
@logger = Logger.new self.class.name
|
19
|
-
|
20
23
|
@transport.register_acceptable_service SERVICE_NAME
|
21
24
|
|
22
25
|
@closed = nil
|
23
26
|
|
24
27
|
@username = nil
|
28
|
+
@variables = {}
|
25
29
|
end
|
26
30
|
|
27
31
|
def send payload
|
@@ -29,6 +33,7 @@ module HrrRbSsh
|
|
29
33
|
begin
|
30
34
|
@transport.send payload
|
31
35
|
rescue Error::ClosedTransport
|
36
|
+
close
|
32
37
|
raise Error::ClosedAuthentication
|
33
38
|
end
|
34
39
|
end
|
@@ -38,19 +43,28 @@ module HrrRbSsh
|
|
38
43
|
begin
|
39
44
|
@transport.receive
|
40
45
|
rescue Error::ClosedTransport
|
46
|
+
close
|
41
47
|
raise Error::ClosedAuthentication
|
42
48
|
end
|
43
49
|
end
|
44
50
|
|
45
51
|
def start
|
46
|
-
|
47
|
-
|
52
|
+
log_info { "start authentication" }
|
53
|
+
begin
|
54
|
+
@transport.start
|
55
|
+
authenticate
|
56
|
+
rescue Error::ClosedTransport
|
57
|
+
close
|
58
|
+
raise Error::ClosedAuthentication
|
59
|
+
end
|
48
60
|
end
|
49
61
|
|
50
62
|
def close
|
51
63
|
return if @closed
|
64
|
+
log_info { "close authentication" }
|
52
65
|
@closed = true
|
53
66
|
@transport.close
|
67
|
+
log_info { "authentication closed" }
|
54
68
|
end
|
55
69
|
|
56
70
|
def closed?
|
@@ -62,43 +76,110 @@ module HrrRbSsh
|
|
62
76
|
@username
|
63
77
|
end
|
64
78
|
|
79
|
+
def variables
|
80
|
+
raise Error::ClosedAuthentication if @closed
|
81
|
+
@variables
|
82
|
+
end
|
83
|
+
|
65
84
|
def authenticate
|
85
|
+
case @mode
|
86
|
+
when Mode::SERVER
|
87
|
+
respond_to_authentication
|
88
|
+
when Mode::CLIENT
|
89
|
+
request_authentication
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def respond_to_authentication
|
94
|
+
authentication_methods = (@options['authentication_preferred_authentication_methods'].dup rescue nil) || Method.list_preferred # rescue nil.dup for Ruby version < 2.4
|
95
|
+
log_info { "preferred authentication methods: #{authentication_methods}" }
|
66
96
|
loop do
|
67
97
|
payload = @transport.receive
|
68
98
|
case payload[0,1].unpack("C")[0]
|
69
99
|
when Message::SSH_MSG_USERAUTH_REQUEST::VALUE
|
70
|
-
userauth_request_message = Message::SSH_MSG_USERAUTH_REQUEST.decode payload
|
100
|
+
userauth_request_message = Message::SSH_MSG_USERAUTH_REQUEST.new(logger: logger).decode payload
|
71
101
|
method_name = userauth_request_message[:'method name']
|
72
|
-
|
102
|
+
log_info { "authentication method: #{method_name}" }
|
103
|
+
method = Method[method_name].new(@transport, {'session id' => @transport.session_id}.merge(@options), @variables, authentication_methods, logger: logger)
|
73
104
|
result = method.authenticate(userauth_request_message)
|
74
105
|
case result
|
75
|
-
when
|
76
|
-
|
106
|
+
when true, SUCCESS
|
107
|
+
log_info { "verified" }
|
77
108
|
send_userauth_success
|
78
109
|
@username = userauth_request_message[:'user name']
|
79
110
|
@closed = false
|
80
111
|
break
|
81
|
-
when
|
82
|
-
|
83
|
-
|
112
|
+
when PARTIAL_SUCCESS
|
113
|
+
log_info { "partially verified" }
|
114
|
+
authentication_methods.delete method_name
|
115
|
+
log_info { "authentication methods that can continue: #{authentication_methods}" }
|
116
|
+
if authentication_methods.empty?
|
117
|
+
log_info { "verified" }
|
118
|
+
send_userauth_success
|
119
|
+
@username = userauth_request_message[:'user name']
|
120
|
+
@closed = false
|
121
|
+
break
|
122
|
+
else
|
123
|
+
log_info { "continue" }
|
124
|
+
send_userauth_failure authentication_methods, true
|
125
|
+
end
|
84
126
|
when String
|
85
|
-
|
127
|
+
log_info { "send method specific message to continue" }
|
86
128
|
send_method_specific_message result
|
129
|
+
else # when false, FAILURE
|
130
|
+
log_info { "verify failed" }
|
131
|
+
send_userauth_failure authentication_methods, false
|
87
132
|
end
|
88
133
|
else
|
89
|
-
|
90
|
-
raise
|
134
|
+
close
|
135
|
+
raise Error::ClosedAuthentication
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def request_authentication
|
141
|
+
authentication_methods = (@options['authentication_preferred_authentication_methods'].dup rescue nil) || Method.list_preferred # rescue nil.dup for Ruby version < 2.4
|
142
|
+
log_info { "preferred authentication methods: #{authentication_methods}" }
|
143
|
+
next_method_name = "none"
|
144
|
+
log_info { "authentication request begins with none method" }
|
145
|
+
loop do
|
146
|
+
log_info { "authentication method: #{next_method_name}" }
|
147
|
+
method = Method[next_method_name].new(@transport, {'session id' => @transport.session_id}.merge(@options), @variables, authentication_methods, logger: logger)
|
148
|
+
payload = method.request_authentication @options['username'], "ssh-connection"
|
149
|
+
case payload[0,1].unpack("C")[0]
|
150
|
+
when Message::SSH_MSG_USERAUTH_SUCCESS::VALUE
|
151
|
+
log_info { "verified" }
|
152
|
+
@username = @options['username']
|
153
|
+
@closed = false
|
154
|
+
break
|
155
|
+
when Message::SSH_MSG_USERAUTH_FAILURE::VALUE
|
156
|
+
message = Message::SSH_MSG_USERAUTH_FAILURE.new(logger: logger).decode payload
|
157
|
+
partial_success = message[:'partial success']
|
158
|
+
if partial_success
|
159
|
+
log_info { "partially verified" }
|
160
|
+
end
|
161
|
+
authentication_methods_that_can_continue = message[:'authentications that can continue']
|
162
|
+
log_info { "authentication methods that can continue: #{authentication_methods_that_can_continue}" }
|
163
|
+
next_method_name = authentication_methods.find{ |local_m| authentication_methods_that_can_continue.find{ |remote_m| local_m == remote_m } }
|
164
|
+
if next_method_name
|
165
|
+
authentication_methods.delete next_method_name
|
166
|
+
log_info { "continue" }
|
167
|
+
else
|
168
|
+
log_info { "no more available authentication methods" }
|
169
|
+
@closed = true
|
170
|
+
raise "failed authentication"
|
171
|
+
end
|
91
172
|
end
|
92
173
|
end
|
93
174
|
end
|
94
175
|
|
95
|
-
def send_userauth_failure
|
176
|
+
def send_userauth_failure authentication_methods, partial_success
|
96
177
|
message = {
|
97
178
|
:'message number' => Message::SSH_MSG_USERAUTH_FAILURE::VALUE,
|
98
|
-
:'authentications that can continue' =>
|
99
|
-
:'partial success' =>
|
179
|
+
:'authentications that can continue' => authentication_methods,
|
180
|
+
:'partial success' => partial_success,
|
100
181
|
}
|
101
|
-
payload = Message::SSH_MSG_USERAUTH_FAILURE.encode message
|
182
|
+
payload = Message::SSH_MSG_USERAUTH_FAILURE.new(logger: logger).encode message
|
102
183
|
@transport.send payload
|
103
184
|
end
|
104
185
|
|
@@ -106,7 +187,7 @@ module HrrRbSsh
|
|
106
187
|
message = {
|
107
188
|
:'message number' => Message::SSH_MSG_USERAUTH_SUCCESS::VALUE,
|
108
189
|
}
|
109
|
-
payload = Message::SSH_MSG_USERAUTH_SUCCESS.encode message
|
190
|
+
payload = Message::SSH_MSG_USERAUTH_SUCCESS.new(logger: logger).encode message
|
110
191
|
@transport.send payload
|
111
192
|
end
|
112
193
|
|
@@ -1,29 +1,66 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
# vim: et ts=2 sw=2
|
3
3
|
|
4
|
-
require 'hrr_rb_ssh/
|
4
|
+
require 'hrr_rb_ssh/loggable'
|
5
5
|
|
6
6
|
module HrrRbSsh
|
7
7
|
class Authentication
|
8
8
|
class Method
|
9
9
|
class KeyboardInteractive < Method
|
10
|
+
include Loggable
|
11
|
+
|
10
12
|
NAME = 'keyboard-interactive'
|
11
13
|
PREFERENCE = 30
|
12
14
|
|
13
|
-
def initialize transport, options
|
14
|
-
|
15
|
+
def initialize transport, options, variables, authentication_methods, logger: nil
|
16
|
+
self.logger = logger
|
15
17
|
@transport = transport
|
16
|
-
@
|
18
|
+
@options = options
|
19
|
+
@authenticator = options.fetch( 'authentication_keyboard_interactive_authenticator', Authenticator.new{ false } )
|
20
|
+
@variables = variables
|
21
|
+
@authentication_methods = authentication_methods
|
17
22
|
end
|
18
23
|
|
19
24
|
def authenticate userauth_request_message
|
20
|
-
|
21
|
-
@logger.debug { "userauth request: " + userauth_request_message.inspect }
|
25
|
+
log_info { "authenticate" }
|
22
26
|
username = userauth_request_message[:'user name']
|
23
27
|
submethods = userauth_request_message[:'submethods']
|
24
|
-
context = Context.new(@transport, username, submethods)
|
28
|
+
context = Context.new(@transport, username, submethods, @variables, @authentication_methods, logger: logger)
|
25
29
|
@authenticator.authenticate context
|
26
30
|
end
|
31
|
+
|
32
|
+
def request_authentication username, service_name
|
33
|
+
message = {
|
34
|
+
:'message number' => Message::SSH_MSG_USERAUTH_REQUEST::VALUE,
|
35
|
+
:"user name" => username,
|
36
|
+
:"service name" => service_name,
|
37
|
+
:"method name" => NAME,
|
38
|
+
:"language tag" => "",
|
39
|
+
:'submethods' => "",
|
40
|
+
}
|
41
|
+
payload = Message::SSH_MSG_USERAUTH_REQUEST.new(logger: logger).encode message
|
42
|
+
@transport.send payload
|
43
|
+
|
44
|
+
payload = @transport.receive
|
45
|
+
case payload[0,1].unpack("C")[0]
|
46
|
+
when Message::SSH_MSG_USERAUTH_INFO_REQUEST::VALUE
|
47
|
+
message = Message::SSH_MSG_USERAUTH_INFO_REQUEST.new(logger: logger).decode payload
|
48
|
+
num_responses = @options['client_authentication_keyboard_interactive'].size
|
49
|
+
message = {
|
50
|
+
:'message number' => Message::SSH_MSG_USERAUTH_INFO_RESPONSE::VALUE,
|
51
|
+
:'num-responses' => num_responses,
|
52
|
+
}
|
53
|
+
message_responses = @options['client_authentication_keyboard_interactive'].map.with_index{ |response, i|
|
54
|
+
{:"response[#{i+1}]" => response}
|
55
|
+
}.inject(Hash.new){ |a, b| a.merge(b) }
|
56
|
+
message.update(message_responses)
|
57
|
+
payload = Message::SSH_MSG_USERAUTH_INFO_RESPONSE.new(logger: logger).encode message
|
58
|
+
@transport.send payload
|
59
|
+
@transport.receive
|
60
|
+
else
|
61
|
+
payload
|
62
|
+
end
|
63
|
+
end
|
27
64
|
end
|
28
65
|
end
|
29
66
|
end
|