summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRobey Pointer <robey@lag.net>2006-05-09 09:45:49 -0700
committerRobey Pointer <robey@lag.net>2006-05-09 09:45:49 -0700
commit8843feb633827cb65066ce01f3e0347038cbb10c (patch)
treeefcec69aa4df2dfaa364683fbb94937d6d0756c7
parent02e81785104d97e0634e5a41e87f3b083ea0e952 (diff)
[project @ robey@lag.net-20060509164549-14e664f234b4b747]
new parent exception for all auth failures, and new specific exception for bad host key
-rw-r--r--paramiko/__init__.py12
-rw-r--r--paramiko/auth_handler.py8
-rw-r--r--paramiko/client.py19
-rw-r--r--paramiko/ssh_exception.py41
-rw-r--r--paramiko/transport.py17
-rw-r--r--tests/test_transport.py2
6 files changed, 70 insertions, 29 deletions
diff --git a/paramiko/__init__.py b/paramiko/__init__.py
index a3769859..9cc6be34 100644
--- a/paramiko/__init__.py
+++ b/paramiko/__init__.py
@@ -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',
diff --git a/paramiko/auth_handler.py b/paramiko/auth_handler.py
index 6b5c952e..f471f243 100644
--- a/paramiko/auth_handler.py
+++ b/paramiko/auth_handler.py
@@ -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,
}
-
diff --git a/paramiko/client.py b/paramiko/client.py
index d3898dc5..b7ffbeef 100644
--- a/paramiko/client.py
+++ b/paramiko/client.py
@@ -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()
diff --git a/paramiko/ssh_exception.py b/paramiko/ssh_exception.py
index 99eaa648..55b0197f 100644
--- a/paramiko/ssh_exception.py
+++ b/paramiko/ssh_exception.py
@@ -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
+
diff --git a/paramiko/transport.py b/paramiko/transport.py
index 95bc88da..d61207af 100644
--- a/paramiko/transport.py
+++ b/paramiko/transport.py
@@ -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
"""
diff --git a/tests/test_transport.py b/tests/test_transport.py
index f73f0f7f..75d33419 100644
--- a/tests/test_transport.py
+++ b/tests/test_transport.py
@@ -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())