add WarningPolicy to SSHClient, which logs a warning when a server host key
isn't known, but allows the connection. also added an option to avoid
searching for private keys, and made it check ~/ssh/ for windows.
This commit is contained in:
Robey Pointer 2008-02-18 23:47:36 -08:00
parent 9e67c45053
commit 3319f556d6
2 changed files with 34 additions and 8 deletions

View File

@ -61,13 +61,13 @@ if sys.version_info < (2, 2):
__author__ = "Robey Pointer <robey@lag.net>" __author__ = "Robey Pointer <robey@lag.net>"
__date__ = "21 Jan 2008" __date__ = "21 Jan 2008"
__version__ = "1.7.2 (Basil)" __version__ = "1.7.3 (C...)"
__version_info__ = (1, 7, 2) __version_info__ = (1, 7, 2)
__license__ = "GNU Lesser General Public License (LGPL)" __license__ = "GNU Lesser General Public License (LGPL)"
from transport import randpool, SecurityOptions, Transport from transport import randpool, SecurityOptions, Transport
from client import SSHClient, MissingHostKeyPolicy, AutoAddPolicy, RejectPolicy from client import SSHClient, MissingHostKeyPolicy, AutoAddPolicy, RejectPolicy, WarningPolicy
from auth_handler import AuthHandler from auth_handler import AuthHandler
from channel import Channel, ChannelFile from channel import Channel, ChannelFile
from ssh_exception import SSHException, PasswordRequiredException, \ from ssh_exception import SSHException, PasswordRequiredException, \
@ -110,6 +110,7 @@ __all__ = [ 'Transport',
'MissingHostKeyPolicy', 'MissingHostKeyPolicy',
'AutoAddPolicy', 'AutoAddPolicy',
'RejectPolicy', 'RejectPolicy',
'WarningPolicy',
'SecurityOptions', 'SecurityOptions',
'SubsystemHandler', 'SubsystemHandler',
'Channel', 'Channel',

View File

@ -24,6 +24,7 @@ from binascii import hexlify
import getpass import getpass
import os import os
import socket import socket
import warnings
from paramiko.agent import Agent from paramiko.agent import Agent
from paramiko.common import * from paramiko.common import *
@ -81,7 +82,17 @@ class RejectPolicy (MissingHostKeyPolicy):
(key.get_name(), hostname, hexlify(key.get_fingerprint()))) (key.get_name(), hostname, hexlify(key.get_fingerprint())))
raise SSHException('Unknown server %s' % hostname) raise SSHException('Unknown server %s' % hostname)
class WarningPolicy (MissingHostKeyPolicy):
"""
Policy for logging a python-style warning for an unknown host key, but
accepting it. This is used by L{SSHClient}.
"""
def missing_host_key(self, client, hostname, key):
warnings.warn('Unknown %s host key for %s: %s' %
(key.get_name(), hostname, hexlify(key.get_fingerprint())))
class SSHClient (object): class SSHClient (object):
""" """
A high-level representation of a session with an SSH server. This class A high-level representation of a session with an SSH server. This class
@ -213,7 +224,7 @@ class SSHClient (object):
self._policy = policy self._policy = policy
def connect(self, hostname, port=22, username=None, password=None, pkey=None, def connect(self, hostname, port=22, username=None, password=None, pkey=None,
key_filename=None, timeout=None, allow_agent=True): key_filename=None, timeout=None, allow_agent=True, look_for_keys=True):
""" """
Connect to an SSH server and authenticate to it. The server's host key Connect to an SSH server and authenticate to it. The server's host key
is checked against the system host keys (see L{load_system_host_keys}) is checked against the system host keys (see L{load_system_host_keys})
@ -251,6 +262,9 @@ class SSHClient (object):
@type timeout: float @type timeout: float
@param allow_agent: set to False to disable connecting to the SSH agent @param allow_agent: set to False to disable connecting to the SSH agent
@type allow_agent: bool @type allow_agent: bool
@param look_for_keys: set to False to disable searching for discoverable
private key files in C{~/.ssh/}
@type look_for_keys: bool
@raise BadHostKeyException: if the server's host key could not be @raise BadHostKeyException: if the server's host key could not be
verified verified
@ -291,7 +305,7 @@ class SSHClient (object):
if username is None: if username is None:
username = getpass.getuser() username = getpass.getuser()
self._auth(username, password, pkey, key_filename, allow_agent) self._auth(username, password, pkey, key_filename, allow_agent, look_for_keys)
def close(self): def close(self):
""" """
@ -367,13 +381,13 @@ class SSHClient (object):
""" """
return self._transport return self._transport
def _auth(self, username, password, pkey, key_filename, allow_agent): def _auth(self, username, password, pkey, key_filename, allow_agent, look_for_keys):
""" """
Try, in order: Try, in order:
- The key passed in, if one was passed in. - The key passed in, if one was passed in.
- Any key we can find through an SSH agent. - Any key we can find through an SSH agent (if allowed).
- Any "id_rsa" or "id_dsa" key discoverable in ~/.ssh/. - Any "id_rsa" or "id_dsa" key discoverable in ~/.ssh/ (if allowed).
- Plain username/password auth, if a password was given. - Plain username/password auth, if a password was given.
(The password might be needed to unlock a private key.) (The password might be needed to unlock a private key.)
@ -414,6 +428,17 @@ class SSHClient (object):
keyfiles.append((RSAKey, rsa_key)) keyfiles.append((RSAKey, rsa_key))
if os.path.isfile(dsa_key): if os.path.isfile(dsa_key):
keyfiles.append((DSSKey, dsa_key)) keyfiles.append((DSSKey, dsa_key))
# look in ~/ssh/ for windows users:
rsa_key = os.path.expanduser('~/ssh/id_rsa')
dsa_key = os.path.expanduser('~/ssh/id_dsa')
if os.path.isfile(rsa_key):
keyfiles.append((RSAKey, rsa_key))
if os.path.isfile(dsa_key):
keyfiles.append((DSSKey, dsa_key))
if not look_for_keys:
keyfiles = []
for pkey_class, filename in keyfiles: for pkey_class, filename in keyfiles:
try: try:
key = pkey_class.from_private_key_file(filename, password) key = pkey_class.from_private_key_file(filename, password)