ssh config: do environment variable replacement
OpenSSH 8.4 has introduced simple environment variable substitution for some keys. Implement that feature in our ssh config file parser, too. Bug: 572103 Change-Id: I360f2c5510eea4ec3329aeedf3d29dfefc9163f0 Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
This commit is contained in:
parent
8edde18c8c
commit
1de2a9fbe7
|
@ -58,6 +58,7 @@ public void setUp() throws Exception {
|
||||||
FileUtils.mkdir(configFile.getParentFile());
|
FileUtils.mkdir(configFile.getParentFile());
|
||||||
|
|
||||||
mockSystemReader.setProperty(Constants.OS_USER_NAME_KEY, "jex_junit");
|
mockSystemReader.setProperty(Constants.OS_USER_NAME_KEY, "jex_junit");
|
||||||
|
mockSystemReader.setProperty("TST_VAR", "TEST");
|
||||||
osc = new OpenSshConfig(home, configFile);
|
osc = new OpenSshConfig(home, configFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -497,4 +498,23 @@ public void testEolComments() throws Exception {
|
||||||
assertEquals("^ssh-rsa",
|
assertEquals("^ssh-rsa",
|
||||||
c.getValue(SshConstants.PUBKEY_ACCEPTED_ALGORITHMS));
|
c.getValue(SshConstants.PUBKEY_ACCEPTED_ALGORITHMS));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnVarSubstitution() throws Exception {
|
||||||
|
config("Host orcz\nIdentityFile /tmp/${TST_VAR}\n"
|
||||||
|
+ "CertificateFile /tmp/${}/foo\nUser ${TST_VAR}\nIdentityAgent /tmp/${TST_VAR/bar");
|
||||||
|
Host h = osc.lookup("orcz");
|
||||||
|
assertNotNull(h);
|
||||||
|
Config c = h.getConfig();
|
||||||
|
assertEquals("/tmp/TEST",
|
||||||
|
c.getValue(SshConstants.IDENTITY_FILE));
|
||||||
|
// No variable name
|
||||||
|
assertEquals("/tmp/${}/foo", c.getValue(SshConstants.CERTIFICATE_FILE));
|
||||||
|
// User doesn't get env var substitution:
|
||||||
|
assertEquals("${TST_VAR}", c.getValue(SshConstants.USER));
|
||||||
|
assertEquals("${TST_VAR}", h.getUser());
|
||||||
|
// Unterminated:
|
||||||
|
assertEquals("/tmp/${TST_VAR/bar",
|
||||||
|
c.getValue(SshConstants.IDENTITY_AGENT));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -708,10 +708,10 @@ void merge(HostEntry entry) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> substitute(List<String> values, String allowed,
|
private List<String> substitute(List<String> values, String allowed,
|
||||||
Replacer r) {
|
Replacer r, boolean withEnv) {
|
||||||
List<String> result = new ArrayList<>(values.size());
|
List<String> result = new ArrayList<>(values.size());
|
||||||
for (String value : values) {
|
for (String value : values) {
|
||||||
result.add(r.substitute(value, allowed));
|
result.add(r.substitute(value, allowed, withEnv));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -743,7 +743,7 @@ void substitute(String originalHostName, int port, String userName,
|
||||||
if (hostName == null || hostName.isEmpty()) {
|
if (hostName == null || hostName.isEmpty()) {
|
||||||
options.put(SshConstants.HOST_NAME, originalHostName);
|
options.put(SshConstants.HOST_NAME, originalHostName);
|
||||||
} else {
|
} else {
|
||||||
hostName = r.substitute(hostName, "h"); //$NON-NLS-1$
|
hostName = r.substitute(hostName, "h", false); //$NON-NLS-1$
|
||||||
options.put(SshConstants.HOST_NAME, hostName);
|
options.put(SshConstants.HOST_NAME, hostName);
|
||||||
r.update('h', hostName);
|
r.update('h', hostName);
|
||||||
}
|
}
|
||||||
|
@ -752,13 +752,13 @@ void substitute(String originalHostName, int port, String userName,
|
||||||
List<String> values = multiOptions
|
List<String> values = multiOptions
|
||||||
.get(SshConstants.IDENTITY_FILE);
|
.get(SshConstants.IDENTITY_FILE);
|
||||||
if (values != null) {
|
if (values != null) {
|
||||||
values = substitute(values, "dhlru", r); //$NON-NLS-1$
|
values = substitute(values, "dhlru", r, true); //$NON-NLS-1$
|
||||||
values = replaceTilde(values, home);
|
values = replaceTilde(values, home);
|
||||||
multiOptions.put(SshConstants.IDENTITY_FILE, values);
|
multiOptions.put(SshConstants.IDENTITY_FILE, values);
|
||||||
}
|
}
|
||||||
values = multiOptions.get(SshConstants.CERTIFICATE_FILE);
|
values = multiOptions.get(SshConstants.CERTIFICATE_FILE);
|
||||||
if (values != null) {
|
if (values != null) {
|
||||||
values = substitute(values, "dhlru", r); //$NON-NLS-1$
|
values = substitute(values, "dhlru", r, true); //$NON-NLS-1$
|
||||||
values = replaceTilde(values, home);
|
values = replaceTilde(values, home);
|
||||||
multiOptions.put(SshConstants.CERTIFICATE_FILE, values);
|
multiOptions.put(SshConstants.CERTIFICATE_FILE, values);
|
||||||
}
|
}
|
||||||
|
@ -775,29 +775,29 @@ void substitute(String originalHostName, int port, String userName,
|
||||||
// HOSTNAME already done above
|
// HOSTNAME already done above
|
||||||
String value = options.get(SshConstants.IDENTITY_AGENT);
|
String value = options.get(SshConstants.IDENTITY_AGENT);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
value = r.substitute(value, "dhlru"); //$NON-NLS-1$
|
value = r.substitute(value, "dhlru", true); //$NON-NLS-1$
|
||||||
value = toFile(value, home).getPath();
|
value = toFile(value, home).getPath();
|
||||||
options.put(SshConstants.IDENTITY_AGENT, value);
|
options.put(SshConstants.IDENTITY_AGENT, value);
|
||||||
}
|
}
|
||||||
value = options.get(SshConstants.CONTROL_PATH);
|
value = options.get(SshConstants.CONTROL_PATH);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
value = r.substitute(value, "ChLlnpru"); //$NON-NLS-1$
|
value = r.substitute(value, "ChLlnpru", true); //$NON-NLS-1$
|
||||||
value = toFile(value, home).getPath();
|
value = toFile(value, home).getPath();
|
||||||
options.put(SshConstants.CONTROL_PATH, value);
|
options.put(SshConstants.CONTROL_PATH, value);
|
||||||
}
|
}
|
||||||
value = options.get(SshConstants.LOCAL_COMMAND);
|
value = options.get(SshConstants.LOCAL_COMMAND);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
value = r.substitute(value, "CdhlnprTu"); //$NON-NLS-1$
|
value = r.substitute(value, "CdhlnprTu", false); //$NON-NLS-1$
|
||||||
options.put(SshConstants.LOCAL_COMMAND, value);
|
options.put(SshConstants.LOCAL_COMMAND, value);
|
||||||
}
|
}
|
||||||
value = options.get(SshConstants.REMOTE_COMMAND);
|
value = options.get(SshConstants.REMOTE_COMMAND);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
value = r.substitute(value, "Cdhlnpru"); //$NON-NLS-1$
|
value = r.substitute(value, "Cdhlnpru", false); //$NON-NLS-1$
|
||||||
options.put(SshConstants.REMOTE_COMMAND, value);
|
options.put(SshConstants.REMOTE_COMMAND, value);
|
||||||
}
|
}
|
||||||
value = options.get(SshConstants.PROXY_COMMAND);
|
value = options.get(SshConstants.PROXY_COMMAND);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
value = r.substitute(value, "hpr"); //$NON-NLS-1$
|
value = r.substitute(value, "hpr", false); //$NON-NLS-1$
|
||||||
options.put(SshConstants.PROXY_COMMAND, value);
|
options.put(SshConstants.PROXY_COMMAND, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -871,7 +871,7 @@ public Replacer(String host, int port, String user,
|
||||||
replacements.put(Character.valueOf('r'), user == null ? "" : user); //$NON-NLS-1$
|
replacements.put(Character.valueOf('r'), user == null ? "" : user); //$NON-NLS-1$
|
||||||
replacements.put(Character.valueOf('u'), localUserName);
|
replacements.put(Character.valueOf('u'), localUserName);
|
||||||
replacements.put(Character.valueOf('C'),
|
replacements.put(Character.valueOf('C'),
|
||||||
substitute("%l%h%p%r", "hlpr")); //$NON-NLS-1$ //$NON-NLS-2$
|
substitute("%l%h%p%r", "hlpr", false)); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
replacements.put(Character.valueOf('T'), "NONE"); //$NON-NLS-1$
|
replacements.put(Character.valueOf('T'), "NONE"); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -879,36 +879,63 @@ public void update(char key, String value) {
|
||||||
replacements.put(Character.valueOf(key), value);
|
replacements.put(Character.valueOf(key), value);
|
||||||
if ("lhpr".indexOf(key) >= 0) { //$NON-NLS-1$
|
if ("lhpr".indexOf(key) >= 0) { //$NON-NLS-1$
|
||||||
replacements.put(Character.valueOf('C'),
|
replacements.put(Character.valueOf('C'),
|
||||||
substitute("%l%h%p%r", "hlpr")); //$NON-NLS-1$ //$NON-NLS-2$
|
substitute("%l%h%p%r", "hlpr", false)); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String substitute(String input, String allowed) {
|
public String substitute(String input, String allowed,
|
||||||
|
boolean withEnv) {
|
||||||
if (input == null || input.length() <= 1
|
if (input == null || input.length() <= 1
|
||||||
|| input.indexOf('%') < 0) {
|
|| input.indexOf('%') < 0
|
||||||
|
&& (!withEnv || input.indexOf("${") < 0)) { //$NON-NLS-1$
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
int start = 0;
|
int start = 0;
|
||||||
int length = input.length();
|
int length = input.length();
|
||||||
while (start < length) {
|
while (start < length) {
|
||||||
int percent = input.indexOf('%', start);
|
char ch = input.charAt(start);
|
||||||
if (percent < 0 || percent + 1 >= length) {
|
switch (ch) {
|
||||||
builder.append(input.substring(start));
|
case '%':
|
||||||
|
if (start + 1 >= length) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
String replacement = null;
|
||||||
|
ch = input.charAt(start + 1);
|
||||||
|
if (ch == '%' || allowed.indexOf(ch) >= 0) {
|
||||||
|
replacement = replacements.get(Character.valueOf(ch));
|
||||||
|
}
|
||||||
|
if (replacement == null) {
|
||||||
|
builder.append('%').append(ch);
|
||||||
|
} else {
|
||||||
|
builder.append(replacement);
|
||||||
|
}
|
||||||
|
start += 2;
|
||||||
|
continue;
|
||||||
|
case '$':
|
||||||
|
if (!withEnv || start + 2 >= length) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ch = input.charAt(start + 1);
|
||||||
|
if (ch == '{') {
|
||||||
|
int close = input.indexOf('}', start + 2);
|
||||||
|
if (close > start + 2) {
|
||||||
|
String variable = SystemReader.getInstance()
|
||||||
|
.getenv(input.substring(start + 2, close));
|
||||||
|
if (!StringUtils.isEmptyOrNull(variable)) {
|
||||||
|
builder.append(variable);
|
||||||
|
}
|
||||||
|
start = close + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ch = '$';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
String replacement = null;
|
builder.append(ch);
|
||||||
char ch = input.charAt(percent + 1);
|
start++;
|
||||||
if (ch == '%' || allowed.indexOf(ch) >= 0) {
|
|
||||||
replacement = replacements.get(Character.valueOf(ch));
|
|
||||||
}
|
|
||||||
if (replacement == null) {
|
|
||||||
builder.append(input.substring(start, percent + 2));
|
|
||||||
} else {
|
|
||||||
builder.append(input.substring(start, percent))
|
|
||||||
.append(replacement);
|
|
||||||
}
|
|
||||||
start = percent + 2;
|
|
||||||
}
|
}
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue