Open ut-adamc opened 2 years ago
For the purposes of using this with a mock server password credentials seems irrelevant; instead create a set of credentials just for running the tests against, through either or fixture or as a command you invoke via tox prior to running pytest.
Is there a reason as not to merge this? I would be really interested in this feature as well!
I just checked and saw the tests failing right now but the fix for them to pass again is very straight forward:
diff --git a/mockssh/test_server.py b/mockssh/test_server.py
index 15108b7..1740f53 100644
--- a/mockssh/test_server.py
+++ b/mockssh/test_server.py
@@ -104,6 +104,8 @@ def test_overwrite_handler(server: Server, monkeypatch: MonkeyPatch):
if username == "foo" and password == "bar":
return paramiko.AUTH_SUCCESSFUL
return paramiko.AUTH_FAILED
+ def get_allowed_auths(self, username):
+ return "password"
monkeypatch.setattr(server, 'handler_cls', MyHandler)
with paramiko.SSHClient() as client:
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
@ut-adamc , I don't see any stand-out issues with the implementation. Can you please update README.rst to include a password example?
@ut-adamc please add documentation for this on the README, the following test case fails:
import os
import tempfile
from pytest import yield_fixture
import mockssh
@yield_fixture()
def server():
users = {
"type": "password",
"password": "mypassword",
}
with mockssh.Server(users) as s:
yield s
def test_ssh_session(server):
for uid in server.users:
with server.client(uid) as c:
_, stdout, _ = c.exec_command("ls /")
assert stdout.read()
def test_sftp_session(server):
for uid in server.users:
target_dir = tempfile.mkdtemp()
target_fname = os.path.join(target_dir, "foo")
assert not os.access(target_fname, os.F_OK)
with server.client(uid) as c:
sftp = c.open_sftp()
sftp.put(__file__, target_fname, confirm=True)
assert os.access(target_fname, os.F_OK)
outputs:
|@ pytest
================================================================================================================================================== test session starts ===================================================================================================================================================
platform linux -- Python 3.10.12, pytest-8.3.2, pluggy-1.5.0
rootdir: /home/kyle/Repos/github/mock-ssh-server-test
collected 2 items
tests/mock_test.py EE [100%]
========================================================================================================================================================= ERRORS =========================================================================================================================================================
___________________________________________________________________________________________________________________________________________ ERROR at setup of test_ssh_session ___________________________________________________________________________________________________________________________________________
@yield_fixture()
def server():
users = {
"type": "password",
"password": "mypassword",
# "sample-user": "mypassword",
}
> with mockssh.Server(users) as s:
tests/mock_test.py:17:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.venv/lib/python3.10/site-packages/mockssh/server.py:227: in __init__
user_data = UserData(credential)
.venv/lib/python3.10/site-packages/mockssh/server.py:77: in __init__
self.public_key = self.calculate_public_key(
.venv/lib/python3.10/site-packages/mockssh/server.py:95: in calculate_public_key
public_key = paramiko.RSAKey.from_private_key_file(
.venv/lib/python3.10/site-packages/paramiko/pkey.py:435: in from_private_key_file
key = cls(filename=filename, password=password)
.venv/lib/python3.10/site-packages/paramiko/rsakey.py:64: in __init__
self._from_private_key_file(filename, password)
.venv/lib/python3.10/site-packages/paramiko/rsakey.py:196: in _from_private_key_file
data = self._read_private_key_file("RSA", filename, password)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <[AttributeError("'NoneType' object has no attribute 'key_size'") raised in repr()] RSAKey object at 0x7f0d4a574250>, tag = 'RSA', filename = 'password', password = None
def _read_private_key_file(self, tag, filename, password=None):
"""
Read an SSH2-format private key file, looking for a string of the type
``"BEGIN xxx PRIVATE KEY"`` for some ``xxx``, base64-decode the text we
find, and return it as a string. If the private key is encrypted and
``password`` is not ``None``, the given password will be used to
decrypt the key (otherwise `.PasswordRequiredException` is thrown).
:param str tag: ``"RSA"`` or ``"DSA"``, the tag used to mark the
data block.
:param str filename: name of the file to read.
:param str password:
an optional password to use to decrypt the key file, if it's
encrypted.
:return: the `bytes` that make up the private key.
:raises: ``IOError`` -- if there was an error reading the file.
:raises: `.PasswordRequiredException` -- if the private key file is
encrypted, and ``password`` is ``None``.
:raises: `.SSHException` -- if the key file is invalid.
"""
> with open(filename, "r") as f:
E FileNotFoundError: [Errno 2] No such file or directory: 'password'
.venv/lib/python3.10/site-packages/paramiko/pkey.py:508: FileNotFoundError
__________________________________________________________________________________________________________________________________________ ERROR at setup of test_sftp_session ___________________________________________________________________________________________________________________________________________
@yield_fixture()
def server():
users = {
"type": "password",
"password": "mypassword",
# "sample-user": "mypassword",
}
> with mockssh.Server(users) as s:
tests/mock_test.py:17:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.venv/lib/python3.10/site-packages/mockssh/server.py:227: in __init__
user_data = UserData(credential)
.venv/lib/python3.10/site-packages/mockssh/server.py:77: in __init__
self.public_key = self.calculate_public_key(
.venv/lib/python3.10/site-packages/mockssh/server.py:95: in calculate_public_key
public_key = paramiko.RSAKey.from_private_key_file(
.venv/lib/python3.10/site-packages/paramiko/pkey.py:435: in from_private_key_file
key = cls(filename=filename, password=password)
.venv/lib/python3.10/site-packages/paramiko/rsakey.py:64: in __init__
self._from_private_key_file(filename, password)
.venv/lib/python3.10/site-packages/paramiko/rsakey.py:196: in _from_private_key_file
data = self._read_private_key_file("RSA", filename, password)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <[AttributeError("'NoneType' object has no attribute 'key_size'") raised in repr()] RSAKey object at 0x7f0d4a5ca530>, tag = 'RSA', filename = 'password', password = None
def _read_private_key_file(self, tag, filename, password=None):
"""
Read an SSH2-format private key file, looking for a string of the type
``"BEGIN xxx PRIVATE KEY"`` for some ``xxx``, base64-decode the text we
find, and return it as a string. If the private key is encrypted and
``password`` is not ``None``, the given password will be used to
decrypt the key (otherwise `.PasswordRequiredException` is thrown).
:param str tag: ``"RSA"`` or ``"DSA"``, the tag used to mark the
data block.
:param str filename: name of the file to read.
:param str password:
an optional password to use to decrypt the key file, if it's
encrypted.
:return: the `bytes` that make up the private key.
:raises: ``IOError`` -- if there was an error reading the file.
:raises: `.PasswordRequiredException` -- if the private key file is
encrypted, and ``password`` is ``None``.
:raises: `.SSHException` -- if the key file is invalid.
"""
> with open(filename, "r") as f:
E FileNotFoundError: [Errno 2] No such file or directory: 'password'
.venv/lib/python3.10/site-packages/paramiko/pkey.py:508: FileNotFoundError
==================================================================================================================================================== warnings summary ====================================================================================================================================================
tests/mock_test.py:9
/home/kyle/Repos/github/mock-ssh-server-test/tests/mock_test.py:9: PytestDeprecationWarning: @pytest.yield_fixture is deprecated.
Use @pytest.fixture instead; they are the same.
@yield_fixture()
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================================================================================================================================================ short test summary info =================================================================================================================================================
ERROR tests/mock_test.py::test_ssh_session - FileNotFoundError: [Errno 2] No such file or directory: 'password'
ERROR tests/mock_test.py::test_sftp_session - FileNotFoundError: [Errno 2] No such file or directory: 'password'
============================================================================================================================================== 1 warning, 2 errors in 0.11s ==============================================================================================================================================
Return 1
Also test_overwrite_handler fails
Useful for those of us who sometimes have password credentials.
I don't know how close this would be to a viable solution, but I wanted to run it by you and get feedback. It works in local testing. It relies on changing the data structure for users to accommodate having more than one kind of credential. See the doc string for UserData in mockssh.server.