ronf / asyncssh

AsyncSSH is a Python package which provides an asynchronous client and server implementation of the SSHv2 protocol on top of the Python asyncio framework.
Eclipse Public License 2.0
1.55k stars 151 forks source link

Dell iDRAC Authentication Issue #357

Closed Zelaskal closed 3 years ago

Zelaskal commented 3 years ago

Hello,

I'm having issues getting authentication with new(er) Dell iDRAC v8 2.70.70.70 or higher. The same username/password works via command line OpenSSH, and via Paramiko with a tweak, but I cannot figure out how to do the same thing with AsyncSSH.

The code that ended up working with Paramiko is here: https://stackoverflow.com/a/63346132 , but for brevity (shortened):

    client.connect(host, port=port, username=username, password=password, allow_agent=False, look_for_keys=False)
    transport = client.get_transport()

    if not transport.is_authenticated():
        transport.auth_interactive_dumb(username)

    if transport.is_authenticated():
        logger.info('transport is authenticated')
        _stdin, stdout, stderr = client.exec_command(cmd)
        res = stdout.read()
        logger.info('Command {0}:\n{1}'.format(cmd, res))
    else:
        logger.error('transport is not authenticated')

The most important part there being the transport.auth_interactive_dumb(username) portion.

Thanks for your help!

ronf commented 3 years ago

AsyncSSH can definitely support keyboard-interactive authentication, and you can provide your own handler to look at the prompts and answer them. AsyncSSH doesn't provide anything which directly challenges the end-user on stdin/stdout as it expects you'll be scripting hat, but if you really wanted to call out to something like getpass() to interactively prompt the end user for a password, you can. You just need to be careful with such a blocking call if you have other stuff running in parallel in the asyncio event loop. You might need to use something like an executor so that runs in its own thread so the event loop can keep running in parallel for any other activity.

In your example here, I see you providing a password, but then still finding the transport isn't authenticated. AsyncSSH works differently in that regard. If the server requires auth, it will always be completed (or fail) before the connect() call returns. So, you need to provide callbacks on your subclass of SSHClient which indicate what forms of auth you want to support and whatever is needed to complete that auth. See https://asyncssh.readthedocs.io/en/latest/api.html#sshclient (scroll down to the keyboard-interactive auth handlers section) for details.

You should be able to enable both normal password auth and keyboard-interactive auth if you need to to handle something like two factor auth, if that's what's going on here. Alternately, specifying a username and password in the connect() call should work for the first factor, without the need to explicitly enable password authentication. In that regard, AsyncSSH is similar to what's going on above in Paramiko.

For the second factor, you'll need to implement kbdint_auth_requested() to indicate you can handle that form of auth and then kbdint_challenge_received() to actually receive the prompts and return your responses.

ronf commented 3 years ago

Closing due to inactivity. Please open a new issue if you have additional questions.