I'm trying to implement a very basic sftp server in python with asyncssh to be used during a unittest. I want to use a custom path to set the root of the sftp server and it would be better to set a username/password.
So far I have this:
import asyncio
import asyncssh
import os
import logging
logging.basicConfig(level=logging.DEBUG)
class BasicSFTPServer(asyncssh.SFTPServer):
def __init__(self):
super().__init__(chan=22, chroot=os.path.basename(__file__))
async def main():
host_key = asyncssh.generate_private_key("ssh-rsa")
server = await asyncssh.listen(
host="127.0.0.1",
port=0,
server_host_keys=[host_key],
sftp_factory=BasicSFTPServer
)
server_port = server.get_port()
async with asyncssh.connect(host="localhost", port=server_port, known_hosts=None) as conn:
async with conn.start_sftp_client() as sftp:
result = await sftp.listdir()
print(result)
server.close()
await server.wait_closed()
if(__name__ == "__main__"):
asyncio.run(main())
But I get a permission error:
DEBUG:asyncio:Using proactor: IocpProactor
INFO:asyncssh:Creating SSH listener on 127.0.0.1
INFO:asyncssh:Host canonicalization disabled
INFO:asyncssh:Opening SSH connection to localhost, port 53559
INFO:asyncssh:[conn=0] Connected to SSH server at localhost, port 53559
INFO:asyncssh:[conn=0] Local address: 127.0.0.1, port 53561
INFO:asyncssh:[conn=0] Peer address: 127.0.0.1, port 53559
DEBUG:asyncssh:[conn=0] Sending version SSH-2.0-AsyncSSH_2.21.0
INFO:asyncssh:[conn=1] Accepted SSH client connection
INFO:asyncssh:[conn=1] Local address: 127.0.0.1, port 53559
INFO:asyncssh:[conn=1] Peer address: 127.0.0.1, port 53561
DEBUG:asyncssh:[conn=1] Sending version SSH-2.0-AsyncSSH_2.21.0
DEBUG:asyncssh:[conn=1] Received version SSH-2.0-AsyncSSH_2.21.0
DEBUG:asyncssh:[conn=1] Requesting key exchange
DEBUG:asyncssh:[conn=0] Received version SSH-2.0-AsyncSSH_2.21.0
DEBUG:asyncssh:[conn=0] Requesting key exchange
DEBUG:asyncssh:[conn=0] Received key exchange request
DEBUG:asyncssh:[conn=0] Beginning key exchange
DEBUG:asyncssh:[conn=1] Received key exchange request
DEBUG:asyncssh:[conn=1] Beginning key exchange
DEBUG:asyncssh:[conn=0] Completed key exchange
DEBUG:asyncssh:[conn=1] Completed key exchange
INFO:asyncssh:[conn=0] Beginning auth for user Manuel
INFO:asyncssh:[conn=1] Beginning auth for user Manuel
INFO:asyncssh:[conn=0] Auth failed for user Manuel
INFO:asyncssh:[conn=0] Connection failure: Permission denied for user Manuel on host localhost
INFO:asyncssh:[conn=0] Aborting connection
Traceback (most recent call last):
File "...\Documents\workspace\repos\template-python-service\debug\main.py", line 34, in <module>
asyncio.run(main())
~~~~~~~~~~~^^^^^^^^
File "...\AppData\Roaming\uv\python\cpython-3.13.1-windows-x86_64-none\Lib\asyncio\runners.py", line 194, in run
return runner.run(main)
~~~~~~~~~~^^^^^^
File "...\AppData\Roaming\uv\python\cpython-3.13.1-windows-x86_64-none\Lib\asyncio\runners.py", line 118, in run
return self._loop.run_until_complete(task)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "...\AppData\Roaming\uv\python\cpython-3.13.1-windows-x86_64-none\Lib\asyncio\base_events.py", line 720, in run_until_complete
return future.result()
~~~~~~~~~~~~~^^
File "...\Documents\workspace\repos\template-python-service\debug\main.py", line 25, in main
async with asyncssh.connect(host="localhost", port=server_port, known_hosts=None) as conn:
~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "...\Documents\workspace\repos\template-python-service\.venv\Lib\site-packages\asyncssh\misc.py", line 386, in __aenter__
self._coro_result = await self._coro
^^^^^^^^^^^^^^^^
File "...\Documents\workspace\repos\template-python-service\.venv\Lib\site-packages\asyncssh\connection.py", line 9186, in connect
return await asyncio.wait_for(
^^^^^^^^^^^^^^^^^^^^^^^
...<2 lines>...
timeout=new_options.connect_timeout)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "...\AppData\Roaming\uv\python\cpython-3.13.1-windows-x86_64-none\Lib\asyncio\tasks.py", line 507, in wait_for
return await fut
^^^^^^^^^
File "...\.venv\Lib\site-packages\asyncssh\connection.py", line 528, in _connect
await options.waiter
asyncssh.misc.PermissionDenied: Permission denied for user xxxx on host localhost
I know I'm missing something but I can't find any example...
127.0.0.1, but connecting tolocalhost? Be consistent.