diff options
author | Yan Kalchevskiy <yan.kalchevskiy@gmail.com> | 2013-07-16 14:02:24 +0700 |
---|---|---|
committer | Yan Kalchevksiy <yan.kalchevskiy@gmail.com> | 2014-04-22 10:56:08 +0700 |
commit | 8a836942d545ffa44ed139099dfea4f96d336add (patch) | |
tree | ca45e71a0d9c9361414f3fe2dbe1aba8d03e4fd0 | |
parent | 417102dbea0fbe2f7df6c690ee610b2cc2c18b19 (diff) |
Add support quoted values for SSHConfig (#157)
-rw-r--r-- | paramiko/config.py | 54 | ||||
-rw-r--r-- | tests/test_util.py | 68 |
2 files changed, 108 insertions, 14 deletions
diff --git a/paramiko/config.py b/paramiko/config.py index 77fa13d7..28dc5231 100644 --- a/paramiko/config.py +++ b/paramiko/config.py @@ -53,6 +53,27 @@ class SSHConfig (object): :param file file_obj: a file-like object to read the config file from """ + def get_hosts(val): + i, length = 0, len(val) + hosts = [] + while i < length: + if val[i] == '"': + end = val.find('"', i + 1) + if end < 0: + raise Exception("Unparsable host %s" % val) + hosts.append(val[i + 1:end]) + i = end + 1 + elif not val[i].isspace(): + end = i + 1 + while end < length and not val[end].isspace(): + end += 1 + hosts.append(val[i:end]) + i = end + 1 + else: + i += 1 + + return hosts + host = {"host": ['*'], "config": {}} for line in file_obj: line = line.rstrip('\n').lstrip() @@ -75,22 +96,27 @@ class SSHConfig (object): raise Exception('Unparsable line: %r' % line) key = line[:i].lower() value = line[i:].lstrip() - + if key == 'host': self._config.append(host) - value = value.split() - host = {key: value, 'config': {}} - #identityfile, localforward, remoteforward keys are special cases, since they are allowed to be - # specified multiple times and they should be tried in order - # of specification. - - elif key in ['identityfile', 'localforward', 'remoteforward']: - if key in host['config']: - host['config'][key].append(value) - else: - host['config'][key] = [value] - elif key not in host['config']: - host['config'].update({key: value}) + host = { + 'host': get_hosts(value), + 'config': {} + } + else: + if value.startswith('"') and value.endswith('"'): + value = value[1:-1] + + #identityfile, localforward, remoteforward keys are special cases, since they are allowed to be + # specified multiple times and they should be tried in order + # of specification. + if key in ['identityfile', 'localforward', 'remoteforward']: + if key in host['config']: + host['config'][key].append(value) + else: + host['config'][key] = [value] + elif key not in host['config']: + host['config'][key] = value self._config.append(host) def lookup(self, hostname): diff --git a/tests/test_util.py b/tests/test_util.py index 69c75518..4e67e071 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -333,3 +333,71 @@ 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_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(): + self.assertEquals( + 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(): + self.assertEquals( + paramiko.util.lookup_ssh_host_config(host, config), + values + ) |