[project @ Arch-1:robey@lag.net--2003-public%secsh--dev--1.0--patch-125]

add client-side multi-part auth support
added support for multi-part authentication (even though nobody supports it
that i've seen).  on a successful "partial" auth, the auth_* method will
return a list of acceptable means to continue authenticating.
This commit is contained in:
Robey Pointer 2004-12-12 09:16:03 +00:00
parent 438673c11f
commit 83a932a1b3
2 changed files with 42 additions and 12 deletions

View File

@ -32,7 +32,7 @@ from common import *
import util import util
from transport import BaseTransport from transport import BaseTransport
from message import Message from message import Message
from ssh_exception import SSHException, BadAuthenticationType from ssh_exception import SSHException, BadAuthenticationType, PartialAuthentication
class Transport (BaseTransport): class Transport (BaseTransport):
@ -118,6 +118,10 @@ class Transport (BaseTransport):
authentication succeeds or fails. On failure, an exception is raised. authentication succeeds or fails. On failure, an exception is raised.
Otherwise, the method simply returns. Otherwise, the method simply returns.
If the server requires multi-step authentication (which is very rare),
this method will return a list of auth types permissible for the next
step. Otherwise, in the normal case, an empty list is returned.
@param username: the username to authenticate as. @param username: the username to authenticate as.
@type username: string @type username: string
@param key: the private key to authenticate with. @param key: the private key to authenticate with.
@ -125,6 +129,9 @@ class Transport (BaseTransport):
@param event: an event to trigger when the authentication attempt is @param event: an event to trigger when the authentication attempt is
complete (whether it was successful or not) complete (whether it was successful or not)
@type event: threading.Event @type event: threading.Event
@return: list of auth types permissible for the next stage of
authentication (normally empty).
@rtype: list
@raise BadAuthenticationType: if public-key authentication isn't @raise BadAuthenticationType: if public-key authentication isn't
allowed by the server for this user (and no event was passed in). allowed by the server for this user (and no event was passed in).
@ -149,8 +156,8 @@ class Transport (BaseTransport):
self.lock.release() self.lock.release()
if event is not None: if event is not None:
# caller wants to wait for event themselves # caller wants to wait for event themselves
return return []
self._wait_for_response(my_event) return self._wait_for_response(my_event)
def auth_password(self, username, password, event=None): def auth_password(self, username, password, event=None):
""" """
@ -165,7 +172,11 @@ class Transport (BaseTransport):
Since 1.1, if no event is passed, this method will block until the Since 1.1, if no event is passed, this method will block until the
authentication succeeds or fails. On failure, an exception is raised. authentication succeeds or fails. On failure, an exception is raised.
Otherwise, the method simply returns. Otherwise, the method simply returns.
If the server requires multi-step authentication (which is very rare),
this method will return a list of auth types permissible for the next
step. Otherwise, in the normal case, an empty list is returned.
@param username: the username to authenticate as. @param username: the username to authenticate as.
@type username: string @type username: string
@param password: the password to authenticate with. @param password: the password to authenticate with.
@ -173,6 +184,9 @@ class Transport (BaseTransport):
@param event: an event to trigger when the authentication attempt is @param event: an event to trigger when the authentication attempt is
complete (whether it was successful or not) complete (whether it was successful or not)
@type event: threading.Event @type event: threading.Event
@return: list of auth types permissible for the next stage of
authentication (normally empty).
@rtype: list
@raise BadAuthenticationType: if password authentication isn't @raise BadAuthenticationType: if password authentication isn't
allowed by the server for this user (and no event was passed in). allowed by the server for this user (and no event was passed in).
@ -197,8 +211,8 @@ class Transport (BaseTransport):
self.lock.release() self.lock.release()
if event is not None: if event is not None:
# caller wants to wait for event themselves # caller wants to wait for event themselves
return return []
self._wait_for_response(my_event) return self._wait_for_response(my_event)
### internals... ### internals...
@ -254,8 +268,13 @@ class Transport (BaseTransport):
e = self.get_exception() e = self.get_exception()
if e is None: if e is None:
e = SSHException('Authentication failed.') e = SSHException('Authentication failed.')
# this is horrible. python Exception isn't yet descended from
# object, so type(e) won't work. :(
if issubclass(e.__class__, PartialAuthentication):
return e.allowed_types
raise e raise e
return []
def _parse_service_request(self, m): def _parse_service_request(self, m):
service = m.get_string() service = m.get_string()
if self.server_mode and (service == 'ssh-userauth'): if self.server_mode and (service == 'ssh-userauth'):
@ -396,12 +415,13 @@ class Transport (BaseTransport):
partial = m.get_boolean() partial = m.get_boolean()
if partial: if partial:
self._log(INFO, 'Authentication continues...') self._log(INFO, 'Authentication continues...')
self._log(DEBUG, 'Methods: ' + str(partial)) self._log(DEBUG, 'Methods: ' + str(authlist))
# FIXME: multi-part auth not supported self.saved_exception = PartialAuthentication(authlist)
pass elif self.auth_method not in authlist:
if self.auth_method not in authlist: self._log(INFO, 'Authentication type not permitted.')
self.saved_exception = BadAuthenticationType('Bad authentication type', authlist) self.saved_exception = BadAuthenticationType('Bad authentication type', authlist)
self._log(INFO, 'Authentication failed.') else:
self._log(INFO, 'Authentication failed.')
self.authenticated = False self.authenticated = False
self.username = None self.username = None
if self.auth_event != None: if self.auth_event != None:

View File

@ -53,3 +53,13 @@ class BadAuthenticationType (SSHException):
def __init__(self, explanation, types): def __init__(self, explanation, types):
SSHException.__init__(self, explanation) SSHException.__init__(self, explanation)
self.allowed_types = types self.allowed_types = types
class PartialAuthentication (SSHException):
"""
An internal exception thrown in the case of partial authentication.
"""
allowed_types = []
def __init__(self, types):
SSHException.__init__(self, 'partial authentication')
self.allowed_types = types