From 3b9eaefebb1b2e55b6392d5c55ac07594cc057e3 Mon Sep 17 00:00:00 2001 From: Cory Benfield Date: Thu, 14 Aug 2014 20:43:55 +0100 Subject: Test banner timeout. --- tests/test_client.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'tests/test_client.py') diff --git a/tests/test_client.py b/tests/test_client.py index 7e5c80b4..1867fb78 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -27,6 +27,7 @@ import unittest import weakref import warnings import os +import time from tests.util import test_path import paramiko from paramiko.common import PY2 @@ -72,12 +73,14 @@ class SSHClientTest (unittest.TestCase): if hasattr(self, attr): getattr(self, attr).close() - def _run(self): + def _run(self, delay=0): self.socks, addr = self.sockl.accept() self.ts = paramiko.Transport(self.socks) host_key = paramiko.RSAKey.from_private_key_file(test_path('test_rsa.key')) self.ts.add_server_key(host_key) server = NullServer() + if delay: + time.sleep(delay) self.ts.start_server(self.event, server) def test_1_client(self): @@ -252,3 +255,25 @@ class SSHClientTest (unittest.TestCase): gc.collect() self.assertTrue(p() is None) + + def test_7_banner_timeout(self): + """ + verify that the SSHClient has a configurable banner timeout. + """ + # Start the thread with a 5 second wait. + threading.Thread(target=self._run, args=(5,)).start() + host_key = paramiko.RSAKey.from_private_key_file(test_path('test_rsa.key')) + public_host_key = paramiko.RSAKey(data=host_key.asbytes()) + + self.tc = paramiko.SSHClient() + self.tc.get_host_keys().add('[%s]:%d' % (self.addr, self.port), 'ssh-rsa', public_host_key) + # Connect with a three second banner timeout. + self.assertRaises( + paramiko.SSHException, + self.tc.connect, + self.addr, + self.port, + username='slowdive', + password='pygmalion', + banner_timeout=3 + ) -- cgit v1.2.3 From 021160d8db62b8873f7deda3f7d89750941d2704 Mon Sep 17 00:00:00 2001 From: Cory Benfield Date: Thu, 14 Aug 2014 21:35:31 +0100 Subject: Use a shorter timeout in banner timeout test. --- tests/test_client.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'tests/test_client.py') diff --git a/tests/test_client.py b/tests/test_client.py index 1867fb78..48e2e9b0 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -260,14 +260,14 @@ class SSHClientTest (unittest.TestCase): """ verify that the SSHClient has a configurable banner timeout. """ - # Start the thread with a 5 second wait. - threading.Thread(target=self._run, args=(5,)).start() + # Start the thread with a 1 second wait. + threading.Thread(target=self._run, args=(1,)).start() host_key = paramiko.RSAKey.from_private_key_file(test_path('test_rsa.key')) public_host_key = paramiko.RSAKey(data=host_key.asbytes()) self.tc = paramiko.SSHClient() self.tc.get_host_keys().add('[%s]:%d' % (self.addr, self.port), 'ssh-rsa', public_host_key) - # Connect with a three second banner timeout. + # Connect with a half second banner timeout. self.assertRaises( paramiko.SSHException, self.tc.connect, @@ -275,5 +275,5 @@ class SSHClientTest (unittest.TestCase): self.port, username='slowdive', password='pygmalion', - banner_timeout=3 + banner_timeout=0.5 ) -- cgit v1.2.3 From f88189835eebab72a3792f67de4aacc7fca68df6 Mon Sep 17 00:00:00 2001 From: Olle Lundberg Date: Fri, 15 Aug 2014 12:21:44 +0200 Subject: Document what is breaking in the client tests. --- tests/test_client.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tests/test_client.py') diff --git a/tests/test_client.py b/tests/test_client.py index 7e5c80b4..93574fc8 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -221,6 +221,8 @@ class SSHClientTest (unittest.TestCase): """ # Unclear why this is borked on Py3, but it is, and does not seem worth # pursuing at the moment. + # XXX: It's the release of the references to e.g packetizer that fails + # in py3... if not PY2: return threading.Thread(target=self._run).start() -- cgit v1.2.3 From 76c2073e9e098bec89837ae980167ee9b0a6efcf Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Fri, 5 Sep 2014 14:22:11 -0700 Subject: Add a (failing :() test re: ECDSA private keys Re #218 --- tests/test_client.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'tests/test_client.py') diff --git a/tests/test_client.py b/tests/test_client.py index 7e5c80b4..3576ef32 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -148,6 +148,40 @@ class SSHClientTest (unittest.TestCase): stdout.close() stderr.close() + def test_2_5_client_ecdsa(self): + """ + verify that SSHClient works with an ECDSA key. + """ + threading.Thread(target=self._run).start() + host_key = paramiko.RSAKey.from_private_key_file(test_path('test_rsa.key')) + public_host_key = paramiko.RSAKey(data=host_key.asbytes()) + + self.tc = paramiko.SSHClient() + self.tc.get_host_keys().add('[%s]:%d' % (self.addr, self.port), 'ssh-rsa', public_host_key) + self.tc.connect(self.addr, self.port, username='slowdive', key_filename=test_path('test_ecdsa.key')) + + self.event.wait(1.0) + self.assertTrue(self.event.isSet()) + self.assertTrue(self.ts.is_active()) + self.assertEqual('slowdive', self.ts.get_username()) + self.assertEqual(True, self.ts.is_authenticated()) + + stdin, stdout, stderr = self.tc.exec_command('yes') + schan = self.ts.accept(1.0) + + schan.send('Hello there.\n') + schan.send_stderr('This is on stderr.\n') + schan.close() + + self.assertEqual('Hello there.\n', stdout.readline()) + self.assertEqual('', stdout.readline()) + self.assertEqual('This is on stderr.\n', stderr.readline()) + self.assertEqual('', stderr.readline()) + + stdin.close() + stdout.close() + stderr.close() + def test_3_multiple_key_files(self): """ verify that SSHClient accepts and tries multiple key files. -- cgit v1.2.3 From 6c8a5eb8fbf023194634f3077479a70ac9f024a2 Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Fri, 5 Sep 2014 16:05:30 -0700 Subject: Refactor horrible old copypasta --- tests/test_client.py | 95 ++++++++++++---------------------------------------- 1 file changed, 21 insertions(+), 74 deletions(-) (limited to 'tests/test_client.py') diff --git a/tests/test_client.py b/tests/test_client.py index 3576ef32..0697d289 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -80,24 +80,30 @@ class SSHClientTest (unittest.TestCase): server = NullServer() self.ts.start_server(self.event, server) - def test_1_client(self): + def _test_connection(self, **kwargs): """ - verify that the SSHClient stuff works too. + kwargs get passed directly into SSHClient.connect(). """ + # Server setup threading.Thread(target=self._run).start() host_key = paramiko.RSAKey.from_private_key_file(test_path('test_rsa.key')) public_host_key = paramiko.RSAKey(data=host_key.asbytes()) + # Client setup self.tc = paramiko.SSHClient() self.tc.get_host_keys().add('[%s]:%d' % (self.addr, self.port), 'ssh-rsa', public_host_key) - self.tc.connect(self.addr, self.port, username='slowdive', password='pygmalion') + # Actual connection + self.tc.connect(self.addr, self.port, username='slowdive', **kwargs) + + # Authentication successful? self.event.wait(1.0) self.assertTrue(self.event.isSet()) self.assertTrue(self.ts.is_active()) self.assertEqual('slowdive', self.ts.get_username()) self.assertEqual(True, self.ts.is_authenticated()) + # Command execution functions? stdin, stdout, stderr = self.tc.exec_command('yes') schan = self.ts.accept(1.0) @@ -110,95 +116,36 @@ class SSHClientTest (unittest.TestCase): self.assertEqual('This is on stderr.\n', stderr.readline()) self.assertEqual('', stderr.readline()) + # Cleanup stdin.close() stdout.close() stderr.close() + def test_1_client(self): + """ + verify that the SSHClient stuff works too. + """ + self._test_connection(password='pygmalion') + def test_2_client_dsa(self): """ verify that SSHClient works with a DSA key. """ - threading.Thread(target=self._run).start() - host_key = paramiko.RSAKey.from_private_key_file(test_path('test_rsa.key')) - public_host_key = paramiko.RSAKey(data=host_key.asbytes()) - - self.tc = paramiko.SSHClient() - self.tc.get_host_keys().add('[%s]:%d' % (self.addr, self.port), 'ssh-rsa', public_host_key) - self.tc.connect(self.addr, self.port, username='slowdive', key_filename=test_path('test_dss.key')) - - self.event.wait(1.0) - self.assertTrue(self.event.isSet()) - self.assertTrue(self.ts.is_active()) - self.assertEqual('slowdive', self.ts.get_username()) - self.assertEqual(True, self.ts.is_authenticated()) - - stdin, stdout, stderr = self.tc.exec_command('yes') - schan = self.ts.accept(1.0) - - schan.send('Hello there.\n') - schan.send_stderr('This is on stderr.\n') - schan.close() - - self.assertEqual('Hello there.\n', stdout.readline()) - self.assertEqual('', stdout.readline()) - self.assertEqual('This is on stderr.\n', stderr.readline()) - self.assertEqual('', stderr.readline()) - - stdin.close() - stdout.close() - stderr.close() + self._test_connection(key_filename=test_path('test_dss.key')) def test_2_5_client_ecdsa(self): """ verify that SSHClient works with an ECDSA key. """ - threading.Thread(target=self._run).start() - host_key = paramiko.RSAKey.from_private_key_file(test_path('test_rsa.key')) - public_host_key = paramiko.RSAKey(data=host_key.asbytes()) - - self.tc = paramiko.SSHClient() - self.tc.get_host_keys().add('[%s]:%d' % (self.addr, self.port), 'ssh-rsa', public_host_key) - self.tc.connect(self.addr, self.port, username='slowdive', key_filename=test_path('test_ecdsa.key')) - - self.event.wait(1.0) - self.assertTrue(self.event.isSet()) - self.assertTrue(self.ts.is_active()) - self.assertEqual('slowdive', self.ts.get_username()) - self.assertEqual(True, self.ts.is_authenticated()) - - stdin, stdout, stderr = self.tc.exec_command('yes') - schan = self.ts.accept(1.0) - - schan.send('Hello there.\n') - schan.send_stderr('This is on stderr.\n') - schan.close() - - self.assertEqual('Hello there.\n', stdout.readline()) - self.assertEqual('', stdout.readline()) - self.assertEqual('This is on stderr.\n', stderr.readline()) - self.assertEqual('', stderr.readline()) - - stdin.close() - stdout.close() - stderr.close() + self._test_connection(key_filename=test_path('test_ecdsa.key')) def test_3_multiple_key_files(self): """ verify that SSHClient accepts and tries multiple key files. """ - threading.Thread(target=self._run).start() - host_key = paramiko.RSAKey.from_private_key_file(test_path('test_rsa.key')) - public_host_key = paramiko.RSAKey(data=host_key.asbytes()) - - self.tc = paramiko.SSHClient() - self.tc.get_host_keys().add('[%s]:%d' % (self.addr, self.port), 'ssh-rsa', public_host_key) - self.tc.connect(self.addr, self.port, username='slowdive', key_filename=[test_path('test_rsa.key'), test_path('test_dss.key')]) - - self.event.wait(1.0) - self.assertTrue(self.event.isSet()) - self.assertTrue(self.ts.is_active()) - self.assertEqual('slowdive', self.ts.get_username()) - self.assertEqual(True, self.ts.is_authenticated()) + self._test_connection(key_filename=[ + test_path('test_rsa.key'), test_path('test_dss.key') + ]) def test_4_auto_add_policy(self): """ -- cgit v1.2.3 From f7f3b4560f8a6a44d3738db798cba977bb5daf4f Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Fri, 5 Sep 2014 16:08:05 -0700 Subject: Add an explicit RSA test, which fails (!) --- tests/test_client.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tests/test_client.py') diff --git a/tests/test_client.py b/tests/test_client.py index 0697d289..1791363a 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -133,6 +133,12 @@ class SSHClientTest (unittest.TestCase): """ self._test_connection(key_filename=test_path('test_dss.key')) + def test_client_rsa(self): + """ + verify that SSHClient works with an RSA key. + """ + self._test_connection(key_filename=test_path('test_rsa.key')) + def test_2_5_client_ecdsa(self): """ verify that SSHClient works with an ECDSA key. -- cgit v1.2.3 From a8fd0bd9b2811a989fb646842a2dc17f9d94fd01 Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Fri, 5 Sep 2014 17:54:33 -0700 Subject: Set things up for cleaner test key tomfoolery --- tests/test_client.py | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) (limited to 'tests/test_client.py') diff --git a/tests/test_client.py b/tests/test_client.py index 1791363a..7ccf92b0 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -29,10 +29,25 @@ import warnings import os from tests.util import test_path import paramiko -from paramiko.common import PY2 +from paramiko.common import PY2, b + + +def _fingerprint_to_bytes(fingerprint): + """ + Takes ssh-keygen style fingerprint, returns hex-y bytestring. + """ + encoded = b(''.join([r'\x{0}'.format(x) for x in fingerprint.split(':')])) + return encoded.decode('string-escape') class NullServer (paramiko.ServerInterface): + def __init__(self, *args, **kwargs): + # Allow tests to enable/disable specific key types + self.__allowed_keys = kwargs.pop('allowed_keys', []) + self.__fingerprints = { + 'dss': '44:78:f0:b9:a2:3c:c5:18:20:09:ff:75:5b:c1:d2:6c', + } + super(NullServer, self).__init__(*args, **kwargs) def get_allowed_auths(self, username): if username == 'slowdive': @@ -45,7 +60,16 @@ class NullServer (paramiko.ServerInterface): return paramiko.AUTH_FAILED def check_auth_publickey(self, username, key): - if (key.get_name() == 'ssh-dss') and key.get_fingerprint() == b'\x44\x78\xf0\xb9\xa2\x3c\xc5\x18\x20\x09\xff\x75\x5b\xc1\xd2\x6c': + type_ = key.get_name() + fingerprint = key.get_fingerprint() + if not type_.startswith('ssh-'): + return paramiko.AUTH_FAILED + # TODO: honor allowed_keys + try: + expected = self.__fingerprints[type_[4:]] + except KeyError: + return paramiko.AUTH_FAILED + if fingerprint == _fingerprint_to_bytes(expected): return paramiko.AUTH_SUCCESSFUL return paramiko.AUTH_FAILED -- cgit v1.2.3 From 70e44d6386197ec77ca0f4fec8bba47ee22c3198 Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Fri, 5 Sep 2014 17:55:22 -0700 Subject: Add RSA key fingerprint, now that test passes --- tests/test_client.py | 1 + 1 file changed, 1 insertion(+) (limited to 'tests/test_client.py') diff --git a/tests/test_client.py b/tests/test_client.py index 7ccf92b0..cabc0c6f 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -46,6 +46,7 @@ class NullServer (paramiko.ServerInterface): self.__allowed_keys = kwargs.pop('allowed_keys', []) self.__fingerprints = { 'dss': '44:78:f0:b9:a2:3c:c5:18:20:09:ff:75:5b:c1:d2:6c', + 'rsa': '60:73:38:44:cb:51:86:65:7f:de:da:a2:2b:5a:57:d5', } super(NullServer, self).__init__(*args, **kwargs) -- cgit v1.2.3 From 7d72ce55b8b14a36fcd9e46253ed268eab816c5e Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Fri, 5 Sep 2014 18:18:36 -0700 Subject: More cleanup to support ECDSA key, and now it works! --- tests/test_client.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'tests/test_client.py') diff --git a/tests/test_client.py b/tests/test_client.py index cabc0c6f..1db2046d 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -45,8 +45,9 @@ class NullServer (paramiko.ServerInterface): # Allow tests to enable/disable specific key types self.__allowed_keys = kwargs.pop('allowed_keys', []) self.__fingerprints = { - 'dss': '44:78:f0:b9:a2:3c:c5:18:20:09:ff:75:5b:c1:d2:6c', - 'rsa': '60:73:38:44:cb:51:86:65:7f:de:da:a2:2b:5a:57:d5', + 'ssh-dss': '44:78:f0:b9:a2:3c:c5:18:20:09:ff:75:5b:c1:d2:6c', + 'ssh-rsa': '60:73:38:44:cb:51:86:65:7f:de:da:a2:2b:5a:57:d5', + 'ecdsa-sha2-nistp256': '25:19:eb:55:e6:a1:47:ff:4f:38:d2:75:6f:a5:d5:60', } super(NullServer, self).__init__(*args, **kwargs) @@ -61,16 +62,12 @@ class NullServer (paramiko.ServerInterface): return paramiko.AUTH_FAILED def check_auth_publickey(self, username, key): - type_ = key.get_name() - fingerprint = key.get_fingerprint() - if not type_.startswith('ssh-'): - return paramiko.AUTH_FAILED # TODO: honor allowed_keys try: - expected = self.__fingerprints[type_[4:]] + expected = self.__fingerprints[key.get_name()] except KeyError: return paramiko.AUTH_FAILED - if fingerprint == _fingerprint_to_bytes(expected): + if key.get_fingerprint() == _fingerprint_to_bytes(expected): return paramiko.AUTH_SUCCESSFUL return paramiko.AUTH_FAILED -- cgit v1.2.3 From d8047a2e6d1aa06e113e0a9dc9e8f3e89ce2f70e Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Fri, 5 Sep 2014 19:23:15 -0700 Subject: Factor fingerprint data out of class --- tests/test_client.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'tests/test_client.py') diff --git a/tests/test_client.py b/tests/test_client.py index 1db2046d..0293ec75 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -32,6 +32,12 @@ import paramiko from paramiko.common import PY2, b +FINGERPRINTS = { + 'ssh-dss': '44:78:f0:b9:a2:3c:c5:18:20:09:ff:75:5b:c1:d2:6c', + 'ssh-rsa': '60:73:38:44:cb:51:86:65:7f:de:da:a2:2b:5a:57:d5', + 'ecdsa-sha2-nistp256': '25:19:eb:55:e6:a1:47:ff:4f:38:d2:75:6f:a5:d5:60', +} + def _fingerprint_to_bytes(fingerprint): """ Takes ssh-keygen style fingerprint, returns hex-y bytestring. @@ -44,11 +50,6 @@ class NullServer (paramiko.ServerInterface): def __init__(self, *args, **kwargs): # Allow tests to enable/disable specific key types self.__allowed_keys = kwargs.pop('allowed_keys', []) - self.__fingerprints = { - 'ssh-dss': '44:78:f0:b9:a2:3c:c5:18:20:09:ff:75:5b:c1:d2:6c', - 'ssh-rsa': '60:73:38:44:cb:51:86:65:7f:de:da:a2:2b:5a:57:d5', - 'ecdsa-sha2-nistp256': '25:19:eb:55:e6:a1:47:ff:4f:38:d2:75:6f:a5:d5:60', - } super(NullServer, self).__init__(*args, **kwargs) def get_allowed_auths(self, username): @@ -64,7 +65,7 @@ class NullServer (paramiko.ServerInterface): def check_auth_publickey(self, username, key): # TODO: honor allowed_keys try: - expected = self.__fingerprints[key.get_name()] + expected = FINGERPRINTS[key.get_name()] except KeyError: return paramiko.AUTH_FAILED if key.get_fingerprint() == _fingerprint_to_bytes(expected): -- cgit v1.2.3 From dd0c618ea02024e06806ab99c79fcff8affeba03 Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Fri, 5 Sep 2014 19:32:50 -0700 Subject: Overhaul multi-key test to set up multiple scenarios --- tests/test_client.py | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) (limited to 'tests/test_client.py') diff --git a/tests/test_client.py b/tests/test_client.py index 0293ec75..ae10b814 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -95,20 +95,26 @@ class SSHClientTest (unittest.TestCase): if hasattr(self, attr): getattr(self, attr).close() - def _run(self): + def _run(self, allowed_keys=None): + if allowed_keys is None: + allowed_keys = FINGERPRINTS.keys() self.socks, addr = self.sockl.accept() self.ts = paramiko.Transport(self.socks) host_key = paramiko.RSAKey.from_private_key_file(test_path('test_rsa.key')) self.ts.add_server_key(host_key) - server = NullServer() + server = NullServer(allowed_keys=allowed_keys) self.ts.start_server(self.event, server) def _test_connection(self, **kwargs): """ - kwargs get passed directly into SSHClient.connect(). + (Most) kwargs get passed directly into SSHClient.connect(). + + The exception is ``allowed_keys`` which is stripped and handed to the + ``NullServer`` used for testing. """ + run_kwargs = {'allowed_keys': kwargs.pop('allowed_keys', None)} # Server setup - threading.Thread(target=self._run).start() + threading.Thread(target=self._run, kwargs=run_kwargs).start() host_key = paramiko.RSAKey.from_private_key_file(test_path('test_rsa.key')) public_host_key = paramiko.RSAKey(data=host_key.asbytes()) @@ -172,9 +178,23 @@ class SSHClientTest (unittest.TestCase): """ verify that SSHClient accepts and tries multiple key files. """ - self._test_connection(key_filename=[ - test_path('test_rsa.key'), test_path('test_dss.key') - ]) + # This is dumb :( + types_ = { + 'rsa': 'ssh-rsa', + 'dss': 'ssh-dss', + 'ecdsa': 'ecdsa-sha2-nistp256', + } + # Various combos of attempted & valid keys + for attempt, accept in ( + (['rsa', 'dss'], ['dss']), # Original test #3 + (['dss', 'rsa'], ['dss']), # Ordering matters sometimes, sadly + ): + self._test_connection( + key_filename=[ + test_path('test_{0}.key'.format(x)) for x in attempt + ], + allowed_keys=[types_[x] for x in accept], + ) def test_4_auto_add_policy(self): """ -- cgit v1.2.3 From 689ac4d9c6a30eccfba21d068239dc5b06c16bc4 Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Fri, 5 Sep 2014 19:39:02 -0700 Subject: Add a couple more permutations --- tests/test_client.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'tests/test_client.py') diff --git a/tests/test_client.py b/tests/test_client.py index ae10b814..a1ef490c 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -185,9 +185,12 @@ class SSHClientTest (unittest.TestCase): 'ecdsa': 'ecdsa-sha2-nistp256', } # Various combos of attempted & valid keys + # TODO: try every possible combo using itertools functions for attempt, accept in ( (['rsa', 'dss'], ['dss']), # Original test #3 (['dss', 'rsa'], ['dss']), # Ordering matters sometimes, sadly + (['dss', 'rsa', 'ecdsa'], ['dss']), # Try ECDSA but fail + (['rsa', 'ecdsa'], ['ecdsa']), # ECDSA success ): self._test_connection( key_filename=[ -- cgit v1.2.3 From 5c81c60090b991f7fc4c87c850460a4adc48986e Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Fri, 5 Sep 2014 20:35:29 -0700 Subject: Forgot to actually implement allowed-keys/reverse testing --- tests/test_client.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'tests/test_client.py') diff --git a/tests/test_client.py b/tests/test_client.py index a1ef490c..4ba66828 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -30,6 +30,7 @@ import os from tests.util import test_path import paramiko from paramiko.common import PY2, b +from paramiko.ssh_exception import PasswordRequiredException FINGERPRINTS = { @@ -63,12 +64,14 @@ class NullServer (paramiko.ServerInterface): return paramiko.AUTH_FAILED def check_auth_publickey(self, username, key): - # TODO: honor allowed_keys try: expected = FINGERPRINTS[key.get_name()] except KeyError: return paramiko.AUTH_FAILED - if key.get_fingerprint() == _fingerprint_to_bytes(expected): + if ( + key.get_name() in self.__allowed_keys and + key.get_fingerprint() == _fingerprint_to_bytes(expected) + ): return paramiko.AUTH_SUCCESSFUL return paramiko.AUTH_FAILED @@ -199,6 +202,16 @@ class SSHClientTest (unittest.TestCase): allowed_keys=[types_[x] for x in accept], ) + def test_multiple_key_files_failure(self): + """ + Expect failure when multiple keys in play and none are accepted + """ + self.assertRaises(PasswordRequiredException, + self._test_connection, + key_filename=[test_path('test_rsa.key')], + allowed_keys=['ecdsa-sha2-nistp256'], + ) + def test_4_auto_add_policy(self): """ verify that SSHClient's AutoAddPolicy works. -- cgit v1.2.3 From ff419627b3676a598d10cd581282d21ec33136bb Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Fri, 5 Sep 2014 20:45:09 -0700 Subject: Fix a Python 3 encoding dealie --- tests/test_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests/test_client.py') diff --git a/tests/test_client.py b/tests/test_client.py index 4ba66828..b0ea0dc7 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -44,7 +44,7 @@ def _fingerprint_to_bytes(fingerprint): Takes ssh-keygen style fingerprint, returns hex-y bytestring. """ encoded = b(''.join([r'\x{0}'.format(x) for x in fingerprint.split(':')])) - return encoded.decode('string-escape') + return encoded.decode('string-escape' if PY2 else 'unicode_escape') class NullServer (paramiko.ServerInterface): -- cgit v1.2.3 From 774bc5e3fff41a53b986d1663e6e0d35bf695195 Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Fri, 5 Sep 2014 20:54:22 -0700 Subject: Yup, that was indeed too fucking clever. Bad bitprophet! --- tests/test_client.py | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'tests/test_client.py') diff --git a/tests/test_client.py b/tests/test_client.py index b0ea0dc7..76fda68d 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -34,18 +34,11 @@ from paramiko.ssh_exception import PasswordRequiredException FINGERPRINTS = { - 'ssh-dss': '44:78:f0:b9:a2:3c:c5:18:20:09:ff:75:5b:c1:d2:6c', - 'ssh-rsa': '60:73:38:44:cb:51:86:65:7f:de:da:a2:2b:5a:57:d5', - 'ecdsa-sha2-nistp256': '25:19:eb:55:e6:a1:47:ff:4f:38:d2:75:6f:a5:d5:60', + 'ssh-dss': b'\x44\x78\xf0\xb9\xa2\x3c\xc5\x18\x20\x09\xff\x75\x5b\xc1\xd2\x6c', + 'ssh-rsa': b'\x60\x73\x38\x44\xcb\x51\x86\x65\x7f\xde\xda\xa2\x2b\x5a\x57\xd5', + 'ecdsa-sha2-nistp256': b'\x25\x19\xeb\x55\xe6\xa1\x47\xff\x4f\x38\xd2\x75\x6f\xa5\xd5\x60', } -def _fingerprint_to_bytes(fingerprint): - """ - Takes ssh-keygen style fingerprint, returns hex-y bytestring. - """ - encoded = b(''.join([r'\x{0}'.format(x) for x in fingerprint.split(':')])) - return encoded.decode('string-escape' if PY2 else 'unicode_escape') - class NullServer (paramiko.ServerInterface): def __init__(self, *args, **kwargs): @@ -70,7 +63,7 @@ class NullServer (paramiko.ServerInterface): return paramiko.AUTH_FAILED if ( key.get_name() in self.__allowed_keys and - key.get_fingerprint() == _fingerprint_to_bytes(expected) + key.get_fingerprint() == expected ): return paramiko.AUTH_SUCCESSFUL return paramiko.AUTH_FAILED -- cgit v1.2.3 From 6a6ac4d78421667b810f5e3a017fb669853133f9 Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Sat, 6 Sep 2014 15:59:49 -0700 Subject: Bah humbug --- tests/test_client.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'tests/test_client.py') diff --git a/tests/test_client.py b/tests/test_client.py index 76fda68d..7c094628 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -30,7 +30,7 @@ import os from tests.util import test_path import paramiko from paramiko.common import PY2, b -from paramiko.ssh_exception import PasswordRequiredException +from paramiko.ssh_exception import SSHException FINGERPRINTS = { @@ -199,7 +199,9 @@ class SSHClientTest (unittest.TestCase): """ Expect failure when multiple keys in play and none are accepted """ - self.assertRaises(PasswordRequiredException, + # Until #387 is fixed we have to catch a high-up exception since + # various platforms trigger different errors here >_< + self.assertRaises(SSHException, self._test_connection, key_filename=[test_path('test_rsa.key')], allowed_keys=['ecdsa-sha2-nistp256'], -- cgit v1.2.3 From 0063e64046c732e8c50fc5f54234942feaa313d9 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Sun, 29 Sep 2013 18:10:12 +0100 Subject: Convert SSHClient into a context manager --- paramiko/client.py | 6 ++++-- tests/test_client.py | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) (limited to 'tests/test_client.py') diff --git a/paramiko/client.py b/paramiko/client.py index 4326abbd..d718135e 100644 --- a/paramiko/client.py +++ b/paramiko/client.py @@ -37,10 +37,10 @@ from paramiko.resource import ResourceManager from paramiko.rsakey import RSAKey from paramiko.ssh_exception import SSHException, BadHostKeyException from paramiko.transport import Transport -from paramiko.util import retry_on_signal +from paramiko.util import retry_on_signal, ClosingContextManager -class SSHClient (object): +class SSHClient (ClosingContextManager): """ A high-level representation of a session with an SSH server. This class wraps `.Transport`, `.Channel`, and `.SFTPClient` to take care of most @@ -55,6 +55,8 @@ class SSHClient (object): checking. The default mechanism is to try to use local key files or an SSH agent (if one is running). + Instances of this class may be used as context managers. + .. versionadded:: 1.6 """ diff --git a/tests/test_client.py b/tests/test_client.py index 7c094628..b3635272 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -20,6 +20,8 @@ Some unit tests for SSHClient. """ +from __future__ import with_statement + import socket from tempfile import mkstemp import threading @@ -293,3 +295,25 @@ class SSHClientTest (unittest.TestCase): gc.collect() self.assertTrue(p() is None) + + def test_6_client_can_be_used_as_context_manager(self): + """ + verify that an SSHClient can be used a context manager + """ + threading.Thread(target=self._run).start() + host_key = paramiko.RSAKey.from_private_key_file(test_path('test_rsa.key')) + public_host_key = paramiko.RSAKey(data=host_key.asbytes()) + + with paramiko.SSHClient() as tc: + self.tc = tc + self.tc.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + self.assertEquals(0, len(self.tc.get_host_keys())) + self.tc.connect(self.addr, self.port, username='slowdive', password='pygmalion') + + self.event.wait(1.0) + self.assertTrue(self.event.isSet()) + self.assertTrue(self.ts.is_active()) + + self.assertTrue(self.tc._transport is not None) + + self.assertTrue(self.tc._transport is None) -- cgit v1.2.3 From 05030b2d5e63349c6abacd1e3a65c70faadbb35f Mon Sep 17 00:00:00 2001 From: Olle Lundberg Date: Thu, 16 Oct 2014 17:20:20 +0200 Subject: Use modern api to check if event is set. Since we are a python2.6+ code base now, we want to be as forward compatible as possible. --- demos/demo_server.py | 2 +- paramiko/auth_handler.py | 2 +- paramiko/channel.py | 6 +++--- paramiko/transport.py | 12 ++++++------ tests/test_auth.py | 4 ++-- tests/test_client.py | 8 ++++---- tests/test_kex_gss.py | 2 +- tests/test_ssh_gss.py | 2 +- tests/test_transport.py | 22 +++++++++++----------- 9 files changed, 30 insertions(+), 30 deletions(-) (limited to 'tests/test_client.py') diff --git a/demos/demo_server.py b/demos/demo_server.py index 5b3d5164..c4af9b10 100644 --- a/demos/demo_server.py +++ b/demos/demo_server.py @@ -159,7 +159,7 @@ try: print('Authenticated!') server.event.wait(10) - if not server.event.isSet(): + if not server.event.is_set(): print('*** Client never asked for a shell.') sys.exit(1) diff --git a/paramiko/auth_handler.py b/paramiko/auth_handler.py index b5fea654..c001aeee 100644 --- a/paramiko/auth_handler.py +++ b/paramiko/auth_handler.py @@ -195,7 +195,7 @@ class AuthHandler (object): if (e is None) or issubclass(e.__class__, EOFError): e = AuthenticationException('Authentication failed.') raise e - if event.isSet(): + if event.is_set(): break if not self.is_authenticated(): e = self.transport.get_exception() diff --git a/paramiko/channel.py b/paramiko/channel.py index 9de278cb..f1b0483d 100644 --- a/paramiko/channel.py +++ b/paramiko/channel.py @@ -290,7 +290,7 @@ class Channel (ClosingContextManager): .. versionadded:: 1.7.3 """ - return self.closed or self.status_event.isSet() + return self.closed or self.status_event.is_set() def recv_exit_status(self): """ @@ -305,7 +305,7 @@ class Channel (ClosingContextManager): .. versionadded:: 1.2 """ self.status_event.wait() - assert self.status_event.isSet() + assert self.status_event.is_set() return self.exit_status def send_exit_status(self, status): @@ -1077,7 +1077,7 @@ class Channel (ClosingContextManager): def _wait_for_event(self): self.event.wait() - assert self.event.isSet() + assert self.event.is_set() if self.event_ready: return e = self.transport.get_exception() diff --git a/paramiko/transport.py b/paramiko/transport.py index cf2c49f5..2a700a88 100644 --- a/paramiko/transport.py +++ b/paramiko/transport.py @@ -405,7 +405,7 @@ class Transport (threading.Thread, ClosingContextManager): if e is not None: raise e raise SSHException('Negotiation failed.') - if event.isSet(): + if event.is_set(): break def start_server(self, event=None, server=None): @@ -470,7 +470,7 @@ class Transport (threading.Thread, ClosingContextManager): if e is not None: raise e raise SSHException('Negotiation failed.') - if event.isSet(): + if event.is_set(): break def add_server_key(self, key): @@ -729,7 +729,7 @@ class Transport (threading.Thread, ClosingContextManager): if e is None: e = SSHException('Unable to open channel.') raise e - if event.isSet(): + if event.is_set(): break chan = self._channels.get(chanid) if chan is not None: @@ -849,7 +849,7 @@ class Transport (threading.Thread, ClosingContextManager): if e is not None: raise e raise SSHException('Negotiation failed.') - if self.completion_event.isSet(): + if self.completion_event.is_set(): break return @@ -900,7 +900,7 @@ class Transport (threading.Thread, ClosingContextManager): self.completion_event.wait(0.1) if not self.active: return None - if self.completion_event.isSet(): + if self.completion_event.is_set(): break return self.global_response @@ -1461,7 +1461,7 @@ class Transport (threading.Thread, ClosingContextManager): self._log(DEBUG, 'Dropping user packet because connection is dead.') return self.clear_to_send_lock.acquire() - if self.clear_to_send.isSet(): + if self.clear_to_send.is_set(): break self.clear_to_send_lock.release() if time.time() > start + self.clear_to_send_timeout: diff --git a/tests/test_auth.py b/tests/test_auth.py index 1d972d53..ec78e3ce 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -118,12 +118,12 @@ class AuthTest (unittest.TestCase): self.ts.add_server_key(host_key) self.event = threading.Event() self.server = NullServer() - self.assertTrue(not self.event.isSet()) + self.assertTrue(not self.event.is_set()) self.ts.start_server(self.event, self.server) def verify_finished(self): self.event.wait(1.0) - self.assertTrue(self.event.isSet()) + self.assertTrue(self.event.is_set()) self.assertTrue(self.ts.is_active()) def test_1_bad_auth_type(self): diff --git a/tests/test_client.py b/tests/test_client.py index 28d1cb46..3d2e75c9 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -128,7 +128,7 @@ class SSHClientTest (unittest.TestCase): # Authentication successful? self.event.wait(1.0) - self.assertTrue(self.event.isSet()) + self.assertTrue(self.event.is_set()) self.assertTrue(self.ts.is_active()) self.assertEqual('slowdive', self.ts.get_username()) self.assertEqual(True, self.ts.is_authenticated()) @@ -226,7 +226,7 @@ class SSHClientTest (unittest.TestCase): self.tc.connect(self.addr, self.port, username='slowdive', password='pygmalion') self.event.wait(1.0) - self.assertTrue(self.event.isSet()) + self.assertTrue(self.event.is_set()) self.assertTrue(self.ts.is_active()) self.assertEqual('slowdive', self.ts.get_username()) self.assertEqual(True, self.ts.is_authenticated()) @@ -281,7 +281,7 @@ class SSHClientTest (unittest.TestCase): self.tc.connect(self.addr, self.port, username='slowdive', password='pygmalion') self.event.wait(1.0) - self.assertTrue(self.event.isSet()) + self.assertTrue(self.event.is_set()) self.assertTrue(self.ts.is_active()) p = weakref.ref(self.tc._transport.packetizer) @@ -316,7 +316,7 @@ class SSHClientTest (unittest.TestCase): self.tc.connect(self.addr, self.port, username='slowdive', password='pygmalion') self.event.wait(1.0) - self.assertTrue(self.event.isSet()) + self.assertTrue(self.event.is_set()) self.assertTrue(self.ts.is_active()) self.assertTrue(self.tc._transport is not None) diff --git a/tests/test_kex_gss.py b/tests/test_kex_gss.py index 91d4c9b2..3bf788da 100644 --- a/tests/test_kex_gss.py +++ b/tests/test_kex_gss.py @@ -109,7 +109,7 @@ class GSSKexTest(unittest.TestCase): gss_auth=True, gss_kex=True) self.event.wait(1.0) - self.assert_(self.event.isSet()) + self.assert_(self.event.is_set()) self.assert_(self.ts.is_active()) self.assertEquals(self.username, self.ts.get_username()) self.assertEquals(True, self.ts.is_authenticated()) diff --git a/tests/test_ssh_gss.py b/tests/test_ssh_gss.py index 99ccdc9c..e20d348f 100644 --- a/tests/test_ssh_gss.py +++ b/tests/test_ssh_gss.py @@ -102,7 +102,7 @@ class GSSAuthTest(unittest.TestCase): gss_auth=True) self.event.wait(1.0) - self.assert_(self.event.isSet()) + self.assert_(self.event.is_set()) self.assert_(self.ts.is_active()) self.assertEquals(self.username, self.ts.get_username()) self.assertEquals(True, self.ts.is_authenticated()) diff --git a/tests/test_transport.py b/tests/test_transport.py index 50b1d86b..dd522c4e 100644 --- a/tests/test_transport.py +++ b/tests/test_transport.py @@ -136,12 +136,12 @@ class TransportTest(unittest.TestCase): event = threading.Event() self.server = NullServer() - self.assertTrue(not event.isSet()) + self.assertTrue(not event.is_set()) self.ts.start_server(event, self.server) self.tc.connect(hostkey=public_host_key, username='slowdive', password='pygmalion') event.wait(1.0) - self.assertTrue(event.isSet()) + self.assertTrue(event.is_set()) self.assertTrue(self.ts.is_active()) def test_1_security_options(self): @@ -180,7 +180,7 @@ class TransportTest(unittest.TestCase): self.ts.add_server_key(host_key) event = threading.Event() server = NullServer() - self.assertTrue(not event.isSet()) + self.assertTrue(not event.is_set()) self.assertEqual(None, self.tc.get_username()) self.assertEqual(None, self.ts.get_username()) self.assertEqual(False, self.tc.is_authenticated()) @@ -189,7 +189,7 @@ class TransportTest(unittest.TestCase): self.tc.connect(hostkey=public_host_key, username='slowdive', password='pygmalion') event.wait(1.0) - self.assertTrue(event.isSet()) + self.assertTrue(event.is_set()) self.assertTrue(self.ts.is_active()) self.assertEqual('slowdive', self.tc.get_username()) self.assertEqual('slowdive', self.ts.get_username()) @@ -205,13 +205,13 @@ class TransportTest(unittest.TestCase): self.ts.add_server_key(host_key) event = threading.Event() server = NullServer() - self.assertTrue(not event.isSet()) + self.assertTrue(not event.is_set()) self.socks.send(LONG_BANNER) self.ts.start_server(event, server) self.tc.connect(hostkey=public_host_key, username='slowdive', password='pygmalion') event.wait(1.0) - self.assertTrue(event.isSet()) + self.assertTrue(event.is_set()) self.assertTrue(self.ts.is_active()) def test_4_special(self): @@ -680,7 +680,7 @@ class TransportTest(unittest.TestCase): def run(self): try: for i in range(1, 1+self.iterations): - if self.done_event.isSet(): + if self.done_event.is_set(): break self.watchdog_event.set() #print i, "SEND" @@ -699,7 +699,7 @@ class TransportTest(unittest.TestCase): def run(self): try: - while not self.done_event.isSet(): + while not self.done_event.is_set(): if self.chan.recv_ready(): chan.recv(65536) self.watchdog_event.set() @@ -753,12 +753,12 @@ class TransportTest(unittest.TestCase): # Act as a watchdog timer, checking deadlocked = False - while not deadlocked and not done_event.isSet(): + while not deadlocked and not done_event.is_set(): for event in (st.watchdog_event, rt.watchdog_event): event.wait(timeout) - if done_event.isSet(): + if done_event.is_set(): break - if not event.isSet(): + if not event.is_set(): deadlocked = True break event.clear() -- cgit v1.2.3