diff options
author | Jeff Forcier <jeff@bitprophet.org> | 2019-07-02 14:48:28 -0400 |
---|---|---|
committer | Jeff Forcier <jeff@bitprophet.org> | 2019-08-26 20:48:21 -0400 |
commit | c50f825aac15f878647ffb7533fdbe157399ca8b (patch) | |
tree | ec5197cf0a7ef4098b57a9b87ef4533e7f6f98b4 | |
parent | 426675482caaedffa2b39337a1e736956575dad2 (diff) |
Move all SSHConfig related tests to test_config.py
Includes cleanup of unittest-isms and migrating recently added
SSHConfigDict tests to a distinct class vs top-level funcs.
-rw-r--r-- | paramiko/config.py | 3 | ||||
-rw-r--r-- | tests/test_config.py | 467 | ||||
-rw-r--r-- | tests/test_util.py | 441 |
3 files changed, 445 insertions, 466 deletions
diff --git a/paramiko/config.py b/paramiko/config.py index aeb59593..af194452 100644 --- a/paramiko/config.py +++ b/paramiko/config.py @@ -27,6 +27,9 @@ import re import shlex import socket +from .py3compat import StringIO + + SSH_PORT = 22 diff --git a/tests/test_config.py b/tests/test_config.py index cbd3f623..903690f7 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1,74 +1,463 @@ # This file is part of Paramiko and subject to the license in /LICENSE in this # repository +from os.path import expanduser + import pytest +from pytest import raises, mark -from paramiko import config -from paramiko.util import parse_ssh_config from paramiko.py3compat import StringIO +from paramiko import SSHConfig, SSHConfigDict +from paramiko.util import lookup_ssh_host_config, parse_ssh_config -def test_SSHConfigDict_construct_empty(): - assert not config.SSHConfigDict() +# Note some lines in this configuration have trailing spaces on purpose +test_config_file = """\ +Host * + User robey + IdentityFile =~/.ssh/id_rsa -def test_SSHConfigDict_construct_from_list(): - assert config.SSHConfigDict([(1, 2)])[1] == 2 +# comment +Host *.example.com + \tUser bjork +Port=3333 +Host * +""" +dont_strip_whitespace_please = "\t \t Crazy something dumb " -def test_SSHConfigDict_construct_from_dict(): - assert config.SSHConfigDict({1: 2})[1] == 2 +test_config_file += dont_strip_whitespace_please +test_config_file += """ +Host spoo.example.com +Crazy something else +""" -@pytest.mark.parametrize("true_ish", ("yes", "YES", "Yes", True)) -def test_SSHConfigDict_as_bool_true_ish(true_ish): - assert config.SSHConfigDict({"key": true_ish}).as_bool("key") is True +class TestSSHConfig(object): + def test_parse_config(self): + global test_config_file + f = StringIO(test_config_file) + config = parse_ssh_config(f) + expected = [ + {"host": ["*"], "config": {}}, + { + "host": ["*"], + "config": {"identityfile": ["~/.ssh/id_rsa"], "user": "robey"}, + }, + { + "host": ["*.example.com"], + "config": {"user": "bjork", "port": "3333"}, + }, + {"host": ["*"], "config": {"crazy": "something dumb"}}, + { + "host": ["spoo.example.com"], + "config": {"crazy": "something else"}, + }, + ] + assert config._config == expected + def test_host_config(self): + global test_config_file + f = StringIO(test_config_file) + config = parse_ssh_config(f) -@pytest.mark.parametrize("false_ish", ("no", "NO", "No", False)) -def test_SSHConfigDict_as_bool(false_ish): - assert config.SSHConfigDict({"key": false_ish}).as_bool("key") is False + for host, values in { + "irc.danger.com": { + "crazy": "something dumb", + "hostname": "irc.danger.com", + "user": "robey", + }, + "irc.example.com": { + "crazy": "something dumb", + "hostname": "irc.example.com", + "user": "robey", + "port": "3333", + }, + "spoo.example.com": { + "crazy": "something dumb", + "hostname": "spoo.example.com", + "user": "robey", + "port": "3333", + }, + }.items(): + values = dict( + values, + hostname=host, + identityfile=[expanduser("~/.ssh/id_rsa")], + ) + assert lookup_ssh_host_config(host, config) == values + def test_host_config_expose_fabric_issue_33(self): + test_config_file = """ +Host www13.* + Port 22 -@pytest.mark.parametrize("int_val", ("42", 42)) -def test_SSHConfigDict_as_int(int_val): - assert config.SSHConfigDict({"key": int_val}).as_int("key") == 42 +Host *.example.com + Port 2222 +Host * + Port 3333 + """ + f = StringIO(test_config_file) + config = parse_ssh_config(f) + host = "www13.example.com" + expected = {"hostname": host, "port": "22"} + assert lookup_ssh_host_config(host, config) == expected -@pytest.mark.parametrize("non_int", ("not an int", None, object())) -def test_SSHConfigDict_as_int_failures(non_int): - conf = config.SSHConfigDict({"key": non_int}) + def test_proxycommand_config_equals_parsing(self): + """ + ProxyCommand should not split on equals signs within the value. + """ + conf = """ +Host space-delimited + ProxyCommand foo bar=biz baz - try: - int(non_int) - except Exception as e: - exception_type = type(e) +Host equals-delimited + ProxyCommand=foo bar=biz baz +""" + f = StringIO(conf) + config = parse_ssh_config(f) + for host in ("space-delimited", "equals-delimited"): + value = lookup_ssh_host_config(host, config)["proxycommand"] + assert value == "foo bar=biz baz" - with pytest.raises(exception_type): - conf.as_int("key") + def test_proxycommand_interpolation(self): + """ + ProxyCommand should perform interpolation on the value + """ + config = parse_ssh_config( + StringIO( + """ +Host specific + Port 37 + ProxyCommand host %h port %p lol +Host portonly + Port 155 -def test_SSHConfig_host_dicts_are_SSHConfigDict_instances(): - test_config_file = """ -Host *.example.com +Host * + Port 25 + ProxyCommand host %h port %p +""" + ) + ) + for host, val in ( + ("foo.com", "host foo.com port 25"), + ("specific", "host specific port 37 lol"), + ("portonly", "host portonly port 155"), + ): + assert lookup_ssh_host_config(host, config)["proxycommand"] == val + + def test_proxycommand_tilde_expansion(self): + """ + Tilde (~) should be expanded inside ProxyCommand + """ + config = parse_ssh_config( + StringIO( + """ +Host test + ProxyCommand ssh -F ~/.ssh/test_config bastion nc %h %p +""" + ) + ) + expected = "ssh -F {}/.ssh/test_config bastion nc test 22".format( + expanduser("~") + ) + got = lookup_ssh_host_config("test", config)["proxycommand"] + assert got == expected + + def test_host_config_test_negation(self): + test_config_file = """ +Host www13.* !*.example.com + Port 22 + +Host *.example.com !www13.* Port 2222 +Host www13.* + Port 8080 + Host * Port 3333 """ - f = StringIO(test_config_file) - config = parse_ssh_config(f) - assert config.lookup("foo.example.com").as_int("port") == 2222 + f = StringIO(test_config_file) + config = parse_ssh_config(f) + host = "www13.example.com" + expected = {"hostname": host, "port": "8080"} + assert lookup_ssh_host_config(host, config) == expected + def test_host_config_test_proxycommand(self): + test_config_file = """ +Host proxy-with-equal-divisor-and-space +ProxyCommand = foo=bar -def test_SSHConfig_wildcard_host_dicts_are_SSHConfigDict_instances(): - test_config_file = """\ -Host *.example.com - Port 2222 +Host proxy-with-equal-divisor-and-no-space +ProxyCommand=foo=bar + +Host proxy-without-equal-divisor +ProxyCommand foo=bar:%h-%p + """ + for host, values in { + "proxy-with-equal-divisor-and-space": { + "hostname": "proxy-with-equal-divisor-and-space", + "proxycommand": "foo=bar", + }, + "proxy-with-equal-divisor-and-no-space": { + "hostname": "proxy-with-equal-divisor-and-no-space", + "proxycommand": "foo=bar", + }, + "proxy-without-equal-divisor": { + "hostname": "proxy-without-equal-divisor", + "proxycommand": "foo=bar:proxy-without-equal-divisor-22", + }, + }.items(): + + f = StringIO(test_config_file) + config = parse_ssh_config(f) + assert lookup_ssh_host_config(host, config) == values + + def test_host_config_test_identityfile(self): + test_config_file = """ + +IdentityFile id_dsa0 Host * +IdentityFile id_dsa1 + +Host dsa2 +IdentityFile id_dsa2 + +Host dsa2* +IdentityFile id_dsa22 + """ + for host, values in { + "foo": {"hostname": "foo", "identityfile": ["id_dsa0", "id_dsa1"]}, + "dsa2": { + "hostname": "dsa2", + "identityfile": ["id_dsa0", "id_dsa1", "id_dsa2", "id_dsa22"], + }, + "dsa22": { + "hostname": "dsa22", + "identityfile": ["id_dsa0", "id_dsa1", "id_dsa22"], + }, + }.items(): + + f = StringIO(test_config_file) + config = parse_ssh_config(f) + assert lookup_ssh_host_config(host, config) == values + + def test_config_addressfamily_and_lazy_fqdn(self): + """ + Ensure the code path honoring non-'all' AddressFamily doesn't asplode + """ + test_config = """ +AddressFamily inet +IdentityFile something_%l_using_fqdn +""" + config = parse_ssh_config(StringIO(test_config)) + assert config.lookup( + "meh" + ) # will die during lookup() if bug regresses + + def test_config_dos_crlf_succeeds(self): + config_file = StringIO("host abcqwerty\r\nHostName 127.0.0.1\r\n") + config = SSHConfig() + config.parse(config_file) + assert config.lookup("abcqwerty")["hostname"] == "127.0.0.1" + + def test_get_hostnames(self): + f = StringIO(test_config_file) + config = parse_ssh_config(f) + expected = {"*", "*.example.com", "spoo.example.com"} + assert config.get_hostnames() == expected + + def test_quoted_host_names(self): + test_config_file = """\ +Host "param pam" param "pam" + Port 1111 + +Host "param2" + Port 2222 + +Host param3 parara Port 3333 + +Host param4 "p a r" "p" "par" para + Port 4444 +""" + res = { + "param pam": {"hostname": "param pam", "port": "1111"}, + "param": {"hostname": "param", "port": "1111"}, + "pam": {"hostname": "pam", "port": "1111"}, + "param2": {"hostname": "param2", "port": "2222"}, + "param3": {"hostname": "param3", "port": "3333"}, + "parara": {"hostname": "parara", "port": "3333"}, + "param4": {"hostname": "param4", "port": "4444"}, + "p a r": {"hostname": "p a r", "port": "4444"}, + "p": {"hostname": "p", "port": "4444"}, + "par": {"hostname": "par", "port": "4444"}, + "para": {"hostname": "para", "port": "4444"}, + } + f = StringIO(test_config_file) + config = parse_ssh_config(f) + for host, values in res.items(): + assert lookup_ssh_host_config(host, config) == values + + def test_quoted_params_in_config(self): + test_config_file = """\ +Host "param pam" param "pam" + IdentityFile id_rsa + +Host "param2" + IdentityFile "test rsa key" + +Host param3 parara + IdentityFile id_rsa + IdentityFile "test rsa key" +""" + res = { + "param pam": {"hostname": "param pam", "identityfile": ["id_rsa"]}, + "param": {"hostname": "param", "identityfile": ["id_rsa"]}, + "pam": {"hostname": "pam", "identityfile": ["id_rsa"]}, + "param2": {"hostname": "param2", "identityfile": ["test rsa key"]}, + "param3": { + "hostname": "param3", + "identityfile": ["id_rsa", "test rsa key"], + }, + "parara": { + "hostname": "parara", + "identityfile": ["id_rsa", "test rsa key"], + }, + } + f = StringIO(test_config_file) + config = parse_ssh_config(f) + for host, values in res.items(): + assert lookup_ssh_host_config(host, config) == values + + def test_quoted_host_in_config(self): + conf = SSHConfig() + correct_data = { + "param": ["param"], + '"param"': ["param"], + "param pam": ["param", "pam"], + '"param" "pam"': ["param", "pam"], + '"param" pam': ["param", "pam"], + 'param "pam"': ["param", "pam"], + 'param "pam" p': ["param", "pam", "p"], + '"param" pam "p"': ["param", "pam", "p"], + '"pa ram"': ["pa ram"], + '"pa ram" pam': ["pa ram", "pam"], + 'param "p a m"': ["param", "p a m"], + } + incorrect_data = ['param"', '"param', 'param "pam', 'param "pam" "p a'] + for host, values in correct_data.items(): + assert conf._get_hosts(host) == values + for host in incorrect_data: + with raises(Exception): + conf._get_hosts(host) + + def test_proxycommand_none_issue_418(self): + test_config_file = """ +Host proxycommand-standard-none + ProxyCommand None + +Host proxycommand-with-equals-none + ProxyCommand=None """ - f = StringIO(test_config_file) - config = parse_ssh_config(f) - assert config.lookup("anything-else").as_int("port") == 3333 + for host, values in { + "proxycommand-standard-none": { + "hostname": "proxycommand-standard-none" + }, + "proxycommand-with-equals-none": { + "hostname": "proxycommand-with-equals-none" + }, + }.items(): + + f = StringIO(test_config_file) + config = parse_ssh_config(f) + assert lookup_ssh_host_config(host, config) == values + + def test_proxycommand_none_masking(self): + # Re: https://github.com/paramiko/paramiko/issues/670 + source_config = """ +Host specific-host + ProxyCommand none + +Host other-host + ProxyCommand other-proxy + +Host * + ProxyCommand default-proxy +""" + config = SSHConfig() + config.parse(StringIO(source_config)) + # When bug is present, the full stripping-out of specific-host's + # ProxyCommand means it actually appears to pick up the default + # ProxyCommand value instead, due to cascading. It should (for + # backwards compatibility reasons in 1.x/2.x) appear completely blank, + # as if the host had no ProxyCommand whatsoever. + # Threw another unrelated host in there just for sanity reasons. + assert "proxycommand" not in config.lookup("specific-host") + assert config.lookup("other-host")["proxycommand"] == "other-proxy" + cmd = config.lookup("some-random-host")["proxycommand"] + assert cmd == "default-proxy" + + +class TestSSHConfigDict(object): + def test_SSHConfigDict_construct_empty(self): + assert not SSHConfigDict() + + def test_SSHConfigDict_construct_from_list(self): + assert SSHConfigDict([(1, 2)])[1] == 2 + + def test_SSHConfigDict_construct_from_dict(self): + assert SSHConfigDict({1: 2})[1] == 2 + + @mark.parametrize("true_ish", ("yes", "YES", "Yes", True)) + def test_SSHConfigDict_as_bool_true_ish(self, true_ish): + assert SSHConfigDict({"key": true_ish}).as_bool("key") is True + + @mark.parametrize("false_ish", ("no", "NO", "No", False)) + def test_SSHConfigDict_as_bool(self, false_ish): + assert SSHConfigDict({"key": false_ish}).as_bool("key") is False + + @mark.parametrize("int_val", ("42", 42)) + def test_SSHConfigDict_as_int(self, int_val): + assert SSHConfigDict({"key": int_val}).as_int("key") == 42 + + @mark.parametrize("non_int", ("not an int", None, object())) + def test_SSHConfigDict_as_int_failures(self, non_int): + conf = SSHConfigDict({"key": non_int}) + + try: + int(non_int) + except Exception as e: + exception_type = type(e) + + with raises(exception_type): + conf.as_int("key") + + def test_SSHConfig_host_dicts_are_SSHConfigDict_instances(self): + test_config_file = """ + Host *.example.com + Port 2222 + + Host * + Port 3333 + """ + f = StringIO(test_config_file) + config = parse_ssh_config(f) + assert config.lookup("foo.example.com").as_int("port") == 2222 + + def test_SSHConfig_wildcard_host_dicts_are_SSHConfigDict_instances(self): + test_config_file = """\ + Host *.example.com + Port 2222 + + Host * + Port 3333 + """ + f = StringIO(test_config_file) + config = parse_ssh_config(f) + assert config.lookup("anything-else").as_int("port") == 3333 diff --git a/tests/test_util.py b/tests/test_util.py index 695608cb..0cc9b220 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -28,32 +28,10 @@ import unittest import paramiko import paramiko.util -from paramiko import SSHConfig -from paramiko.util import lookup_ssh_host_config as host_config, safe_string -from paramiko.py3compat import StringIO, byte_ord +from paramiko.util import safe_string +from paramiko.py3compat import byte_ord -# Note some lines in this configuration have trailing spaces on purpose -test_config_file = """\ -Host * - User robey - IdentityFile =~/.ssh/id_rsa - -# comment -Host *.example.com - \tUser bjork -Port=3333 -Host * -""" - -dont_strip_whitespace_please = "\t \t Crazy something dumb " - -test_config_file += dont_strip_whitespace_please -test_config_file += """ -Host spoo.example.com -Crazy something else -""" - test_hosts_file = """\ secure.example.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA1PD6U2/TVxET6lkpKhOk5r\ 9q/kAYG6sP9f5zuUYP8i7FOFp/6ncCEbbtg/lB+A3iidyxoSWl+9jtoyyDOOVX4UIDV9G11Ml8om3\ @@ -104,112 +82,31 @@ class UtilTest(unittest.TestCase): self.assertTrue("SSHConfigDict" in symbols) self.assertTrue("util" in symbols) - def test_parse_config(self): - global test_config_file - f = StringIO(test_config_file) - config = paramiko.util.parse_ssh_config(f) - self.assertEqual( - config._config, - [ - {"host": ["*"], "config": {}}, - { - "host": ["*"], - "config": { - "identityfile": ["~/.ssh/id_rsa"], - "user": "robey", - }, - }, - { - "host": ["*.example.com"], - "config": {"user": "bjork", "port": "3333"}, - }, - {"host": ["*"], "config": {"crazy": "something dumb"}}, - { - "host": ["spoo.example.com"], - "config": {"crazy": "something else"}, - }, - ], - ) - - def test_host_config(self): - global test_config_file - f = StringIO(test_config_file) - config = paramiko.util.parse_ssh_config(f) - - for host, values in { - "irc.danger.com": { - "crazy": "something dumb", - "hostname": "irc.danger.com", - "user": "robey", - }, - "irc.example.com": { - "crazy": "something dumb", - "hostname": "irc.example.com", - "user": "robey", - "port": "3333", - }, - "spoo.example.com": { - "crazy": "something dumb", - "hostname": "spoo.example.com", - "user": "robey", - "port": "3333", - }, - }.items(): - values = dict( - values, - hostname=host, - identityfile=[os.path.expanduser("~/.ssh/id_rsa")], - ) - self.assertEqual( - paramiko.util.lookup_ssh_host_config(host, config), values - ) - def test_generate_key_bytes(self): x = paramiko.util.generate_key_bytes( sha1, b"ABCDEFGH", "This is my secret passphrase.", 64 ) hex = "".join(["%02x" % byte_ord(c) for c in x]) - self.assertEqual( - hex, - "9110e2f6793b69363e58173e9436b13a5a4b339005741d5c680e505f57d871347b4239f14fb5c46e857d5e100424873ba849ac699cea98d729e57b3e84378e8b", # noqa - ) + hexpected = "9110e2f6793b69363e58173e9436b13a5a4b339005741d5c680e505f57d871347b4239f14fb5c46e857d5e100424873ba849ac699cea98d729e57b3e84378e8b" # noqa + assert hex == hexpected def test_host_keys(self): with open("hostfile.temp", "w") as f: f.write(test_hosts_file) try: hostdict = paramiko.util.load_host_keys("hostfile.temp") - self.assertEqual(2, len(hostdict)) - self.assertEqual(1, len(list(hostdict.values())[0])) - self.assertEqual(1, len(list(hostdict.values())[1])) + assert 2 == len(hostdict) + assert 1 == len(list(hostdict.values())[0]) + assert 1 == len(list(hostdict.values())[1]) fp = hexlify( hostdict["secure.example.com"]["ssh-rsa"].get_fingerprint() ).upper() - self.assertEqual(b"E6684DB30E109B67B70FF1DC5C7F1363", fp) + assert b"E6684DB30E109B67B70FF1DC5C7F1363" == fp finally: os.unlink("hostfile.temp") - def test_host_config_expose_issue_33(self): - test_config_file = """ -Host www13.* - Port 22 - -Host *.example.com - Port 2222 - -Host * - Port 3333 - """ - f = StringIO(test_config_file) - config = paramiko.util.parse_ssh_config(f) - host = "www13.example.com" - self.assertEqual( - paramiko.util.lookup_ssh_host_config(host, config), - {"hostname": host, "port": "22"}, - ) - def test_eintr_retry(self): - self.assertEqual("foo", paramiko.util.retry_on_signal(lambda: "foo")) + assert "foo" == paramiko.util.retry_on_signal(lambda: "foo") # Variables that are set by raises_intr intr_errors_remaining = [3] @@ -222,8 +119,8 @@ Host * raise IOError(errno.EINTR, "file", "interrupted system call") self.assertTrue(paramiko.util.retry_on_signal(raises_intr) is None) - self.assertEqual(0, intr_errors_remaining[0]) - self.assertEqual(4, call_count[0]) + assert 0 == intr_errors_remaining[0] + assert 4 == call_count[0] def raises_ioerror_not_eintr(): raise IOError(errno.ENOENT, "file", "file not found") @@ -241,269 +138,10 @@ Host * lambda: paramiko.util.retry_on_signal(raises_other_exception), ) - def test_proxycommand_config_equals_parsing(self): - """ - ProxyCommand should not split on equals signs within the value. - """ - conf = """ -Host space-delimited - ProxyCommand foo bar=biz baz - -Host equals-delimited - ProxyCommand=foo bar=biz baz -""" - f = StringIO(conf) - config = paramiko.util.parse_ssh_config(f) - for host in ("space-delimited", "equals-delimited"): - self.assertEqual( - host_config(host, config)["proxycommand"], "foo bar=biz baz" - ) - - def test_proxycommand_interpolation(self): - """ - ProxyCommand should perform interpolation on the value - """ - config = paramiko.util.parse_ssh_config( - StringIO( - """ -Host specific - Port 37 - ProxyCommand host %h port %p lol - -Host portonly - Port 155 - -Host * - Port 25 - ProxyCommand host %h port %p -""" - ) - ) - for host, val in ( - ("foo.com", "host foo.com port 25"), - ("specific", "host specific port 37 lol"), - ("portonly", "host portonly port 155"), - ): - self.assertEqual(host_config(host, config)["proxycommand"], val) - - def test_proxycommand_tilde_expansion(self): - """ - Tilde (~) should be expanded inside ProxyCommand - """ - config = paramiko.util.parse_ssh_config( - StringIO( - """ -Host test - ProxyCommand ssh -F ~/.ssh/test_config bastion nc %h %p -""" - ) - ) - self.assertEqual( - "ssh -F %s/.ssh/test_config bastion nc test 22" - % os.path.expanduser("~"), - host_config("test", config)["proxycommand"], - ) - - def test_host_config_test_negation(self): - test_config_file = """ -Host www13.* !*.example.com - Port 22 - -Host *.example.com !www13.* - Port 2222 - -Host www13.* - Port 8080 - -Host * - Port 3333 - """ - f = StringIO(test_config_file) - config = paramiko.util.parse_ssh_config(f) - host = "www13.example.com" - self.assertEqual( - paramiko.util.lookup_ssh_host_config(host, config), - {"hostname": host, "port": "8080"}, - ) - - def test_host_config_test_proxycommand(self): - test_config_file = """ -Host proxy-with-equal-divisor-and-space -ProxyCommand = foo=bar - -Host proxy-with-equal-divisor-and-no-space -ProxyCommand=foo=bar - -Host proxy-without-equal-divisor -ProxyCommand foo=bar:%h-%p - """ - for host, values in { - "proxy-with-equal-divisor-and-space": { - "hostname": "proxy-with-equal-divisor-and-space", - "proxycommand": "foo=bar", - }, - "proxy-with-equal-divisor-and-no-space": { - "hostname": "proxy-with-equal-divisor-and-no-space", - "proxycommand": "foo=bar", - }, - "proxy-without-equal-divisor": { - "hostname": "proxy-without-equal-divisor", - "proxycommand": "foo=bar:proxy-without-equal-divisor-22", - }, - }.items(): - - f = StringIO(test_config_file) - config = paramiko.util.parse_ssh_config(f) - self.assertEqual( - paramiko.util.lookup_ssh_host_config(host, config), values - ) - - def test_host_config_test_identityfile(self): - test_config_file = """ - -IdentityFile id_dsa0 - -Host * -IdentityFile id_dsa1 - -Host dsa2 -IdentityFile id_dsa2 - -Host dsa2* -IdentityFile id_dsa22 - """ - for host, values in { - "foo": {"hostname": "foo", "identityfile": ["id_dsa0", "id_dsa1"]}, - "dsa2": { - "hostname": "dsa2", - "identityfile": ["id_dsa0", "id_dsa1", "id_dsa2", "id_dsa22"], - }, - "dsa22": { - "hostname": "dsa22", - "identityfile": ["id_dsa0", "id_dsa1", "id_dsa22"], - }, - }.items(): - - f = StringIO(test_config_file) - config = paramiko.util.parse_ssh_config(f) - self.assertEqual( - paramiko.util.lookup_ssh_host_config(host, config), values - ) - - def test_config_addressfamily_and_lazy_fqdn(self): - """ - Ensure the code path honoring non-'all' AddressFamily doesn't asplode - """ - test_config = """ -AddressFamily inet -IdentityFile something_%l_using_fqdn -""" - config = paramiko.util.parse_ssh_config(StringIO(test_config)) - assert config.lookup( - "meh" - ) # will die during lookup() if bug regresses - def test_clamp_value(self): - self.assertEqual(32768, paramiko.util.clamp_value(32767, 32768, 32769)) - self.assertEqual(32767, paramiko.util.clamp_value(32767, 32765, 32769)) - self.assertEqual(32769, paramiko.util.clamp_value(32767, 32770, 32769)) - - def test_config_dos_crlf_succeeds(self): - config_file = StringIO("host abcqwerty\r\nHostName 127.0.0.1\r\n") - config = paramiko.SSHConfig() - config.parse(config_file) - self.assertEqual(config.lookup("abcqwerty")["hostname"], "127.0.0.1") - - def test_get_hostnames(self): - f = StringIO(test_config_file) - config = paramiko.util.parse_ssh_config(f) - self.assertEqual( - config.get_hostnames(), {"*", "*.example.com", "spoo.example.com"} - ) - - def test_quoted_host_names(self): - test_config_file = """\ -Host "param pam" param "pam" - Port 1111 - -Host "param2" - Port 2222 - -Host param3 parara - Port 3333 - -Host param4 "p a r" "p" "par" para - Port 4444 -""" - res = { - "param pam": {"hostname": "param pam", "port": "1111"}, - "param": {"hostname": "param", "port": "1111"}, - "pam": {"hostname": "pam", "port": "1111"}, - "param2": {"hostname": "param2", "port": "2222"}, - "param3": {"hostname": "param3", "port": "3333"}, - "parara": {"hostname": "parara", "port": "3333"}, - "param4": {"hostname": "param4", "port": "4444"}, - "p a r": {"hostname": "p a r", "port": "4444"}, - "p": {"hostname": "p", "port": "4444"}, - "par": {"hostname": "par", "port": "4444"}, - "para": {"hostname": "para", "port": "4444"}, - } - f = StringIO(test_config_file) - config = paramiko.util.parse_ssh_config(f) - for host, values in res.items(): - assert paramiko.util.lookup_ssh_host_config(host, config) == values - - def test_quoted_params_in_config(self): - test_config_file = """\ -Host "param pam" param "pam" - IdentityFile id_rsa - -Host "param2" - IdentityFile "test rsa key" - -Host param3 parara - IdentityFile id_rsa - IdentityFile "test rsa key" -""" - res = { - "param pam": {"hostname": "param pam", "identityfile": ["id_rsa"]}, - "param": {"hostname": "param", "identityfile": ["id_rsa"]}, - "pam": {"hostname": "pam", "identityfile": ["id_rsa"]}, - "param2": {"hostname": "param2", "identityfile": ["test rsa key"]}, - "param3": { - "hostname": "param3", - "identityfile": ["id_rsa", "test rsa key"], - }, - "parara": { - "hostname": "parara", - "identityfile": ["id_rsa", "test rsa key"], - }, - } - f = StringIO(test_config_file) - config = paramiko.util.parse_ssh_config(f) - for host, values in res.items(): - assert paramiko.util.lookup_ssh_host_config(host, config) == values - - def test_quoted_host_in_config(self): - conf = SSHConfig() - correct_data = { - "param": ["param"], - '"param"': ["param"], - "param pam": ["param", "pam"], - '"param" "pam"': ["param", "pam"], - '"param" pam': ["param", "pam"], - 'param "pam"': ["param", "pam"], - 'param "pam" p': ["param", "pam", "p"], - '"param" pam "p"': ["param", "pam", "p"], - '"pa ram"': ["pa ram"], - '"pa ram" pam': ["pa ram", "pam"], - 'param "p a m"': ["param", "p a m"], - } - incorrect_data = ['param"', '"param', 'param "pam', 'param "pam" "p a'] - for host, values in correct_data.items(): - assert conf._get_hosts(host) == values - for host in incorrect_data: - self.assertRaises(Exception, conf._get_hosts, host) + assert 32768 == paramiko.util.clamp_value(32767, 32768, 32769) + assert 32767 == paramiko.util.clamp_value(32767, 32765, 32769) + assert 32769 == paramiko.util.clamp_value(32767, 32770, 32769) def test_safe_string(self): vanilla = b"vanilla" @@ -516,54 +154,3 @@ Host param3 parara assert safe_vanilla == vanilla, msg msg = err.format(safe_has_bytes, expected_bytes) assert safe_has_bytes == expected_bytes, msg - - def test_proxycommand_none_issue_418(self): - test_config_file = """ -Host proxycommand-standard-none - ProxyCommand None - -Host proxycommand-with-equals-none - ProxyCommand=None - """ - for host, values in { - "proxycommand-standard-none": { - "hostname": "proxycommand-standard-none" - }, - "proxycommand-with-equals-none": { - "hostname": "proxycommand-with-equals-none" - }, - }.items(): - - f = StringIO(test_config_file) - config = paramiko.util.parse_ssh_config(f) - self.assertEqual( - paramiko.util.lookup_ssh_host_config(host, config), values - ) - - def test_proxycommand_none_masking(self): - # Re: https://github.com/paramiko/paramiko/issues/670 - source_config = """ -Host specific-host - ProxyCommand none - -Host other-host - ProxyCommand other-proxy - -Host * - ProxyCommand default-proxy -""" - config = paramiko.SSHConfig() - config.parse(StringIO(source_config)) - # When bug is present, the full stripping-out of specific-host's - # ProxyCommand means it actually appears to pick up the default - # ProxyCommand value instead, due to cascading. It should (for - # backwards compatibility reasons in 1.x/2.x) appear completely blank, - # as if the host had no ProxyCommand whatsoever. - # Threw another unrelated host in there just for sanity reasons. - self.assertFalse("proxycommand" in config.lookup("specific-host")) - self.assertEqual( - config.lookup("other-host")["proxycommand"], "other-proxy" - ) - self.assertEqual( - config.lookup("some-random-host")["proxycommand"], "default-proxy" - ) |