diff --git a/lib/jnpr/junos/device.py b/lib/jnpr/junos/device.py index 26138722b..86577e77a 100644 --- a/lib/jnpr/junos/device.py +++ b/lib/jnpr/junos/device.py @@ -218,7 +218,6 @@ def _sshconf_lkup(self): self._hostname = found.get('hostname', self._hostname) self._port = found.get('port', self._port) self._conf_auth_user = found.get('user') - self._conf_ssh_private_key_file = found.get('identityfile') return sshconf_path def display_xml_rpc(self, command, format='xml'): @@ -820,6 +819,7 @@ def __init__(self, *vargs, **kvargs): self._hostname = 'localhost' self._ssh_private_key_file = None self._ssh_config = None + self._allow_agent = False else: # -------------------------- # making a remote connection @@ -830,17 +830,21 @@ def __init__(self, *vargs, **kvargs): # user will default to $USER self._auth_user = os.getenv('USER') self._conf_auth_user = None - self._conf_ssh_private_key_file = None # user can get updated by ssh_config self._ssh_config = kvargs.get('ssh_config') self._sshconf_lkup() # but if user or private key is explicit from call, then use it. self._auth_user = kvargs.get('user') or self._conf_auth_user or \ self._auth_user - self._ssh_private_key_file = kvargs.get('ssh_private_key_file') \ - or self._conf_ssh_private_key_file + self._ssh_private_key_file = kvargs.get('ssh_private_key_file') self._auth_password = kvargs.get( 'password') or kvargs.get('passwd') + # we want to enable the ssh-agent if-and-only-if we are + # not given a password or an ssh key file. + # in this condition it means we want to query the agent + # for available ssh keys + self._allow_agent = bool((self._auth_password is None) and + (self._ssh_private_key_file is None)) # ----------------------------- # initialize instance variables @@ -907,14 +911,6 @@ def open(self, *vargs, **kvargs): try: ts_start = datetime.datetime.now() - # we want to enable the ssh-agent if-and-only-if we are - # not given a password or an ssh key file. - # in this condition it means we want to query the agent - # for available ssh keys - - allow_agent = bool((self._auth_password is None) and - (self._ssh_private_key_file is None)) - # open connection using ncclient transport self._conn = netconf_ssh.connect( host=self._hostname, @@ -923,7 +919,7 @@ def open(self, *vargs, **kvargs): password=self._auth_password, hostkey_verify=False, key_filename=self._ssh_private_key_file, - allow_agent=allow_agent, + allow_agent=self._allow_agent, ssh_config=self._sshconf_lkup(), device_params={'name': 'junos', 'local': False}) diff --git a/lib/jnpr/junos/utils/misc.py b/lib/jnpr/junos/utils/misc.py new file mode 100644 index 000000000..9b06a3996 --- /dev/null +++ b/lib/jnpr/junos/utils/misc.py @@ -0,0 +1,34 @@ +# utils/misc.py + +import paramiko + +def get_ssh_client(junos): + """Get a Paramiko SSHClient using settings from the provided device.""" + ssh = paramiko.SSHClient() + ssh.load_system_host_keys() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + + # use junos._hostname since this will be correct if we are going + # through a jumphost. + + # Retrieve ProxyCommand and IdentityFile + sock = None + key_file = junos._ssh_private_key_file + ssh_config = junos._sshconf_path + if ssh_config: + config = paramiko.SSHConfig() + config.parse(open(ssh_config)) + config = config.lookup(junos._hostname) + if config.get("proxycommand"): + sock = paramiko.proxy.ProxyCommand(config.get("proxycommand")) + key_file = key_file or config.get("identityfile") + + ssh.connect(hostname=junos._hostname, + port=(22, int(junos._port))[ + junos._hostname == 'localhost'], + username=junos._auth_user, + password=junos._auth_password, + key_filename=key_file, + allow_agent=junos._allow_agent, + sock=sock) + return ssh diff --git a/lib/jnpr/junos/utils/scp.py b/lib/jnpr/junos/utils/scp.py index 8a150d6cb..5e502da7c 100644 --- a/lib/jnpr/junos/utils/scp.py +++ b/lib/jnpr/junos/utils/scp.py @@ -1,9 +1,10 @@ from __future__ import absolute_import import inspect -import paramiko from scp import SCPClient +from jnpr.junos.utils.misc import get_ssh_client + """ Secure Copy Utility """ @@ -81,36 +82,7 @@ def open(self, **scpargs): #@@@ should check for multi-calls to connect to ensure we don't keep #@@@ opening new connections junos = self._junos - self._ssh = paramiko.SSHClient() - self._ssh.load_system_host_keys() - self._ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - - # use junos._hostname since this will be correct if we are going - # through a jumphost. - - config = {} - kwargs = {} - ssh_config = getattr(junos, '_sshconf_path') - if ssh_config: - config = paramiko.SSHConfig() - config.parse(open(ssh_config)) - config = config.lookup(junos._hostname) - sock = None - if config.get("proxycommand"): - sock = paramiko.proxy.ProxyCommand(config.get("proxycommand")) - - if self._junos._ssh_private_key_file is not None: - kwargs['key_filename']=self._junos._ssh_private_key_file - - self._ssh.connect(hostname=junos._hostname, - port=( - 22, int( - junos._port))[ - junos._hostname == 'localhost'], - username=junos._auth_user, - password=junos._auth_password, - sock=sock, **kwargs - ) + self._ssh = get_ssh_client(junos) return SCPClient(self._ssh.get_transport(), **scpargs) def close(self): diff --git a/lib/jnpr/junos/utils/start_shell.py b/lib/jnpr/junos/utils/start_shell.py index 07956c0ee..f2e2386e2 100644 --- a/lib/jnpr/junos/utils/start_shell.py +++ b/lib/jnpr/junos/utils/start_shell.py @@ -1,8 +1,9 @@ -import paramiko from select import select import re import datetime +from jnpr.junos.utils.misc import get_ssh_client + _JUNOS_PROMPT = '> ' _SHELL_PROMPT = '(%|#)\s' _SELECT_WAIT = 0.1 @@ -82,16 +83,7 @@ def open(self): :class:`paramiko.SSHClient` instance. """ junos = self._nc - - client = paramiko.SSHClient() - client.load_system_host_keys() - client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - client.connect(hostname=junos.hostname, - port=(22, junos._port)[junos.hostname == 'localhost'], - username=junos._auth_user, - password=junos._auth_password, - ) - + client = get_ssh_client(junos) chan = client.invoke_shell() self._client = client self._chan = chan