Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

OpenSshConfigTest.java 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. /*
  2. * Copyright (C) 2008, 2017 Google Inc.
  3. * and other copyright owners as documented in the project's IP log.
  4. *
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Eclipse Distribution License v1.0 which
  7. * accompanies this distribution, is reproduced below, and is
  8. * available at http://www.eclipse.org/org/documents/edl-v10.php
  9. *
  10. * All rights reserved.
  11. *
  12. * Redistribution and use in source and binary forms, with or
  13. * without modification, are permitted provided that the following
  14. * conditions are met:
  15. *
  16. * - Redistributions of source code must retain the above copyright
  17. * notice, this list of conditions and the following disclaimer.
  18. *
  19. * - Redistributions in binary form must reproduce the above
  20. * copyright notice, this list of conditions and the following
  21. * disclaimer in the documentation and/or other materials provided
  22. * with the distribution.
  23. *
  24. * - Neither the name of the Eclipse Foundation, Inc. nor the
  25. * names of its contributors may be used to endorse or promote
  26. * products derived from this software without specific prior
  27. * written permission.
  28. *
  29. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  30. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  31. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  32. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  34. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  35. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  36. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  37. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  38. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  40. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  41. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  42. */
  43. package org.eclipse.jgit.transport;
  44. import static java.nio.charset.StandardCharsets.UTF_8;
  45. import static org.junit.Assert.assertArrayEquals;
  46. import static org.junit.Assert.assertEquals;
  47. import static org.junit.Assert.assertFalse;
  48. import static org.junit.Assert.assertNotNull;
  49. import static org.junit.Assert.assertNotSame;
  50. import static org.junit.Assert.assertNull;
  51. import static org.junit.Assert.assertTrue;
  52. import java.io.File;
  53. import java.io.FileOutputStream;
  54. import java.io.IOException;
  55. import java.io.OutputStreamWriter;
  56. import org.eclipse.jgit.junit.RepositoryTestCase;
  57. import org.eclipse.jgit.lib.Constants;
  58. import org.eclipse.jgit.transport.OpenSshConfig.Host;
  59. import org.eclipse.jgit.util.FileUtils;
  60. import org.eclipse.jgit.util.SystemReader;
  61. import org.junit.Before;
  62. import org.junit.Test;
  63. import com.jcraft.jsch.ConfigRepository;
  64. import com.jcraft.jsch.ConfigRepository.Config;
  65. public class OpenSshConfigTest extends RepositoryTestCase {
  66. private File home;
  67. private File configFile;
  68. private OpenSshConfig osc;
  69. @Override
  70. @Before
  71. public void setUp() throws Exception {
  72. super.setUp();
  73. home = new File(trash, "home");
  74. FileUtils.mkdir(home);
  75. configFile = new File(new File(home, ".ssh"), Constants.CONFIG);
  76. FileUtils.mkdir(configFile.getParentFile());
  77. mockSystemReader.setProperty(Constants.OS_USER_NAME_KEY, "jex_junit");
  78. osc = new OpenSshConfig(home, configFile);
  79. }
  80. private void config(String data) throws IOException {
  81. long lastMtime = configFile.lastModified();
  82. do {
  83. try (final OutputStreamWriter fw = new OutputStreamWriter(
  84. new FileOutputStream(configFile), UTF_8)) {
  85. fw.write(data);
  86. }
  87. } while (lastMtime == configFile.lastModified());
  88. }
  89. @Test
  90. public void testNoConfig() {
  91. final Host h = osc.lookup("repo.or.cz");
  92. assertNotNull(h);
  93. assertEquals("repo.or.cz", h.getHostName());
  94. assertEquals("jex_junit", h.getUser());
  95. assertEquals(22, h.getPort());
  96. assertEquals(1, h.getConnectionAttempts());
  97. assertNull(h.getIdentityFile());
  98. }
  99. @Test
  100. public void testSeparatorParsing() throws Exception {
  101. config("Host\tfirst\n" +
  102. "\tHostName\tfirst.tld\n" +
  103. "\n" +
  104. "Host second\n" +
  105. " HostName\tsecond.tld\n" +
  106. "Host=third\n" +
  107. "HostName=third.tld\n\n\n" +
  108. "\t Host = fourth\n\n\n" +
  109. " \t HostName\t=fourth.tld\n" +
  110. "Host\t = last\n" +
  111. "HostName \t last.tld");
  112. assertNotNull(osc.lookup("first"));
  113. assertEquals("first.tld", osc.lookup("first").getHostName());
  114. assertNotNull(osc.lookup("second"));
  115. assertEquals("second.tld", osc.lookup("second").getHostName());
  116. assertNotNull(osc.lookup("third"));
  117. assertEquals("third.tld", osc.lookup("third").getHostName());
  118. assertNotNull(osc.lookup("fourth"));
  119. assertEquals("fourth.tld", osc.lookup("fourth").getHostName());
  120. assertNotNull(osc.lookup("last"));
  121. assertEquals("last.tld", osc.lookup("last").getHostName());
  122. }
  123. @Test
  124. public void testQuoteParsing() throws Exception {
  125. config("Host \"good\"\n" +
  126. " HostName=\"good.tld\"\n" +
  127. " Port=\"6007\"\n" +
  128. " User=\"gooduser\"\n" +
  129. "Host multiple unquoted and \"quoted\" \"hosts\"\n" +
  130. " Port=\"2222\"\n" +
  131. "Host \"spaced\"\n" +
  132. "# Bad host name, but testing preservation of spaces\n" +
  133. " HostName=\" spaced\ttld \"\n" +
  134. "# Misbalanced quotes\n" +
  135. "Host \"bad\"\n" +
  136. "# OpenSSH doesn't allow this but ...\n" +
  137. " HostName=bad.tld\"\n");
  138. assertEquals("good.tld", osc.lookup("good").getHostName());
  139. assertEquals("gooduser", osc.lookup("good").getUser());
  140. assertEquals(6007, osc.lookup("good").getPort());
  141. assertEquals(2222, osc.lookup("multiple").getPort());
  142. assertEquals(2222, osc.lookup("quoted").getPort());
  143. assertEquals(2222, osc.lookup("and").getPort());
  144. assertEquals(2222, osc.lookup("unquoted").getPort());
  145. assertEquals(2222, osc.lookup("hosts").getPort());
  146. assertEquals(" spaced\ttld ", osc.lookup("spaced").getHostName());
  147. assertEquals("bad.tld\"", osc.lookup("bad").getHostName());
  148. }
  149. @Test
  150. public void testCaseInsensitiveKeyLookup() throws Exception {
  151. config("Host orcz\n" + "Port 29418\n"
  152. + "\tHostName repo.or.cz\nStrictHostKeyChecking yes\n");
  153. final Host h = osc.lookup("orcz");
  154. Config c = h.getConfig();
  155. String exactCase = c.getValue("StrictHostKeyChecking");
  156. assertEquals("yes", exactCase);
  157. assertEquals(exactCase, c.getValue("stricthostkeychecking"));
  158. assertEquals(exactCase, c.getValue("STRICTHOSTKEYCHECKING"));
  159. assertEquals(exactCase, c.getValue("sTrIcThostKEYcheckING"));
  160. assertNull(c.getValue("sTrIcThostKEYcheckIN"));
  161. }
  162. @Test
  163. public void testAlias_DoesNotMatch() throws Exception {
  164. config("Host orcz\n" + "Port 29418\n" + "\tHostName repo.or.cz\n");
  165. final Host h = osc.lookup("repo.or.cz");
  166. assertNotNull(h);
  167. assertEquals("repo.or.cz", h.getHostName());
  168. assertEquals("jex_junit", h.getUser());
  169. assertEquals(22, h.getPort());
  170. assertNull(h.getIdentityFile());
  171. final Host h2 = osc.lookup("orcz");
  172. assertEquals("repo.or.cz", h.getHostName());
  173. assertEquals("jex_junit", h.getUser());
  174. assertEquals(29418, h2.getPort());
  175. assertNull(h.getIdentityFile());
  176. }
  177. @Test
  178. public void testAlias_OptionsSet() throws Exception {
  179. config("Host orcz\n" + "\tHostName repo.or.cz\n" + "\tPort 2222\n"
  180. + "\tUser jex\n" + "\tIdentityFile .ssh/id_jex\n"
  181. + "\tForwardX11 no\n");
  182. final Host h = osc.lookup("orcz");
  183. assertNotNull(h);
  184. assertEquals("repo.or.cz", h.getHostName());
  185. assertEquals("jex", h.getUser());
  186. assertEquals(2222, h.getPort());
  187. assertEquals(new File(home, ".ssh/id_jex"), h.getIdentityFile());
  188. }
  189. @Test
  190. public void testAlias_OptionsKeywordCaseInsensitive() throws Exception {
  191. config("hOsT orcz\n" + "\thOsTnAmE repo.or.cz\n" + "\tPORT 2222\n"
  192. + "\tuser jex\n" + "\tidentityfile .ssh/id_jex\n"
  193. + "\tForwardX11 no\n");
  194. final Host h = osc.lookup("orcz");
  195. assertNotNull(h);
  196. assertEquals("repo.or.cz", h.getHostName());
  197. assertEquals("jex", h.getUser());
  198. assertEquals(2222, h.getPort());
  199. assertEquals(new File(home, ".ssh/id_jex"), h.getIdentityFile());
  200. }
  201. @Test
  202. public void testAlias_OptionsInherit() throws Exception {
  203. config("Host orcz\n" + "\tHostName repo.or.cz\n" + "\n" + "Host *\n"
  204. + "\tHostName not.a.host.example.com\n" + "\tPort 2222\n"
  205. + "\tUser jex\n" + "\tIdentityFile .ssh/id_jex\n"
  206. + "\tForwardX11 no\n");
  207. final Host h = osc.lookup("orcz");
  208. assertNotNull(h);
  209. assertEquals("repo.or.cz", h.getHostName());
  210. assertEquals("jex", h.getUser());
  211. assertEquals(2222, h.getPort());
  212. assertEquals(new File(home, ".ssh/id_jex"), h.getIdentityFile());
  213. }
  214. @Test
  215. public void testAlias_PreferredAuthenticationsDefault() throws Exception {
  216. final Host h = osc.lookup("orcz");
  217. assertNotNull(h);
  218. assertNull(h.getPreferredAuthentications());
  219. }
  220. @Test
  221. public void testAlias_PreferredAuthentications() throws Exception {
  222. config("Host orcz\n" + "\tPreferredAuthentications publickey\n");
  223. final Host h = osc.lookup("orcz");
  224. assertNotNull(h);
  225. assertEquals("publickey", h.getPreferredAuthentications());
  226. }
  227. @Test
  228. public void testAlias_InheritPreferredAuthentications() throws Exception {
  229. config("Host orcz\n" + "\tHostName repo.or.cz\n" + "\n" + "Host *\n"
  230. + "\tPreferredAuthentications publickey, hostbased\n");
  231. final Host h = osc.lookup("orcz");
  232. assertNotNull(h);
  233. assertEquals("publickey,hostbased", h.getPreferredAuthentications());
  234. }
  235. @Test
  236. public void testAlias_BatchModeDefault() throws Exception {
  237. final Host h = osc.lookup("orcz");
  238. assertNotNull(h);
  239. assertFalse(h.isBatchMode());
  240. }
  241. @Test
  242. public void testAlias_BatchModeYes() throws Exception {
  243. config("Host orcz\n" + "\tBatchMode yes\n");
  244. final Host h = osc.lookup("orcz");
  245. assertNotNull(h);
  246. assertTrue(h.isBatchMode());
  247. }
  248. @Test
  249. public void testAlias_InheritBatchMode() throws Exception {
  250. config("Host orcz\n" + "\tHostName repo.or.cz\n" + "\n" + "Host *\n"
  251. + "\tBatchMode yes\n");
  252. final Host h = osc.lookup("orcz");
  253. assertNotNull(h);
  254. assertTrue(h.isBatchMode());
  255. }
  256. @Test
  257. public void testAlias_ConnectionAttemptsDefault() throws Exception {
  258. final Host h = osc.lookup("orcz");
  259. assertNotNull(h);
  260. assertEquals(1, h.getConnectionAttempts());
  261. }
  262. @Test
  263. public void testAlias_ConnectionAttempts() throws Exception {
  264. config("Host orcz\n" + "\tConnectionAttempts 5\n");
  265. final Host h = osc.lookup("orcz");
  266. assertNotNull(h);
  267. assertEquals(5, h.getConnectionAttempts());
  268. }
  269. @Test
  270. public void testAlias_invalidConnectionAttempts() throws Exception {
  271. config("Host orcz\n" + "\tConnectionAttempts -1\n");
  272. final Host h = osc.lookup("orcz");
  273. assertNotNull(h);
  274. assertEquals(1, h.getConnectionAttempts());
  275. }
  276. @Test
  277. public void testAlias_badConnectionAttempts() throws Exception {
  278. config("Host orcz\n" + "\tConnectionAttempts xxx\n");
  279. final Host h = osc.lookup("orcz");
  280. assertNotNull(h);
  281. assertEquals(1, h.getConnectionAttempts());
  282. }
  283. @Test
  284. public void testDefaultBlock() throws Exception {
  285. config("ConnectionAttempts 5\n\nHost orcz\nConnectionAttempts 3\n");
  286. final Host h = osc.lookup("orcz");
  287. assertNotNull(h);
  288. assertEquals(5, h.getConnectionAttempts());
  289. }
  290. @Test
  291. public void testHostCaseInsensitive() throws Exception {
  292. config("hOsT orcz\nConnectionAttempts 3\n");
  293. final Host h = osc.lookup("orcz");
  294. assertNotNull(h);
  295. assertEquals(3, h.getConnectionAttempts());
  296. }
  297. @Test
  298. public void testListValueSingle() throws Exception {
  299. config("Host orcz\nUserKnownHostsFile /foo/bar\n");
  300. final ConfigRepository.Config c = osc.getConfig("orcz");
  301. assertNotNull(c);
  302. assertEquals("/foo/bar", c.getValue("UserKnownHostsFile"));
  303. }
  304. @Test
  305. public void testListValueMultiple() throws Exception {
  306. // Tilde expansion occurs within the parser
  307. config("Host orcz\nUserKnownHostsFile \"~/foo/ba z\" /foo/bar \n");
  308. final ConfigRepository.Config c = osc.getConfig("orcz");
  309. assertNotNull(c);
  310. assertArrayEquals(new Object[] { new File(home, "foo/ba z").getPath(),
  311. "/foo/bar" },
  312. c.getValues("UserKnownHostsFile"));
  313. }
  314. @Test
  315. public void testRepeatedLookupsWithModification() throws Exception {
  316. config("Host orcz\n" + "\tConnectionAttempts -1\n");
  317. final Host h1 = osc.lookup("orcz");
  318. assertNotNull(h1);
  319. assertEquals(1, h1.getConnectionAttempts());
  320. config("Host orcz\n" + "\tConnectionAttempts 5\n");
  321. final Host h2 = osc.lookup("orcz");
  322. assertNotNull(h2);
  323. assertNotSame(h1, h2);
  324. assertEquals(5, h2.getConnectionAttempts());
  325. assertEquals(1, h1.getConnectionAttempts());
  326. assertNotSame(h1.getConfig(), h2.getConfig());
  327. }
  328. @Test
  329. public void testIdentityFile() throws Exception {
  330. config("Host orcz\nIdentityFile \"~/foo/ba z\"\nIdentityFile /foo/bar");
  331. final Host h = osc.lookup("orcz");
  332. assertNotNull(h);
  333. File f = h.getIdentityFile();
  334. assertNotNull(f);
  335. // Host does tilde replacement
  336. assertEquals(new File(home, "foo/ba z"), f);
  337. final ConfigRepository.Config c = h.getConfig();
  338. // Config does tilde replacement, too
  339. assertArrayEquals(new Object[] { new File(home, "foo/ba z").getPath(),
  340. "/foo/bar" },
  341. c.getValues("IdentityFile"));
  342. }
  343. @Test
  344. public void testMultiIdentityFile() throws Exception {
  345. config("IdentityFile \"~/foo/ba z\"\nHost orcz\nIdentityFile /foo/bar\nHOST *\nIdentityFile /foo/baz");
  346. final Host h = osc.lookup("orcz");
  347. assertNotNull(h);
  348. File f = h.getIdentityFile();
  349. assertNotNull(f);
  350. // Host does tilde replacement
  351. assertEquals(new File(home, "foo/ba z"), f);
  352. final ConfigRepository.Config c = h.getConfig();
  353. // Config does tilde replacement, too
  354. assertArrayEquals(new Object[] { new File(home, "foo/ba z").getPath(),
  355. "/foo/bar", "/foo/baz" },
  356. c.getValues("IdentityFile"));
  357. }
  358. @Test
  359. public void testNegatedPattern() throws Exception {
  360. config("Host repo.or.cz\nIdentityFile ~/foo/bar\nHOST !*.or.cz\nIdentityFile /foo/baz");
  361. final Host h = osc.lookup("repo.or.cz");
  362. assertNotNull(h);
  363. assertEquals(new File(home, "foo/bar"), h.getIdentityFile());
  364. assertArrayEquals(new Object[] { new File(home, "foo/bar").getPath() },
  365. h.getConfig().getValues("IdentityFile"));
  366. }
  367. @Test
  368. public void testPattern() throws Exception {
  369. config("Host repo.or.cz\nIdentityFile ~/foo/bar\nHOST *.or.cz\nIdentityFile /foo/baz");
  370. final Host h = osc.lookup("repo.or.cz");
  371. assertNotNull(h);
  372. assertEquals(new File(home, "foo/bar"), h.getIdentityFile());
  373. assertArrayEquals(new Object[] { new File(home, "foo/bar").getPath(),
  374. "/foo/baz" },
  375. h.getConfig().getValues("IdentityFile"));
  376. }
  377. @Test
  378. public void testMultiHost() throws Exception {
  379. config("Host orcz *.or.cz\nIdentityFile ~/foo/bar\nHOST *.or.cz\nIdentityFile /foo/baz");
  380. final Host h1 = osc.lookup("repo.or.cz");
  381. assertNotNull(h1);
  382. assertEquals(new File(home, "foo/bar"), h1.getIdentityFile());
  383. assertArrayEquals(new Object[] { new File(home, "foo/bar").getPath(),
  384. "/foo/baz" },
  385. h1.getConfig().getValues("IdentityFile"));
  386. final Host h2 = osc.lookup("orcz");
  387. assertNotNull(h2);
  388. assertEquals(new File(home, "foo/bar"), h2.getIdentityFile());
  389. assertArrayEquals(new Object[] { new File(home, "foo/bar").getPath() },
  390. h2.getConfig().getValues("IdentityFile"));
  391. }
  392. @Test
  393. public void testEqualsSign() throws Exception {
  394. config("Host=orcz\n\tConnectionAttempts = 5\n\tUser=\t foobar\t\n");
  395. final Host h = osc.lookup("orcz");
  396. assertNotNull(h);
  397. assertEquals(5, h.getConnectionAttempts());
  398. assertEquals("foobar", h.getUser());
  399. }
  400. @Test
  401. public void testMissingArgument() throws Exception {
  402. config("Host=orcz\n\tSendEnv\nIdentityFile\t\nForwardX11\n\tUser=\t foobar\t\n");
  403. final Host h = osc.lookup("orcz");
  404. assertNotNull(h);
  405. assertEquals("foobar", h.getUser());
  406. assertArrayEquals(new String[0], h.getConfig().getValues("SendEnv"));
  407. assertNull(h.getIdentityFile());
  408. assertNull(h.getConfig().getValue("ForwardX11"));
  409. }
  410. @Test
  411. public void testHomeDirUserReplacement() throws Exception {
  412. config("Host=orcz\n\tIdentityFile %d/.ssh/%u_id_dsa");
  413. final Host h = osc.lookup("orcz");
  414. assertNotNull(h);
  415. assertEquals(new File(new File(home, ".ssh"), "jex_junit_id_dsa"),
  416. h.getIdentityFile());
  417. }
  418. @Test
  419. public void testHostnameReplacement() throws Exception {
  420. config("Host=orcz\nHost *.*\n\tHostname %h\nHost *\n\tHostname %h.example.org");
  421. final Host h = osc.lookup("orcz");
  422. assertNotNull(h);
  423. assertEquals("orcz.example.org", h.getHostName());
  424. }
  425. @Test
  426. public void testRemoteUserReplacement() throws Exception {
  427. config("Host=orcz\n\tUser foo\n" + "Host *.*\n\tHostname %h\n"
  428. + "Host *\n\tHostname %h.ex%%20ample.org\n\tIdentityFile ~/.ssh/%h_%r_id_dsa");
  429. final Host h = osc.lookup("orcz");
  430. assertNotNull(h);
  431. assertEquals(
  432. new File(new File(home, ".ssh"),
  433. "orcz.ex%20ample.org_foo_id_dsa"),
  434. h.getIdentityFile());
  435. }
  436. @Test
  437. public void testLocalhostFQDNReplacement() throws Exception {
  438. String localhost = SystemReader.getInstance().getHostname();
  439. config("Host=orcz\n\tIdentityFile ~/.ssh/%l_id_dsa");
  440. final Host h = osc.lookup("orcz");
  441. assertNotNull(h);
  442. assertEquals(
  443. new File(new File(home, ".ssh"), localhost + "_id_dsa"),
  444. h.getIdentityFile());
  445. }
  446. }