Connection failure if the remote requires Two-Factor Authentication (2FA)
See original GitHub issueHi @ronf, thanks for this amazing project! I get Permission denied when trying to use AsyncSSH to connect to a remote which requires Two-Factor Authentication (2FA).
Test Code
import logging
import asyncssh
import asyncio as aio
async def ssh_test():
async with asyncssh.connect("c1f81187-cc18-451e-a611-34b82c4cd429", known_hosts=None):
pass
logging.basicConfig()
asyncssh.set_log_level('DEBUG')
asyncssh.set_debug_level(2)
if __name__ == "__main__":
print(aio.run(asyncssh.get_server_auth_methods("c1f81187-cc18-451e-a611-34b82c4cd429")))
aio.run(ssh_test())
Log
DEBUG:asyncssh:Reading config from "/private/home/xinyuanz/.ssh/config"
DEBUG:asyncssh:Reading config from "/private/home/xinyuanz/.ssh/fair_ssh/includes"
DEBUG:asyncssh:Reading config from "/private/home/xinyuanz/.ssh/fair_ssh/xinyuanz/config"
INFO:asyncssh:Fetching server auth methods from nlb-34b82c4cd429-8c30cef286658237.elb.us-east-1.amazonaws.com, port 22
INFO:asyncssh:[conn=0] Connected to SSH server at nlb-34b82c4cd429-8c30cef286658237.elb.us-east-1.amazonaws.com, port 22
INFO:asyncssh:[conn=0] Local address: 100.96.183.110, port 36196
INFO:asyncssh:[conn=0] Peer address: 34.224.194.26, port 22
DEBUG:asyncssh:[conn=0] Sending version SSH-2.0-AsyncSSH_2.12.0
DEBUG:asyncssh:[conn=0] Received version SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.5
DEBUG:asyncssh:[conn=0] Requesting key exchange
DEBUG:asyncssh:[conn=0] Key exchange algs: curve25519-sha256,curve25519-sha256@libssh.org,curve448-sha512,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,ecdh-sha2-1.3.132.0.10,diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha256,diffie-hellman-group15-sha512,diffie-hellman-group16-sha512,diffie-hellman-group17-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256@ssh.com,diffie-hellman-group14-sha1,rsa2048-sha256,ext-info-c
DEBUG:asyncssh:[conn=0] Host key algs: sk-ssh-ed25519-cert-v01@openssh.com,sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,ssh-ed448-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-1.3.132.0.10-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,sk-ecdsa-sha2-nistp256@openssh.com,ssh-ed25519,ssh-ed448,ecdsa-sha2-nistp521,ecdsa-sha2-nistp384,ecdsa-sha2-nistp256,ecdsa-sha2-1.3.132.0.10,rsa-sha2-256,rsa-sha2-512,ssh-rsa-sha224@ssh.com,ssh-rsa-sha256@ssh.com,ssh-rsa-sha384@ssh.com,ssh-rsa-sha512@ssh.com,ssh-rsa
DEBUG:asyncssh:[conn=0] Encryption algs: chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
DEBUG:asyncssh:[conn=0] MAC algs: umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1,hmac-sha256-2@ssh.com,hmac-sha224@ssh.com,hmac-sha256@ssh.com,hmac-sha384@ssh.com,hmac-sha512@ssh.com
DEBUG:asyncssh:[conn=0] Compression algs: zlib@openssh.com,none
DEBUG:asyncssh:[conn=0] Received key exchange request
DEBUG:asyncssh:[conn=0] Key exchange algs: curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256
DEBUG:asyncssh:[conn=0] Host key algs: rsa-sha2-512,rsa-sha2-256,ssh-rsa,ecdsa-sha2-nistp256,ssh-ed25519
DEBUG:asyncssh:[conn=0] Client to server:
DEBUG:asyncssh:[conn=0] Encryption algs: aes128-cbc,aes192-cbc,aes256-cbc,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com
DEBUG:asyncssh:[conn=0] MAC algs: hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256
DEBUG:asyncssh:[conn=0] Compression algs: none,zlib@openssh.com
DEBUG:asyncssh:[conn=0] Server to client:
DEBUG:asyncssh:[conn=0] Encryption algs: aes128-cbc,aes192-cbc,aes256-cbc,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com
DEBUG:asyncssh:[conn=0] MAC algs: hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256
DEBUG:asyncssh:[conn=0] Compression algs: none,zlib@openssh.com
DEBUG:asyncssh:[conn=0] Beginning key exchange
DEBUG:asyncssh:[conn=0] Key exchange alg: curve25519-sha256
DEBUG:asyncssh:[conn=0] Client to server:
DEBUG:asyncssh:[conn=0] Encryption alg: aes256-gcm@openssh.com
DEBUG:asyncssh:[conn=0] MAC alg: aes256-gcm@openssh.com
DEBUG:asyncssh:[conn=0] Compression alg: zlib@openssh.com
DEBUG:asyncssh:[conn=0] Server to client:
DEBUG:asyncssh:[conn=0] Encryption alg: aes256-gcm@openssh.com
DEBUG:asyncssh:[conn=0] MAC alg: aes256-gcm@openssh.com
DEBUG:asyncssh:[conn=0] Compression alg: zlib@openssh.com
DEBUG:asyncssh:[conn=0] Requesting service ssh-userauth
DEBUG:asyncssh:[conn=0] Completed key exchange
DEBUG:asyncssh:[conn=0] Received extension info
DEBUG:asyncssh:[conn=0] server-sig-algs: ssh-ed25519,sk-ssh-ed25519@openssh.com,ssh-rsa,rsa-sha2-256,rsa-sha2-512,ssh-dss,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,sk-ecdsa-sha2-nistp256@openssh.com
DEBUG:asyncssh:[conn=0] Request for service ssh-userauth accepted
INFO:asyncssh:[conn=0] Beginning auth for user xinyuanz
DEBUG:asyncssh:[conn=0] Remaining auth methods: publickey
INFO:asyncssh:[conn=0] Aborting connection
INFO:asyncssh:[conn=0] Connection closed
['publickey']
DEBUG:asyncssh:Reading config from "/private/home/xinyuanz/.ssh/config"
DEBUG:asyncssh:Reading config from "/private/home/xinyuanz/.ssh/fair_ssh/includes"
DEBUG:asyncssh:Reading config from "/private/home/xinyuanz/.ssh/fair_ssh/xinyuanz/config"
INFO:asyncssh:Opening SSH connection to nlb-34b82c4cd429-8c30cef286658237.elb.us-east-1.amazonaws.com, port 22
INFO:asyncssh:[conn=1] Connected to SSH server at nlb-34b82c4cd429-8c30cef286658237.elb.us-east-1.amazonaws.com, port 22
INFO:asyncssh:[conn=1] Local address: 100.96.183.110, port 36198
INFO:asyncssh:[conn=1] Peer address: 34.224.194.26, port 22
DEBUG:asyncssh:[conn=1] Sending version SSH-2.0-AsyncSSH_2.12.0
DEBUG:asyncssh:[conn=1] Received version SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.5
DEBUG:asyncssh:[conn=1] Requesting key exchange
DEBUG:asyncssh:[conn=1] Key exchange algs: curve25519-sha256,curve25519-sha256@libssh.org,curve448-sha512,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,ecdh-sha2-1.3.132.0.10,diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha256,diffie-hellman-group15-sha512,diffie-hellman-group16-sha512,diffie-hellman-group17-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256@ssh.com,diffie-hellman-group14-sha1,rsa2048-sha256,ext-info-c
DEBUG:asyncssh:[conn=1] Host key algs: sk-ssh-ed25519-cert-v01@openssh.com,sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,ssh-ed448-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-1.3.132.0.10-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,sk-ecdsa-sha2-nistp256@openssh.com,ssh-ed25519,ssh-ed448,ecdsa-sha2-nistp521,ecdsa-sha2-nistp384,ecdsa-sha2-nistp256,ecdsa-sha2-1.3.132.0.10,rsa-sha2-256,rsa-sha2-512,ssh-rsa-sha224@ssh.com,ssh-rsa-sha256@ssh.com,ssh-rsa-sha384@ssh.com,ssh-rsa-sha512@ssh.com,ssh-rsa
DEBUG:asyncssh:[conn=1] Encryption algs: chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
DEBUG:asyncssh:[conn=1] MAC algs: umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1,hmac-sha256-2@ssh.com,hmac-sha224@ssh.com,hmac-sha256@ssh.com,hmac-sha384@ssh.com,hmac-sha512@ssh.com
DEBUG:asyncssh:[conn=1] Compression algs: zlib@openssh.com,none
DEBUG:asyncssh:[conn=1] Received key exchange request
DEBUG:asyncssh:[conn=1] Key exchange algs: curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256
DEBUG:asyncssh:[conn=1] Host key algs: rsa-sha2-512,rsa-sha2-256,ssh-rsa,ecdsa-sha2-nistp256,ssh-ed25519
DEBUG:asyncssh:[conn=1] Client to server:
DEBUG:asyncssh:[conn=1] Encryption algs: aes128-cbc,aes192-cbc,aes256-cbc,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com
DEBUG:asyncssh:[conn=1] MAC algs: hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256
DEBUG:asyncssh:[conn=1] Compression algs: none,zlib@openssh.com
DEBUG:asyncssh:[conn=1] Server to client:
DEBUG:asyncssh:[conn=1] Encryption algs: aes128-cbc,aes192-cbc,aes256-cbc,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com
DEBUG:asyncssh:[conn=1] MAC algs: hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256
DEBUG:asyncssh:[conn=1] Compression algs: none,zlib@openssh.com
DEBUG:asyncssh:[conn=1] Beginning key exchange
DEBUG:asyncssh:[conn=1] Key exchange alg: curve25519-sha256
DEBUG:asyncssh:[conn=1] Client to server:
DEBUG:asyncssh:[conn=1] Encryption alg: aes256-gcm@openssh.com
DEBUG:asyncssh:[conn=1] MAC alg: aes256-gcm@openssh.com
DEBUG:asyncssh:[conn=1] Compression alg: zlib@openssh.com
DEBUG:asyncssh:[conn=1] Server to client:
DEBUG:asyncssh:[conn=1] Encryption alg: aes256-gcm@openssh.com
DEBUG:asyncssh:[conn=1] MAC alg: aes256-gcm@openssh.com
DEBUG:asyncssh:[conn=1] Compression alg: zlib@openssh.com
DEBUG:asyncssh:[conn=1] Requesting service ssh-userauth
DEBUG:asyncssh:[conn=1] Completed key exchange
DEBUG:asyncssh:[conn=1] Received extension info
DEBUG:asyncssh:[conn=1] server-sig-algs: ssh-ed25519,sk-ssh-ed25519@openssh.com,ssh-rsa,rsa-sha2-256,rsa-sha2-512,ssh-dss,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,sk-ecdsa-sha2-nistp256@openssh.com
DEBUG:asyncssh:[conn=1] Request for service ssh-userauth accepted
INFO:asyncssh:[conn=1] Beginning auth for user xinyuanz
DEBUG:asyncssh:[conn=1] Remaining auth methods: publickey
DEBUG:asyncssh:[conn=1] Preferred auth methods: gssapi-keyex,gssapi-with-mic,hostbased,publickey,keyboard-interactive,password
DEBUG:asyncssh:[conn=1] Trying public key auth with rsa-sha2-256 key
DEBUG:asyncssh:[conn=1] Signing request with rsa-sha2-256 key
DEBUG:asyncssh:[conn=1] Remaining auth methods: keyboard-interactive
DEBUG:asyncssh:[conn=1] Preferred auth methods: gssapi-keyex,gssapi-with-mic,hostbased,publickey,keyboard-interactive,password
INFO:asyncssh:[conn=1] Auth failed for user xinyuanz
INFO:asyncssh:[conn=1] Connection failure: Permission denied
INFO:asyncssh:[conn=1] Aborting connection
Traceback (most recent call last):
File "/private/home/xinyuanz/OneDevEx/test1.py", line 15, in <module>
aio.run(ssh_test())
File "/private/home/xinyuanz/miniconda3/envs/my-dev-env/lib/python3.10/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/private/home/xinyuanz/miniconda3/envs/my-dev-env/lib/python3.10/asyncio/base_events.py", line 646, in run_until_complete
return future.result()
File "/private/home/xinyuanz/OneDevEx/test1.py", line 6, in ssh_test
async with asyncssh.connect("c1f81187-cc18-451e-a611-34b82c4cd429", known_hosts=None):
File "/private/home/xinyuanz/miniconda3/envs/my-dev-env/lib/python3.10/site-packages/asyncssh/misc.py", line 274, in __aenter__
self._coro_result = await self._coro
File "/private/home/xinyuanz/miniconda3/envs/my-dev-env/lib/python3.10/site-packages/asyncssh/connection.py", line 7834, in connect
return await asyncio.wait_for(
File "/private/home/xinyuanz/miniconda3/envs/my-dev-env/lib/python3.10/asyncio/tasks.py", line 408, in wait_for
return await fut
File "/private/home/xinyuanz/miniconda3/envs/my-dev-env/lib/python3.10/site-packages/asyncssh/connection.py", line 447, in _connect
await options.waiter
asyncssh.misc.PermissionDenied: Permission denied
I expected a prompt asking for the authentication token (just like using the command line tool), but got denied directly. Please help! Thanks in advance!
Issue Analytics
- State:
- Created a year ago
- Comments:5 (3 by maintainers)
Top Results From Across the Web
Two-Factor Authentication for connections
This article provides a step-by-step guide to activating Two-factor authentication for connections (also known as TFA for connections).
Read more >2FA (Two-factor Authentication) - remote.it
With 2FA enabled, you'll need to provide an authentication code when accessing remote.it through your browser, desktop and mobile apps. If you ......
Read more >Multi-Factor Authentication (MFA) For Remote Access
Multi -factor authentication is a security system that requires two or more methods of authentication from different categories that verify a ...
Read more >What is Two-Factor Authentication (2FA) and How Does It Work?
Two -factor authentication adds an additional layer of security to the authentication process by making it harder for attackers to gain access to...
Read more >Limit number of reconnections to avoid spamming 2fa requests
The server I am connecting to via the remote SSH extension uses SSH ... if the two-factor authentication requires the code to be...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
AsyncSSH isn’t intended to be an interactive SSH client, so it’s never going to prompt you for anything. In particular, if you want to use password or keyboard-interactive auth, you will need to prompt the user yourself for the password and 2FA token. You can do this by implementing the kbdint_auth_requested() and kbdint_challenge_received() methods in a subclass of SSHClient. Here’s more info on these methods:
You’ll probably want kbdint_auth_requested() to return an empty string, to let the server pick the specific type of keyboard-interactive auth to use. Then, when the server challenges you, your kbdint_challenge_received() method should be called with the name, instructions, lang, and prompts arguments shown here. You’d then prompt the user using the values in the
prompts
argument and return a list of strings matching the length ofprompts
with your answers.For your 2FA case, I’m not sure if you’ll get a single challenge with two prompts or of it will do that as two different rounds of authentication. I don’t have an SSH setup here that does 2FA auth.
Also, keep in mind that you’ll want to keep your user prompting as async-friendly, if you don’t want the whole event loop to stop running when prompting the user. That means if you want to use something like getpass(), you’ll probably need to run that in an executor. See the ainput() example at https://gist.github.com/delivrance/675a4295ce7dc70f0ce0b164fcdbd798?permalink_comment_id=3590322#gistcomment-3590322 for an example of what this might look like.
OpenSSH is a standalone executable, so it has total control over whether it exits or stays running in the background after the session it was started for closes. This isn’t the case with AsyncSSH – it is a library, and it relies on the application using it to provide the Python interpreter and asyncio event loop. If that application code decides to exit, AsyncSSH really has no say in the matter, and all of the connections it was managing will end up getting closed.
It might be possible to do something using atexit(), but I don’t think that would allow AsyncSSH to prevent the process from exiting. At best, it would have to do something like fork() (which is only available on UNIX systems) and preserve all the file descriptors associated with AsyncSSH while closing everything else. That’s still dangerous, though, as there’s no way to know what other resources the application may have created that aren’t cleaned up prior to the fork. In fact, the application may never attempt to clean up these resources, counting on exiting the process to do so.
I’m just not seeing a good way to work around these issues. Even I were to create a standalone agent which AsyncSSH had total control over for this purpose, there would be the issue of copying the connection state from the application process to this agent process. Since AsyncSSH is a library, that has other challenges, like the fact that the application may have subclassed some of the AsyncSSH classes, and there’d be no way to get that custom code running over in the other interpreter. There’d be a lot of other state which would have to be copied over as well for the agent to be able to continue to read/write data on the open connections. AsyncSSH has no mechanism for anything like that, and doesn’t need any such code today, as connections are never expected to used outside of a single Python interpreter and asyncio event loop.