[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
from transport import BaseTransport
from message import Message
from ssh_exception import SSHException, BadAuthenticationType
from ssh_exception import SSHException, BadAuthenticationType, PartialAuthentication
class Transport (BaseTransport):
@ -118,6 +118,10 @@ class Transport (BaseTransport):
authentication succeeds or fails. On failure, an exception is raised.
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.
@type username: string
@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
complete (whether it was successful or not)
@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
allowed by the server for this user (and no event was passed in).
@ -149,8 +156,8 @@ class Transport (BaseTransport):
self.lock.release()
if event is not None:
# caller wants to wait for event themselves
return
self._wait_for_response(my_event)
return []
return self._wait_for_response(my_event)
def auth_password(self, username, password, event=None):
"""
@ -166,6 +173,10 @@ class Transport (BaseTransport):
authentication succeeds or fails. On failure, an exception is raised.
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.
@type username: string
@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
complete (whether it was successful or not)
@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
allowed by the server for this user (and no event was passed in).
@ -197,8 +211,8 @@ class Transport (BaseTransport):
self.lock.release()
if event is not None:
# caller wants to wait for event themselves
return
self._wait_for_response(my_event)
return []
return self._wait_for_response(my_event)
### internals...
@ -254,7 +268,12 @@ class Transport (BaseTransport):
e = self.get_exception()
if e is None:
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
return []
def _parse_service_request(self, m):
service = m.get_string()
@ -396,12 +415,13 @@ class Transport (BaseTransport):
partial = m.get_boolean()
if partial:
self._log(INFO, 'Authentication continues...')
self._log(DEBUG, 'Methods: ' + str(partial))
# FIXME: multi-part auth not supported
pass
if self.auth_method not in authlist:
self._log(DEBUG, 'Methods: ' + str(authlist))
self.saved_exception = PartialAuthentication(authlist)
elif self.auth_method not in authlist:
self._log(INFO, 'Authentication type not permitted.')
self.saved_exception = BadAuthenticationType('Bad authentication type', authlist)
self._log(INFO, 'Authentication failed.')
else:
self._log(INFO, 'Authentication failed.')
self.authenticated = False
self.username = None
if self.auth_event != None:

View File

@ -53,3 +53,13 @@ class BadAuthenticationType (SSHException):
def __init__(self, explanation, types):
SSHException.__init__(self, explanation)
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