1
2
3
4
5
6
7
8
9
10 package org.eclipse.jgit.junit.ssh;
11
12 import static java.nio.charset.StandardCharsets.UTF_8;
13 import static org.junit.Assert.assertArrayEquals;
14 import static org.junit.Assert.assertEquals;
15 import static org.junit.Assert.assertFalse;
16 import static org.junit.Assert.assertNotNull;
17 import static org.junit.Assert.assertThrows;
18 import static org.junit.Assert.assertTrue;
19 import static org.junit.Assume.assumeTrue;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.nio.file.Files;
24 import java.util.List;
25 import java.util.Locale;
26 import java.util.concurrent.TimeUnit;
27
28 import org.eclipse.jgit.api.errors.TransportException;
29 import org.eclipse.jgit.errors.CommandFailedException;
30 import org.eclipse.jgit.transport.CredentialItem;
31 import org.eclipse.jgit.transport.URIish;
32 import org.eclipse.jgit.util.FS;
33 import org.eclipse.jgit.util.SshSupport;
34 import org.junit.Test;
35 import org.junit.experimental.theories.DataPoints;
36 import org.junit.experimental.theories.Theory;
37
38
39
40
41
42
43 public abstract class SshTestBase extends SshBasicTestBase {
44
45 @DataPoints
46 public static String[] KEY_RESOURCES = {
47 "id_dsa",
48 "id_rsa_1024",
49 "id_rsa_2048",
50 "id_rsa_3072",
51 "id_rsa_4096",
52 "id_ecdsa_256",
53 "id_ecdsa_384",
54 "id_ecdsa_521",
55 "id_ed25519",
56
57 "id_dsa_testpass",
58 "id_rsa_1024_testpass",
59 "id_rsa_2048_testpass",
60 "id_rsa_3072_testpass",
61 "id_rsa_4096_testpass",
62 "id_ecdsa_256_testpass",
63 "id_ecdsa_384_testpass",
64 "id_ecdsa_521_testpass",
65 "id_ed25519_testpass",
66 "id_ed25519_expensive_testpass" };
67
68 @Test
69 public void testSshWithoutConfig() throws Exception {
70 assertThrows(TransportException.class,
71 () -> cloneWith("ssh://" + TEST_USER + "@localhost:" + testPort
72 + "/doesntmatter", defaultCloneDir, null));
73 }
74
75 @Test
76 public void testSingleCommand() throws Exception {
77 installConfig("IdentityFile " + privateKey1.getAbsolutePath());
78 String command = SshTestGitServer.ECHO_COMMAND + " 1 without timeout";
79 long start = System.nanoTime();
80 String reply = SshSupport.runSshCommand(
81 new URIish("ssh://" + TEST_USER + "@localhost:" + testPort),
82 null, FS.DETECTED, command, 0);
83 long elapsed = System.nanoTime() - start;
84 assertEquals(command, reply);
85
86
87 command = SshTestGitServer.ECHO_COMMAND + " 1 expecting no timeout";
88
89 int timeout = 10 * ((int) TimeUnit.NANOSECONDS.toSeconds(elapsed) + 1);
90 reply = SshSupport.runSshCommand(
91 new URIish("ssh://" + TEST_USER + "@localhost:" + testPort),
92 null, FS.DETECTED, command, timeout);
93 assertEquals(command, reply);
94 }
95
96 @Test
97 public void testSingleCommandWithTimeoutExpired() throws Exception {
98 installConfig("IdentityFile " + privateKey1.getAbsolutePath());
99 String command = SshTestGitServer.ECHO_COMMAND + " 2 EXPECTING TIMEOUT";
100
101 CommandFailedException e = assertThrows(CommandFailedException.class,
102 () -> SshSupport.runSshCommand(new URIish(
103 "ssh://" + TEST_USER + "@localhost:" + testPort), null,
104 FS.DETECTED, command, 1));
105 assertTrue(e.getMessage().contains(command));
106 assertTrue(e.getMessage().contains("time"));
107 }
108
109 @Test
110 public void testSshWithGlobalIdentity() throws Exception {
111 cloneWith(
112 "ssh://" + TEST_USER + "@localhost:" + testPort
113 + "/doesntmatter",
114 defaultCloneDir, null,
115 "IdentityFile " + privateKey1.getAbsolutePath());
116 }
117
118 @Test
119 public void testSshWithDefaultIdentity() throws Exception {
120 File idRsa = new File(privateKey1.getParentFile(), "id_rsa");
121 Files.copy(privateKey1.toPath(), idRsa.toPath());
122
123 cloneWith("ssh://" + TEST_USER + "@localhost:" + testPort
124 + "/doesntmatter", defaultCloneDir, null);
125 }
126
127 @Test
128 public void testSshWithConfigEncryptedUnusedKey() throws Exception {
129
130 File encryptedKey = new File(sshDir, "id_dsa");
131 copyTestResource("id_dsa_testpass", encryptedKey);
132 TestCredentialsProvider provider = new TestCredentialsProvider(
133 "testpass");
134 cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
135 "Host localhost",
136 "HostName localhost",
137 "Port " + testPort,
138 "User " + TEST_USER,
139 "IdentityFile " + privateKey1.getAbsolutePath());
140 assertEquals("CredentialsProvider should not have been called", 0,
141 provider.getLog().size());
142 }
143
144 @Test
145 public void testSshWithConfigEncryptedUnusedKeyInConfigLast()
146 throws Exception {
147
148 File encryptedKey = new File(sshDir, "id_dsa_test_key");
149 copyTestResource("id_dsa_testpass", encryptedKey);
150 TestCredentialsProvider provider = new TestCredentialsProvider(
151 "testpass");
152 cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
153 "Host localhost",
154 "HostName localhost",
155 "Port " + testPort,
156 "User " + TEST_USER,
157 "IdentityFile " + privateKey1.getAbsolutePath(),
158 "IdentityFile " + encryptedKey.getAbsolutePath());
159
160
161 assertEquals("CredentialsProvider should not have been called", 0,
162 provider.getLog().size());
163 }
164
165 private boolean isJsch() {
166 return getSessionFactory().getType().equals("jsch");
167 }
168
169 @Test
170 public void testSshWithConfigEncryptedUnusedKeyInConfigFirst()
171 throws Exception {
172
173
174
175
176
177 if (isJsch()) {
178 return;
179 }
180
181 File encryptedKey = new File(sshDir, "id_dsa_test_key");
182 copyTestResource("id_dsa_testpass", encryptedKey);
183 TestCredentialsProvider provider = new TestCredentialsProvider(
184 "testpass");
185 cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
186 "Host localhost",
187 "HostName localhost",
188 "Port " + testPort,
189 "User " + TEST_USER,
190 "IdentityFile " + encryptedKey.getAbsolutePath(),
191 "IdentityFile " + privateKey1.getAbsolutePath());
192 assertEquals("CredentialsProvider should have been called once", 1,
193 provider.getLog().size());
194 }
195
196 @Test
197 public void testSshEncryptedUsedKeyCached() throws Exception {
198
199
200 File encryptedKey = new File(sshDir, "id_dsa_test_key");
201 copyTestResource("id_dsa_testpass", encryptedKey);
202 File encryptedPublicKey = new File(sshDir, "id_dsa_test_key.pub");
203 copyTestResource("id_dsa_testpass.pub", encryptedPublicKey);
204 server.setTestUserPublicKey(encryptedPublicKey.toPath());
205 TestCredentialsProvider provider = new TestCredentialsProvider(
206 "testpass");
207 pushTo(provider,
208 cloneWith("ssh://localhost/doesntmatter", //
209 defaultCloneDir, provider,
210 "Host localhost",
211 "HostName localhost",
212 "Port " + testPort,
213 "User " + TEST_USER,
214 "IdentityFile " + encryptedKey.getAbsolutePath()));
215 assertEquals("CredentialsProvider should have been called once", 1,
216 provider.getLog().size());
217 }
218
219 @Test(expected = TransportException.class)
220 public void testSshEncryptedUsedKeyWrongPassword() throws Exception {
221 File encryptedKey = new File(sshDir, "id_dsa_test_key");
222 copyTestResource("id_dsa_testpass", encryptedKey);
223 File encryptedPublicKey = new File(sshDir, "id_dsa_test_key.pub");
224 copyTestResource("id_dsa_testpass.pub", encryptedPublicKey);
225 server.setTestUserPublicKey(encryptedPublicKey.toPath());
226 TestCredentialsProvider provider = new TestCredentialsProvider(
227 "wrongpass");
228 cloneWith("ssh://localhost/doesntmatter", //
229 defaultCloneDir, provider,
230 "Host localhost",
231 "HostName localhost",
232 "Port " + testPort,
233 "User " + TEST_USER,
234 "NumberOfPasswordPrompts 1",
235 "IdentityFile " + encryptedKey.getAbsolutePath());
236 }
237
238 @Test
239 public void testSshEncryptedUsedKeySeveralPassword() throws Exception {
240 File encryptedKey = new File(sshDir, "id_dsa_test_key");
241 copyTestResource("id_dsa_testpass", encryptedKey);
242 File encryptedPublicKey = new File(sshDir, "id_dsa_test_key.pub");
243 copyTestResource("id_dsa_testpass.pub", encryptedPublicKey);
244 server.setTestUserPublicKey(encryptedPublicKey.toPath());
245 TestCredentialsProvider provider = new TestCredentialsProvider(
246 "wrongpass", "wrongpass2", "testpass");
247 cloneWith("ssh://localhost/doesntmatter", //
248 defaultCloneDir, provider,
249 "Host localhost",
250 "HostName localhost",
251 "Port " + testPort,
252 "User " + TEST_USER,
253 "IdentityFile " + encryptedKey.getAbsolutePath());
254 assertEquals("CredentialsProvider should have been called 3 times", 3,
255 provider.getLog().size());
256 }
257
258 @Test(expected = TransportException.class)
259 public void testSshWithoutKnownHosts() throws Exception {
260 assertTrue("Could not delete known_hosts", knownHosts.delete());
261 cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
262 "Host localhost",
263 "HostName localhost",
264 "Port " + testPort,
265 "User " + TEST_USER,
266 "IdentityFile " + privateKey1.getAbsolutePath());
267 }
268
269 @Test
270 public void testSshWithoutKnownHostsWithProviderAsk()
271 throws Exception {
272 File copiedHosts = new File(knownHosts.getParentFile(),
273 "copiedKnownHosts");
274 assertTrue("Failed to rename known_hosts",
275 knownHosts.renameTo(copiedHosts));
276
277
278 TestCredentialsProvider provider = new TestCredentialsProvider();
279 cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
280 "Host localhost",
281 "HostName localhost",
282 "Port " + testPort,
283 "User " + TEST_USER,
284 "IdentityFile " + privateKey1.getAbsolutePath());
285 List<LogEntry> messages = provider.getLog();
286 assertFalse("Expected user interaction", messages.isEmpty());
287 if (isJsch()) {
288
289 assertEquals("Expected to be asked about the key", 1,
290 messages.size());
291 return;
292 }
293 assertEquals(
294 "Expected to be asked about the key, and the file creation",
295 2, messages.size());
296 assertTrue("~/.ssh/known_hosts should exist now", knownHosts.exists());
297
298
299
300 File clonedAgain = new File(getTemporaryDirectory(), "cloned2");
301 cloneWith("ssh://localhost/doesntmatter", clonedAgain, null, //
302 "Host localhost",
303 "HostName localhost",
304 "Port " + testPort,
305 "User " + TEST_USER,
306 "IdentityFile " + privateKey1.getAbsolutePath());
307 }
308
309 @Test
310 public void testSshWithoutKnownHostsWithProviderAcceptNew()
311 throws Exception {
312 File copiedHosts = new File(knownHosts.getParentFile(),
313 "copiedKnownHosts");
314 assertTrue("Failed to rename known_hosts",
315 knownHosts.renameTo(copiedHosts));
316 TestCredentialsProvider provider = new TestCredentialsProvider();
317 cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
318 "Host localhost",
319 "HostName localhost",
320 "Port " + testPort,
321 "User " + TEST_USER,
322 "StrictHostKeyChecking accept-new",
323 "IdentityFile " + privateKey1.getAbsolutePath());
324 if (isJsch()) {
325
326 assertTrue("CredentialsProvider not called",
327 provider.getLog().isEmpty());
328 return;
329 }
330 assertEquals("Expected to be asked about the file creation", 1,
331 provider.getLog().size());
332 assertTrue("~/.ssh/known_hosts should exist now", knownHosts.exists());
333
334
335
336 File clonedAgain = new File(getTemporaryDirectory(), "cloned2");
337 cloneWith("ssh://localhost/doesntmatter", clonedAgain, null, //
338 "Host localhost",
339 "HostName localhost",
340 "Port " + testPort,
341 "User " + TEST_USER,
342 "IdentityFile " + privateKey1.getAbsolutePath());
343 }
344
345 @Test(expected = TransportException.class)
346 public void testSshWithoutKnownHostsDeny() throws Exception {
347 File copiedHosts = new File(knownHosts.getParentFile(),
348 "copiedKnownHosts");
349 assertTrue("Failed to rename known_hosts",
350 knownHosts.renameTo(copiedHosts));
351 cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
352 "Host localhost",
353 "HostName localhost",
354 "Port " + testPort,
355 "User " + TEST_USER,
356 "StrictHostKeyChecking yes",
357 "IdentityFile " + privateKey1.getAbsolutePath());
358 }
359
360 @Test(expected = TransportException.class)
361 public void testSshModifiedHostKeyDeny()
362 throws Exception {
363 File copiedHosts = new File(knownHosts.getParentFile(),
364 "copiedKnownHosts");
365 assertTrue("Failed to rename known_hosts",
366 knownHosts.renameTo(copiedHosts));
367
368 createKnownHostsFile(knownHosts, "localhost", testPort, publicKey1);
369 cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
370 "Host localhost",
371 "HostName localhost",
372 "Port " + testPort,
373 "User " + TEST_USER,
374 "StrictHostKeyChecking yes",
375 "IdentityFile " + privateKey1.getAbsolutePath());
376 }
377
378 @Test(expected = TransportException.class)
379 public void testSshModifiedHostKeyWithProviderDeny() throws Exception {
380 File copiedHosts = new File(knownHosts.getParentFile(),
381 "copiedKnownHosts");
382 assertTrue("Failed to rename known_hosts",
383 knownHosts.renameTo(copiedHosts));
384
385 createKnownHostsFile(knownHosts, "localhost", testPort, publicKey1);
386 TestCredentialsProvider provider = new TestCredentialsProvider();
387 try {
388 cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
389 "Host localhost",
390 "HostName localhost",
391 "Port " + testPort,
392 "User " + TEST_USER,
393 "StrictHostKeyChecking yes",
394 "IdentityFile " + privateKey1.getAbsolutePath());
395 } catch (Exception e) {
396 assertEquals("Expected to be told about the modified key", 1,
397 provider.getLog().size());
398 assertTrue("Only messages expected", provider.getLog().stream()
399 .flatMap(l -> l.getItems().stream()).allMatch(
400 c -> c instanceof CredentialItem.InformationalMessage));
401 throw e;
402 }
403 }
404
405 private void checkKnownHostsModifiedHostKey(File backup, File newFile,
406 String wrongKey) throws IOException {
407 List<String> oldLines = Files.readAllLines(backup.toPath(), UTF_8);
408
409 String oldKeyPart = null;
410 for (String oldLine : oldLines) {
411 if (oldLine.contains("[localhost]:")) {
412 String[] parts = oldLine.split("\\s+");
413 if (parts.length > 2) {
414 oldKeyPart = parts[parts.length - 2] + ' '
415 + parts[parts.length - 1];
416 break;
417 }
418 }
419 }
420 assertNotNull("Old key not found", oldKeyPart);
421 List<String> newLines = Files.readAllLines(newFile.toPath(), UTF_8);
422 assertFalse("Old host key still found in known_hosts file" + newFile,
423 hasHostKey("localhost", testPort, wrongKey, newLines));
424 assertTrue("New host key not found in known_hosts file" + newFile,
425 hasHostKey("localhost", testPort, oldKeyPart, newLines));
426
427 }
428
429 @Test
430 public void testSshModifiedHostKeyAllow() throws Exception {
431 assertTrue("Failed to delete known_hosts", knownHosts.delete());
432 createKnownHostsFile(knownHosts, "localhost", testPort, publicKey1);
433 File backup = new File(getTemporaryDirectory(), "backupKnownHosts");
434 Files.copy(knownHosts.toPath(), backup.toPath());
435 cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
436 "Host localhost",
437 "HostName localhost",
438 "Port " + testPort,
439 "User " + TEST_USER,
440 "StrictHostKeyChecking no",
441 "IdentityFile " + privateKey1.getAbsolutePath());
442
443 String[] oldLines = Files
444 .readAllLines(backup.toPath(), UTF_8)
445 .toArray(new String[0]);
446 String[] newLines = Files
447 .readAllLines(knownHosts.toPath(), UTF_8)
448 .toArray(new String[0]);
449 assertArrayEquals("Known hosts file should not be modified", oldLines,
450 newLines);
451 }
452
453 @Test
454 public void testSshModifiedHostKeyAsk() throws Exception {
455 File copiedHosts = new File(knownHosts.getParentFile(),
456 "copiedKnownHosts");
457 assertTrue("Failed to rename known_hosts",
458 knownHosts.renameTo(copiedHosts));
459 String wrongKeyPart = createKnownHostsFile(knownHosts, "localhost",
460 testPort, publicKey1);
461 TestCredentialsProvider provider = new TestCredentialsProvider();
462 cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
463 "Host localhost",
464 "HostName localhost",
465 "Port " + testPort,
466 "User " + TEST_USER,
467 "IdentityFile " + privateKey1.getAbsolutePath());
468 checkKnownHostsModifiedHostKey(copiedHosts, knownHosts, wrongKeyPart);
469 assertEquals("Expected to be asked about the modified key", 1,
470 provider.getLog().size());
471 }
472
473 @Test
474 public void testSshCloneWithConfigAndPush() throws Exception {
475 pushTo(cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
476 "Host localhost",
477 "HostName localhost",
478 "Port " + testPort,
479 "User " + TEST_USER,
480 "IdentityFile " + privateKey1.getAbsolutePath()));
481 }
482
483 @Test
484 public void testSftpWithConfig() throws Exception {
485 cloneWith("sftp://localhost/.git", defaultCloneDir, null, //
486 "Host localhost",
487 "HostName localhost",
488 "Port " + testPort,
489 "User " + TEST_USER,
490 "IdentityFile " + privateKey1.getAbsolutePath());
491 }
492
493 @Test
494 public void testSftpCloneWithConfigAndPush() throws Exception {
495 pushTo(cloneWith("sftp://localhost/.git", defaultCloneDir, null, //
496 "Host localhost",
497 "HostName localhost",
498 "Port " + testPort,
499 "User " + TEST_USER,
500 "IdentityFile " + privateKey1.getAbsolutePath()));
501 }
502
503 @Test(expected = TransportException.class)
504 public void testSshWithConfigWrongKey() throws Exception {
505 cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
506 "Host localhost",
507 "HostName localhost",
508 "Port " + testPort,
509 "User " + TEST_USER,
510 "IdentityFile " + privateKey2.getAbsolutePath());
511 }
512
513 @Test
514 public void testSshWithWrongUserNameInConfig() throws Exception {
515
516 cloneWith(
517 "ssh://" + TEST_USER + "@localhost:" + testPort
518 + "/doesntmatter",
519 defaultCloneDir, null,
520 "Host localhost",
521 "HostName localhost",
522 "User sombody_else",
523 "IdentityFile " + privateKey1.getAbsolutePath());
524 }
525
526 @Test
527 public void testSshWithWrongPortInConfig() throws Exception {
528
529 cloneWith(
530 "ssh://" + TEST_USER + "@localhost:" + testPort
531 + "/doesntmatter",
532 defaultCloneDir, null,
533 "Host localhost",
534 "HostName localhost",
535 "Port 22",
536 "User " + TEST_USER,
537 "IdentityFile " + privateKey1.getAbsolutePath());
538 }
539
540 @Test
541 public void testSshWithAliasInConfig() throws Exception {
542
543 cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
544 "Host git",
545 "HostName localhost",
546 "Port " + testPort,
547 "User " + TEST_USER,
548 "IdentityFile " + privateKey1.getAbsolutePath(), "",
549 "Host localhost",
550 "HostName localhost",
551 "Port 22",
552 "User someone_else",
553 "IdentityFile " + privateKey2.getAbsolutePath());
554 }
555
556 @Test
557 public void testSshWithUnknownCiphersInConfig() throws Exception {
558
559 cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
560 "Host git",
561 "HostName localhost",
562 "Port " + testPort,
563 "User " + TEST_USER,
564 "IdentityFile " + privateKey1.getAbsolutePath(),
565 "Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr");
566 }
567
568 @Test
569 public void testSshWithUnknownHostKeyAlgorithmsInConfig()
570 throws Exception {
571
572 cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
573 "Host git",
574 "HostName localhost",
575 "Port " + testPort,
576 "User " + TEST_USER,
577 "IdentityFile " + privateKey1.getAbsolutePath(),
578 "HostKeyAlgorithms foobar,ssh-rsa,ssh-dss");
579 }
580
581 @Test
582 public void testSshWithUnknownKexAlgorithmsInConfig()
583 throws Exception {
584
585 cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
586 "Host git",
587 "HostName localhost",
588 "Port " + testPort,
589 "User " + TEST_USER,
590 "IdentityFile " + privateKey1.getAbsolutePath(),
591 "KexAlgorithms foobar,diffie-hellman-group14-sha1,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521");
592 }
593
594 @Test
595 public void testSshWithMinimalHostKeyAlgorithmsInConfig()
596 throws Exception {
597
598 cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
599 "Host git",
600 "HostName localhost",
601 "Port " + testPort,
602 "User " + TEST_USER,
603 "IdentityFile " + privateKey1.getAbsolutePath(),
604 "HostKeyAlgorithms ssh-rsa,ssh-dss");
605 }
606
607 @Test
608 public void testSshWithUnknownAuthInConfig() throws Exception {
609 cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
610 "Host git",
611 "HostName localhost",
612 "Port " + testPort,
613 "User " + TEST_USER,
614 "IdentityFile " + privateKey1.getAbsolutePath(),
615 "PreferredAuthentications gssapi-with-mic,hostbased,publickey,keyboard-interactive,password");
616 }
617
618 @Test(expected = TransportException.class)
619 public void testSshWithNoMatchingAuthInConfig() throws Exception {
620
621 cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
622 "Host git",
623 "HostName localhost",
624 "Port " + testPort,
625 "User " + TEST_USER,
626 "IdentityFile " + privateKey1.getAbsolutePath(),
627 "PreferredAuthentications password");
628 }
629
630 @Test
631 public void testRsaHostKeySecond() throws Exception {
632
633
634
635 File newHostKey = new File(getTemporaryDirectory(), "newhostkey");
636 copyTestResource("id_ecdsa_256", newHostKey);
637 server.addHostKey(newHostKey.toPath(), true);
638 cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
639 "Host git",
640 "HostName localhost",
641 "Port " + testPort,
642 "User " + TEST_USER,
643 "IdentityFile " + privateKey1.getAbsolutePath());
644 }
645
646 @Test
647 public void testEcDsaHostKey() throws Exception {
648
649
650
651 File newHostKey = new File(getTemporaryDirectory(), "newhostkey");
652 copyTestResource("id_ecdsa_256", newHostKey);
653 server.addHostKey(newHostKey.toPath(), false);
654 File newHostKeyPub = new File(getTemporaryDirectory(),
655 "newhostkey.pub");
656 copyTestResource("id_ecdsa_256.pub", newHostKeyPub);
657 createKnownHostsFile(knownHosts, "localhost", testPort, newHostKeyPub);
658 cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
659 "Host git",
660 "HostName localhost",
661 "Port " + testPort,
662 "User " + TEST_USER,
663 "IdentityFile " + privateKey1.getAbsolutePath());
664 }
665
666 @Test
667 public void testPasswordAuth() throws Exception {
668 server.enablePasswordAuthentication();
669 TestCredentialsProvider provider = new TestCredentialsProvider(
670 TEST_USER.toUpperCase(Locale.ROOT));
671 cloneWith("ssh://git/doesntmatter", defaultCloneDir, provider, //
672 "Host git",
673 "HostName localhost",
674 "Port " + testPort,
675 "User " + TEST_USER,
676 "PreferredAuthentications password");
677 }
678
679 @Test
680 public void testPasswordAuthSeveralTimes() throws Exception {
681 server.enablePasswordAuthentication();
682 TestCredentialsProvider provider = new TestCredentialsProvider(
683 "wrongpass", "wrongpass", TEST_USER.toUpperCase(Locale.ROOT));
684 cloneWith("ssh://git/doesntmatter", defaultCloneDir, provider, //
685 "Host git",
686 "HostName localhost",
687 "Port " + testPort,
688 "User " + TEST_USER,
689 "PreferredAuthentications password");
690 }
691
692 @Test(expected = TransportException.class)
693 public void testPasswordAuthWrongPassword() throws Exception {
694 server.enablePasswordAuthentication();
695 TestCredentialsProvider provider = new TestCredentialsProvider(
696 "wrongpass");
697 cloneWith("ssh://git/doesntmatter", defaultCloneDir, provider, //
698 "Host git",
699 "HostName localhost",
700 "Port " + testPort,
701 "User " + TEST_USER,
702 "PreferredAuthentications password");
703 }
704
705 @Test(expected = TransportException.class)
706 public void testPasswordAuthNoPassword() throws Exception {
707 server.enablePasswordAuthentication();
708 TestCredentialsProvider provider = new TestCredentialsProvider();
709 cloneWith("ssh://git/doesntmatter", defaultCloneDir, provider, //
710 "Host git",
711 "HostName localhost",
712 "Port " + testPort,
713 "User " + TEST_USER,
714 "PreferredAuthentications password");
715 }
716
717 @Test(expected = TransportException.class)
718 public void testPasswordAuthCorrectPasswordTooLate() throws Exception {
719 server.enablePasswordAuthentication();
720 TestCredentialsProvider provider = new TestCredentialsProvider(
721 "wrongpass", "wrongpass", "wrongpass",
722 TEST_USER.toUpperCase(Locale.ROOT));
723 cloneWith("ssh://git/doesntmatter", defaultCloneDir, provider, //
724 "Host git",
725 "HostName localhost",
726 "Port " + testPort,
727 "User " + TEST_USER,
728 "PreferredAuthentications password");
729 }
730
731 @Test
732 public void testKeyboardInteractiveAuth() throws Exception {
733 server.enableKeyboardInteractiveAuthentication();
734 TestCredentialsProvider provider = new TestCredentialsProvider(
735 TEST_USER.toUpperCase(Locale.ROOT));
736 cloneWith("ssh://git/doesntmatter", defaultCloneDir, provider, //
737 "Host git",
738 "HostName localhost",
739 "Port " + testPort,
740 "User " + TEST_USER,
741 "PreferredAuthentications keyboard-interactive");
742 }
743
744 @Test
745 public void testKeyboardInteractiveAuthSeveralTimes() throws Exception {
746 server.enableKeyboardInteractiveAuthentication();
747 TestCredentialsProvider provider = new TestCredentialsProvider(
748 "wrongpass", "wrongpass", TEST_USER.toUpperCase(Locale.ROOT));
749 cloneWith("ssh://git/doesntmatter", defaultCloneDir, provider, //
750 "Host git",
751 "HostName localhost",
752 "Port " + testPort,
753 "User " + TEST_USER,
754 "PreferredAuthentications keyboard-interactive");
755 }
756
757 @Test(expected = TransportException.class)
758 public void testKeyboardInteractiveAuthWrongPassword() throws Exception {
759 server.enableKeyboardInteractiveAuthentication();
760 TestCredentialsProvider provider = new TestCredentialsProvider(
761 "wrongpass");
762 cloneWith("ssh://git/doesntmatter", defaultCloneDir, provider, //
763 "Host git",
764 "HostName localhost",
765 "Port " + testPort,
766 "User " + TEST_USER,
767 "PreferredAuthentications keyboard-interactive");
768 }
769
770 @Test(expected = TransportException.class)
771 public void testKeyboardInteractiveAuthNoPassword() throws Exception {
772 server.enableKeyboardInteractiveAuthentication();
773 TestCredentialsProvider provider = new TestCredentialsProvider();
774 cloneWith("ssh://git/doesntmatter", defaultCloneDir, provider, //
775 "Host git",
776 "HostName localhost",
777 "Port " + testPort,
778 "User " + TEST_USER,
779 "PreferredAuthentications keyboard-interactive");
780 }
781
782 @Test(expected = TransportException.class)
783 public void testKeyboardInteractiveAuthCorrectPasswordTooLate()
784 throws Exception {
785 server.enableKeyboardInteractiveAuthentication();
786 TestCredentialsProvider provider = new TestCredentialsProvider(
787 "wrongpass", "wrongpass", "wrongpass",
788 TEST_USER.toUpperCase(Locale.ROOT));
789 cloneWith("ssh://git/doesntmatter", defaultCloneDir, provider, //
790 "Host git",
791 "HostName localhost",
792 "Port " + testPort,
793 "User " + TEST_USER,
794 "PreferredAuthentications keyboard-interactive");
795 }
796
797 @Theory
798 public void testSshKeys(String keyName) throws Exception {
799
800
801 assumeTrue(!(isJsch() && (keyName.contains("ed25519")
802 || keyName.startsWith("id_ecdsa_384")
803 || keyName.startsWith("id_ecdsa_521"))));
804 File cloned = new File(getTemporaryDirectory(), "cloned");
805 String keyFileName = keyName + "_key";
806 File privateKey = new File(sshDir, keyFileName);
807 copyTestResource(keyName, privateKey);
808 File publicKey = new File(sshDir, keyFileName + ".pub");
809 copyTestResource(keyName + ".pub", publicKey);
810 server.setTestUserPublicKey(publicKey.toPath());
811 TestCredentialsProvider provider = new TestCredentialsProvider(
812 "testpass");
813 pushTo(provider,
814 cloneWith("ssh://localhost/doesntmatter", //
815 cloned, provider,
816 "Host localhost",
817 "HostName localhost",
818 "Port " + testPort,
819 "User " + TEST_USER,
820 "IdentityFile " + privateKey.getAbsolutePath()));
821 int expectedCalls = keyName.endsWith("testpass") ? 1 : 0;
822 assertEquals("Unexpected calls to CredentialsProvider", expectedCalls,
823 provider.getLog().size());
824
825
826 cloned = new File(getTemporaryDirectory(), "cloned2");
827 pushTo(null,
828 cloneWith("ssh://localhost/doesntmatter", //
829 cloned, null,
830 "Host localhost",
831 "HostName localhost",
832 "Port " + testPort,
833 "User " + TEST_USER,
834 "IdentityFile " + privateKey.getAbsolutePath()));
835 }
836 }