1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 """
20 L{AuthHandler}
21 """
22
23 import threading
24 import weakref
25
26
27 import encodings.utf_8
28
29 from paramiko.common import *
30 from paramiko import util
31 from paramiko.message import Message
32 from paramiko.ssh_exception import SSHException, AuthenticationException, \
33 BadAuthenticationType, PartialAuthentication
34 from paramiko.server import InteractiveQuery
35
36
38 """
39 Internal class to handle the mechanics of authentication.
40 """
41
43 self.transport = weakref.proxy(transport)
44 self.username = None
45 self.authenticated = False
46 self.auth_event = None
47 self.auth_method = ''
48 self.password = None
49 self.private_key = None
50 self.interactive_handler = None
51 self.submethods = None
52
53 self.auth_username = None
54 self.auth_fail_count = 0
55
57 return self.authenticated
58
60 if self.transport.server_mode:
61 return self.auth_username
62 else:
63 return self.username
64
66 self.transport.lock.acquire()
67 try:
68 self.auth_event = event
69 self.auth_method = 'none'
70 self.username = username
71 self._request_auth()
72 finally:
73 self.transport.lock.release()
74
76 self.transport.lock.acquire()
77 try:
78 self.auth_event = event
79 self.auth_method = 'publickey'
80 self.username = username
81 self.private_key = key
82 self._request_auth()
83 finally:
84 self.transport.lock.release()
85
87 self.transport.lock.acquire()
88 try:
89 self.auth_event = event
90 self.auth_method = 'password'
91 self.username = username
92 self.password = password
93 self._request_auth()
94 finally:
95 self.transport.lock.release()
96
98 """
99 response_list = handler(title, instructions, prompt_list)
100 """
101 self.transport.lock.acquire()
102 try:
103 self.auth_event = event
104 self.auth_method = 'keyboard-interactive'
105 self.username = username
106 self.interactive_handler = handler
107 self.submethods = submethods
108 self._request_auth()
109 finally:
110 self.transport.lock.release()
111
113 if self.auth_event is not None:
114 self.auth_event.set()
115
116
117
118
119
125
134
143
155
176
188
221
243
256
258 if not self.transport.server_mode:
259
260 m = Message()
261 m.add_byte(chr(MSG_USERAUTH_FAILURE))
262 m.add_string('none')
263 m.add_boolean(0)
264 self.transport._send_message(m)
265 return
266 if self.authenticated:
267
268 return
269 username = m.get_string()
270 service = m.get_string()
271 method = m.get_string()
272 self.transport._log(DEBUG, 'Auth request (type=%s) service=%s, username=%s' % (method, service, username))
273 if service != 'ssh-connection':
274 self._disconnect_service_not_available()
275 return
276 if (self.auth_username is not None) and (self.auth_username != username):
277 self.transport._log(WARNING, 'Auth rejected because the client attempted to change username in mid-flight')
278 self._disconnect_no_more_auth()
279 return
280 self.auth_username = username
281
282 if method == 'none':
283 result = self.transport.server_object.check_auth_none(username)
284 elif method == 'password':
285 changereq = m.get_boolean()
286 password = m.get_string()
287 try:
288 password = password.decode('UTF-8')
289 except UnicodeError:
290
291
292 pass
293 if changereq:
294
295
296 self.transport._log(DEBUG, 'Auth request to change passwords (rejected)')
297 newpassword = m.get_string()
298 try:
299 newpassword = newpassword.decode('UTF-8', 'replace')
300 except UnicodeError:
301 pass
302 result = AUTH_FAILED
303 else:
304 result = self.transport.server_object.check_auth_password(username, password)
305 elif method == 'publickey':
306 sig_attached = m.get_boolean()
307 keytype = m.get_string()
308 keyblob = m.get_string()
309 try:
310 key = self.transport._key_info[keytype](Message(keyblob))
311 except SSHException, e:
312 self.transport._log(INFO, 'Auth rejected: public key: %s' % str(e))
313 key = None
314 except:
315 self.transport._log(INFO, 'Auth rejected: unsupported or mangled public key')
316 key = None
317 if key is None:
318 self._disconnect_no_more_auth()
319 return
320
321 result = self.transport.server_object.check_auth_publickey(username, key)
322 if result != AUTH_FAILED:
323
324 if not sig_attached:
325
326
327 m = Message()
328 m.add_byte(chr(MSG_USERAUTH_PK_OK))
329 m.add_string(keytype)
330 m.add_string(keyblob)
331 self.transport._send_message(m)
332 return
333 sig = Message(m.get_string())
334 blob = self._get_session_blob(key, service, username)
335 if not key.verify_ssh_sig(blob, sig):
336 self.transport._log(INFO, 'Auth rejected: invalid signature')
337 result = AUTH_FAILED
338 elif method == 'keyboard-interactive':
339 lang = m.get_string()
340 submethods = m.get_string()
341 result = self.transport.server_object.check_auth_interactive(username, submethods)
342 if isinstance(result, InteractiveQuery):
343
344 self._interactive_query(result)
345 return
346 else:
347 result = self.transport.server_object.check_auth_none(username)
348
349 self._send_auth_result(username, method, result)
350
352 self.transport._log(INFO, 'Authentication (%s) successful!' % self.auth_method)
353 self.authenticated = True
354 self.transport._auth_trigger()
355 if self.auth_event != None:
356 self.auth_event.set()
357
359 authlist = m.get_list()
360 partial = m.get_boolean()
361 if partial:
362 self.transport._log(INFO, 'Authentication continues...')
363 self.transport._log(DEBUG, 'Methods: ' + str(authlist))
364 self.transport.saved_exception = PartialAuthentication(authlist)
365 elif self.auth_method not in authlist:
366 self.transport._log(INFO, 'Authentication type (%s) not permitted.' % self.auth_method)
367 self.transport._log(DEBUG, 'Allowed methods: ' + str(authlist))
368 self.transport.saved_exception = BadAuthenticationType('Bad authentication type', authlist)
369 else:
370 self.transport._log(INFO, 'Authentication (%s) failed.' % self.auth_method)
371 self.authenticated = False
372 self.username = None
373 if self.auth_event != None:
374 self.auth_event.set()
375
380
381
400
402 if not self.transport.server_mode:
403 raise SSHException('Illegal info response from server')
404 n = m.get_int()
405 responses = []
406 for i in range(n):
407 responses.append(m.get_string())
408 result = self.transport.server_object.check_auth_interactive_response(responses)
409 if isinstance(type(result), InteractiveQuery):
410
411 self._interactive_query(result)
412 return
413 self._send_auth_result(self.auth_username, 'keyboard-interactive', result)
414
415
416 _handler_table = {
417 MSG_SERVICE_REQUEST: _parse_service_request,
418 MSG_SERVICE_ACCEPT: _parse_service_accept,
419 MSG_USERAUTH_REQUEST: _parse_userauth_request,
420 MSG_USERAUTH_SUCCESS: _parse_userauth_success,
421 MSG_USERAUTH_FAILURE: _parse_userauth_failure,
422 MSG_USERAUTH_BANNER: _parse_userauth_banner,
423 MSG_USERAUTH_INFO_REQUEST: _parse_userauth_info_request,
424 MSG_USERAUTH_INFO_RESPONSE: _parse_userauth_info_response,
425 }
426