Using the python interactive shell and openssh running locally, I keep getting an "No existing session" exception using paramiko. My code is below.
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('localhost',username=name,password=pw)
Results in:
No handlers could be found for logger "paramiko.transport"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python2.6/dist-packages/paramiko-1.7.7.1-py2.6.egg/paramiko/client.py", line 332, in connect
self._auth(username, password, pkey, key_filenames, allow_agent, look_for_keys)
File "/usr/local/lib/python2.6/dist-packages/paramiko-1.7.7.1-py2.6.egg/paramiko/client.py", line 493, in _auth
raise saved_exception
paramiko.SSHException: No existing session
I was able to connect previously, but had been trying to adjust this to allow for key based authorization. That failed, and since then I have not been able to connect locally. I have tried restarting openssh, and have connected to another server successfully. After searching through here, all I have found are mentions of authorization exceptions, which does not appear to be the case here.
As you already have password you don't need to talk to agent or look for private keys stored on your machine. So try passing extra parameters allow_agent, look_for_keys:
ssh.connect('localhost',username=name,password=pw,allow_agent=False,look_for_keys=False)
I had a spare public key with a key pass phrase in my ssh-add list. Once I removed it, I was able to execute my paramiko based script properly.
To list:
ssh-add -l
To delete all:
ssh-add -D
To re-add:
ssh-add /FULL/PATH/TO/id_rsa
https://bugs.launchpad.net/paramiko/+bug/912123
Which OS are you using?
Maybe you can check your env variable:
SSH_AUTH_SOCK
for "connect", it will try to use ssh agent.
in agent.py
self.conn = None
self.keys = ()
if ('SSH_AUTH_SOCK' in os.environ) and (sys.platform != 'win32'):
conn = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
conn.connect(os.environ['SSH_AUTH_SOCK'])
except:
# probably a dangling env var: the ssh agent is gone
return
self.conn = conn
elif sys.platform == 'win32':
import win_pageant
if win_pageant.can_talk_to_agent():
self.conn = win_pageant.PageantConnection()
else:
return
Just got the same error ERROR:SSHException('No existing session',) but since it was in a clean docker container, there was no ssh-agent.
After some hours of debugging, I found a different solution: it can happen when there is a timeout during key exchange! In my case, the ssh server is a router over GSM link, which is very slow.
You can enable debug on paramiko with:
logging.getLogger("paramiko").setLevel(logging.DEBUG)
And if you see the exception between the Connected and the Switch to new keys ..., it means the timeout was during the key exchange. In this case, you have to set timeout to a bigger value! (documentation says timeout is only for TCP connect, but in fact, it is also for the whole negotiation before auth!)
In my case ,I have try use allow_agent=False,look_for_keys=False, but not work .
I ssh to a 2G device, so timeout=10 is Ok, timeout=3 get" Unable to establish SSH connection: No existing session". Not timeout except.
So try timeout= a long time,if connect to a not establish ssh.
try:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(ip,22,username,passwd,timeout=10,allow_agent=True,look_for_keys=True)
print ('%s\tOK\n'%(ip) )
except socket.timeout:
print ("%s time out"%(ip))
except paramiko.AuthenticationException:
print("Authentication failed, please verify your credentials: %s"%(ip))
except paramiko.SSHException as sshException:
print("Unable to establish SSH connection: %s" %(sshException))
except paramiko.BadHostKeyException as badHostKeyException:
print("Unable to verify server's host key: %s" %(badHostKeyException))
finally:
ssh.close()
Replace 'localhost' by '127.0.0.1'.
Related
I am trying to connect to a remote server and list files inside a path using the below code:
import pysftp
myHostname = "myhostname.com"
myPort = <someportnumber>
myUsername = "<valid username>"
myPassword = "<valid password>"
cnopts = pysftp.CnOpts()
cnopts.hostkeys = None
with pysftp.Connection(host=myHostname, username=myUsername, password=myPassword, cnopts= cnopts, port=myPort) as sftp:
print("Connection succesfully established ... ")
sftp.chdir('/logs/dev')
# Obtain structure of the remote directory
directory_structure = sftp.listdir_attr()
# Print data
for attr in directory_structure:
print(attr.filename, attr)
But when I am running it, It is unable to establish a connection. It's throwing below exception:
Traceback (most recent call last):
File "c:/Users/611841191/Documents/SFTP File Download/SFTPFileDownload.py", line 11, in <module>
with pysftp.Connection(host=myHostname, username=myUsername, password=myPassword, cnopts= cnopts, port=myPort) as sftp:
File "C:\Users\611841191\AppData\Roaming\Python\Python38\site-packages\pysftp\__init__.py", line 140, in __init__
self._start_transport(host, port)
File "C:\Users\611841191\AppData\Roaming\Python\Python38\site-packages\pysftp\__init__.py", line 176, in _start_transport
self._transport = paramiko.Transport((host, port))
File "C:\Users\611841191\AppData\Roaming\Python\Python38\site-packages\paramiko\transport.py", line 415, in __init__
raise SSHException(
paramiko.ssh_exception.SSHException: Unable to connect to <myhostname.com>: [WinError 10060] A connection attempt failed because the connected party did not properly respond after a period of time or established connection failed because connected host has failed to respond
Can anyone help me out with why this exception is being thrown because I tried with other remote servers and the code seems to be working fine for them? The code is throwing exception for one particular remote server only.
If your code cannot connect somewhere using some protocol (SFTP in this case), the first thing to test is, whether you can connect using the same protocol using any existing GUI/commandline client from the same machine that runs your code.
If that does not work either, you do not have a programming question, but a simple network connectivity problem.
If you need a help resolving the problem, please go to Super User or Server Fault.
I am trying to use Paramiko to make an SSH communication between 2 servers on a private network. The client server is a web server and the host server is going to be a "worker" server. The idea was to not open up the worker server to HTTP connections. The only communication that needs to happen, is the web server needs to pass strings to a script on the worker server. For this I was hoping to use Paramiko and pass the information to the script via SSH.
I set up a new user and created a test script in Python 3, which works when I run it from the command line from my own user's SSH session. I put the same code into my Django web app, thinking that it should work, since it tests OK from the command line, and I get the following error:
Server 'worker-server' not found in known_hosts
Now, I think I understand this error. When performing the test script, I was using a certain user to access the server, and the known hosts information is saved to ~/.ssh/known_hosts even though the user is actually a 3rd party user created just for this one job. So the Django app is running under a different user who doesn't find the saved known hosts info because it doesn't have access to that folder. As far as I can tell the user which Apache uses to execute the Django scripts doesn't have a home directory.
Is there a way I can add this known host in a way that the Django process can see it?
Script:
import paramiko
client = paramiko.SSHClient()
client.load_system_host_keys()
client.connect('worker-server', 22, 'workeruser', 'workerpass')
code = "123wfdv"
survey_id = 111
stdin, stdout, stderr =
client.exec_command('python3 /path/to/test_script/test.py %s %s' % ( code, survey_id ))
print( "ssh successful. Closing connection" )
stdout = stdout.readlines()
client.close()
print ( "Connection closed" )
output = ""
for line in stdout:
output = output + line
if output!="":
print ( output )
else:
print ( "There was no output for this command" )
You can hard-code the host key in your Python code, using HostKeys.add:
import paramiko
from base64 import decodebytes
keydata = b"""AAAAB3NzaC1yc2EAAAABIwAAAQEA0hV..."""
key = paramiko.RSAKey(data=decodebytes(keydata))
client = paramiko.SSHClient()
client.get_host_keys().add('example.com', 'ssh-rsa', key)
client.connect(...)
This is based on my answer to:
Paramiko "Unknown Server".
To see how to obtain the fingerprint for use in the code, see my answer to:
Verify host key with pysftp.
If using pysftp, instead of Paramiko directly, see:
PySFTP failing with "No hostkey for host X found" when deploying Django/Heroku
Or, as you are connecting within a private network, you can give up on verifying host key altogether, using AutoAddPolicy:
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(...)
(This can be done only if you really do not need the connection to be secure)
I'm able to connect to an SFTP connection with a Bash script but want to account for bad connections, like there's no internet connection, the key file goes bad, etc.
Is there a way to throw an error in Bash if I have a bad connection? It seems like SFTP automatically denies permission if the key is bad and then closes the connection.
Would this be possible in Python?
Bash errors are pretty simple: you either exit with a return code in the middle of your script [and document it for yourself somewhere for handling it in another script], or handle the return code through if statements (as in retry your sftp command).
You could use function and specify a set of return codes to do this that way within a single script.
Python is a more full-featured language: if you use a library to do the calls (such as subprocess to make your shell commands directly, or paramiko if you're doing commands over ssh) you can catch the errors more directly using a try/except block:
try:
rc = subprocess.check_call('ssh 348.3454.342.21', shell=True) # bogus IP
except CalledProcessError, e:
print e
It'll output:
ssh: Could not resolve hostname 348.3454.342.21: Name or service not known
CalledProcessError: Command 'ssh 348.3454.342.21' returned non-zero exit status 255
Paramiko will have more explicit error types for connection failures and the like. However, commands run with paramiko that fail on the remote host will not throw errors if they error out on the remote device.
def setup_session(server,key_filename):
paramiko.util.log_to_file('%s_paramiko.log'%(server))
ssh = paramiko.SSHClient()
ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.
try:
ssh.connect(server,username='root',key_filename=key_filename)
except BadHostKeyException, e:
do_badhostkey_thing()
except AuthenticationException, e:
do_authenticationexception_thing()
except SSHException, e:
do_sshexception_thing()
return ssh
I was running the demo_sftp.py file from the demo folder in the paramiko github. I was stepping through it in PyDev and expected to get an error because I didn't have a key to the server I was trying to connect to but I got the print statement saying that the script couldn't open the host key file and then it went ahead and did the get and put.
Here's a code snippet.
try:
host_keys = paramiko.util.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
except IOError:
try:
# try ~/ssh/ too, because windows can't have a folder named ~/.ssh/
host_keys = paramiko.util.load_host_keys(os.path.expanduser('~/ssh/known_hosts'))
except IOError:
print '*** Unable to open host keys file'
host_keys = {}
if host_keys.has_key(hostname):
hostkeytype = host_keys[hostname].keys()[0]
hostkey = host_keys[hostname][hostkeytype]
print 'Using host key of type %s' % hostkeytype
# now, connect and use paramiko Transport to negotiate SSH2 across the connection
try:
t = paramiko.Transport((hostname, port))
t.connect(username=username, password=password, hostkey=hostkey)
sftp = paramiko.SFTPClient.from_transport(t)
# dirlist on remote host
dirlist = sftp.listdir('.')
print "Dirlist:", dirlist
I really expected it to go to the except on the t.connect line because hostkey is NoneType.
When I open an ssh connection with
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
ssh.connect('.'.join([self.name, self.domain]),
username=self.username, password=self.password)
stdin, stdout, stderr = ssh.exec_command("ps aux | grep Xvnc | wc -l")
I have to have the AutoAddPolicy() line or it fails. So what's the difference? Obviously I'm just learning this but I thought that sftp would be just as strict as ssh.
It looks like this is an acceptable practice.
Comment from Transport.connect
'''
Negotiate an SSH2 session, and optionally verify the server's host key
and authenticate using a password or private key. This is a shortcut
for L{start_client}, L{get_remote_server_key}, and
L{Transport.auth_password} or L{Transport.auth_publickey}. Use those
methods if you want more control.
You can use this method immediately after creating a Transport to
negotiate encryption with a server. If it fails, an exception will be
thrown. On success, the method will return cleanly, and an encrypted
session exists. You may immediately call L{open_channel} or
L{open_session} to get a L{Channel} object, which is used for data
transfer.
#note: If you fail to supply a password or private key, this method may
succeed, but a subsequent L{open_channel} or L{open_session} call may
fail because you haven't authenticated yet.
'''
Comment from SSHClient.connect
'''
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})
and any local host keys (L{load_host_keys}). If the server's hostname
is not found in either set of host keys, the missing host key policy
is used (see L{set_missing_host_key_policy}). The default policy is
to reject the key and raise an L{SSHException}.
'''
Maybe it is due to the fact that sftp can only transport data while ssh can run terminal commands. I do find it interesting that a man-in-the-middle attack doesn't seem to be a concern.
You can use below syntax
import pysftp
cnopts = pysftp.CnOpts()
cnopts.hostkeys = None
with pysftp.Connection(hostname, port=port, username=user_id, password=password,
cnopts=cnopts) as sftp:
with sftp.cd(self.directory): # temporarily chdir to public
sftp.put(filepath)
I'm on Windows 7.
I cannot connect to my iPad with a simple Python script:
HOST = '192.168.1.122'
try:
f = ftplib.FTP(HOST)
except (socket.error, socket.gaierror), e:
MessageBox.Show('ERROR: cannot reach "%s"' % HOST)
return
try:
f.connect(HOST,2121)
f.login()
except ftplib.error_perm:
MessageBox.Show('ERROR: cannot login anonymously')
f.quit()
return
The errors I have is "getaddrinfo returns an empty list" and the "cannot reach..." message... Cannot solve it...
I tried to FTP with several programs on the iPad without success. If I FTP via DOS box or using a FTP software it works. I tried as well another FTP server on my PC and it works.
I am forced to use port 2121, so can't change it.
Any clue or experience?
You should read docs before anything:
class ftplib.FTP([host[, user[,
passwd[, acct[, timeout]]]]]) Return a
new instance of the FTP class. When
host is given, the method call
connect(host) is made. When user is
given, additionally the method call
login(user, passwd, acct) is made
(where passwd and acct default to the
empty string when not given). The
optional timeout parameter specifies a
timeout in seconds for blocking
operations like the connection attempt
(if is not specified, the global
default timeout setting will be used).
So, if you do f = ftplib.FTP(HOST) it fails because it will try to connect to standard port (21) and not 2121.
You should get an instance of ftplib and later use f.connect(HOST, 2121).
http://docs.python.org/library/ftplib.html