Search code examples
pythonsshparamikopysftp

Use Paramiko AutoAddPolicy with pysftp


This code is not working:

def sftp_connection(self):
    import pysftp
    connection = pysftp.Connection(self.host, username=self.system_name,
                  private_key=os.path.join(HOME, '.ssh', 'id_rsa'))

    # in the next lines I try to use AutoAddPolicy
    client = connection.sftp_client()
    client.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
    client.set_missing_host_key_policy(paramiko.client.AutoAddPolicy)
    return connection

This is the exception:

Traceback (most recent call last):
  File "/home/u/src/myapp-glo/myapp_doxis_archiv/tests/test_doxis_archiv.py", line 85, in test_beleg_to_archiv__ftpservercontext
    info_dict = beleg_to_archiv(beleg, self.archiv_belegart)
  File "/home/u/src/myapp-glo/myapp_doxis_archiv/beleg_to_archiv.py", line 28, in beleg_to_archiv
    transfer_log=send_data_via_ftp(temp_directory, archiv_belegart.doxis_archiv)
  File "/home/u/src/myapp-glo/myapp_doxis_archiv/beleg_to_archiv.py", line 71, in send_data_via_ftp
    with doxis_archiv.sftp_connection() as sftp:
  File "/home/u/src/myapp-glo/myapp_doxis_archiv/models.py", line 43, in sftp_connection
    private_key=os.path.join(HOME, '.ssh', 'id_rsa'))
  File "/home/u/local/lib/python2.7/site-packages/pysftp/__init__.py", line 132, in __init__
    self._tconnect['hostkey'] = self._cnopts.get_hostkey(host)
  File "/home/u/local/lib/python2.7/site-packages/pysftp/__init__.py", line 71, in get_hostkey
    raise SSHException("No hostkey for host %s found." % host)
SSHException: No hostkey for host localhost found.

I get the exception before I try to set the host_key_policy.

I could not find a different way to access the client instance via pysftp.

Is there a way to set AutoAddPolicy before I get the exception?

There is a related question. My question is about how to apply one of the several solutions which are provided in the old question.


Solution

  • pysftp does not use Paramiko SSHClient class at all, it uses more low-level Transport class. So it does not have the MissingHostKeyPolicy functionality of SSHClient.

    You would have to implement it on your own.

    One possible implementation can be:

    host = 'example.com'
    
    # Loads .ssh/known_hosts    
    cnopts = CnOpts()
    
    hostkeys = None
    
    if cnopts.hostkeys.lookup(host) == None:
        print("New host - will accept any host key")
        # Backup loaded .ssh/known_hosts file
        hostkeys = cnopts.hostkeys
        # And do not verify host key of the new host
        cnopts.hostkeys = None
    
    with Connection(host, username=user, private_key=pkey, cnopts=cnopts) as sftp:
        if hostkeys != None:
            print("Connected to new host, caching its hostkey")
            hostkeys.add(
                host, sftp.remote_server_key.get_name(), sftp.remote_server_key)
            hostkeys.save(pysftp.helpers.known_hosts())
    

    Though, due to a bug in pysftp, this still might not work satisfactory. I suggest you switch to Paramiko altogether. See pysftp vs. Paramiko.