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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2a478983b765002a5277ac63e5ae06e4eccde19d35394b762c13760c33a9cf4b
4
- data.tar.gz: d541edd1bd30026919fbf0b4d47369d6853a7ad9f9705b00a43054eaf85d41bd
3
+ metadata.gz: e5758ec1e3457a1aaa41ec25677bd85711eb176fa9478d786c70c885e2206c58
4
+ data.tar.gz: 37e411ed657bceca996dcaf71c4b36c706984738005dce48043649a55d6ba022
5
5
  SHA512:
6
- metadata.gz: e7c09c9e54fa096de5b2417490860e0e80f5ac3c73e2d8fda28b53bdf77fbc7233bede1ecc961bc31cdc817be39fc32bb2b72708d266a4fd46138bdae980e439
7
- data.tar.gz: 536e9e52e0eaa7d88449f740ae379d9c2bb0a7c9e29bde06762da14d7220fcc89178cc8f835afc63e1bf9f28c23a7ca876826d219364f4fa7b7dab94a7d1f989
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
- - [Password authentication](#password-authentication)
23
- - [Publickey authentication](#publickey-authentication)
24
- - [Keyboard-interactive authentication](#keyboard-interactive-authentication)
25
- - [None authentication (NOT recomended)](#none-authentication-not-recomended)
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
- ##### Password authentication
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
- ##### Publickey authentication
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
- ##### Keyboard-interactive authentication
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
- ##### None authentication (NOT recomended)
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
- SERVICE_NAME = 'ssh-userauth'
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
- method = Method[method_name].new(@transport, {'session id' => @transport.session_id}.merge(@options), @variables)
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 TrueClass
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 FalseClass
88
- @logger.info { "verify failed" }
89
- send_userauth_failure
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' => Method.list_preferred,
105
- :'partial success' => false,
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
@@ -0,0 +1,14 @@
1
+ # coding: utf-8
2
+ # vim: et ts=2 sw=2
3
+
4
+ module HrrRbSsh
5
+ class Authentication
6
+ module Constant
7
+ SERVICE_NAME = 'ssh-userauth'
8
+
9
+ SUCCESS = :success
10
+ PARTIAL_SUCCESS = :partial_success
11
+ FAILURE = :failure
12
+ end
13
+ end
14
+ end
@@ -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']
@@ -2,5 +2,5 @@
2
2
  # vim: et ts=2 sw=2
3
3
 
4
4
  module HrrRbSsh
5
- VERSION = "0.3.0.pre2"
5
+ VERSION = "0.3.0.pre3"
6
6
  end
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.pre2
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-06-20 00:00:00.000000000 Z
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