1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.internal.transport.ssh;
12
13 import static java.nio.charset.StandardCharsets.UTF_8;
14 import static org.junit.Assert.assertArrayEquals;
15 import static org.junit.Assert.assertEquals;
16 import static org.junit.Assert.assertNotNull;
17 import static org.junit.Assert.assertNotSame;
18 import static org.junit.Assert.assertNull;
19 import static org.junit.Assert.assertTrue;
20
21 import java.io.File;
22 import java.io.FileOutputStream;
23 import java.io.IOException;
24 import java.io.OutputStreamWriter;
25 import java.time.Instant;
26 import java.util.concurrent.TimeUnit;
27
28 import org.eclipse.jgit.junit.RepositoryTestCase;
29 import org.eclipse.jgit.lib.Constants;
30 import org.eclipse.jgit.transport.SshConfigStore.HostConfig;
31 import org.eclipse.jgit.transport.SshConstants;
32 import org.eclipse.jgit.util.FS;
33 import org.eclipse.jgit.util.FileUtils;
34 import org.eclipse.jgit.util.SystemReader;
35 import org.junit.Before;
36 import org.junit.Test;
37
38 public class OpenSshConfigFileTest extends RepositoryTestCase {
39
40 private File home;
41
42 private File configFile;
43
44 private OpenSshConfigFile osc;
45
46 @Override
47 @Before
48 public void setUp() throws Exception {
49 super.setUp();
50
51 home = new File(trash, "home");
52 FileUtils.mkdir(home);
53
54 configFile = new File(new File(home, ".ssh"), Constants.CONFIG);
55 FileUtils.mkdir(configFile.getParentFile());
56
57 mockSystemReader.setProperty(Constants.OS_USER_NAME_KEY, "jex_junit");
58 mockSystemReader.setProperty("TST_VAR", "TEST");
59 osc = new OpenSshConfigFile(home, configFile, "jex_junit");
60 }
61
62 private void config(String data) throws IOException {
63 FS fs = FS.DETECTED;
64 long resolution = FS.getFileStoreAttributes(configFile.toPath())
65 .getFsTimestampResolution().toNanos();
66 Instant lastMtime = fs.lastModifiedInstant(configFile);
67 do {
68 try (final OutputStreamWriter fw = new OutputStreamWriter(
69 new FileOutputStream(configFile), UTF_8)) {
70 fw.write(data);
71 TimeUnit.NANOSECONDS.sleep(resolution);
72 } catch (InterruptedException e) {
73 Thread.interrupted();
74 }
75 } while (lastMtime.equals(fs.lastModifiedInstant(configFile)));
76 }
77
78 private HostConfig lookup(String hostname) {
79 return osc.lookupDefault(hostname, 0, null);
80 }
81
82 private void assertHost(String expected, HostConfig h) {
83 assertEquals(expected, h.getValue(SshConstants.HOST_NAME));
84 }
85
86 private void assertUser(String expected, HostConfig h) {
87 assertEquals(expected, h.getValue(SshConstants.USER));
88 }
89
90 private void assertPort(int expected, HostConfig h) {
91 assertEquals(expected,
92 OpenSshConfigFile.positive(h.getValue(SshConstants.PORT)));
93 }
94
95 private void assertIdentity(File expected, HostConfig h) {
96 String actual = h.getValue(SshConstants.IDENTITY_FILE);
97 if (expected == null) {
98 assertNull(actual);
99 } else {
100 assertEquals(expected, new File(actual));
101 }
102 }
103
104 private void assertAttempts(int expected, HostConfig h) {
105 assertEquals(expected, OpenSshConfigFile
106 .positive(h.getValue(SshConstants.CONNECTION_ATTEMPTS)));
107 }
108
109 @Test
110 public void testNoConfig() {
111 final HostConfig h = lookup("repo.or.cz");
112 assertNotNull(h);
113 assertHost("repo.or.cz", h);
114 assertUser("jex_junit", h);
115 assertPort(22, h);
116 assertAttempts(1, h);
117 assertIdentity(null, h);
118 }
119
120 @Test
121 public void testSeparatorParsing() throws Exception {
122 config("Host\tfirst\n" +
123 "\tHostName\tfirst.tld\n" +
124 "\n" +
125 "Host second\n" +
126 " HostName\tsecond.tld\n" +
127 "Host=third\n" +
128 "HostName=third.tld\n\n\n" +
129 "\t Host = fourth\n\n\n" +
130 " \t HostName\t=fourth.tld\n" +
131 "Host\t = last\n" +
132 "HostName \t last.tld");
133 assertNotNull(lookup("first"));
134 assertHost("first.tld", lookup("first"));
135 assertNotNull(lookup("second"));
136 assertHost("second.tld", lookup("second"));
137 assertNotNull(lookup("third"));
138 assertHost("third.tld", lookup("third"));
139 assertNotNull(lookup("fourth"));
140 assertHost("fourth.tld", lookup("fourth"));
141 assertNotNull(lookup("last"));
142 assertHost("last.tld", lookup("last"));
143 }
144
145 @Test
146 public void testQuoteParsing() throws Exception {
147 config("Host \"good\"\n" +
148 " HostName=\"good.tld\"\n" +
149 " Port=\"6007\"\n" +
150 " User=\"gooduser\"\n" +
151 "Host multiple unquoted and \"quoted\" \"hosts\"\n" +
152 " Port=\"2222\"\n" +
153 "Host \"spaced\"\n" +
154 "# Bad host name, but testing preservation of spaces\n" +
155 " HostName=\" spaced\ttld \"\n" +
156 "# Misbalanced quotes\n" +
157 "Host \"bad\"\n" +
158 "# OpenSSH doesn't allow this but ...\n" +
159 " HostName=bad.tld\"\n");
160 assertHost("good.tld", lookup("good"));
161 assertUser("gooduser", lookup("good"));
162 assertPort(6007, lookup("good"));
163 assertPort(2222, lookup("multiple"));
164 assertPort(2222, lookup("quoted"));
165 assertPort(2222, lookup("and"));
166 assertPort(2222, lookup("unquoted"));
167 assertPort(2222, lookup("hosts"));
168 assertHost(" spaced\ttld ", lookup("spaced"));
169 assertHost("bad.tld", lookup("bad"));
170 }
171
172 @Test
173 public void testAdvancedParsing() throws Exception {
174
175 config("Host foo\n"
176 + " HostName=\"foo\\\"d.tld\"\n"
177 + " User= someone#foo\n"
178 + "Host bar\n"
179 + " User ' some one#two' # Comment\n"
180 + " GlobalKnownHostsFile '/a folder/with spaces/hosts' '/other/more hosts' # Comment\n"
181 + "Host foobar\n"
182 + " User a\\ u\\ thor\n"
183 + "Host backslash\n"
184 + " User some\\one\\\\\\ foo\n"
185 + "Host backslash_before_quote\n"
186 + " User \\\"someone#\"el#se\" #Comment\n"
187 + "Host backslash_in_quote\n"
188 + " User 'some\\one\\\\\\ foo'\n");
189 assertHost("foo\"d.tld", lookup("foo"));
190 assertUser("someone#foo", lookup("foo"));
191 HostConfig c = lookup("bar");
192 assertUser(" some one#two", c);
193 assertArrayEquals(
194 new Object[] { "/a folder/with spaces/hosts",
195 "/other/more hosts" },
196 c.getValues("GlobalKnownHostsFile").toArray());
197 assertUser("a u thor", lookup("foobar"));
198 assertUser("some\\one\\ foo", lookup("backslash"));
199 assertUser("\"someone#el#se", lookup("backslash_before_quote"));
200 assertUser("some\\one\\\\ foo", lookup("backslash_in_quote"));
201 }
202
203 @Test
204 public void testCaseInsensitiveKeyLookup() throws Exception {
205 config("Host orcz\n" + "Port 29418\n"
206 + "\tHostName repo.or.cz\nStrictHostKeyChecking yes\n");
207 final HostConfig c = lookup("orcz");
208 String exactCase = c.getValue("StrictHostKeyChecking");
209 assertEquals("yes", exactCase);
210 assertEquals(exactCase, c.getValue("stricthostkeychecking"));
211 assertEquals(exactCase, c.getValue("STRICTHOSTKEYCHECKING"));
212 assertEquals(exactCase, c.getValue("sTrIcThostKEYcheckING"));
213 assertNull(c.getValue("sTrIcThostKEYcheckIN"));
214 }
215
216 @Test
217 public void testAlias_DoesNotMatch() throws Exception {
218 config("Host orcz\n" + "Port 29418\n"
219 + "\tHostName repo.or.cz\n");
220 final HostConfig h = lookup("repo.or.cz");
221 assertNotNull(h);
222 assertHost("repo.or.cz", h);
223 assertUser("jex_junit", h);
224 assertPort(22, h);
225 assertIdentity(null, h);
226 final HostConfig h2 = lookup("orcz");
227 assertHost("repo.or.cz", h);
228 assertUser("jex_junit", h);
229 assertPort(29418, h2);
230 assertIdentity(null, h);
231 }
232
233 @Test
234 public void testAlias_OptionsSet() throws Exception {
235 config("Host orcz\n" + "\tHostName repo.or.cz\n" + "\tPort 2222\n"
236 + "\tUser jex\n" + "\tIdentityFile .ssh/id_jex\n"
237 + "\tForwardX11 no\n");
238 final HostConfig h = lookup("orcz");
239 assertNotNull(h);
240 assertHost("repo.or.cz", h);
241 assertUser("jex", h);
242 assertPort(2222, h);
243 assertIdentity(new File(home, ".ssh/id_jex"), h);
244 }
245
246 @Test
247 public void testAlias_OptionsKeywordCaseInsensitive() throws Exception {
248 config("hOsT orcz\n" + "\thOsTnAmE repo.or.cz\n" + "\tPORT 2222\n"
249 + "\tuser jex\n" + "\tidentityfile .ssh/id_jex\n"
250 + "\tForwardX11 no\n");
251 final HostConfig h = lookup("orcz");
252 assertNotNull(h);
253 assertHost("repo.or.cz", h);
254 assertUser("jex", h);
255 assertPort(2222, h);
256 assertIdentity(new File(home, ".ssh/id_jex"), h);
257 }
258
259 @Test
260 public void testAlias_OptionsInherit() throws Exception {
261 config("Host orcz\n" + "\tHostName repo.or.cz\n" + "\n" + "Host *\n"
262 + "\tHostName not.a.host.example.com\n" + "\tPort 2222\n"
263 + "\tUser jex\n" + "\tIdentityFile .ssh/id_jex\n"
264 + "\tForwardX11 no\n");
265 final HostConfig h = lookup("orcz");
266 assertNotNull(h);
267 assertHost("repo.or.cz", h);
268 assertUser("jex", h);
269 assertPort(2222, h);
270 assertIdentity(new File(home, ".ssh/id_jex"), h);
271 }
272
273 @Test
274 public void testAlias_PreferredAuthenticationsDefault() throws Exception {
275 final HostConfig h = lookup("orcz");
276 assertNotNull(h);
277 assertNull(h.getValue(SshConstants.PREFERRED_AUTHENTICATIONS));
278 }
279
280 @Test
281 public void testAlias_PreferredAuthentications() throws Exception {
282 config("Host orcz\n" + "\tPreferredAuthentications publickey\n");
283 final HostConfig h = lookup("orcz");
284 assertNotNull(h);
285 assertEquals("publickey",
286 h.getValue(SshConstants.PREFERRED_AUTHENTICATIONS));
287 }
288
289 @Test
290 public void testAlias_InheritPreferredAuthentications() throws Exception {
291 config("Host orcz\n" + "\tHostName repo.or.cz\n" + "\n" + "Host *\n"
292 + "\tPreferredAuthentications 'publickey, hostbased'\n");
293 final HostConfig h = lookup("orcz");
294 assertNotNull(h);
295 assertEquals("publickey,hostbased",
296 h.getValue(SshConstants.PREFERRED_AUTHENTICATIONS));
297 }
298
299 @Test
300 public void testAlias_BatchModeDefault() throws Exception {
301 final HostConfig h = lookup("orcz");
302 assertNotNull(h);
303 assertNull(h.getValue(SshConstants.BATCH_MODE));
304 }
305
306 @Test
307 public void testAlias_BatchModeYes() throws Exception {
308 config("Host orcz\n" + "\tBatchMode yes\n");
309 final HostConfig h = lookup("orcz");
310 assertNotNull(h);
311 assertTrue(OpenSshConfigFile.flag(h.getValue(SshConstants.BATCH_MODE)));
312 }
313
314 @Test
315 public void testAlias_InheritBatchMode() throws Exception {
316 config("Host orcz\n" + "\tHostName repo.or.cz\n" + "\n" + "Host *\n"
317 + "\tBatchMode yes\n");
318 final HostConfig h = lookup("orcz");
319 assertNotNull(h);
320 assertTrue(OpenSshConfigFile.flag(h.getValue(SshConstants.BATCH_MODE)));
321 }
322
323 @Test
324 public void testAlias_ConnectionAttemptsDefault() throws Exception {
325 final HostConfig h = lookup("orcz");
326 assertNotNull(h);
327 assertAttempts(1, h);
328 }
329
330 @Test
331 public void testAlias_ConnectionAttempts() throws Exception {
332 config("Host orcz\n" + "\tConnectionAttempts 5\n");
333 final HostConfig h = lookup("orcz");
334 assertNotNull(h);
335 assertAttempts(5, h);
336 }
337
338 @Test
339 public void testAlias_invalidConnectionAttempts() throws Exception {
340 config("Host orcz\n" + "\tConnectionAttempts -1\n");
341 final HostConfig h = lookup("orcz");
342 assertNotNull(h);
343 assertAttempts(1, h);
344 }
345
346 @Test
347 public void testAlias_badConnectionAttempts() throws Exception {
348 config("Host orcz\n" + "\tConnectionAttempts xxx\n");
349 final HostConfig h = lookup("orcz");
350 assertNotNull(h);
351 assertAttempts(1, h);
352 }
353
354 @Test
355 public void testDefaultBlock() throws Exception {
356 config("ConnectionAttempts 5\n\nHost orcz\nConnectionAttempts 3\n");
357 final HostConfig h = lookup("orcz");
358 assertNotNull(h);
359 assertAttempts(5, h);
360 }
361
362 @Test
363 public void testHostCaseInsensitive() throws Exception {
364 config("hOsT orcz\nConnectionAttempts 3\n");
365 final HostConfig h = lookup("orcz");
366 assertNotNull(h);
367 assertAttempts(3, h);
368 }
369
370 @Test
371 public void testListValueSingle() throws Exception {
372 config("Host orcz\nUserKnownHostsFile ~/foo/bar\n");
373 final HostConfig c = lookup("orcz");
374 assertNotNull(c);
375 assertEquals(new File(home, "foo/bar").getPath(),
376 c.getValue("UserKnownHostsFile"));
377 }
378
379 @Test
380 public void testListValueMultiple() throws Exception {
381
382 config("Host orcz\nUserKnownHostsFile \"~/foo/ba z\" ~/foo/bar \n");
383 final HostConfig c = lookup("orcz");
384 assertNotNull(c);
385 assertArrayEquals(new Object[] { new File(home, "foo/ba z").getPath(),
386 new File(home, "foo/bar").getPath() },
387 c.getValues("UserKnownHostsFile").toArray());
388 }
389
390 @Test
391 public void testRepeatedLookupsWithModification() throws Exception {
392 config("Host orcz\n" + "\tConnectionAttempts -1\n");
393 final HostConfig h1 = lookup("orcz");
394 assertNotNull(h1);
395 assertAttempts(1, h1);
396 config("Host orcz\n" + "\tConnectionAttempts 5\n");
397 final HostConfig h2 = lookup("orcz");
398 assertNotNull(h2);
399 assertNotSame(h1, h2);
400 assertAttempts(5, h2);
401 assertAttempts(1, h1);
402 assertNotSame(h1, h2);
403 }
404
405 @Test
406 public void testIdentityFile() throws Exception {
407 config("Host orcz\nIdentityFile \"~/foo/ba z\"\nIdentityFile ~/foo/bar");
408 final HostConfig h = lookup("orcz");
409 assertNotNull(h);
410
411 assertArrayEquals(new Object[] { new File(home, "foo/ba z").getPath(),
412 new File(home, "foo/bar").getPath() },
413 h.getValues(SshConstants.IDENTITY_FILE).toArray());
414 }
415
416 @Test
417 public void testMultiIdentityFile() throws Exception {
418 config("IdentityFile \"~/foo/ba z\"\nHost orcz\nIdentityFile ~/foo/bar\nHOST *\nIdentityFile ~/foo/baz");
419 final HostConfig h = lookup("orcz");
420 assertNotNull(h);
421 assertArrayEquals(new Object[] { new File(home, "foo/ba z").getPath(),
422 new File(home, "foo/bar").getPath(),
423 new File(home, "foo/baz").getPath() },
424 h.getValues(SshConstants.IDENTITY_FILE).toArray());
425 }
426
427 @Test
428 public void testNegatedPattern() throws Exception {
429 config("Host repo.or.cz\nIdentityFile ~/foo/bar\nHOST !*.or.cz\nIdentityFile /foo/baz");
430 final HostConfig h = lookup("repo.or.cz");
431 assertNotNull(h);
432 assertIdentity(new File(home, "foo/bar"), h);
433 assertArrayEquals(new Object[] { new File(home, "foo/bar").getPath() },
434 h.getValues(SshConstants.IDENTITY_FILE).toArray());
435 }
436
437 @Test
438 public void testPattern() throws Exception {
439 config("Host repo.or.cz\nIdentityFile ~/foo/bar\nHOST *.or.cz\nIdentityFile ~/foo/baz");
440 final HostConfig h = lookup("repo.or.cz");
441 assertNotNull(h);
442 assertIdentity(new File(home, "foo/bar"), h);
443 assertArrayEquals(new Object[] { new File(home, "foo/bar").getPath(),
444 new File(home, "foo/baz").getPath() },
445 h.getValues(SshConstants.IDENTITY_FILE).toArray());
446 }
447
448 @Test
449 public void testMultiHost() throws Exception {
450 config("Host orcz *.or.cz\nIdentityFile ~/foo/bar\nHOST *.or.cz\nIdentityFile ~/foo/baz");
451 final HostConfig h1 = lookup("repo.or.cz");
452 assertNotNull(h1);
453 assertIdentity(new File(home, "foo/bar"), h1);
454 assertArrayEquals(new Object[] { new File(home, "foo/bar").getPath(),
455 new File(home, "foo/baz").getPath() },
456 h1.getValues(SshConstants.IDENTITY_FILE).toArray());
457 final HostConfig h2 = lookup("orcz");
458 assertNotNull(h2);
459 assertIdentity(new File(home, "foo/bar"), h2);
460 assertArrayEquals(new Object[] { new File(home, "foo/bar").getPath() },
461 h2.getValues(SshConstants.IDENTITY_FILE).toArray());
462 }
463
464 @Test
465 public void testEqualsSign() throws Exception {
466 config("Host=orcz\n\tConnectionAttempts = 5\n\tUser=\t foobar\t\n");
467 final HostConfig h = lookup("orcz");
468 assertNotNull(h);
469 assertAttempts(5, h);
470 assertUser("foobar", h);
471 }
472
473 @Test
474 public void testMissingArgument() throws Exception {
475 config("Host=orcz\n\tSendEnv\nIdentityFile\t\nForwardX11\n\tUser=\t foobar\t\n");
476 final HostConfig h = lookup("orcz");
477 assertNotNull(h);
478 assertUser("foobar", h);
479 assertEquals("[]", h.getValues("SendEnv").toString());
480 assertIdentity(null, h);
481 assertNull(h.getValue("ForwardX11"));
482 }
483
484 @Test
485 public void testHomeDirUserReplacement() throws Exception {
486 config("Host=orcz\n\tIdentityFile %d/.ssh/%u_id_dsa");
487 final HostConfig h = lookup("orcz");
488 assertNotNull(h);
489 assertIdentity(new File(new File(home, ".ssh"), "jex_junit_id_dsa"), h);
490 }
491
492 @Test
493 public void testHostnameReplacement() throws Exception {
494 config("Host=orcz\nHost *.*\n\tHostname %h\nHost *\n\tHostname %h.example.org");
495 final HostConfig h = lookup("orcz");
496 assertNotNull(h);
497 assertHost("orcz.example.org", h);
498 }
499
500 @Test
501 public void testRemoteUserReplacement() throws Exception {
502 config("Host=orcz\n\tUser foo\n" + "Host *.*\n\tHostname %h\n"
503 + "Host *\n\tHostname %h.ex%%20ample.org\n\tIdentityFile ~/.ssh/%h_%r_id_dsa");
504 final HostConfig h = lookup("orcz");
505 assertNotNull(h);
506 assertIdentity(
507 new File(new File(home, ".ssh"),
508 "orcz.ex%20ample.org_foo_id_dsa"),
509 h);
510 }
511
512 @Test
513 public void testLocalhostFQDNReplacement() throws Exception {
514 String localhost = SystemReader.getInstance().getHostname();
515 config("Host=orcz\n\tIdentityFile ~/.ssh/%l_id_dsa");
516 final HostConfig h = lookup("orcz");
517 assertNotNull(h);
518 assertIdentity(
519 new File(new File(home, ".ssh"), localhost + "_id_dsa"),
520 h);
521 }
522
523 @Test
524 public void testPubKeyAcceptedAlgorithms() throws Exception {
525 config("Host=orcz\n\tPubkeyAcceptedAlgorithms ^ssh-rsa");
526 HostConfig h = lookup("orcz");
527 assertEquals("^ssh-rsa",
528 h.getValue(SshConstants.PUBKEY_ACCEPTED_ALGORITHMS));
529 assertEquals("^ssh-rsa", h.getValue("PubkeyAcceptedKeyTypes"));
530 }
531
532 @Test
533 public void testPubKeyAcceptedKeyTypes() throws Exception {
534 config("Host=orcz\n\tPubkeyAcceptedKeyTypes ^ssh-rsa");
535 HostConfig h = lookup("orcz");
536 assertEquals("^ssh-rsa",
537 h.getValue(SshConstants.PUBKEY_ACCEPTED_ALGORITHMS));
538 assertEquals("^ssh-rsa", h.getValue("PubkeyAcceptedKeyTypes"));
539 }
540
541 @Test
542 public void testEolComments() throws Exception {
543 config("#Comment\nHost=orcz #Comment\n\tPubkeyAcceptedAlgorithms ^ssh-rsa # Comment\n#Comment");
544 HostConfig h = lookup("orcz");
545 assertNotNull(h);
546 assertEquals("^ssh-rsa",
547 h.getValue(SshConstants.PUBKEY_ACCEPTED_ALGORITHMS));
548 }
549
550 @Test
551 public void testEnVarSubstitution() throws Exception {
552 config("Host orcz\nIdentityFile ~/tmp/${TST_VAR}\n"
553 + "CertificateFile ~/tmp/${}/foo\nUser ${TST_VAR}\nIdentityAgent ~/tmp/${TST_VAR/bar");
554 HostConfig h = lookup("orcz");
555 assertNotNull(h);
556 File tmp = new File(home, "tmp");
557 assertEquals(new File(tmp, "TEST").getPath(),
558 h.getValue(SshConstants.IDENTITY_FILE));
559
560 assertEquals(new File(new File(tmp, "${}"), "foo").getPath(),
561 h.getValue(SshConstants.CERTIFICATE_FILE));
562
563 assertUser("${TST_VAR}", h);
564
565 assertEquals(new File(new File(tmp, "${TST_VAR"), "bar").getPath(),
566 h.getValue(SshConstants.IDENTITY_AGENT));
567 }
568
569 @Test
570 public void testIdentityAgentNone() throws Exception {
571 config("Host orcz\nIdentityAgent none\n");
572 HostConfig h = lookup("orcz");
573 assertEquals(SshConstants.NONE,
574 h.getValue(SshConstants.IDENTITY_AGENT));
575 }
576
577 @Test
578 public void testIdentityAgentSshAuthSock() throws Exception {
579 config("Host orcz\nIdentityAgent SSH_AUTH_SOCK\n");
580 HostConfig h = lookup("orcz");
581 assertEquals(SshConstants.ENV_SSH_AUTH_SOCKET,
582 h.getValue(SshConstants.IDENTITY_AGENT));
583 }
584
585 @Test
586 public void testNegativeMatch() throws Exception {
587 config("Host foo.bar !foobar.baz *.baz\n" + "Port 29418\n");
588 HostConfig h = lookup("foo.bar");
589 assertNotNull(h);
590 assertPort(29418, h);
591 h = lookup("foobar.baz");
592 assertNotNull(h);
593 assertPort(22, h);
594 h = lookup("foo.baz");
595 assertNotNull(h);
596 assertPort(29418, h);
597 }
598
599 @Test
600 public void testNegativeMatch2() throws Exception {
601
602 config("Host foo.bar *.baz !foobar.baz\n" + "Port 29418\n");
603 HostConfig h = lookup("foo.bar");
604 assertNotNull(h);
605 assertPort(29418, h);
606 h = lookup("foobar.baz");
607 assertNotNull(h);
608 assertPort(22, h);
609 h = lookup("foo.baz");
610 assertNotNull(h);
611 assertPort(29418, h);
612 }
613
614 @Test
615 public void testNoMatch() throws Exception {
616 config("Host !host1 !host2\n" + "Port 29418\n");
617 HostConfig h = lookup("host1");
618 assertNotNull(h);
619 assertPort(22, h);
620 h = lookup("host2");
621 assertNotNull(h);
622 assertPort(22, h);
623 h = lookup("host3");
624 assertNotNull(h);
625 assertPort(22, h);
626 }
627
628 @Test
629 public void testMultipleMatch() throws Exception {
630 config("Host foo.bar\nPort 29418\nIdentityFile ~/foo\n\n"
631 + "Host *.bar\nPort 22\nIdentityFile ~/bar\n"
632 + "Host foo.bar\nPort 47\nIdentityFile ~/baz\n");
633 HostConfig h = lookup("foo.bar");
634 assertNotNull(h);
635 assertPort(29418, h);
636 assertArrayEquals(
637 new Object[] { new File(home, "foo").getPath(),
638 new File(home, "bar").getPath(),
639 new File(home, "baz").getPath() },
640 h.getValues(SshConstants.IDENTITY_FILE).toArray());
641 }
642
643 @Test
644 public void testWhitespace() throws Exception {
645 config("Host foo \tbar baz\nPort 29418\n");
646 HostConfig h = lookup("foo");
647 assertNotNull(h);
648 assertPort(29418, h);
649 h = lookup("bar");
650 assertNotNull(h);
651 assertPort(29418, h);
652 h = lookup("baz");
653 assertNotNull(h);
654 assertPort(29418, h);
655 h = lookup("\tbar");
656 assertNotNull(h);
657 assertPort(22, h);
658 }
659
660 @Test
661 public void testTimeSpec() throws Exception {
662 assertEquals(-1, OpenSshConfigFile.timeSpec(null));
663 assertEquals(-1, OpenSshConfigFile.timeSpec(""));
664 assertEquals(-1, OpenSshConfigFile.timeSpec(" "));
665 assertEquals(-1, OpenSshConfigFile.timeSpec("s"));
666 assertEquals(-1, OpenSshConfigFile.timeSpec(" s"));
667 assertEquals(-1, OpenSshConfigFile.timeSpec(" +s"));
668 assertEquals(-1, OpenSshConfigFile.timeSpec(" -s"));
669 assertEquals(-1, OpenSshConfigFile.timeSpec("1ms"));
670 assertEquals(600, OpenSshConfigFile.timeSpec("600"));
671 assertEquals(600, OpenSshConfigFile.timeSpec("600s"));
672 assertEquals(600, OpenSshConfigFile.timeSpec(" 600s"));
673 assertEquals(600, OpenSshConfigFile.timeSpec(" 600s "));
674 assertEquals(600, OpenSshConfigFile.timeSpec("\t600s"));
675 assertEquals(600, OpenSshConfigFile.timeSpec(" \t600 "));
676 assertEquals(-1, OpenSshConfigFile.timeSpec(" 600 s "));
677 assertEquals(-1, OpenSshConfigFile.timeSpec("600 s"));
678 assertEquals(600, OpenSshConfigFile.timeSpec("10m"));
679 assertEquals(5400, OpenSshConfigFile.timeSpec("1h30m"));
680 assertEquals(5400, OpenSshConfigFile.timeSpec("1h 30m"));
681 assertEquals(5400, OpenSshConfigFile.timeSpec("1h \t30m"));
682 assertEquals(5400, OpenSshConfigFile.timeSpec("1h+30m"));
683 assertEquals(5400, OpenSshConfigFile.timeSpec("1h +30m"));
684 assertEquals(-1, OpenSshConfigFile.timeSpec("1h + 30m"));
685 assertEquals(-1, OpenSshConfigFile.timeSpec("1h -30m"));
686 assertEquals(3630, OpenSshConfigFile.timeSpec("1h30s"));
687 assertEquals(5400, OpenSshConfigFile.timeSpec("30m 1h"));
688 assertEquals(3600, OpenSshConfigFile.timeSpec("30m 30m"));
689 assertEquals(60, OpenSshConfigFile.timeSpec("30 30"));
690 assertEquals(0, OpenSshConfigFile.timeSpec("0"));
691 assertEquals(1, OpenSshConfigFile.timeSpec("1"));
692 assertEquals(1, OpenSshConfigFile.timeSpec("1S"));
693 assertEquals(1, OpenSshConfigFile.timeSpec("1s"));
694 assertEquals(60, OpenSshConfigFile.timeSpec("1M"));
695 assertEquals(60, OpenSshConfigFile.timeSpec("1m"));
696 assertEquals(3600, OpenSshConfigFile.timeSpec("1H"));
697 assertEquals(3600, OpenSshConfigFile.timeSpec("1h"));
698 assertEquals(86400, OpenSshConfigFile.timeSpec("1D"));
699 assertEquals(86400, OpenSshConfigFile.timeSpec("1d"));
700 assertEquals(604800, OpenSshConfigFile.timeSpec("1W"));
701 assertEquals(604800, OpenSshConfigFile.timeSpec("1w"));
702 assertEquals(172800, OpenSshConfigFile.timeSpec("2d"));
703 assertEquals(604800, OpenSshConfigFile.timeSpec("1w"));
704 assertEquals(604800 + 172800 + 3 * 3600 + 30 * 60 + 10,
705 OpenSshConfigFile.timeSpec("1w2d3h30m10s"));
706 assertEquals(-1, OpenSshConfigFile.timeSpec("-7"));
707 assertEquals(-1, OpenSshConfigFile.timeSpec("-9d"));
708 assertEquals(Integer.MAX_VALUE, OpenSshConfigFile
709 .timeSpec(Integer.toString(Integer.MAX_VALUE)));
710 assertEquals(-1, OpenSshConfigFile
711 .timeSpec(Long.toString(Integer.MAX_VALUE + 1L)));
712 assertEquals(-1, OpenSshConfigFile
713 .timeSpec(Integer.toString(Integer.MAX_VALUE / 60 + 1) + 'M'));
714 assertEquals(-1, OpenSshConfigFile.timeSpec("1000000000000000000000w"));
715 }
716 }