summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorYan Kalchevskiy <yan.kalchevskiy@gmail.com>2013-07-16 14:02:24 +0700
committerYan Kalchevksiy <yan.kalchevskiy@gmail.com>2014-04-22 10:56:08 +0700
commit8a836942d545ffa44ed139099dfea4f96d336add (patch)
treeca45e71a0d9c9361414f3fe2dbe1aba8d03e4fd0
parent417102dbea0fbe2f7df6c690ee610b2cc2c18b19 (diff)
Add support quoted values for SSHConfig (#157)
-rw-r--r--paramiko/config.py54
-rw-r--r--tests/test_util.py68
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
+ )