[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:
parent
438673c11f
commit
83a932a1b3
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue