hrr_rb_ssh 0.3.0.pre2 → 0.3.0.pre3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +84 -8
- data/demo/more_flexible_auth.rb +99 -0
- data/demo/multi_step_auth.rb +93 -0
- data/lib/hrr_rb_ssh/authentication.rb +27 -9
- data/lib/hrr_rb_ssh/authentication/constant.rb +14 -0
- data/lib/hrr_rb_ssh/authentication/method/keyboard_interactive.rb +3 -2
- data/lib/hrr_rb_ssh/authentication/method/keyboard_interactive/context.rb +4 -2
- data/lib/hrr_rb_ssh/authentication/method/none.rb +3 -2
- data/lib/hrr_rb_ssh/authentication/method/none/context.rb +4 -2
- data/lib/hrr_rb_ssh/authentication/method/password.rb +3 -2
- data/lib/hrr_rb_ssh/authentication/method/password/context.rb +4 -2
- data/lib/hrr_rb_ssh/authentication/method/publickey.rb +3 -2
- data/lib/hrr_rb_ssh/authentication/method/publickey/context.rb +3 -1
- data/lib/hrr_rb_ssh/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e5758ec1e3457a1aaa41ec25677bd85711eb176fa9478d786c70c885e2206c58
|
4
|
+
data.tar.gz: 37e411ed657bceca996dcaf71c4b36c706984738005dce48043649a55d6ba022
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a2ebfcb6fad617c0c8201ff30815e03d28e9e688f43fedbb14e3dd67d83426f3d9c06145392c1d84f4bb3e16d7daf78adf83fc57ba1d152136070b74cb0b93ba
|
7
|
+
data.tar.gz: 9dcc34deaca035e461c98a9891f4e1d0876fcdf379e08438cc01e97e9965526dbf7a6306f0bbd87b090ce815e079a7f407aca3a3c9c5138c4d4ac5707b24be3e
|
data/README.md
CHANGED
@@ -19,10 +19,13 @@ With hrr_rb_ssh, it is possible to write an SSH server easily, and also possible
|
|
19
19
|
- [Logging](#logging)
|
20
20
|
- [Registering pre\-generated secret keys for server host key](#registering-pre-generated-secret-keys-for-server-host-key)
|
21
21
|
- [Defining authentications](#defining-authentications)
|
22
|
-
- [
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
- [Single authentication](#single-authentication)
|
23
|
+
- [Password authentication](#password-authentication)
|
24
|
+
- [Publickey authentication](#publickey-authentication)
|
25
|
+
- [Keyboard-interactive authentication](#keyboard-interactive-authentication)
|
26
|
+
- [None authentication (NOT recomended)](#none-authentication-not-recomended)
|
27
|
+
- [Multi\-step authentication](#multi-step-authentication)
|
28
|
+
- [More flexible authentication](#more-flexible-authentication)
|
26
29
|
- [Handling session channel requests](#handling-session-channel-requests)
|
27
30
|
- [Reference request handlers](#reference-request-handlers)
|
28
31
|
- [Custom request handlers](#custom-request-handlers)
|
@@ -138,7 +141,13 @@ EOB
|
|
138
141
|
|
139
142
|
By default, any authentications get failed. To allow users to login to the SSH service, at least one of the authentication methods must be defined and registered into the instance of HrrRbSsh::Authentication through `options` variable.
|
140
143
|
|
141
|
-
|
144
|
+
The library defines a sort of strategies to implement handling authentication.
|
145
|
+
|
146
|
+
##### Single authentication
|
147
|
+
|
148
|
+
Each authenticator returns `true` (or `HrrRbSsh::Authentication::SUCCESS`) or `false` (or `HrrRbSsh::Authentication::FAILURE`). When it is true, the user is accepted. When it is false, the user is not accepted and a subsequent authenticator is called.
|
149
|
+
|
150
|
+
###### Password authentication
|
142
151
|
|
143
152
|
Password authentication is the most simple way to allow users to login to the SSH service. Password authentication requires user-name and password.
|
144
153
|
|
@@ -165,7 +174,7 @@ The `context` variable in password authentication context provides the following
|
|
165
174
|
- `#vars` : The same object that `#variables` returns
|
166
175
|
- `#verify(username, password)` : Returns `true` when username and password arguments match with the context's username and password. Or returns `false` when username and password arguments don't match.
|
167
176
|
|
168
|
-
|
177
|
+
###### Publickey authentication
|
169
178
|
|
170
179
|
The second one is public key authentication. Public key authentication requires user-name, public key algorithm name, and PEM or DER formed public key.
|
171
180
|
|
@@ -186,7 +195,7 @@ The `context` variable in public key authentication context provides the `#verif
|
|
186
195
|
|
187
196
|
And public keys that is in OpenSSH public key format is now available. To use OpenSSH public keys, it is easy to use $USER_HOME/.ssh/authorized_keys file.
|
188
197
|
|
189
|
-
|
198
|
+
###### Keyboard-interactive authentication
|
190
199
|
|
191
200
|
The third one is keyboard-interactive authentication. This is also known as challenge-response authentication.
|
192
201
|
|
@@ -215,7 +224,7 @@ The `#info_request` method takes four arguments: name, instruction, language tag
|
|
215
224
|
|
216
225
|
The responses are listed in the same order as request prompts.
|
217
226
|
|
218
|
-
|
227
|
+
###### None authentication (NOT recomended)
|
219
228
|
|
220
229
|
The last one is none authentication. None authentication is usually NOT used.
|
221
230
|
|
@@ -234,6 +243,73 @@ options['authentication_none_authenticator'] = auth_none
|
|
234
243
|
|
235
244
|
In none authentication context, `context` variable provides the `#username` method.
|
236
245
|
|
246
|
+
##### Multi-step authentication
|
247
|
+
|
248
|
+
In this strategy that conbines single authentications, it is possible to implement multi-step authentication. In case that the combination is a publickey authentication method and a password authentication method, it is so-called two-factor authentication.
|
249
|
+
|
250
|
+
A return value of each authentication handler can be `HrrRbSsh::Authentication::PARTIAL_SUCCESS`. The value means that the authentication method returns success and another authenticatoin method is requested (i.e. the authentication method is deleted from the list of authentication that can continue, and then the server sends USERAUTH_FAILURE message with the updated list of authentication that can continue and partial success true). When all preferred authentication methods returns `PARTIAL_SUCCESS` (i.e. there is no more authentication that can continue), then the user is treated as authenticated.
|
251
|
+
|
252
|
+
```ruby
|
253
|
+
auth_preferred_authentication_methods = ["publickey", "password"]
|
254
|
+
auth_publickey = HrrRbSsh::Authentication::Authenticator.new { |context|
|
255
|
+
is_verified = some_verification_method(context)
|
256
|
+
if is_verified
|
257
|
+
HrrRbSsh::Authentication::PARTIAL_SUCCESS
|
258
|
+
else
|
259
|
+
false
|
260
|
+
end
|
261
|
+
}
|
262
|
+
auth_password = HrrRbSsh::Authentication::Authenticator.new { |context|
|
263
|
+
is_verified = some_verification_method(context)
|
264
|
+
if is_verified
|
265
|
+
HrrRbSsh::Authentication::PARTIAL_SUCCESS
|
266
|
+
else
|
267
|
+
false
|
268
|
+
end
|
269
|
+
}
|
270
|
+
options['authentication_preferred_authentication_methods'] = auth_preferred_authentication_methods
|
271
|
+
options['authentication_publickey_authenticator'] = auth_publickey
|
272
|
+
options['authentication_password_authenticator'] = auth_password
|
273
|
+
```
|
274
|
+
|
275
|
+
##### More flexible authentication
|
276
|
+
|
277
|
+
A `context` variable in an authenticator gives an access to remaining authentication methods that can continue. In this strategy, an implementer is able to control the order of authentication methods and to control which authentication methods are used for the user.
|
278
|
+
|
279
|
+
The below is an example. It is expected that any user must be verified by publickey and then another authentication is requested for the user accordingly.
|
280
|
+
|
281
|
+
```ruby
|
282
|
+
auth_preferred_authentication_methods = ['none']
|
283
|
+
auth_none = HrrRbSsh::Authentication::Authenticator.new{ |context|
|
284
|
+
context.authentication_methods.push 'publickey'
|
285
|
+
HrrRbSsh::Authentication::PARTIAL_SUCCESS
|
286
|
+
}
|
287
|
+
auth_publickey = HrrRbSsh::Authentication::Authenticator.new{ |context|
|
288
|
+
if some_verification(context)
|
289
|
+
case context.username
|
290
|
+
when 'user1'
|
291
|
+
context.authentiation_methods.push 'keyboard-interactive'
|
292
|
+
HrrRbSsh::Authentication::PARTIAL_SUCCESS
|
293
|
+
else
|
294
|
+
false
|
295
|
+
end
|
296
|
+
else
|
297
|
+
false
|
298
|
+
end
|
299
|
+
}
|
300
|
+
auth_keyboard_interactive = HrrRbSsh::Authentication::Authenticator.new{ |context|
|
301
|
+
if some_verification(context)
|
302
|
+
true # or HrrRbSsh::Authentication::PARTIAL_SUCCESS; both will accept the user because remaining authentication method is only 'keyboard-interactive' in this case
|
303
|
+
else
|
304
|
+
false
|
305
|
+
end
|
306
|
+
}
|
307
|
+
options['authentication_preferred_authentication_methods'] = auth_preferred_authentication_methods
|
308
|
+
options['authentication_none_authenticator'] = auth_none
|
309
|
+
options['authentication_publickey_authenticator'] = auth_publickey
|
310
|
+
options['authentication_keyboard_interactive_authenticator'] = auth_keyboard_interactive
|
311
|
+
```
|
312
|
+
|
237
313
|
#### Handling session channel requests
|
238
314
|
|
239
315
|
By default, any channel requests belonging to session channel are implicitly ignored. To handle the requests, defining request handlers are required.
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'logger'
|
5
|
+
require 'socket'
|
6
|
+
|
7
|
+
|
8
|
+
def start_service io, logger=nil
|
9
|
+
require 'etc'
|
10
|
+
|
11
|
+
begin
|
12
|
+
require 'hrr_rb_ssh'
|
13
|
+
rescue LoadError
|
14
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
15
|
+
require 'hrr_rb_ssh'
|
16
|
+
end
|
17
|
+
|
18
|
+
HrrRbSsh::Logger.initialize logger if logger
|
19
|
+
|
20
|
+
auth_none = HrrRbSsh::Authentication::Authenticator.new { |context|
|
21
|
+
context.authentication_methods.push 'publickey'
|
22
|
+
HrrRbSsh::Authentication::PARTIAL_SUCCESS
|
23
|
+
}
|
24
|
+
auth_publickey = HrrRbSsh::Authentication::Authenticator.new { |context|
|
25
|
+
users = ['user1', 'user2']
|
26
|
+
is_verified = users.any?{ |username|
|
27
|
+
passwd = Etc.getpwnam(username)
|
28
|
+
homedir = passwd.dir
|
29
|
+
authorized_keys = HrrRbSsh::Compat::OpenSSH::AuthorizedKeys.new(File.read(File.join(homedir, '.ssh', 'authorized_keys')))
|
30
|
+
authorized_keys.any?{ |public_key| context.verify username, public_key.algorithm_name, public_key.to_pem }
|
31
|
+
}
|
32
|
+
if is_verified
|
33
|
+
context.authentication_methods.push 'password'
|
34
|
+
HrrRbSsh::Authentication::PARTIAL_SUCCESS
|
35
|
+
else
|
36
|
+
HrrRbSsh::Authentication::FAILURE
|
37
|
+
end
|
38
|
+
}
|
39
|
+
auth_password = HrrRbSsh::Authentication::Authenticator.new { |context|
|
40
|
+
user_and_pass = [
|
41
|
+
['user1', 'password1'],
|
42
|
+
['user2', 'password2'],
|
43
|
+
]
|
44
|
+
is_verified = user_and_pass.any? { |user, pass| context.verify user, pass }
|
45
|
+
if is_verified
|
46
|
+
HrrRbSsh::Authentication::SUCCESS # or HrrRbSsh::Authentication::PARTIAL_SUCCESS
|
47
|
+
else
|
48
|
+
HrrRbSsh::Authentication::FAILURE
|
49
|
+
end
|
50
|
+
}
|
51
|
+
|
52
|
+
auth_preferred_authentication_methods = ["none"]
|
53
|
+
|
54
|
+
|
55
|
+
options = {}
|
56
|
+
|
57
|
+
options['authentication_none_authenticator'] = auth_none
|
58
|
+
options['authentication_publickey_authenticator'] = auth_publickey
|
59
|
+
options['authentication_password_authenticator'] = auth_password
|
60
|
+
|
61
|
+
options['authentication_preferred_authentication_methods'] = auth_preferred_authentication_methods
|
62
|
+
|
63
|
+
options['connection_channel_request_pty_req'] = HrrRbSsh::Connection::RequestHandler::ReferencePtyReqRequestHandler.new
|
64
|
+
options['connection_channel_request_env'] = HrrRbSsh::Connection::RequestHandler::ReferenceEnvRequestHandler.new
|
65
|
+
options['connection_channel_request_shell'] = HrrRbSsh::Connection::RequestHandler::ReferenceShellRequestHandler.new
|
66
|
+
options['connection_channel_request_exec'] = HrrRbSsh::Connection::RequestHandler::ReferenceExecRequestHandler.new
|
67
|
+
options['connection_channel_request_window_change'] = HrrRbSsh::Connection::RequestHandler::ReferenceWindowChangeRequestHandler.new
|
68
|
+
|
69
|
+
server = HrrRbSsh::Server.new options
|
70
|
+
server.start io
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
logger = Logger.new STDOUT
|
75
|
+
logger.level = Logger::INFO
|
76
|
+
|
77
|
+
server = TCPServer.new 10022
|
78
|
+
loop do
|
79
|
+
Thread.new(server.accept) do |io|
|
80
|
+
begin
|
81
|
+
pid = fork do
|
82
|
+
begin
|
83
|
+
start_service io, logger
|
84
|
+
rescue => e
|
85
|
+
logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
86
|
+
exit false
|
87
|
+
end
|
88
|
+
end
|
89
|
+
logger.info { "process #{pid} started" }
|
90
|
+
io.close rescue nil
|
91
|
+
pid, status = Process.waitpid2 pid
|
92
|
+
rescue => e
|
93
|
+
logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
94
|
+
ensure
|
95
|
+
status ||= nil
|
96
|
+
logger.info { "process #{pid} finished with status #{status.inspect}" }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'logger'
|
5
|
+
require 'socket'
|
6
|
+
|
7
|
+
|
8
|
+
def start_service io, logger=nil
|
9
|
+
require 'etc'
|
10
|
+
|
11
|
+
begin
|
12
|
+
require 'hrr_rb_ssh'
|
13
|
+
rescue LoadError
|
14
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
15
|
+
require 'hrr_rb_ssh'
|
16
|
+
end
|
17
|
+
|
18
|
+
HrrRbSsh::Logger.initialize logger if logger
|
19
|
+
|
20
|
+
auth_publickey = HrrRbSsh::Authentication::Authenticator.new { |context|
|
21
|
+
users = ['user1', 'user2']
|
22
|
+
is_verified = users.any?{ |username|
|
23
|
+
passwd = Etc.getpwnam(username)
|
24
|
+
homedir = passwd.dir
|
25
|
+
authorized_keys = HrrRbSsh::Compat::OpenSSH::AuthorizedKeys.new(File.read(File.join(homedir, '.ssh', 'authorized_keys')))
|
26
|
+
authorized_keys.any?{ |public_key| context.verify username, public_key.algorithm_name, public_key.to_pem }
|
27
|
+
}
|
28
|
+
if is_verified
|
29
|
+
HrrRbSsh::Authentication::PARTIAL_SUCCESS
|
30
|
+
else
|
31
|
+
HrrRbSsh::Authentication::FAILURE
|
32
|
+
end
|
33
|
+
}
|
34
|
+
auth_password = HrrRbSsh::Authentication::Authenticator.new { |context|
|
35
|
+
user_and_pass = [
|
36
|
+
['user1', 'password1'],
|
37
|
+
['user2', 'password2'],
|
38
|
+
]
|
39
|
+
is_verified = user_and_pass.any? { |user, pass| context.verify user, pass }
|
40
|
+
if is_verified
|
41
|
+
HrrRbSsh::Authentication::PARTIAL_SUCCESS
|
42
|
+
else
|
43
|
+
HrrRbSsh::Authentication::FAILURE
|
44
|
+
end
|
45
|
+
}
|
46
|
+
|
47
|
+
auth_preferred_authentication_methods = ["publickey", "password"]
|
48
|
+
|
49
|
+
|
50
|
+
options = {}
|
51
|
+
|
52
|
+
options['authentication_publickey_authenticator'] = auth_publickey
|
53
|
+
options['authentication_password_authenticator'] = auth_password
|
54
|
+
|
55
|
+
options['authentication_preferred_authentication_methods'] = auth_preferred_authentication_methods
|
56
|
+
|
57
|
+
options['connection_channel_request_pty_req'] = HrrRbSsh::Connection::RequestHandler::ReferencePtyReqRequestHandler.new
|
58
|
+
options['connection_channel_request_env'] = HrrRbSsh::Connection::RequestHandler::ReferenceEnvRequestHandler.new
|
59
|
+
options['connection_channel_request_shell'] = HrrRbSsh::Connection::RequestHandler::ReferenceShellRequestHandler.new
|
60
|
+
options['connection_channel_request_exec'] = HrrRbSsh::Connection::RequestHandler::ReferenceExecRequestHandler.new
|
61
|
+
options['connection_channel_request_window_change'] = HrrRbSsh::Connection::RequestHandler::ReferenceWindowChangeRequestHandler.new
|
62
|
+
|
63
|
+
server = HrrRbSsh::Server.new options
|
64
|
+
server.start io
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
logger = Logger.new STDOUT
|
69
|
+
logger.level = Logger::INFO
|
70
|
+
|
71
|
+
server = TCPServer.new 10022
|
72
|
+
loop do
|
73
|
+
Thread.new(server.accept) do |io|
|
74
|
+
begin
|
75
|
+
pid = fork do
|
76
|
+
begin
|
77
|
+
start_service io, logger
|
78
|
+
rescue => e
|
79
|
+
logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
80
|
+
exit false
|
81
|
+
end
|
82
|
+
end
|
83
|
+
logger.info { "process #{pid} started" }
|
84
|
+
io.close rescue nil
|
85
|
+
pid, status = Process.waitpid2 pid
|
86
|
+
rescue => e
|
87
|
+
logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
88
|
+
ensure
|
89
|
+
status ||= nil
|
90
|
+
logger.info { "process #{pid} finished with status #{status.inspect}" }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -4,12 +4,13 @@
|
|
4
4
|
require 'hrr_rb_ssh/logger'
|
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 Constant
|
13
14
|
|
14
15
|
def initialize transport, options={}
|
15
16
|
@transport = transport
|
@@ -69,27 +70,44 @@ module HrrRbSsh
|
|
69
70
|
end
|
70
71
|
|
71
72
|
def authenticate
|
73
|
+
authentication_methods = (@options['authentication_preferred_authentication_methods'].dup rescue nil) || Method.list_preferred # rescue nil.dup for Ruby version < 2.4
|
74
|
+
@logger.info { "preferred authentication methods: #{authentication_methods}" }
|
72
75
|
loop do
|
73
76
|
payload = @transport.receive
|
74
77
|
case payload[0,1].unpack("C")[0]
|
75
78
|
when Message::SSH_MSG_USERAUTH_REQUEST::VALUE
|
76
79
|
userauth_request_message = Message::SSH_MSG_USERAUTH_REQUEST.decode payload
|
77
80
|
method_name = userauth_request_message[:'method name']
|
78
|
-
|
81
|
+
@logger.info { "authentication method: #{method_name}" }
|
82
|
+
method = Method[method_name].new(@transport, {'session id' => @transport.session_id}.merge(@options), @variables, authentication_methods)
|
79
83
|
result = method.authenticate(userauth_request_message)
|
80
84
|
case result
|
81
|
-
when
|
85
|
+
when true, SUCCESS
|
82
86
|
@logger.info { "verified" }
|
83
87
|
send_userauth_success
|
84
88
|
@username = userauth_request_message[:'user name']
|
85
89
|
@closed = false
|
86
90
|
break
|
87
|
-
when
|
88
|
-
@logger.info { "
|
89
|
-
|
91
|
+
when PARTIAL_SUCCESS
|
92
|
+
@logger.info { "partially verified" }
|
93
|
+
authentication_methods.delete method_name
|
94
|
+
@logger.debug { "authentication methods that can continue: #{authentication_methods}" }
|
95
|
+
if authentication_methods.empty?
|
96
|
+
@logger.info { "verified" }
|
97
|
+
send_userauth_success
|
98
|
+
@username = userauth_request_message[:'user name']
|
99
|
+
@closed = false
|
100
|
+
break
|
101
|
+
else
|
102
|
+
@logger.info { "continue" }
|
103
|
+
send_userauth_failure authentication_methods, true
|
104
|
+
end
|
90
105
|
when String
|
91
106
|
@logger.info { "send method specific message to continue" }
|
92
107
|
send_method_specific_message result
|
108
|
+
else # when false, FAILURE
|
109
|
+
@logger.info { "verify failed" }
|
110
|
+
send_userauth_failure authentication_methods, false
|
93
111
|
end
|
94
112
|
else
|
95
113
|
@closed = true
|
@@ -98,11 +116,11 @@ module HrrRbSsh
|
|
98
116
|
end
|
99
117
|
end
|
100
118
|
|
101
|
-
def send_userauth_failure
|
119
|
+
def send_userauth_failure authentication_methods, partial_success
|
102
120
|
message = {
|
103
121
|
:'message number' => Message::SSH_MSG_USERAUTH_FAILURE::VALUE,
|
104
|
-
:'authentications that can continue' =>
|
105
|
-
:'partial success' =>
|
122
|
+
:'authentications that can continue' => authentication_methods,
|
123
|
+
:'partial success' => partial_success,
|
106
124
|
}
|
107
125
|
payload = Message::SSH_MSG_USERAUTH_FAILURE.encode message
|
108
126
|
@transport.send payload
|
@@ -10,11 +10,12 @@ module HrrRbSsh
|
|
10
10
|
NAME = 'keyboard-interactive'
|
11
11
|
PREFERENCE = 30
|
12
12
|
|
13
|
-
def initialize transport, options, variables
|
13
|
+
def initialize transport, options, variables, authentication_methods
|
14
14
|
@logger = Logger.new(self.class.name)
|
15
15
|
@transport = transport
|
16
16
|
@authenticator = options.fetch( 'authentication_keyboard_interactive_authenticator', Authenticator.new { false } )
|
17
17
|
@variables = variables
|
18
|
+
@authentication_methods = authentication_methods
|
18
19
|
end
|
19
20
|
|
20
21
|
def authenticate userauth_request_message
|
@@ -22,7 +23,7 @@ module HrrRbSsh
|
|
22
23
|
@logger.debug { "userauth request: " + userauth_request_message.inspect }
|
23
24
|
username = userauth_request_message[:'user name']
|
24
25
|
submethods = userauth_request_message[:'submethods']
|
25
|
-
context = Context.new(@transport, username, submethods, @variables)
|
26
|
+
context = Context.new(@transport, username, submethods, @variables, @authentication_methods)
|
26
27
|
@authenticator.authenticate context
|
27
28
|
end
|
28
29
|
end
|
@@ -15,14 +15,16 @@ module HrrRbSsh
|
|
15
15
|
:submethods,
|
16
16
|
:info_response,
|
17
17
|
:variables,
|
18
|
-
:vars
|
18
|
+
:vars,
|
19
|
+
:authentication_methods
|
19
20
|
|
20
|
-
def initialize transport, username, submethods, variables
|
21
|
+
def initialize transport, username, submethods, variables, authentication_methods
|
21
22
|
@transport = transport
|
22
23
|
@username = username
|
23
24
|
@submethods = submethods
|
24
25
|
@variables = variables
|
25
26
|
@vars = variables
|
27
|
+
@authentication_methods = authentication_methods
|
26
28
|
|
27
29
|
@logger = Logger.new self.class.name
|
28
30
|
end
|
@@ -10,16 +10,17 @@ module HrrRbSsh
|
|
10
10
|
NAME = 'none'
|
11
11
|
PREFERENCE = 0
|
12
12
|
|
13
|
-
def initialize transport, options, variables
|
13
|
+
def initialize transport, options, variables, authentication_methods
|
14
14
|
@logger = Logger.new(self.class.name)
|
15
15
|
@authenticator = options.fetch( 'authentication_none_authenticator', Authenticator.new { false } )
|
16
16
|
@variables = variables
|
17
|
+
@authentication_methods = authentication_methods
|
17
18
|
end
|
18
19
|
|
19
20
|
def authenticate userauth_request_message
|
20
21
|
@logger.info { "authenticate" }
|
21
22
|
@logger.debug { "userauth request: " + userauth_request_message.inspect }
|
22
|
-
context = Context.new(userauth_request_message[:'user name'], @variables)
|
23
|
+
context = Context.new(userauth_request_message[:'user name'], @variables, @authentication_methods)
|
23
24
|
@authenticator.authenticate context
|
24
25
|
end
|
25
26
|
end
|
@@ -11,12 +11,14 @@ module HrrRbSsh
|
|
11
11
|
attr_reader \
|
12
12
|
:username,
|
13
13
|
:variables,
|
14
|
-
:vars
|
14
|
+
:vars,
|
15
|
+
:authentication_methods
|
15
16
|
|
16
|
-
def initialize username, variables
|
17
|
+
def initialize username, variables, authentication_methods
|
17
18
|
@username = username
|
18
19
|
@variables = variables
|
19
20
|
@vars = variables
|
21
|
+
@authentication_methods = authentication_methods
|
20
22
|
|
21
23
|
@logger = Logger.new self.class.name
|
22
24
|
end
|
@@ -10,10 +10,11 @@ module HrrRbSsh
|
|
10
10
|
NAME = 'password'
|
11
11
|
PREFERENCE = 10
|
12
12
|
|
13
|
-
def initialize transport, options, variables
|
13
|
+
def initialize transport, options, variables, authentication_methods
|
14
14
|
@logger = Logger.new(self.class.name)
|
15
15
|
@authenticator = options.fetch( 'authentication_password_authenticator', Authenticator.new { false } )
|
16
16
|
@variables = variables
|
17
|
+
@authentication_methods = authentication_methods
|
17
18
|
end
|
18
19
|
|
19
20
|
def authenticate userauth_request_message
|
@@ -21,7 +22,7 @@ module HrrRbSsh
|
|
21
22
|
@logger.debug { "userauth request: " + userauth_request_message.inspect }
|
22
23
|
username = userauth_request_message[:'user name']
|
23
24
|
password = userauth_request_message[:'plaintext password']
|
24
|
-
context = Context.new(username, password, @variables)
|
25
|
+
context = Context.new(username, password, @variables, @authentication_methods)
|
25
26
|
@authenticator.authenticate context
|
26
27
|
end
|
27
28
|
end
|
@@ -12,13 +12,15 @@ module HrrRbSsh
|
|
12
12
|
:username,
|
13
13
|
:password,
|
14
14
|
:variables,
|
15
|
-
:vars
|
15
|
+
:vars,
|
16
|
+
:authentication_methods
|
16
17
|
|
17
|
-
def initialize username, password, variables
|
18
|
+
def initialize username, password, variables, authentication_methods
|
18
19
|
@username = username
|
19
20
|
@password = password
|
20
21
|
@variables = variables
|
21
22
|
@vars = variables
|
23
|
+
@authentication_methods = authentication_methods
|
22
24
|
|
23
25
|
@logger = Logger.new self.class.name
|
24
26
|
end
|
@@ -10,11 +10,12 @@ module HrrRbSsh
|
|
10
10
|
NAME = 'publickey'
|
11
11
|
PREFERENCE = 20
|
12
12
|
|
13
|
-
def initialize transport, options, variables
|
13
|
+
def initialize transport, options, variables, authentication_methods
|
14
14
|
@logger = Logger.new(self.class.name)
|
15
15
|
@session_id = options['session id']
|
16
16
|
@authenticator = options.fetch( 'authentication_publickey_authenticator', Authenticator.new { false } )
|
17
17
|
@variables = variables
|
18
|
+
@authentication_methods = authentication_methods
|
18
19
|
end
|
19
20
|
|
20
21
|
def authenticate userauth_request_message
|
@@ -31,7 +32,7 @@ module HrrRbSsh
|
|
31
32
|
@logger.info { "verify signature" }
|
32
33
|
username = userauth_request_message[:'user name']
|
33
34
|
algorithm = Algorithm[public_key_algorithm_name].new
|
34
|
-
context = Context.new(username, algorithm, @session_id, userauth_request_message, @variables)
|
35
|
+
context = Context.new(username, algorithm, @session_id, userauth_request_message, @variables, @authentication_methods)
|
35
36
|
@authenticator.authenticate context
|
36
37
|
end
|
37
38
|
end
|
@@ -13,6 +13,7 @@ module HrrRbSsh
|
|
13
13
|
:session_id,
|
14
14
|
:variables,
|
15
15
|
:vars,
|
16
|
+
:authentication_methods,
|
16
17
|
:message_number,
|
17
18
|
:service_name,
|
18
19
|
:method_name,
|
@@ -21,13 +22,14 @@ module HrrRbSsh
|
|
21
22
|
:public_key_blob,
|
22
23
|
:signature
|
23
24
|
|
24
|
-
def initialize username, algorithm, session_id, message, variables
|
25
|
+
def initialize username, algorithm, session_id, message, variables, authentication_methods
|
25
26
|
@username = username
|
26
27
|
@algorithm = algorithm
|
27
28
|
@session_id = session_id
|
28
29
|
@message = message
|
29
30
|
@variables = variables
|
30
31
|
@vars = variables
|
32
|
+
@authentication_methods = authentication_methods
|
31
33
|
|
32
34
|
@message_number = message[:'message number']
|
33
35
|
@service_name = message[:'service name']
|
data/lib/hrr_rb_ssh/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hrr_rb_ssh
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.0.
|
4
|
+
version: 0.3.0.pre3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- hirura
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-07-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ed25519
|
@@ -82,6 +82,8 @@ files:
|
|
82
82
|
- README.md
|
83
83
|
- Rakefile
|
84
84
|
- demo/echo_server.rb
|
85
|
+
- demo/more_flexible_auth.rb
|
86
|
+
- demo/multi_step_auth.rb
|
85
87
|
- demo/server.rb
|
86
88
|
- demo/subsystem_echo_server.rb
|
87
89
|
- hrr_rb_ssh.gemspec
|
@@ -109,6 +111,7 @@ files:
|
|
109
111
|
- lib/hrr_rb_ssh/algorithm/publickey/ssh_rsa/signature.rb
|
110
112
|
- lib/hrr_rb_ssh/authentication.rb
|
111
113
|
- lib/hrr_rb_ssh/authentication/authenticator.rb
|
114
|
+
- lib/hrr_rb_ssh/authentication/constant.rb
|
112
115
|
- lib/hrr_rb_ssh/authentication/method.rb
|
113
116
|
- lib/hrr_rb_ssh/authentication/method/keyboard_interactive.rb
|
114
117
|
- lib/hrr_rb_ssh/authentication/method/keyboard_interactive/context.rb
|