1
2
3
4
5
6
7
8
9
10 package org.eclipse.jgit.transport.sshd;
11
12 import static org.apache.sshd.core.CoreModuleProperties.MAX_CONCURRENT_SESSIONS;
13 import static org.junit.Assert.assertEquals;
14 import static org.junit.Assert.assertFalse;
15 import static org.junit.Assert.assertNotNull;
16 import static org.junit.Assert.assertThrows;
17 import static org.junit.Assert.assertTrue;
18
19 import java.io.BufferedWriter;
20 import java.io.File;
21 import java.io.IOException;
22 import java.io.UncheckedIOException;
23 import java.net.URISyntaxException;
24 import java.nio.charset.StandardCharsets;
25 import java.nio.file.Files;
26 import java.nio.file.StandardOpenOption;
27 import java.security.KeyPair;
28 import java.security.KeyPairGenerator;
29 import java.security.PublicKey;
30 import java.util.Arrays;
31 import java.util.Collections;
32 import java.util.List;
33 import java.util.stream.Collectors;
34
35 import org.apache.sshd.client.config.hosts.KnownHostEntry;
36 import org.apache.sshd.client.config.hosts.KnownHostHashValue;
37 import org.apache.sshd.common.NamedFactory;
38 import org.apache.sshd.common.config.keys.AuthorizedKeyEntry;
39 import org.apache.sshd.common.config.keys.KeyUtils;
40 import org.apache.sshd.common.config.keys.PublicKeyEntry;
41 import org.apache.sshd.common.config.keys.PublicKeyEntryResolver;
42 import org.apache.sshd.common.kex.BuiltinDHFactories;
43 import org.apache.sshd.common.kex.DHFactory;
44 import org.apache.sshd.common.kex.KeyExchangeFactory;
45 import org.apache.sshd.common.session.Session;
46 import org.apache.sshd.common.util.net.SshdSocketAddress;
47 import org.apache.sshd.server.ServerAuthenticationManager;
48 import org.apache.sshd.server.ServerBuilder;
49 import org.apache.sshd.server.SshServer;
50 import org.apache.sshd.server.forward.StaticDecisionForwardingFilter;
51 import org.eclipse.jgit.api.Git;
52 import org.eclipse.jgit.api.errors.TransportException;
53 import org.eclipse.jgit.junit.ssh.SshTestBase;
54 import org.eclipse.jgit.lib.Constants;
55 import org.eclipse.jgit.transport.RemoteSession;
56 import org.eclipse.jgit.transport.SshSessionFactory;
57 import org.eclipse.jgit.transport.URIish;
58 import org.eclipse.jgit.util.FS;
59 import org.junit.Test;
60 import org.junit.experimental.theories.Theories;
61 import org.junit.runner.RunWith;
62
63 @RunWith(Theories.class)
64 public class ApacheSshTest extends SshTestBase {
65
66 @Override
67 protected SshSessionFactory createSessionFactory() {
68 return new SshdSessionFactoryBuilder()
69
70 .setProxyDataFactory(null)
71
72 .setConnectorFactory(null)
73
74 .setHomeDirectory(FS.DETECTED.userHome())
75 .setSshDirectory(sshDir)
76 .build(new JGitKeyCache());
77 }
78
79 @Override
80 protected void installConfig(String... config) {
81 File configFile = new File(sshDir, Constants.CONFIG);
82 if (config != null) {
83 try {
84 Files.write(configFile.toPath(), Arrays.asList(config));
85 } catch (IOException e) {
86 throw new UncheckedIOException(e);
87 }
88 }
89 }
90
91 @Test
92 public void testEd25519HostKey() throws Exception {
93
94
95 File newHostKey = new File(getTemporaryDirectory(), "newhostkey");
96 copyTestResource("id_ed25519", newHostKey);
97 server.addHostKey(newHostKey.toPath(), true);
98 File newHostKeyPub = new File(getTemporaryDirectory(),
99 "newhostkey.pub");
100 copyTestResource("id_ed25519.pub", newHostKeyPub);
101 createKnownHostsFile(knownHosts, "localhost", testPort, newHostKeyPub);
102 cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
103 "Host git",
104 "HostName localhost",
105 "Port " + testPort,
106 "User " + TEST_USER,
107 "IdentityFile " + privateKey1.getAbsolutePath());
108 }
109
110
111
112
113
114
115
116
117
118
119
120 @Test
121 public void testWrongKeyFirst() throws Exception {
122 File userKey = new File(getTemporaryDirectory(), "userkey");
123 copyTestResource("id_ed25519", userKey);
124 File publicKey = new File(getTemporaryDirectory(), "userkey.pub");
125 copyTestResource("id_ed25519.pub", publicKey);
126 server.setTestUserPublicKey(publicKey.toPath());
127 cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
128 "Host git",
129 "HostName localhost",
130 "Port " + testPort,
131 "User " + TEST_USER,
132 "IdentityFile " + privateKey1.getAbsolutePath(),
133 "IdentityFile " + userKey.getAbsolutePath());
134 }
135
136 @Test
137 public void testHashedKnownHosts() throws Exception {
138 assertTrue("Failed to delete known_hosts", knownHosts.delete());
139
140
141 TestCredentialsProvider provider = new TestCredentialsProvider();
142 cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
143 "HashKnownHosts yes",
144 "Host localhost",
145 "HostName localhost",
146 "Port " + testPort,
147 "User " + TEST_USER,
148 "IdentityFile " + privateKey1.getAbsolutePath());
149 List<LogEntry> messages = provider.getLog();
150 assertFalse("Expected user interaction", messages.isEmpty());
151 assertEquals(
152 "Expected to be asked about the key, and the file creation", 2,
153 messages.size());
154 assertTrue("~/.ssh/known_hosts should exist now", knownHosts.exists());
155
156
157 File clonedAgain = new File(getTemporaryDirectory(), "cloned2");
158 cloneWith("ssh://localhost/doesntmatter", clonedAgain, null, //
159 "Host localhost",
160 "HostName localhost",
161 "Port " + testPort,
162 "User " + TEST_USER,
163 "IdentityFile " + privateKey1.getAbsolutePath());
164
165
166 List<String> lines = Files.readAllLines(knownHosts.toPath()).stream()
167 .filter(s -> s != null && s.length() >= 1 && s.charAt(0) != '#'
168 && !s.trim().isEmpty())
169 .collect(Collectors.toList());
170 assertEquals("Unexpected number of known_hosts lines", 1, lines.size());
171 String line = lines.get(0);
172 assertFalse("Found host in line", line.contains("localhost"));
173 assertFalse("Found IP in line", line.contains("127.0.0.1"));
174 assertTrue("Hash not found", line.contains("|"));
175 KnownHostEntry entry = KnownHostEntry.parseKnownHostEntry(line);
176 assertTrue("Hash doesn't match localhost",
177 entry.isHostMatch("localhost", testPort)
178 || entry.isHostMatch("127.0.0.1", testPort));
179 }
180
181 @Test
182 public void testPreamble() throws Exception {
183
184
185 StringBuilder b = new StringBuilder();
186 for (int i = 0; i < 257; i++) {
187 b.append('a');
188 }
189 server.setPreamble("A line with a \000 NUL",
190 "A long line: " + b.toString());
191 cloneWith(
192 "ssh://" + TEST_USER + "@localhost:" + testPort
193 + "/doesntmatter",
194 defaultCloneDir, null,
195 "IdentityFile " + privateKey1.getAbsolutePath());
196 }
197
198 @Test
199 public void testLongPreamble() throws Exception {
200
201 StringBuilder b = new StringBuilder();
202 for (int i = 0; i < 1024; i++) {
203 b.append('a');
204 }
205 String line = b.toString();
206 String[] lines = new String[60];
207 for (int i = 0; i < lines.length; i++) {
208 lines[i] = line;
209 }
210 server.setPreamble(lines);
211 cloneWith(
212 "ssh://" + TEST_USER + "@localhost:" + testPort
213 + "/doesntmatter",
214 defaultCloneDir, null,
215 "IdentityFile " + privateKey1.getAbsolutePath());
216 }
217
218 @Test
219 public void testHugePreamble() throws Exception {
220
221 StringBuilder b = new StringBuilder();
222 for (int i = 0; i < 1024; i++) {
223 b.append('a');
224 }
225 String line = b.toString();
226 String[] lines = new String[70];
227 for (int i = 0; i < lines.length; i++) {
228 lines[i] = line;
229 }
230 server.setPreamble(lines);
231 TransportException e = assertThrows(TransportException.class,
232 () -> cloneWith(
233 "ssh://" + TEST_USER + "@localhost:" + testPort
234 + "/doesntmatter",
235 defaultCloneDir, null,
236 "IdentityFile " + privateKey1.getAbsolutePath()));
237
238 assertFalse(e.getMessage().contains("timeout"));
239 assertTrue(e.getMessage().contains("65536")
240 || e.getMessage().contains("closed"));
241 }
242
243
244
245
246
247
248
249
250
251
252 @Test
253 public void testCloneAndFetchWithSessionLimit() throws Exception {
254 MAX_CONCURRENT_SESSIONS
255 .set(server.getPropertyResolver(), Integer.valueOf(2));
256 File localClone = cloneWith("ssh://localhost/doesntmatter",
257 defaultCloneDir, null,
258 "Host localhost",
259 "HostName localhost",
260 "Port " + testPort,
261 "User " + TEST_USER,
262 "IdentityFile " + privateKey1.getAbsolutePath());
263
264 try (Git git = Git.open(localClone)) {
265 git.fetch().call();
266 git.fetch().call();
267 }
268 }
269
270
271
272
273
274
275
276
277
278
279
280 private SshServer createServer(String user, File userKey) throws Exception {
281 SshServer srv = SshServer.setUpDefaultServer();
282
283 KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
284 generator.initialize(2048);
285 KeyPair proxyHostKey = generator.generateKeyPair();
286 srv.setKeyPairProvider(
287 session -> Collections.singletonList(proxyHostKey));
288
289 srv.setUserAuthFactories(Collections.singletonList(
290 ServerAuthenticationManager.DEFAULT_USER_AUTH_PUBLIC_KEY_FACTORY));
291
292 PublicKey userProxyKey = AuthorizedKeyEntry
293 .readAuthorizedKeys(userKey.toPath()).get(0)
294 .resolvePublicKey(null, PublicKeyEntryResolver.IGNORING);
295 srv.setPublickeyAuthenticator(
296 (userName, publicKey, session) -> user.equals(userName)
297 && KeyUtils.compareKeys(userProxyKey, publicKey));
298 return srv;
299 }
300
301
302
303
304
305
306
307 private void registerServer(SshServer srv) throws Exception {
308
309 try (BufferedWriter writer = Files.newBufferedWriter(
310 knownHosts.toPath(), StandardCharsets.US_ASCII,
311 StandardOpenOption.WRITE, StandardOpenOption.APPEND)) {
312 writer.append('\n');
313 KnownHostHashValue.appendHostPattern(writer, "localhost",
314 srv.getPort());
315 writer.append(',');
316 KnownHostHashValue.appendHostPattern(writer, "127.0.0.1",
317 srv.getPort());
318 writer.append(' ');
319 PublicKeyEntry.appendPublicKeyEntry(writer,
320 srv.getKeyPairProvider().loadKeys(null).iterator().next().getPublic());
321 writer.append('\n');
322 }
323 }
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339 private SshServer createProxy(String user, File userKey,
340 SshdSocketAddress[] report) throws Exception {
341 SshServer proxy = createServer(user, userKey);
342
343 proxy.setForwardingFilter(new StaticDecisionForwardingFilter(true) {
344
345 @Override
346 protected boolean checkAcceptance(String request, Session session,
347 SshdSocketAddress target) {
348 report[0] = target;
349 return super.checkAcceptance(request, session, target);
350 }
351 });
352 proxy.start();
353 registerServer(proxy);
354 return proxy;
355 }
356
357 @Test
358 public void testJumpHost() throws Exception {
359 SshdSocketAddress[] forwarded = { null };
360 try (SshServer proxy = createProxy(TEST_USER + 'X', publicKey2,
361 forwarded)) {
362 try {
363
364 cloneWith("ssh://server/doesntmatter", defaultCloneDir, null, //
365 "Host server",
366 "HostName localhost",
367 "Port " + testPort,
368 "User " + TEST_USER,
369 "IdentityFile " + privateKey1.getAbsolutePath(),
370 "ProxyJump " + TEST_USER + "X@proxy:" + proxy.getPort(),
371 "",
372 "Host proxy",
373 "Hostname localhost",
374 "IdentityFile " + privateKey2.getAbsolutePath());
375 assertNotNull(forwarded[0]);
376 assertEquals(testPort, forwarded[0].getPort());
377 } finally {
378 proxy.stop();
379 }
380 }
381 }
382
383 @Test
384 public void testJumpHostNone() throws Exception {
385
386 cloneWith("ssh://server/doesntmatter", defaultCloneDir, null, //
387 "Host server",
388 "HostName localhost",
389 "Port " + testPort,
390 "User " + TEST_USER,
391 "IdentityFile " + privateKey1.getAbsolutePath(),
392 "ProxyJump none",
393 "",
394 "Host *",
395 "ProxyJump " + TEST_USER + "@localhost:1234");
396 }
397
398 @Test
399 public void testJumpHostWrongKeyAtProxy() throws Exception {
400
401 SshdSocketAddress[] forwarded = { null };
402 try (SshServer proxy = createProxy(TEST_USER + 'X', publicKey2,
403 forwarded)) {
404 try {
405
406 TransportException e = assertThrows(TransportException.class,
407 () -> cloneWith("ssh://server/doesntmatter",
408 defaultCloneDir, null,
409 "Host server",
410 "HostName localhost",
411 "Port " + testPort,
412 "User " + TEST_USER,
413 "IdentityFile " + privateKey1.getAbsolutePath(),
414 "ProxyJump " + TEST_USER + "X@proxy:"
415 + proxy.getPort(),
416 "",
417 "Host proxy",
418 "Hostname localhost",
419 "IdentityFile "
420 + privateKey1.getAbsolutePath()));
421 String message = e.getMessage();
422 assertTrue(message.contains("localhost:" + proxy.getPort()));
423 assertTrue(message.contains("proxy:" + proxy.getPort()));
424 } finally {
425 proxy.stop();
426 }
427 }
428 }
429
430 @Test
431 public void testJumpHostWrongKeyAtServer() throws Exception {
432
433 SshdSocketAddress[] forwarded = { null };
434 try (SshServer proxy = createProxy(TEST_USER + 'X', publicKey2,
435 forwarded)) {
436 try {
437
438 TransportException e = assertThrows(TransportException.class,
439 () -> cloneWith("ssh://server/doesntmatter",
440 defaultCloneDir, null,
441 "Host server",
442 "HostName localhost",
443 "Port " + testPort,
444 "User " + TEST_USER,
445 "IdentityFile " + privateKey2.getAbsolutePath(),
446 "ProxyJump " + TEST_USER + "X@proxy:"
447 + proxy.getPort(),
448 "",
449 "Host proxy",
450 "Hostname localhost",
451 "IdentityFile "
452 + privateKey2.getAbsolutePath()));
453 String message = e.getMessage();
454 assertTrue(message.contains("localhost:" + testPort));
455 assertTrue(message.contains("ssh://server"));
456 } finally {
457 proxy.stop();
458 }
459 }
460 }
461
462 @Test
463 public void testJumpHostNonSsh() throws Exception {
464 SshdSocketAddress[] forwarded = { null };
465 try (SshServer proxy = createProxy(TEST_USER + 'X', publicKey2,
466 forwarded)) {
467 try {
468 TransportException e = assertThrows(TransportException.class,
469 () -> cloneWith("ssh://server/doesntmatter",
470 defaultCloneDir, null,
471 "Host server",
472 "HostName localhost",
473 "Port " + testPort,
474 "User " + TEST_USER,
475 "IdentityFile " + privateKey1.getAbsolutePath(),
476 "ProxyJump http://" + TEST_USER + "X@proxy:"
477 + proxy.getPort(),
478 "",
479 "Host proxy",
480 "Hostname localhost",
481 "IdentityFile "
482 + privateKey2.getAbsolutePath()));
483
484 Throwable t = e;
485 while (t != null) {
486 if (t instanceof URISyntaxException) {
487 break;
488 }
489 t = t.getCause();
490 }
491 assertNotNull(t);
492 assertTrue(t.getMessage().contains("Non-ssh"));
493 } finally {
494 proxy.stop();
495 }
496 }
497 }
498
499 @Test
500 public void testJumpHostWithPath() throws Exception {
501 SshdSocketAddress[] forwarded = { null };
502 try (SshServer proxy = createProxy(TEST_USER + 'X', publicKey2,
503 forwarded)) {
504 try {
505 TransportException e = assertThrows(TransportException.class,
506 () -> cloneWith("ssh://server/doesntmatter",
507 defaultCloneDir, null,
508 "Host server",
509 "HostName localhost",
510 "Port " + testPort,
511 "User " + TEST_USER,
512 "IdentityFile " + privateKey1.getAbsolutePath(),
513 "ProxyJump ssh://" + TEST_USER + "X@proxy:"
514 + proxy.getPort() + "/wrongPath",
515 "",
516 "Host proxy",
517 "Hostname localhost",
518 "IdentityFile "
519 + privateKey2.getAbsolutePath()));
520
521 Throwable t = e;
522 while (t != null) {
523 if (t instanceof URISyntaxException) {
524 break;
525 }
526 t = t.getCause();
527 }
528 assertNotNull(t);
529 assertTrue(t.getMessage().contains("wrongPath"));
530 } finally {
531 proxy.stop();
532 }
533 }
534 }
535
536 @Test
537 public void testJumpHostWithPathShort() throws Exception {
538 SshdSocketAddress[] forwarded = { null };
539 try (SshServer proxy = createProxy(TEST_USER + 'X', publicKey2,
540 forwarded)) {
541 try {
542 TransportException e = assertThrows(TransportException.class,
543 () -> cloneWith("ssh://server/doesntmatter",
544 defaultCloneDir, null,
545 "Host server",
546 "HostName localhost",
547 "Port " + testPort,
548 "User " + TEST_USER,
549 "IdentityFile " + privateKey1.getAbsolutePath(),
550 "ProxyJump " + TEST_USER + "X@proxy:wrongPath",
551 "",
552 "Host proxy",
553 "Hostname localhost",
554 "Port " + proxy.getPort(),
555 "IdentityFile "
556 + privateKey2.getAbsolutePath()));
557
558 Throwable t = e;
559 while (t != null) {
560 if (t instanceof URISyntaxException) {
561 break;
562 }
563 t = t.getCause();
564 }
565 assertNotNull(t);
566 assertTrue(t.getMessage().contains("wrongPath"));
567 } finally {
568 proxy.stop();
569 }
570 }
571 }
572
573 @Test
574 public void testJumpHostChain() throws Exception {
575 SshdSocketAddress[] forwarded1 = { null };
576 SshdSocketAddress[] forwarded2 = { null };
577 try (SshServer proxy1 = createProxy(TEST_USER + 'X', publicKey2,
578 forwarded1);
579 SshServer proxy2 = createProxy("foo", publicKey1, forwarded2)) {
580 try {
581
582 cloneWith("ssh://server/doesntmatter", defaultCloneDir, null, //
583 "Host server",
584 "HostName localhost",
585 "Port " + testPort,
586 "User " + TEST_USER,
587 "IdentityFile " + privateKey1.getAbsolutePath(),
588 "ProxyJump proxy2," + TEST_USER + "X@proxy:"
589 + proxy1.getPort(),
590 "",
591 "Host proxy",
592 "Hostname localhost",
593 "IdentityFile " + privateKey2.getAbsolutePath(),
594 "",
595 "Host proxy2",
596 "Hostname localhost",
597 "User foo",
598 "Port " + proxy2.getPort(),
599 "IdentityFile " + privateKey1.getAbsolutePath());
600 assertNotNull(forwarded1[0]);
601 assertEquals(proxy2.getPort(), forwarded1[0].getPort());
602 assertNotNull(forwarded2[0]);
603 assertEquals(testPort, forwarded2[0].getPort());
604 } finally {
605 proxy1.stop();
606 proxy2.stop();
607 }
608 }
609 }
610
611 @Test
612 public void testJumpHostCascade() throws Exception {
613 SshdSocketAddress[] forwarded1 = { null };
614 SshdSocketAddress[] forwarded2 = { null };
615 try (SshServer proxy1 = createProxy(TEST_USER + 'X', publicKey2,
616 forwarded1);
617 SshServer proxy2 = createProxy("foo", publicKey1, forwarded2)) {
618 try {
619
620 cloneWith("ssh://server/doesntmatter", defaultCloneDir, null, //
621 "Host server",
622 "HostName localhost",
623 "Port " + testPort,
624 "User " + TEST_USER,
625 "IdentityFile " + privateKey1.getAbsolutePath(),
626 "ProxyJump " + TEST_USER + "X@proxy",
627 "",
628 "Host proxy",
629 "Hostname localhost",
630 "Port " + proxy1.getPort(),
631 "ProxyJump ssh://proxy2:" + proxy2.getPort(), //
632 "IdentityFile " + privateKey2.getAbsolutePath(),
633 "",
634 "Host proxy2",
635 "Hostname localhost",
636 "User foo",
637 "IdentityFile " + privateKey1.getAbsolutePath());
638 assertNotNull(forwarded1[0]);
639 assertEquals(testPort, forwarded1[0].getPort());
640 assertNotNull(forwarded2[0]);
641 assertEquals(proxy1.getPort(), forwarded2[0].getPort());
642 } finally {
643 proxy1.stop();
644 proxy2.stop();
645 }
646 }
647 }
648
649 @Test
650 public void testJumpHostRecursion() throws Exception {
651 SshdSocketAddress[] forwarded1 = { null };
652 SshdSocketAddress[] forwarded2 = { null };
653 try (SshServer proxy1 = createProxy(TEST_USER + 'X', publicKey2,
654 forwarded1);
655 SshServer proxy2 = createProxy("foo", publicKey1, forwarded2)) {
656 try {
657 TransportException e = assertThrows(TransportException.class,
658 () -> cloneWith(
659 "ssh://server/doesntmatter", defaultCloneDir, null, //
660 "Host server",
661 "HostName localhost",
662 "Port " + testPort,
663 "User " + TEST_USER,
664 "IdentityFile " + privateKey1.getAbsolutePath(),
665 "ProxyJump " + TEST_USER + "X@proxy",
666 "",
667 "Host proxy",
668 "Hostname localhost",
669 "Port " + proxy1.getPort(),
670 "ProxyJump ssh://proxy2:" + proxy2.getPort(), //
671 "IdentityFile " + privateKey2.getAbsolutePath(),
672 "",
673 "Host proxy2",
674 "Hostname localhost",
675 "User foo",
676 "ProxyJump " + TEST_USER + "X@proxy",
677 "IdentityFile " + privateKey1.getAbsolutePath()));
678 assertTrue(e.getMessage().contains("proxy"));
679 } finally {
680 proxy1.stop();
681 proxy2.stop();
682 }
683 }
684 }
685
686
687
688
689
690
691
692
693
694
695
696 @Test
697 public void testConnectAuthSshRsaPubkeyAcceptedAlgorithms()
698 throws Exception {
699 try (SshServer oldServer = createServer(TEST_USER, publicKey1)) {
700 oldServer.setSignatureFactoriesNames("ssh-rsa");
701 oldServer.start();
702 registerServer(oldServer);
703 installConfig("Host server",
704 "HostName localhost",
705 "Port " + oldServer.getPort(),
706 "User " + TEST_USER,
707 "IdentityFile " + privateKey1.getAbsolutePath(),
708 "PubkeyAcceptedAlgorithms ^ssh-rsa");
709 RemoteSession session = getSessionFactory().getSession(
710 new URIish("ssh://server/doesntmatter"), null, FS.DETECTED,
711 10000);
712 assertNotNull(session);
713 session.disconnect();
714 }
715 }
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736 @Test
737 public void testConnectAuthSshRsa() throws Exception {
738 try (SshServer oldServer = createServer(TEST_USER, publicKey1)) {
739 oldServer.setSignatureFactoriesNames("ssh-rsa");
740 oldServer.start();
741 registerServer(oldServer);
742 installConfig("Host server",
743 "HostName localhost",
744 "Port " + oldServer.getPort(),
745 "User " + TEST_USER,
746 "IdentityFile " + privateKey1.getAbsolutePath());
747 RemoteSession session = getSessionFactory().getSession(
748 new URIish("ssh://server/doesntmatter"), null, FS.DETECTED,
749 10000);
750 assertNotNull(session);
751 session.disconnect();
752 }
753 }
754
755
756
757
758
759
760
761
762
763
764 @Test
765 public void testConnectOnlyRsaSha1() throws Exception {
766 try (SshServer oldServer = createServer(TEST_USER, publicKey1)) {
767 oldServer.setSignatureFactoriesNames("ssh-rsa");
768 List<DHFactory> sha1Factories = BuiltinDHFactories
769 .parseDHFactoriesList(
770 "diffie-hellman-group1-sha1,diffie-hellman-group14-sha1")
771 .getParsedFactories();
772 assertEquals(2, sha1Factories.size());
773 List<KeyExchangeFactory> kexFactories = NamedFactory
774 .setUpTransformedFactories(true, sha1Factories,
775 ServerBuilder.DH2KEX);
776 oldServer.setKeyExchangeFactories(kexFactories);
777 oldServer.start();
778 registerServer(oldServer);
779 installConfig("Host server",
780 "HostName localhost",
781 "Port " + oldServer.getPort(),
782 "User " + TEST_USER,
783 "IdentityFile " + privateKey1.getAbsolutePath(),
784 "KexAlgorithms +diffie-hellman-group1-sha1");
785 RemoteSession session = getSessionFactory().getSession(
786 new URIish("ssh://server/doesntmatter"), null, FS.DETECTED,
787 10000);
788 assertNotNull(session);
789 session.disconnect();
790 }
791 }
792
793 private void verifyAuthLog(String message, String first) {
794 assertTrue(message.contains(System.lineSeparator()));
795 String[] lines = message.split(System.lineSeparator());
796 int pubkeyIndex = -1;
797 int passwordIndex = -1;
798 for (int i = 0; i < lines.length; i++) {
799 String line = lines[i];
800 if (i == 0) {
801 assertTrue(line.contains(first));
802 }
803 if (line.contains("publickey:")) {
804 if (pubkeyIndex < 0) {
805 pubkeyIndex = i;
806 assertTrue(line.contains("/userkey"));
807 }
808 } else if (line.contains("password:")) {
809 if (passwordIndex < 0) {
810 passwordIndex = i;
811 assertTrue(line.contains("attempt 1"));
812 }
813 }
814 }
815 assertTrue(pubkeyIndex > 0 && passwordIndex > 0);
816 assertTrue(pubkeyIndex < passwordIndex);
817 }
818
819 @Test
820 public void testAuthFailureMessageCancel() throws Exception {
821 File userKey = new File(getTemporaryDirectory(), "userkey");
822 copyTestResource("id_ed25519", userKey);
823 File publicKey = new File(getTemporaryDirectory(), "userkey.pub");
824 copyTestResource("id_ed25519.pub", publicKey);
825
826 server.enablePasswordAuthentication();
827 TestCredentialsProvider provider = new TestCredentialsProvider(
828 "wrongpass");
829 TransportException e = assertThrows(TransportException.class,
830 () -> cloneWith("ssh://git/doesntmatter", defaultCloneDir,
831 provider,
832 "Host git",
833 "HostName localhost",
834 "Port " + testPort,
835 "User " + TEST_USER,
836 "IdentityFile " + userKey.getAbsolutePath(),
837 "PreferredAuthentications publickey,password"));
838 verifyAuthLog(e.getMessage(), "canceled");
839 }
840
841 @Test
842 public void testAuthFailureMessage() throws Exception {
843 File userKey = new File(getTemporaryDirectory(), "userkey");
844 copyTestResource("id_ed25519", userKey);
845 File publicKey = new File(getTemporaryDirectory(), "userkey.pub");
846 copyTestResource("id_ed25519.pub", publicKey);
847
848 server.enablePasswordAuthentication();
849
850 TestCredentialsProvider provider = new TestCredentialsProvider(
851 "wrongpass", "wrongpass", "wrongpass");
852 TransportException e = assertThrows(TransportException.class,
853 () -> cloneWith("ssh://git/doesntmatter", defaultCloneDir,
854 provider,
855 "Host git",
856 "HostName localhost",
857 "Port " + testPort,
858 "User " + TEST_USER,
859 "IdentityFile " + userKey.getAbsolutePath(),
860 "PreferredAuthentications publickey,password"));
861 verifyAuthLog(e.getMessage(), "log in");
862 }
863
864 }