new parent exception for all auth failures, and new specific exception for bad host key
This commit is contained in:
Robey Pointer 2006-05-09 09:45:49 -07:00
parent 02e8178510
commit 8843feb633
6 changed files with 70 additions and 29 deletions

View File

@ -60,8 +60,8 @@ if sys.version_info < (2, 2):
__author__ = "Robey Pointer <robey@lag.net>"
__date__ = "11 Mar 2005"
__version__ = "1.5.4 (tentacool)"
__version_info__ = (1, 5, 4)
__version__ = "1.6 (u?)"
__version_info__ = (1, 6, 0)
__license__ = "GNU Lesser General Public License (LGPL)"
@ -69,7 +69,9 @@ from transport import randpool, SecurityOptions, Transport
from client import SSHClient, MissingHostKeyPolicy, AutoAddPolicy, RejectPolicy
from auth_handler import AuthHandler
from channel import Channel, ChannelFile
from ssh_exception import SSHException, PasswordRequiredException, BadAuthenticationType, ChannelException
from ssh_exception import SSHException, PasswordRequiredException, \
BadAuthenticationType, ChannelException, BadHostKeyException, \
AuthenticationException
from server import ServerInterface, SubsystemHandler, InteractiveQuery
from rsakey import RSAKey
from dsskey import DSSKey
@ -96,7 +98,7 @@ for x in (Transport, SecurityOptions, Channel, SFTPServer, SSHException,
SFTPHandle, SFTPServerInterface, BufferedFile, Agent, AgentKey,
PKey, BaseSFTP, SFTPFile, ServerInterface, HostKeys, SSHClient,
MissingHostKeyPolicy, AutoAddPolicy, RejectPolicy, ChannelException,
SSHConfig):
SSHConfig, BadHostKeyException, AuthenticationException):
x.__module__ = 'paramiko'
from common import AUTH_SUCCESSFUL, AUTH_PARTIALLY_SUCCESSFUL, AUTH_FAILED, \
@ -119,9 +121,11 @@ __all__ = [ 'Transport',
'Agent',
'Message',
'SSHException',
'AuthenticationException',
'PasswordRequiredException',
'BadAuthenticationType',
'ChannelException',
'BadHostKeyException',
'SFTP',
'SFTPFile',
'SFTPHandle',

View File

@ -29,7 +29,8 @@ import encodings.utf_8
from paramiko.common import *
from paramiko import util
from paramiko.message import Message
from paramiko.ssh_exception import SSHException, BadAuthenticationType, PartialAuthentication
from paramiko.ssh_exception import SSHException, AuthenticationException, \
BadAuthenticationType, PartialAuthentication
from paramiko.server import InteractiveQuery
@ -158,14 +159,14 @@ class AuthHandler (object):
if not self.transport.is_active():
e = self.transport.get_exception()
if e is None:
e = SSHException('Authentication failed.')
e = AuthenticationException('Authentication failed.')
raise e
if event.isSet():
break
if not self.is_authenticated():
e = self.transport.get_exception()
if e is None:
e = SSHException('Authentication failed.')
e = AuthenticationException('Authentication failed.')
# this is horrible. python Exception isn't yet descended from
# object, so type(e) won't work. :(
if issubclass(e.__class__, PartialAuthentication):
@ -410,4 +411,3 @@ class AuthHandler (object):
MSG_USERAUTH_INFO_RESPONSE: _parse_userauth_info_response,
}

View File

@ -186,7 +186,7 @@ class SSHClient (object):
"""
return self._host_keys
def set_log_channel(self, channel):
def set_log_channel(self, name):
"""
Set the channel for logging. The default is C{"paramiko.transport"}
but it can be set to anything you want.
@ -194,7 +194,7 @@ class SSHClient (object):
@param name: new channel name for logging
@type name: str
"""
self._log_channel = channel
self._log_channel = name
def set_missing_host_key_policy(self, policy):
"""
@ -245,8 +245,11 @@ class SSHClient (object):
for authentication
@type key_filename: str
@raise SSHException: if there was an error authenticating or verifying
the server's host key
@raise BadHostKeyException: if the server's host key could not be
verified
@raise AuthenticationException: if authentication failed
@raise SSHException: if there was any other error connecting or
establishing an SSH session
"""
t = self._transport = Transport((hostname, port))
if self._log_channel is not None:
@ -254,7 +257,6 @@ class SSHClient (object):
t.start_client()
server_key = t.get_remote_server_key()
server_key_hex = hexify(server_key.get_fingerprint())
keytype = server_key.get_name()
our_server_key = self._system_host_keys.get(hostname, {}).get(keytype, None)
@ -263,14 +265,11 @@ class SSHClient (object):
if our_server_key is None:
# will raise exception if the key is rejected; let that fall out
self._policy.missing_host_key(self, hostname, server_key)
# if this continues, assume the key is ok
# if the callback returns, assume the key is ok
our_server_key = server_key
our_server_key_hex = hexify(our_server_key.get_fingerprint())
if server_key != our_server_key:
raise SSHException('Host key for server %s does not match! (%s != %s)' %
(hostname, our_server_key_kex, server_key_hex))
raise BadHostKeyException(hostname, server_key, our_server_key)
if username is None:
username = getpass.getuser()

View File

@ -28,14 +28,25 @@ class SSHException (Exception):
pass
class PasswordRequiredException (SSHException):
class AuthenticationException (SSHException):
"""
Exception raised when authentication failed for some reason. It may be
possible to retry with different credentials. (Other classes specify more
specific reasons.)
@since: 1.6
"""
pass
class PasswordRequiredException (AuthenticationException):
"""
Exception raised when a password is needed to unlock a private key file.
"""
pass
class BadAuthenticationType (SSHException):
class BadAuthenticationType (AuthenticationException):
"""
Exception raised when an authentication type (like password) is used, but
the server isn't allowing that type. (It may only allow public-key, for
@ -58,7 +69,7 @@ class BadAuthenticationType (SSHException):
return SSHException.__str__(self) + ' (allowed_types=%r)' % self.allowed_types
class PartialAuthentication (SSHException):
class PartialAuthentication (AuthenticationException):
"""
An internal exception thrown in the case of partial authentication.
"""
@ -73,8 +84,32 @@ class ChannelException (SSHException):
"""
Exception raised when an attempt to open a new L{Channel} fails.
@ivar code: the error code returned by the server
@type code: int
@since: 1.6
"""
def __init__(self, code, text):
SSHException.__init__(self, text)
self.code = code
class BadHostKeyException (SSHException):
"""
The host key given by the SSH server did not match what we were expecting.
@ivar hostname: the hostname of the SSH server
@type hostname: str
@ivar key: the host key presented by the server
@type key: L{PKey}
@ivar expected_key: the host key expected
@type expected_key: L{PKey}
@since: 1.6
"""
def __init__(self, hostname, got_key, expected_key):
SSHException.__init__(self, 'Host key for server %s does not match!' % hostname)
self.hostname = hostname
self.key = got_key
self.expected_key = expected_key

View File

@ -992,8 +992,9 @@ class Transport (threading.Thread):
@raise BadAuthenticationType: if password authentication isn't
allowed by the server for this user (and no event was passed in)
@raise SSHException: if the authentication failed (and no event was
passed in)
@raise AuthenticationException: if the authentication failed (and no
event was passed in)
@raise SSHException: if there was a network error
"""
if (not self.active) or (not self.initial_kex_done):
# we should never try to send the password unless we're on a secure link
@ -1056,13 +1057,14 @@ class Transport (threading.Thread):
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).
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).
@raise SSHException: if the authentication failed (and no event was
passed in).
allowed by the server for this user (and no event was passed in)
@raise AuthenticationException: if the authentication failed (and no
event was passed in)
@raise SSHException: if there was a network error
"""
if (not self.active) or (not self.initial_kex_done):
# we should never try to authenticate unless we're on a secure link
@ -1119,7 +1121,8 @@ class Transport (threading.Thread):
@raise BadAuthenticationType: if public-key authentication isn't
allowed by the server for this user
@raise SSHException: if the authentication failed
@raise AuthenticationException: if the authentication failed
@raise SSHException: if there was a network error
@since: 1.5
"""

View File

@ -258,7 +258,7 @@ class TransportTest (unittest.TestCase):
self.assert_(False)
except:
etype, evalue, etb = sys.exc_info()
self.assertEquals(SSHException, etype)
self.assert_(issubclass(etype, SSHException))
self.tc.auth_password(username='slowdive', password='pygmalion')
event.wait(1.0)
self.assert_(event.isSet())