You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SshTestBase.java 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. /*
  2. * Copyright (C) 2018, Thomas Wolf <thomas.wolf@paranor.ch>
  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.ssh;
  44. import static org.junit.Assert.assertArrayEquals;
  45. import static org.junit.Assert.assertEquals;
  46. import static org.junit.Assert.assertFalse;
  47. import static org.junit.Assert.assertNotNull;
  48. import static org.junit.Assert.assertTrue;
  49. import static org.junit.Assume.assumeTrue;
  50. import java.io.File;
  51. import java.io.IOException;
  52. import java.nio.charset.StandardCharsets;
  53. import java.nio.file.Files;
  54. import java.util.List;
  55. import java.util.Map;
  56. import org.eclipse.jgit.api.errors.TransportException;
  57. import org.eclipse.jgit.transport.CredentialItem;
  58. import org.eclipse.jgit.transport.JschConfigSessionFactory;
  59. import org.eclipse.jgit.transport.URIish;
  60. import org.junit.Test;
  61. import org.junit.experimental.theories.DataPoints;
  62. import org.junit.experimental.theories.Theory;
  63. /**
  64. * The ssh tests. Concrete subclasses can re-use these tests by implementing the
  65. * abstract operations from {@link SshTestHarness}. This gives a way to test
  66. * different ssh clients against a unified test suite.
  67. */
  68. public abstract class SshTestBase extends SshTestHarness {
  69. @DataPoints
  70. public static String[] KEY_RESOURCES = { //
  71. "id_dsa", //
  72. "id_rsa_1024", //
  73. "id_rsa_2048", //
  74. "id_rsa_3072", //
  75. "id_rsa_4096", //
  76. "id_ecdsa_256", //
  77. "id_ecdsa_384", //
  78. "id_ecdsa_521", //
  79. // And now encrypted. Passphrase is "testpass".
  80. "id_dsa_testpass", //
  81. "id_rsa_1024_testpass", //
  82. "id_rsa_2048_testpass", //
  83. "id_rsa_3072_testpass", //
  84. "id_rsa_4096_testpass", //
  85. "id_ecdsa_256_testpass", //
  86. "id_ecdsa_384_testpass", //
  87. "id_ecdsa_521_testpass" };
  88. protected File defaultCloneDir;
  89. @Override
  90. public void setUp() throws Exception {
  91. super.setUp();
  92. defaultCloneDir = new File(getTemporaryDirectory(), "cloned");
  93. }
  94. @Test(expected = TransportException.class)
  95. public void testSshWithoutConfig() throws Exception {
  96. cloneWith("ssh://" + TEST_USER + "@localhost:" + testPort
  97. + "/doesntmatter", defaultCloneDir, null);
  98. }
  99. @Test
  100. public void testSshWithGlobalIdentity() throws Exception {
  101. cloneWith(
  102. "ssh://" + TEST_USER + "@localhost:" + testPort
  103. + "/doesntmatter",
  104. defaultCloneDir, null,
  105. "IdentityFile " + privateKey1.getAbsolutePath());
  106. }
  107. @Test
  108. public void testSshWithDefaultIdentity() throws Exception {
  109. File idRsa = new File(privateKey1.getParentFile(), "id_rsa");
  110. Files.copy(privateKey1.toPath(), idRsa.toPath());
  111. // We expect the session factory to pick up these keys...
  112. cloneWith("ssh://" + TEST_USER + "@localhost:" + testPort
  113. + "/doesntmatter", defaultCloneDir, null);
  114. }
  115. @Test
  116. public void testSshWithConfig() throws Exception {
  117. cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
  118. "Host localhost", //
  119. "HostName localhost", //
  120. "Port " + testPort, //
  121. "User " + TEST_USER, //
  122. "IdentityFile " + privateKey1.getAbsolutePath());
  123. }
  124. @Test
  125. public void testSshWithConfigEncryptedUnusedKey() throws Exception {
  126. // Copy the encrypted test key from the bundle.
  127. File encryptedKey = new File(sshDir, "id_dsa");
  128. copyTestResource("id_dsa_testpass", encryptedKey);
  129. TestCredentialsProvider provider = new TestCredentialsProvider(
  130. "testpass");
  131. cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
  132. "Host localhost", //
  133. "HostName localhost", //
  134. "Port " + testPort, //
  135. "User " + TEST_USER, //
  136. "IdentityFile " + privateKey1.getAbsolutePath());
  137. assertEquals("CredentialsProvider should not have been called", 0,
  138. provider.getLog().size());
  139. }
  140. @Test
  141. public void testSshWithConfigEncryptedUnusedKeyInConfigLast()
  142. throws Exception {
  143. // Copy the encrypted test key from the bundle.
  144. File encryptedKey = new File(sshDir, "id_dsa_test_key");
  145. copyTestResource("id_dsa_testpass", encryptedKey);
  146. TestCredentialsProvider provider = new TestCredentialsProvider(
  147. "testpass");
  148. cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
  149. "Host localhost", //
  150. "HostName localhost", //
  151. "Port " + testPort, //
  152. "User " + TEST_USER, //
  153. "IdentityFile " + privateKey1.getAbsolutePath(),
  154. "IdentityFile " + encryptedKey.getAbsolutePath());
  155. // This test passes with JSch per chance because JSch completely ignores
  156. // the second IdentityFile
  157. assertEquals("CredentialsProvider should not have been called", 0,
  158. provider.getLog().size());
  159. }
  160. @Test
  161. public void testSshWithConfigEncryptedUnusedKeyInConfigFirst()
  162. throws Exception {
  163. // Test cannot pass with JSch; it handles only one IdentityFile
  164. assumeTrue(!(getSessionFactory() instanceof JschConfigSessionFactory));
  165. // Copy the encrypted test key from the bundle.
  166. File encryptedKey = new File(sshDir, "id_dsa_test_key");
  167. copyTestResource("id_dsa_testpass", encryptedKey);
  168. TestCredentialsProvider provider = new TestCredentialsProvider(
  169. "testpass");
  170. cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
  171. "Host localhost", //
  172. "HostName localhost", //
  173. "Port " + testPort, //
  174. "User " + TEST_USER, //
  175. "IdentityFile " + encryptedKey.getAbsolutePath(),
  176. "IdentityFile " + privateKey1.getAbsolutePath());
  177. assertEquals("CredentialsProvider should have been called once", 1,
  178. provider.getLog().size());
  179. }
  180. @Test
  181. public void testSshEncryptedUsedKeyCached() throws Exception {
  182. // Make sure we are asked for the password only once if we do several
  183. // operations with an encrypted key.
  184. File encryptedKey = new File(sshDir, "id_dsa_test_key");
  185. copyTestResource("id_dsa_testpass", encryptedKey);
  186. File encryptedPublicKey = new File(sshDir, "id_dsa_test_key.pub");
  187. copyTestResource("id_dsa_testpass.pub", encryptedPublicKey);
  188. server.setTestUserPublicKey(encryptedPublicKey.toPath());
  189. TestCredentialsProvider provider = new TestCredentialsProvider(
  190. "testpass");
  191. pushTo(provider,
  192. cloneWith("ssh://localhost/doesntmatter", //
  193. defaultCloneDir, provider, //
  194. "Host localhost", //
  195. "HostName localhost", //
  196. "Port " + testPort, //
  197. "User " + TEST_USER, //
  198. "IdentityFile " + encryptedKey.getAbsolutePath()));
  199. assertEquals("CredentialsProvider should have been called once", 1,
  200. provider.getLog().size());
  201. }
  202. @Test(expected = TransportException.class)
  203. public void testSshWithoutKnownHosts() throws Exception {
  204. assertTrue("Could not delete known_hosts", knownHosts.delete());
  205. cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
  206. "Host localhost", //
  207. "HostName localhost", //
  208. "Port " + testPort, //
  209. "User " + TEST_USER, //
  210. "IdentityFile " + privateKey1.getAbsolutePath());
  211. }
  212. @Test
  213. public void testSshWithoutKnownHostsWithProviderAsk()
  214. throws Exception {
  215. File copiedHosts = new File(knownHosts.getParentFile(),
  216. "copiedKnownHosts");
  217. assertTrue("Failed to rename known_hosts",
  218. knownHosts.renameTo(copiedHosts));
  219. // The provider will answer "yes" to all questions, so we should be able
  220. // to connect and end up with a new known_hosts file with the host key.
  221. TestCredentialsProvider provider = new TestCredentialsProvider();
  222. cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
  223. "Host localhost", //
  224. "HostName localhost", //
  225. "Port " + testPort, //
  226. "User " + TEST_USER, //
  227. "IdentityFile " + privateKey1.getAbsolutePath());
  228. Map<URIish, List<CredentialItem>> messages = provider.getLog();
  229. assertFalse("Expected user interaction", messages.isEmpty());
  230. if (getSessionFactory() instanceof JschConfigSessionFactory) {
  231. // JSch doesn't create a non-existing file.
  232. assertEquals("Expected to be asked about the key", 1,
  233. messages.size());
  234. return;
  235. }
  236. assertEquals(
  237. "Expected to be asked about the key, and the file creation",
  238. 2, messages.size());
  239. assertTrue("~/.ssh/known_hosts should exist now", knownHosts.exists());
  240. // Instead of checking the file contents, let's just clone again
  241. // without provider. If it works, the server host key was written
  242. // correctly.
  243. File clonedAgain = new File(getTemporaryDirectory(), "cloned2");
  244. cloneWith("ssh://localhost/doesntmatter", clonedAgain, provider, //
  245. "Host localhost", //
  246. "HostName localhost", //
  247. "Port " + testPort, //
  248. "User " + TEST_USER, //
  249. "IdentityFile " + privateKey1.getAbsolutePath());
  250. }
  251. @Test
  252. public void testSshWithoutKnownHostsWithProviderAcceptNew()
  253. throws Exception {
  254. File copiedHosts = new File(knownHosts.getParentFile(),
  255. "copiedKnownHosts");
  256. assertTrue("Failed to rename known_hosts",
  257. knownHosts.renameTo(copiedHosts));
  258. TestCredentialsProvider provider = new TestCredentialsProvider();
  259. cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
  260. "Host localhost", //
  261. "HostName localhost", //
  262. "Port " + testPort, //
  263. "User " + TEST_USER, //
  264. "StrictHostKeyChecking accept-new", //
  265. "IdentityFile " + privateKey1.getAbsolutePath());
  266. if (getSessionFactory() instanceof JschConfigSessionFactory) {
  267. // JSch doesn't create new files.
  268. assertTrue("CredentialsProvider not called",
  269. provider.getLog().isEmpty());
  270. return;
  271. }
  272. assertEquals("Expected to be asked about the file creation", 1,
  273. provider.getLog().size());
  274. assertTrue("~/.ssh/known_hosts should exist now", knownHosts.exists());
  275. // Instead of checking the file contents, let's just clone again
  276. // without provider. If it works, the server host key was written
  277. // correctly.
  278. File clonedAgain = new File(getTemporaryDirectory(), "cloned2");
  279. cloneWith("ssh://localhost/doesntmatter", clonedAgain, null, //
  280. "Host localhost", //
  281. "HostName localhost", //
  282. "Port " + testPort, //
  283. "User " + TEST_USER, //
  284. "IdentityFile " + privateKey1.getAbsolutePath());
  285. }
  286. @Test(expected = TransportException.class)
  287. public void testSshWithoutKnownHostsDeny() throws Exception {
  288. File copiedHosts = new File(knownHosts.getParentFile(),
  289. "copiedKnownHosts");
  290. assertTrue("Failed to rename known_hosts",
  291. knownHosts.renameTo(copiedHosts));
  292. cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
  293. "Host localhost", //
  294. "HostName localhost", //
  295. "Port " + testPort, //
  296. "User " + TEST_USER, //
  297. "StrictHostKeyChecking yes", //
  298. "IdentityFile " + privateKey1.getAbsolutePath());
  299. }
  300. @Test(expected = TransportException.class)
  301. public void testSshModifiedHostKeyDeny()
  302. throws Exception {
  303. File copiedHosts = new File(knownHosts.getParentFile(),
  304. "copiedKnownHosts");
  305. assertTrue("Failed to rename known_hosts",
  306. knownHosts.renameTo(copiedHosts));
  307. // Now produce a new known_hosts file containing some other key.
  308. createKnownHostsFile(knownHosts, "localhost", testPort, publicKey1);
  309. cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
  310. "Host localhost", //
  311. "HostName localhost", //
  312. "Port " + testPort, //
  313. "User " + TEST_USER, //
  314. "StrictHostKeyChecking yes", //
  315. "IdentityFile " + privateKey1.getAbsolutePath());
  316. }
  317. @Test(expected = TransportException.class)
  318. public void testSshModifiedHostKeyWithProviderDeny() throws Exception {
  319. File copiedHosts = new File(knownHosts.getParentFile(),
  320. "copiedKnownHosts");
  321. assertTrue("Failed to rename known_hosts",
  322. knownHosts.renameTo(copiedHosts));
  323. // Now produce a new known_hosts file containing some other key.
  324. createKnownHostsFile(knownHosts, "localhost", testPort, publicKey1);
  325. TestCredentialsProvider provider = new TestCredentialsProvider();
  326. try {
  327. cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
  328. "Host localhost", //
  329. "HostName localhost", //
  330. "Port " + testPort, //
  331. "User " + TEST_USER, //
  332. "StrictHostKeyChecking yes", //
  333. "IdentityFile " + privateKey1.getAbsolutePath());
  334. } catch (Exception e) {
  335. assertEquals("Expected to be told about the modified key", 1,
  336. provider.getLog().size());
  337. assertTrue("Only messages expected", provider.getLog().values()
  338. .stream().flatMap(List::stream).allMatch(
  339. c -> c instanceof CredentialItem.InformationalMessage));
  340. throw e;
  341. }
  342. }
  343. private void checkKnownHostsModifiedHostKey(File backup, File newFile,
  344. String wrongKey) throws IOException {
  345. List<String> oldLines = Files.readAllLines(backup.toPath(),
  346. StandardCharsets.UTF_8);
  347. // Find the original entry. We should have that again in known_hosts.
  348. String oldKeyPart = null;
  349. for (String oldLine : oldLines) {
  350. if (oldLine.contains("[localhost]:")) {
  351. String[] parts = oldLine.split("\\s+");
  352. if (parts.length > 2) {
  353. oldKeyPart = parts[parts.length - 2] + ' '
  354. + parts[parts.length - 1];
  355. break;
  356. }
  357. }
  358. }
  359. assertNotNull("Old key not found", oldKeyPart);
  360. List<String> newLines = Files.readAllLines(newFile.toPath(),
  361. StandardCharsets.UTF_8);
  362. assertFalse("Old host key still found in known_hosts file" + newFile,
  363. hasHostKey("localhost", testPort, wrongKey, newLines));
  364. assertTrue("New host key not found in known_hosts file" + newFile,
  365. hasHostKey("localhost", testPort, oldKeyPart, newLines));
  366. }
  367. @Test
  368. public void testSshModifiedHostKeyAllow() throws Exception {
  369. assertTrue("Failed to delete known_hosts", knownHosts.delete());
  370. createKnownHostsFile(knownHosts, "localhost", testPort, publicKey1);
  371. File backup = new File(getTemporaryDirectory(), "backupKnownHosts");
  372. Files.copy(knownHosts.toPath(), backup.toPath());
  373. cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
  374. "Host localhost", //
  375. "HostName localhost", //
  376. "Port " + testPort, //
  377. "User " + TEST_USER, //
  378. "StrictHostKeyChecking no", //
  379. "IdentityFile " + privateKey1.getAbsolutePath());
  380. // File should not have been updated!
  381. String[] oldLines = Files
  382. .readAllLines(backup.toPath(), StandardCharsets.UTF_8)
  383. .toArray(new String[0]);
  384. String[] newLines = Files
  385. .readAllLines(knownHosts.toPath(), StandardCharsets.UTF_8)
  386. .toArray(new String[0]);
  387. assertArrayEquals("Known hosts file should not be modified", oldLines,
  388. newLines);
  389. }
  390. @Test
  391. public void testSshModifiedHostKeyAsk() throws Exception {
  392. File copiedHosts = new File(knownHosts.getParentFile(),
  393. "copiedKnownHosts");
  394. assertTrue("Failed to rename known_hosts",
  395. knownHosts.renameTo(copiedHosts));
  396. String wrongKeyPart = createKnownHostsFile(knownHosts, "localhost",
  397. testPort, publicKey1);
  398. TestCredentialsProvider provider = new TestCredentialsProvider();
  399. cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
  400. "Host localhost", //
  401. "HostName localhost", //
  402. "Port " + testPort, //
  403. "User " + TEST_USER, //
  404. "IdentityFile " + privateKey1.getAbsolutePath());
  405. checkKnownHostsModifiedHostKey(copiedHosts, knownHosts, wrongKeyPart);
  406. assertEquals("Expected to be asked about the modified key", 1,
  407. provider.getLog().size());
  408. }
  409. @Test
  410. public void testSshCloneWithConfigAndPush() throws Exception {
  411. pushTo(cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
  412. "Host localhost", //
  413. "HostName localhost", //
  414. "Port " + testPort, //
  415. "User " + TEST_USER, //
  416. "IdentityFile " + privateKey1.getAbsolutePath()));
  417. }
  418. @Test
  419. public void testSftpWithConfig() throws Exception {
  420. cloneWith("sftp://localhost/.git", defaultCloneDir, null, //
  421. "Host localhost", //
  422. "HostName localhost", //
  423. "Port " + testPort, //
  424. "User " + TEST_USER, //
  425. "IdentityFile " + privateKey1.getAbsolutePath());
  426. }
  427. @Test
  428. public void testSftpCloneWithConfigAndPush() throws Exception {
  429. pushTo(cloneWith("sftp://localhost/.git", defaultCloneDir, null, //
  430. "Host localhost", //
  431. "HostName localhost", //
  432. "Port " + testPort, //
  433. "User " + TEST_USER, //
  434. "IdentityFile " + privateKey1.getAbsolutePath()));
  435. }
  436. @Test(expected = TransportException.class)
  437. public void testSshWithConfigWrongKey() throws Exception {
  438. cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
  439. "Host localhost", //
  440. "HostName localhost", //
  441. "Port " + testPort, //
  442. "User " + TEST_USER, //
  443. "IdentityFile " + privateKey2.getAbsolutePath());
  444. }
  445. @Test
  446. public void testSshWithWrongUserNameInConfig() throws Exception {
  447. // Bug 526778
  448. cloneWith(
  449. "ssh://" + TEST_USER + "@localhost:" + testPort
  450. + "/doesntmatter",
  451. defaultCloneDir, null, //
  452. "Host localhost", //
  453. "HostName localhost", //
  454. "User sombody_else", //
  455. "IdentityFile " + privateKey1.getAbsolutePath());
  456. }
  457. @Test
  458. public void testSshWithWrongPortInConfig() throws Exception {
  459. // Bug 526778
  460. cloneWith(
  461. "ssh://" + TEST_USER + "@localhost:" + testPort
  462. + "/doesntmatter",
  463. defaultCloneDir, null, //
  464. "Host localhost", //
  465. "HostName localhost", //
  466. "Port 22", //
  467. "User " + TEST_USER, //
  468. "IdentityFile " + privateKey1.getAbsolutePath());
  469. }
  470. @Test
  471. public void testSshWithAliasInConfig() throws Exception {
  472. // Bug 531118
  473. cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
  474. "Host git", //
  475. "HostName localhost", //
  476. "Port " + testPort, //
  477. "User " + TEST_USER, //
  478. "IdentityFile " + privateKey1.getAbsolutePath(), "", //
  479. "Host localhost", //
  480. "HostName localhost", //
  481. "Port 22", //
  482. "User someone_else", //
  483. "IdentityFile " + privateKey2.getAbsolutePath());
  484. }
  485. @Test
  486. public void testSshWithUnknownCiphersInConfig() throws Exception {
  487. // Bug 535672
  488. cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
  489. "Host git", //
  490. "HostName localhost", //
  491. "Port " + testPort, //
  492. "User " + TEST_USER, //
  493. "IdentityFile " + privateKey1.getAbsolutePath(), //
  494. "Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr");
  495. }
  496. @Test
  497. public void testSshWithUnknownHostKeyAlgorithmsInConfig()
  498. throws Exception {
  499. // Bug 535672
  500. cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
  501. "Host git", //
  502. "HostName localhost", //
  503. "Port " + testPort, //
  504. "User " + TEST_USER, //
  505. "IdentityFile " + privateKey1.getAbsolutePath(), //
  506. "HostKeyAlgorithms foobar,ssh-rsa,ssh-dss");
  507. }
  508. @Test
  509. public void testSshWithUnknownKexAlgorithmsInConfig()
  510. throws Exception {
  511. // Bug 535672
  512. cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
  513. "Host git", //
  514. "HostName localhost", //
  515. "Port " + testPort, //
  516. "User " + TEST_USER, //
  517. "IdentityFile " + privateKey1.getAbsolutePath(), //
  518. "KexAlgorithms foobar,diffie-hellman-group14-sha1,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521");
  519. }
  520. @Test
  521. public void testSshWithMinimalHostKeyAlgorithmsInConfig()
  522. throws Exception {
  523. // Bug 537790
  524. cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
  525. "Host git", //
  526. "HostName localhost", //
  527. "Port " + testPort, //
  528. "User " + TEST_USER, //
  529. "IdentityFile " + privateKey1.getAbsolutePath(), //
  530. "HostKeyAlgorithms ssh-rsa,ssh-dss");
  531. }
  532. @Theory
  533. public void testSshKeys(String keyName) throws Exception {
  534. // JSch fails on ECDSA 384/521 keys. Compare
  535. // https://sourceforge.net/p/jsch/patches/10/
  536. assumeTrue(!(getSessionFactory() instanceof JschConfigSessionFactory
  537. && (keyName.startsWith("id_ecdsa_384")
  538. || keyName.startsWith("id_ecdsa_521"))));
  539. File cloned = new File(getTemporaryDirectory(), "cloned");
  540. String keyFileName = keyName + "_key";
  541. File privateKey = new File(sshDir, keyFileName);
  542. copyTestResource(keyName, privateKey);
  543. File publicKey = new File(sshDir, keyFileName + ".pub");
  544. copyTestResource(keyName + ".pub", publicKey);
  545. server.setTestUserPublicKey(publicKey.toPath());
  546. TestCredentialsProvider provider = new TestCredentialsProvider(
  547. "testpass");
  548. pushTo(provider,
  549. cloneWith("ssh://localhost/doesntmatter", //
  550. cloned, provider, //
  551. "Host localhost", //
  552. "HostName localhost", //
  553. "Port " + testPort, //
  554. "User " + TEST_USER, //
  555. "IdentityFile " + privateKey.getAbsolutePath()));
  556. int expectedCalls = keyName.endsWith("testpass") ? 1 : 0;
  557. assertEquals("Unexpected calls to CredentialsProvider", expectedCalls,
  558. provider.getLog().size());
  559. // Should now also work without credentials provider, even if the key
  560. // was encrypted.
  561. cloned = new File(getTemporaryDirectory(), "cloned2");
  562. pushTo(null,
  563. cloneWith("ssh://localhost/doesntmatter", //
  564. cloned, null, //
  565. "Host localhost", //
  566. "HostName localhost", //
  567. "Port " + testPort, //
  568. "User " + TEST_USER, //
  569. "IdentityFile " + privateKey.getAbsolutePath()));
  570. }
  571. }