summaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit.test/src/org
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.jgit.test/src/org')
-rw-r--r--org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestBase.java811
-rw-r--r--org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestHarness.java419
2 files changed, 0 insertions, 1230 deletions
diff --git a/org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestBase.java b/org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestBase.java
deleted file mode 100644
index c22c10cb7f..0000000000
--- a/org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestBase.java
+++ /dev/null
@@ -1,811 +0,0 @@
-/*
- * Copyright (C) 2018, Thomas Wolf <thomas.wolf@paranor.ch> and others
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Distribution License v. 1.0 which is available at
- * https://www.eclipse.org/org/documents/edl-v10.php.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-package org.eclipse.jgit.transport.ssh;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.util.List;
-import java.util.Locale;
-
-import org.eclipse.jgit.api.errors.TransportException;
-import org.eclipse.jgit.transport.CredentialItem;
-import org.eclipse.jgit.transport.JschConfigSessionFactory;
-import org.junit.Test;
-import org.junit.experimental.theories.DataPoints;
-import org.junit.experimental.theories.Theory;
-
-/**
- * The ssh tests. Concrete subclasses can re-use these tests by implementing the
- * abstract operations from {@link SshTestHarness}. This gives a way to test
- * different ssh clients against a unified test suite.
- */
-public abstract class SshTestBase extends SshTestHarness {
-
- @DataPoints
- public static String[] KEY_RESOURCES = { //
- "id_dsa", //
- "id_rsa_1024", //
- "id_rsa_2048", //
- "id_rsa_3072", //
- "id_rsa_4096", //
- "id_ecdsa_256", //
- "id_ecdsa_384", //
- "id_ecdsa_521", //
- "id_ed25519", //
- // And now encrypted. Passphrase is "testpass".
- "id_dsa_testpass", //
- "id_rsa_1024_testpass", //
- "id_rsa_2048_testpass", //
- "id_rsa_3072_testpass", //
- "id_rsa_4096_testpass", //
- "id_ecdsa_256_testpass", //
- "id_ecdsa_384_testpass", //
- "id_ecdsa_521_testpass", //
- "id_ed25519_testpass", //
- "id_ed25519_expensive_testpass" };
-
- protected File defaultCloneDir;
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
- defaultCloneDir = new File(getTemporaryDirectory(), "cloned");
- }
-
- @Test(expected = TransportException.class)
- public void testSshWithoutConfig() throws Exception {
- cloneWith("ssh://" + TEST_USER + "@localhost:" + testPort
- + "/doesntmatter", defaultCloneDir, null);
- }
-
- @Test
- public void testSshWithGlobalIdentity() throws Exception {
- cloneWith(
- "ssh://" + TEST_USER + "@localhost:" + testPort
- + "/doesntmatter",
- defaultCloneDir, null,
- "IdentityFile " + privateKey1.getAbsolutePath());
- }
-
- @Test
- public void testSshWithDefaultIdentity() throws Exception {
- File idRsa = new File(privateKey1.getParentFile(), "id_rsa");
- Files.copy(privateKey1.toPath(), idRsa.toPath());
- // We expect the session factory to pick up these keys...
- cloneWith("ssh://" + TEST_USER + "@localhost:" + testPort
- + "/doesntmatter", defaultCloneDir, null);
- }
-
- @Test
- public void testSshWithConfig() throws Exception {
- cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
- "Host localhost", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "IdentityFile " + privateKey1.getAbsolutePath());
- }
-
- @Test
- public void testSshWithConfigEncryptedUnusedKey() throws Exception {
- // Copy the encrypted test key from the bundle.
- File encryptedKey = new File(sshDir, "id_dsa");
- copyTestResource("id_dsa_testpass", encryptedKey);
- TestCredentialsProvider provider = new TestCredentialsProvider(
- "testpass");
- cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
- "Host localhost", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "IdentityFile " + privateKey1.getAbsolutePath());
- assertEquals("CredentialsProvider should not have been called", 0,
- provider.getLog().size());
- }
-
- @Test
- public void testSshWithConfigEncryptedUnusedKeyInConfigLast()
- throws Exception {
- // Copy the encrypted test key from the bundle.
- File encryptedKey = new File(sshDir, "id_dsa_test_key");
- copyTestResource("id_dsa_testpass", encryptedKey);
- TestCredentialsProvider provider = new TestCredentialsProvider(
- "testpass");
- cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
- "Host localhost", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "IdentityFile " + privateKey1.getAbsolutePath(),
- "IdentityFile " + encryptedKey.getAbsolutePath());
- // This test passes with JSch per chance because JSch completely ignores
- // the second IdentityFile
- assertEquals("CredentialsProvider should not have been called", 0,
- provider.getLog().size());
- }
-
- @Test
- public void testSshWithConfigEncryptedUnusedKeyInConfigFirst()
- throws Exception {
- // Test cannot pass with JSch; it handles only one IdentityFile.
- // assumeTrue(!(getSessionFactory() instanceof
- // JschConfigSessionFactory)); gives in bazel a failure with "Never
- // found parameters that satisfied method assumptions."
- // In maven it's fine!?
- if (getSessionFactory() instanceof JschConfigSessionFactory) {
- return;
- }
- // Copy the encrypted test key from the bundle.
- File encryptedKey = new File(sshDir, "id_dsa_test_key");
- copyTestResource("id_dsa_testpass", encryptedKey);
- TestCredentialsProvider provider = new TestCredentialsProvider(
- "testpass");
- cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
- "Host localhost", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "IdentityFile " + encryptedKey.getAbsolutePath(),
- "IdentityFile " + privateKey1.getAbsolutePath());
- assertEquals("CredentialsProvider should have been called once", 1,
- provider.getLog().size());
- }
-
- @Test
- public void testSshEncryptedUsedKeyCached() throws Exception {
- // Make sure we are asked for the password only once if we do several
- // operations with an encrypted key.
- File encryptedKey = new File(sshDir, "id_dsa_test_key");
- copyTestResource("id_dsa_testpass", encryptedKey);
- File encryptedPublicKey = new File(sshDir, "id_dsa_test_key.pub");
- copyTestResource("id_dsa_testpass.pub", encryptedPublicKey);
- server.setTestUserPublicKey(encryptedPublicKey.toPath());
- TestCredentialsProvider provider = new TestCredentialsProvider(
- "testpass");
- pushTo(provider,
- cloneWith("ssh://localhost/doesntmatter", //
- defaultCloneDir, provider, //
- "Host localhost", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "IdentityFile " + encryptedKey.getAbsolutePath()));
- assertEquals("CredentialsProvider should have been called once", 1,
- provider.getLog().size());
- }
-
- @Test(expected = TransportException.class)
- public void testSshEncryptedUsedKeyWrongPassword() throws Exception {
- File encryptedKey = new File(sshDir, "id_dsa_test_key");
- copyTestResource("id_dsa_testpass", encryptedKey);
- File encryptedPublicKey = new File(sshDir, "id_dsa_test_key.pub");
- copyTestResource("id_dsa_testpass.pub", encryptedPublicKey);
- server.setTestUserPublicKey(encryptedPublicKey.toPath());
- TestCredentialsProvider provider = new TestCredentialsProvider(
- "wrongpass");
- cloneWith("ssh://localhost/doesntmatter", //
- defaultCloneDir, provider, //
- "Host localhost", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "NumberOfPasswordPrompts 1", //
- "IdentityFile " + encryptedKey.getAbsolutePath());
- }
-
- @Test
- public void testSshEncryptedUsedKeySeveralPassword() throws Exception {
- File encryptedKey = new File(sshDir, "id_dsa_test_key");
- copyTestResource("id_dsa_testpass", encryptedKey);
- File encryptedPublicKey = new File(sshDir, "id_dsa_test_key.pub");
- copyTestResource("id_dsa_testpass.pub", encryptedPublicKey);
- server.setTestUserPublicKey(encryptedPublicKey.toPath());
- TestCredentialsProvider provider = new TestCredentialsProvider(
- "wrongpass", "wrongpass2", "testpass");
- cloneWith("ssh://localhost/doesntmatter", //
- defaultCloneDir, provider, //
- "Host localhost", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "IdentityFile " + encryptedKey.getAbsolutePath());
- assertEquals("CredentialsProvider should have been called 3 times", 3,
- provider.getLog().size());
- }
-
- @Test(expected = TransportException.class)
- public void testSshWithoutKnownHosts() throws Exception {
- assertTrue("Could not delete known_hosts", knownHosts.delete());
- cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
- "Host localhost", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "IdentityFile " + privateKey1.getAbsolutePath());
- }
-
- @Test
- public void testSshWithoutKnownHostsWithProviderAsk()
- throws Exception {
- File copiedHosts = new File(knownHosts.getParentFile(),
- "copiedKnownHosts");
- assertTrue("Failed to rename known_hosts",
- knownHosts.renameTo(copiedHosts));
- // The provider will answer "yes" to all questions, so we should be able
- // to connect and end up with a new known_hosts file with the host key.
- TestCredentialsProvider provider = new TestCredentialsProvider();
- cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
- "Host localhost", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "IdentityFile " + privateKey1.getAbsolutePath());
- List<LogEntry> messages = provider.getLog();
- assertFalse("Expected user interaction", messages.isEmpty());
- if (getSessionFactory() instanceof JschConfigSessionFactory) {
- // JSch doesn't create a non-existing file.
- assertEquals("Expected to be asked about the key", 1,
- messages.size());
- return;
- }
- assertEquals(
- "Expected to be asked about the key, and the file creation",
- 2, messages.size());
- assertTrue("~/.ssh/known_hosts should exist now", knownHosts.exists());
- // Instead of checking the file contents, let's just clone again
- // without provider. If it works, the server host key was written
- // correctly.
- File clonedAgain = new File(getTemporaryDirectory(), "cloned2");
- cloneWith("ssh://localhost/doesntmatter", clonedAgain, null, //
- "Host localhost", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "IdentityFile " + privateKey1.getAbsolutePath());
- }
-
- @Test
- public void testSshWithoutKnownHostsWithProviderAcceptNew()
- throws Exception {
- File copiedHosts = new File(knownHosts.getParentFile(),
- "copiedKnownHosts");
- assertTrue("Failed to rename known_hosts",
- knownHosts.renameTo(copiedHosts));
- TestCredentialsProvider provider = new TestCredentialsProvider();
- cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
- "Host localhost", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "StrictHostKeyChecking accept-new", //
- "IdentityFile " + privateKey1.getAbsolutePath());
- if (getSessionFactory() instanceof JschConfigSessionFactory) {
- // JSch doesn't create new files.
- assertTrue("CredentialsProvider not called",
- provider.getLog().isEmpty());
- return;
- }
- assertEquals("Expected to be asked about the file creation", 1,
- provider.getLog().size());
- assertTrue("~/.ssh/known_hosts should exist now", knownHosts.exists());
- // Instead of checking the file contents, let's just clone again
- // without provider. If it works, the server host key was written
- // correctly.
- File clonedAgain = new File(getTemporaryDirectory(), "cloned2");
- cloneWith("ssh://localhost/doesntmatter", clonedAgain, null, //
- "Host localhost", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "IdentityFile " + privateKey1.getAbsolutePath());
- }
-
- @Test(expected = TransportException.class)
- public void testSshWithoutKnownHostsDeny() throws Exception {
- File copiedHosts = new File(knownHosts.getParentFile(),
- "copiedKnownHosts");
- assertTrue("Failed to rename known_hosts",
- knownHosts.renameTo(copiedHosts));
- cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
- "Host localhost", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "StrictHostKeyChecking yes", //
- "IdentityFile " + privateKey1.getAbsolutePath());
- }
-
- @Test(expected = TransportException.class)
- public void testSshModifiedHostKeyDeny()
- throws Exception {
- File copiedHosts = new File(knownHosts.getParentFile(),
- "copiedKnownHosts");
- assertTrue("Failed to rename known_hosts",
- knownHosts.renameTo(copiedHosts));
- // Now produce a new known_hosts file containing some other key.
- createKnownHostsFile(knownHosts, "localhost", testPort, publicKey1);
- cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
- "Host localhost", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "StrictHostKeyChecking yes", //
- "IdentityFile " + privateKey1.getAbsolutePath());
- }
-
- @Test(expected = TransportException.class)
- public void testSshModifiedHostKeyWithProviderDeny() throws Exception {
- File copiedHosts = new File(knownHosts.getParentFile(),
- "copiedKnownHosts");
- assertTrue("Failed to rename known_hosts",
- knownHosts.renameTo(copiedHosts));
- // Now produce a new known_hosts file containing some other key.
- createKnownHostsFile(knownHosts, "localhost", testPort, publicKey1);
- TestCredentialsProvider provider = new TestCredentialsProvider();
- try {
- cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
- "Host localhost", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "StrictHostKeyChecking yes", //
- "IdentityFile " + privateKey1.getAbsolutePath());
- } catch (Exception e) {
- assertEquals("Expected to be told about the modified key", 1,
- provider.getLog().size());
- assertTrue("Only messages expected", provider.getLog().stream()
- .flatMap(l -> l.getItems().stream()).allMatch(
- c -> c instanceof CredentialItem.InformationalMessage));
- throw e;
- }
- }
-
- private void checkKnownHostsModifiedHostKey(File backup, File newFile,
- String wrongKey) throws IOException {
- List<String> oldLines = Files.readAllLines(backup.toPath(), UTF_8);
- // Find the original entry. We should have that again in known_hosts.
- String oldKeyPart = null;
- for (String oldLine : oldLines) {
- if (oldLine.contains("[localhost]:")) {
- String[] parts = oldLine.split("\\s+");
- if (parts.length > 2) {
- oldKeyPart = parts[parts.length - 2] + ' '
- + parts[parts.length - 1];
- break;
- }
- }
- }
- assertNotNull("Old key not found", oldKeyPart);
- List<String> newLines = Files.readAllLines(newFile.toPath(), UTF_8);
- assertFalse("Old host key still found in known_hosts file" + newFile,
- hasHostKey("localhost", testPort, wrongKey, newLines));
- assertTrue("New host key not found in known_hosts file" + newFile,
- hasHostKey("localhost", testPort, oldKeyPart, newLines));
-
- }
-
- @Test
- public void testSshModifiedHostKeyAllow() throws Exception {
- assertTrue("Failed to delete known_hosts", knownHosts.delete());
- createKnownHostsFile(knownHosts, "localhost", testPort, publicKey1);
- File backup = new File(getTemporaryDirectory(), "backupKnownHosts");
- Files.copy(knownHosts.toPath(), backup.toPath());
- cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
- "Host localhost", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "StrictHostKeyChecking no", //
- "IdentityFile " + privateKey1.getAbsolutePath());
- // File should not have been updated!
- String[] oldLines = Files
- .readAllLines(backup.toPath(), UTF_8)
- .toArray(new String[0]);
- String[] newLines = Files
- .readAllLines(knownHosts.toPath(), UTF_8)
- .toArray(new String[0]);
- assertArrayEquals("Known hosts file should not be modified", oldLines,
- newLines);
- }
-
- @Test
- public void testSshModifiedHostKeyAsk() throws Exception {
- File copiedHosts = new File(knownHosts.getParentFile(),
- "copiedKnownHosts");
- assertTrue("Failed to rename known_hosts",
- knownHosts.renameTo(copiedHosts));
- String wrongKeyPart = createKnownHostsFile(knownHosts, "localhost",
- testPort, publicKey1);
- TestCredentialsProvider provider = new TestCredentialsProvider();
- cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, provider, //
- "Host localhost", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "IdentityFile " + privateKey1.getAbsolutePath());
- checkKnownHostsModifiedHostKey(copiedHosts, knownHosts, wrongKeyPart);
- assertEquals("Expected to be asked about the modified key", 1,
- provider.getLog().size());
- }
-
- @Test
- public void testSshCloneWithConfigAndPush() throws Exception {
- pushTo(cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
- "Host localhost", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "IdentityFile " + privateKey1.getAbsolutePath()));
- }
-
- @Test
- public void testSftpWithConfig() throws Exception {
- cloneWith("sftp://localhost/.git", defaultCloneDir, null, //
- "Host localhost", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "IdentityFile " + privateKey1.getAbsolutePath());
- }
-
- @Test
- public void testSftpCloneWithConfigAndPush() throws Exception {
- pushTo(cloneWith("sftp://localhost/.git", defaultCloneDir, null, //
- "Host localhost", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "IdentityFile " + privateKey1.getAbsolutePath()));
- }
-
- @Test(expected = TransportException.class)
- public void testSshWithConfigWrongKey() throws Exception {
- cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
- "Host localhost", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "IdentityFile " + privateKey2.getAbsolutePath());
- }
-
- @Test
- public void testSshWithWrongUserNameInConfig() throws Exception {
- // Bug 526778
- cloneWith(
- "ssh://" + TEST_USER + "@localhost:" + testPort
- + "/doesntmatter",
- defaultCloneDir, null, //
- "Host localhost", //
- "HostName localhost", //
- "User sombody_else", //
- "IdentityFile " + privateKey1.getAbsolutePath());
- }
-
- @Test
- public void testSshWithWrongPortInConfig() throws Exception {
- // Bug 526778
- cloneWith(
- "ssh://" + TEST_USER + "@localhost:" + testPort
- + "/doesntmatter",
- defaultCloneDir, null, //
- "Host localhost", //
- "HostName localhost", //
- "Port 22", //
- "User " + TEST_USER, //
- "IdentityFile " + privateKey1.getAbsolutePath());
- }
-
- @Test
- public void testSshWithAliasInConfig() throws Exception {
- // Bug 531118
- cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
- "Host git", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "IdentityFile " + privateKey1.getAbsolutePath(), "", //
- "Host localhost", //
- "HostName localhost", //
- "Port 22", //
- "User someone_else", //
- "IdentityFile " + privateKey2.getAbsolutePath());
- }
-
- @Test
- public void testSshWithUnknownCiphersInConfig() throws Exception {
- // Bug 535672
- cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
- "Host git", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "IdentityFile " + privateKey1.getAbsolutePath(), //
- "Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr");
- }
-
- @Test
- public void testSshWithUnknownHostKeyAlgorithmsInConfig()
- throws Exception {
- // Bug 535672
- cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
- "Host git", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "IdentityFile " + privateKey1.getAbsolutePath(), //
- "HostKeyAlgorithms foobar,ssh-rsa,ssh-dss");
- }
-
- @Test
- public void testSshWithUnknownKexAlgorithmsInConfig()
- throws Exception {
- // Bug 535672
- cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
- "Host git", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "IdentityFile " + privateKey1.getAbsolutePath(), //
- "KexAlgorithms foobar,diffie-hellman-group14-sha1,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521");
- }
-
- @Test
- public void testSshWithMinimalHostKeyAlgorithmsInConfig()
- throws Exception {
- // Bug 537790
- cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
- "Host git", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "IdentityFile " + privateKey1.getAbsolutePath(), //
- "HostKeyAlgorithms ssh-rsa,ssh-dss");
- }
-
- @Test
- public void testSshWithUnknownAuthInConfig() throws Exception {
- cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
- "Host git", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "IdentityFile " + privateKey1.getAbsolutePath(), //
- "PreferredAuthentications gssapi-with-mic,hostbased,publickey,keyboard-interactive,password");
- }
-
- @Test(expected = TransportException.class)
- public void testSshWithNoMatchingAuthInConfig() throws Exception {
- // Server doesn't do password, and anyway we set no password.
- cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
- "Host git", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "IdentityFile " + privateKey1.getAbsolutePath(), //
- "PreferredAuthentications password");
- }
-
- @Test
- public void testRsaHostKeySecond() throws Exception {
- // See https://git.eclipse.org/r/#/c/130402/ : server has EcDSA
- // (preferred), RSA, we have RSA in known_hosts: client and server
- // should agree on RSA.
- File newHostKey = new File(getTemporaryDirectory(), "newhostkey");
- copyTestResource("id_ecdsa_256", newHostKey);
- server.addHostKey(newHostKey.toPath(), true);
- cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
- "Host git", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "IdentityFile " + privateKey1.getAbsolutePath());
- }
-
- @Test
- public void testEcDsaHostKey() throws Exception {
- // See https://git.eclipse.org/r/#/c/130402/ : server has RSA
- // (preferred), EcDSA, we have EcDSA in known_hosts: client and server
- // should agree on EcDSA.
- File newHostKey = new File(getTemporaryDirectory(), "newhostkey");
- copyTestResource("id_ecdsa_256", newHostKey);
- server.addHostKey(newHostKey.toPath(), false);
- File newHostKeyPub = new File(getTemporaryDirectory(),
- "newhostkey.pub");
- copyTestResource("id_ecdsa_256.pub", newHostKeyPub);
- createKnownHostsFile(knownHosts, "localhost", testPort, newHostKeyPub);
- cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
- "Host git", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "IdentityFile " + privateKey1.getAbsolutePath());
- }
-
- @Test
- public void testPasswordAuth() throws Exception {
- server.enablePasswordAuthentication();
- TestCredentialsProvider provider = new TestCredentialsProvider(
- TEST_USER.toUpperCase(Locale.ROOT));
- cloneWith("ssh://git/doesntmatter", defaultCloneDir, provider, //
- "Host git", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "PreferredAuthentications password");
- }
-
- @Test
- public void testPasswordAuthSeveralTimes() throws Exception {
- server.enablePasswordAuthentication();
- TestCredentialsProvider provider = new TestCredentialsProvider(
- "wrongpass", "wrongpass", TEST_USER.toUpperCase(Locale.ROOT));
- cloneWith("ssh://git/doesntmatter", defaultCloneDir, provider, //
- "Host git", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "PreferredAuthentications password");
- }
-
- @Test(expected = TransportException.class)
- public void testPasswordAuthWrongPassword() throws Exception {
- server.enablePasswordAuthentication();
- TestCredentialsProvider provider = new TestCredentialsProvider(
- "wrongpass");
- cloneWith("ssh://git/doesntmatter", defaultCloneDir, provider, //
- "Host git", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "PreferredAuthentications password");
- }
-
- @Test(expected = TransportException.class)
- public void testPasswordAuthNoPassword() throws Exception {
- server.enablePasswordAuthentication();
- TestCredentialsProvider provider = new TestCredentialsProvider();
- cloneWith("ssh://git/doesntmatter", defaultCloneDir, provider, //
- "Host git", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "PreferredAuthentications password");
- }
-
- @Test(expected = TransportException.class)
- public void testPasswordAuthCorrectPasswordTooLate() throws Exception {
- server.enablePasswordAuthentication();
- TestCredentialsProvider provider = new TestCredentialsProvider(
- "wrongpass", "wrongpass", "wrongpass",
- TEST_USER.toUpperCase(Locale.ROOT));
- cloneWith("ssh://git/doesntmatter", defaultCloneDir, provider, //
- "Host git", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "PreferredAuthentications password");
- }
-
- @Test
- public void testKeyboardInteractiveAuth() throws Exception {
- server.enableKeyboardInteractiveAuthentication();
- TestCredentialsProvider provider = new TestCredentialsProvider(
- TEST_USER.toUpperCase(Locale.ROOT));
- cloneWith("ssh://git/doesntmatter", defaultCloneDir, provider, //
- "Host git", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "PreferredAuthentications keyboard-interactive");
- }
-
- @Test
- public void testKeyboardInteractiveAuthSeveralTimes() throws Exception {
- server.enableKeyboardInteractiveAuthentication();
- TestCredentialsProvider provider = new TestCredentialsProvider(
- "wrongpass", "wrongpass", TEST_USER.toUpperCase(Locale.ROOT));
- cloneWith("ssh://git/doesntmatter", defaultCloneDir, provider, //
- "Host git", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "PreferredAuthentications keyboard-interactive");
- }
-
- @Test(expected = TransportException.class)
- public void testKeyboardInteractiveAuthWrongPassword() throws Exception {
- server.enableKeyboardInteractiveAuthentication();
- TestCredentialsProvider provider = new TestCredentialsProvider(
- "wrongpass");
- cloneWith("ssh://git/doesntmatter", defaultCloneDir, provider, //
- "Host git", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "PreferredAuthentications keyboard-interactive");
- }
-
- @Test(expected = TransportException.class)
- public void testKeyboardInteractiveAuthNoPassword() throws Exception {
- server.enableKeyboardInteractiveAuthentication();
- TestCredentialsProvider provider = new TestCredentialsProvider();
- cloneWith("ssh://git/doesntmatter", defaultCloneDir, provider, //
- "Host git", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "PreferredAuthentications keyboard-interactive");
- }
-
- @Test(expected = TransportException.class)
- public void testKeyboardInteractiveAuthCorrectPasswordTooLate()
- throws Exception {
- server.enableKeyboardInteractiveAuthentication();
- TestCredentialsProvider provider = new TestCredentialsProvider(
- "wrongpass", "wrongpass", "wrongpass",
- TEST_USER.toUpperCase(Locale.ROOT));
- cloneWith("ssh://git/doesntmatter", defaultCloneDir, provider, //
- "Host git", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "PreferredAuthentications keyboard-interactive");
- }
-
- @Theory
- public void testSshKeys(String keyName) throws Exception {
- // JSch fails on ECDSA 384/521 keys. Compare
- // https://sourceforge.net/p/jsch/patches/10/
- assumeTrue(!(getSessionFactory() instanceof JschConfigSessionFactory
- && (keyName.contains("ed25519")
- || keyName.startsWith("id_ecdsa_384")
- || keyName.startsWith("id_ecdsa_521"))));
- File cloned = new File(getTemporaryDirectory(), "cloned");
- String keyFileName = keyName + "_key";
- File privateKey = new File(sshDir, keyFileName);
- copyTestResource(keyName, privateKey);
- File publicKey = new File(sshDir, keyFileName + ".pub");
- copyTestResource(keyName + ".pub", publicKey);
- server.setTestUserPublicKey(publicKey.toPath());
- TestCredentialsProvider provider = new TestCredentialsProvider(
- "testpass");
- pushTo(provider,
- cloneWith("ssh://localhost/doesntmatter", //
- cloned, provider, //
- "Host localhost", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "IdentityFile " + privateKey.getAbsolutePath()));
- int expectedCalls = keyName.endsWith("testpass") ? 1 : 0;
- assertEquals("Unexpected calls to CredentialsProvider", expectedCalls,
- provider.getLog().size());
- // Should now also work without credentials provider, even if the key
- // was encrypted.
- cloned = new File(getTemporaryDirectory(), "cloned2");
- pushTo(null,
- cloneWith("ssh://localhost/doesntmatter", //
- cloned, null, //
- "Host localhost", //
- "HostName localhost", //
- "Port " + testPort, //
- "User " + TEST_USER, //
- "IdentityFile " + privateKey.getAbsolutePath()));
- }
-}
diff --git a/org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestHarness.java b/org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestHarness.java
deleted file mode 100644
index 632c24b890..0000000000
--- a/org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestHarness.java
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * Copyright (C) 2018, Thomas Wolf <thomas.wolf@paranor.ch> and others
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Distribution License v. 1.0 which is available at
- * https://www.eclipse.org/org/documents/edl-v10.php.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-package org.eclipse.jgit.transport.ssh;
-
-import static java.nio.charset.StandardCharsets.US_ASCII;
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.file.Files;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-
-import org.eclipse.jgit.api.CloneCommand;
-import org.eclipse.jgit.api.Git;
-import org.eclipse.jgit.api.PushCommand;
-import org.eclipse.jgit.api.ResetCommand.ResetType;
-import org.eclipse.jgit.errors.UnsupportedCredentialItem;
-import org.eclipse.jgit.junit.RepositoryTestCase;
-import org.eclipse.jgit.junit.ssh.SshTestGitServer;
-import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.revwalk.RevCommit;
-import org.eclipse.jgit.transport.CredentialItem;
-import org.eclipse.jgit.transport.CredentialsProvider;
-import org.eclipse.jgit.transport.PushResult;
-import org.eclipse.jgit.transport.RemoteRefUpdate;
-import org.eclipse.jgit.transport.SshSessionFactory;
-import org.eclipse.jgit.transport.URIish;
-import org.eclipse.jgit.util.FS;
-import org.junit.After;
-
-import com.jcraft.jsch.JSch;
-import com.jcraft.jsch.KeyPair;
-
-/**
- * Root class for ssh tests. Sets up the ssh test server. A set of pre-computed
- * keys for testing is provided in the bundle and can be used in test cases via
- * {@link #copyTestResource(String, File)}. These test key files names have four
- * components, separated by a single underscore: "id", the algorithm, the bits
- * (if variable), and the password if the private key is encrypted. For instance
- * "{@code id_ecdsa_384_testpass}" is an encrypted ECDSA-384 key. The passphrase
- * to decrypt is "testpass". The key "{@code id_ecdsa_384}" is the same but
- * unencrypted. All keys were generated and encrypted via ssh-keygen. Note that
- * DSA and ec25519 have no "bits" component. Available keys are listed in
- * {@link SshTestBase#KEY_RESOURCES}.
- */
-public abstract class SshTestHarness extends RepositoryTestCase {
-
- protected static final String TEST_USER = "testuser";
-
- protected File sshDir;
-
- protected File privateKey1;
-
- protected File privateKey2;
-
- protected File publicKey1;
-
- protected SshTestGitServer server;
-
- private SshSessionFactory factory;
-
- protected int testPort;
-
- protected File knownHosts;
-
- private File homeDir;
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
- writeTrashFile("file.txt", "something");
- try (Git git = new Git(db)) {
- git.add().addFilepattern("file.txt").call();
- git.commit().setMessage("Initial commit").call();
- }
- mockSystemReader.setProperty("user.home",
- getTemporaryDirectory().getAbsolutePath());
- mockSystemReader.setProperty("HOME",
- getTemporaryDirectory().getAbsolutePath());
- homeDir = FS.DETECTED.userHome();
- FS.DETECTED.setUserHome(getTemporaryDirectory().getAbsoluteFile());
- sshDir = new File(getTemporaryDirectory(), ".ssh");
- assertTrue(sshDir.mkdir());
- File serverDir = new File(getTemporaryDirectory(), "srv");
- assertTrue(serverDir.mkdir());
- // Create two key pairs. Let's not call them "id_rsa".
- privateKey1 = new File(sshDir, "first_key");
- privateKey2 = new File(sshDir, "second_key");
- publicKey1 = createKeyPair(privateKey1);
- createKeyPair(privateKey2);
- ByteArrayOutputStream publicHostKey = new ByteArrayOutputStream();
- // Start a server with our test user and the first key.
- server = new SshTestGitServer(TEST_USER, publicKey1.toPath(), db,
- createHostKey(publicHostKey));
- testPort = server.start();
- assertTrue(testPort > 0);
- knownHosts = new File(sshDir, "known_hosts");
- Files.write(knownHosts.toPath(), Collections.singleton("[localhost]:"
- + testPort + ' '
- + publicHostKey.toString(US_ASCII.name())));
- factory = createSessionFactory();
- SshSessionFactory.setInstance(factory);
- }
-
- private static File createKeyPair(File privateKeyFile) throws Exception {
- // Found no way to do this with MINA sshd except rolling it all
- // ourselves...
- JSch jsch = new JSch();
- KeyPair pair = KeyPair.genKeyPair(jsch, KeyPair.RSA, 2048);
- try (OutputStream out = new FileOutputStream(privateKeyFile)) {
- pair.writePrivateKey(out);
- }
- File publicKeyFile = new File(privateKeyFile.getParentFile(),
- privateKeyFile.getName() + ".pub");
- try (OutputStream out = new FileOutputStream(publicKeyFile)) {
- pair.writePublicKey(out, TEST_USER);
- }
- return publicKeyFile;
- }
-
- private static byte[] createHostKey(OutputStream publicKey)
- throws Exception {
- JSch jsch = new JSch();
- KeyPair pair = KeyPair.genKeyPair(jsch, KeyPair.RSA, 2048);
- pair.writePublicKey(publicKey, "");
- try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
- pair.writePrivateKey(out);
- out.flush();
- return out.toByteArray();
- }
- }
-
- /**
- * Creates a new known_hosts file with one entry for the given host and port
- * taken from the given public key file.
- *
- * @param file
- * to write the known_hosts file to
- * @param host
- * for the entry
- * @param port
- * for the entry
- * @param publicKey
- * to use
- * @return the public-key part of the line
- * @throws IOException
- */
- protected static String createKnownHostsFile(File file, String host,
- int port, File publicKey) throws IOException {
- List<String> lines = Files.readAllLines(publicKey.toPath(), UTF_8);
- assertEquals("Public key has too many lines", 1, lines.size());
- String pubKey = lines.get(0);
- // Strip off the comment.
- String[] parts = pubKey.split("\\s+");
- assertTrue("Unexpected key content",
- parts.length == 2 || parts.length == 3);
- String keyPart = parts[0] + ' ' + parts[1];
- String line = '[' + host + "]:" + port + ' ' + keyPart;
- Files.write(file.toPath(), Collections.singletonList(line));
- return keyPart;
- }
-
- /**
- * Checks whether there is a line for the given host and port that also
- * matches the given key part in the list of lines.
- *
- * @param host
- * to look for
- * @param port
- * to look for
- * @param keyPart
- * to look for
- * @param lines
- * to look in
- * @return {@code true} if found, {@code false} otherwise
- */
- protected boolean hasHostKey(String host, int port, String keyPart,
- List<String> lines) {
- String h = '[' + host + "]:" + port;
- return lines.stream()
- .anyMatch(l -> l.contains(h) && l.contains(keyPart));
- }
-
- @After
- public void shutdownServer() throws Exception {
- if (server != null) {
- server.stop();
- server = null;
- }
- FS.DETECTED.setUserHome(homeDir);
- SshSessionFactory.setInstance(null);
- factory = null;
- }
-
- protected abstract SshSessionFactory createSessionFactory();
-
- protected SshSessionFactory getSessionFactory() {
- return factory;
- }
-
- protected abstract void installConfig(String... config);
-
- /**
- * Copies a test data file contained in the test bundle to the given file.
- * Equivalent to {@link #copyTestResource(Class, String, File)} with
- * {@code SshTestHarness.class} as first parameter.
- *
- * @param resourceName
- * of the test resource to copy
- * @param to
- * file to copy the resource to
- * @throws IOException
- * if the resource cannot be copied
- */
- protected void copyTestResource(String resourceName, File to)
- throws IOException {
- copyTestResource(SshTestHarness.class, resourceName, to);
- }
-
- /**
- * Copies a test data file contained in the test bundle to the given file,
- * using {@link Class#getResourceAsStream(String)} to get the test resource.
- *
- * @param loader
- * {@link Class} to use to load the resource
- * @param resourceName
- * of the test resource to copy
- * @param to
- * file to copy the resource to
- * @throws IOException
- * if the resource cannot be copied
- */
- protected void copyTestResource(Class<?> loader, String resourceName,
- File to) throws IOException {
- try (InputStream in = loader.getResourceAsStream(resourceName)) {
- Files.copy(in, to.toPath());
- }
- }
-
- protected File cloneWith(String uri, File to, CredentialsProvider provider,
- String... config) throws Exception {
- installConfig(config);
- CloneCommand clone = Git.cloneRepository().setCloneAllBranches(true)
- .setDirectory(to).setURI(uri);
- if (provider != null) {
- clone.setCredentialsProvider(provider);
- }
- try (Git git = clone.call()) {
- Repository repo = git.getRepository();
- assertNotNull(repo.resolve("master"));
- assertNotEquals(db.getWorkTree(),
- git.getRepository().getWorkTree());
- assertTrue(new File(git.getRepository().getWorkTree(), "file.txt")
- .exists());
- return repo.getWorkTree();
- }
- }
-
- protected void pushTo(File localClone) throws Exception {
- pushTo(null, localClone);
- }
-
- protected void pushTo(CredentialsProvider provider, File localClone)
- throws Exception {
- RevCommit commit;
- File newFile = null;
- try (Git git = Git.open(localClone)) {
- // Write a new file and modify a file.
- Repository local = git.getRepository();
- newFile = File.createTempFile("new", "sshtest",
- local.getWorkTree());
- write(newFile, "something new");
- File existingFile = new File(local.getWorkTree(), "file.txt");
- write(existingFile, "something else");
- git.add().addFilepattern("file.txt")
- .addFilepattern(newFile.getName())
- .call();
- commit = git.commit().setMessage("Local commit").call();
- // Push
- PushCommand push = git.push().setPushAll();
- if (provider != null) {
- push.setCredentialsProvider(provider);
- }
- Iterable<PushResult> results = push.call();
- for (PushResult result : results) {
- for (RemoteRefUpdate u : result.getRemoteUpdates()) {
- assertEquals(
- "Could not update " + u.getRemoteName() + ' '
- + u.getMessage(),
- RemoteRefUpdate.Status.OK, u.getStatus());
- }
- }
- }
- // Now check "master" in the remote repo directly:
- assertEquals("Unexpected remote commit", commit, db.resolve("master"));
- assertEquals("Unexpected remote commit", commit,
- db.resolve(Constants.HEAD));
- File remoteFile = new File(db.getWorkTree(), newFile.getName());
- assertFalse("File should not exist on remote", remoteFile.exists());
- try (Git git = new Git(db)) {
- git.reset().setMode(ResetType.HARD).setRef(Constants.HEAD).call();
- }
- assertTrue("File does not exist on remote", remoteFile.exists());
- checkFile(remoteFile, "something new");
- }
-
- protected static class TestCredentialsProvider extends CredentialsProvider {
-
- private final List<String> stringStore;
-
- private final Iterator<String> strings;
-
- public TestCredentialsProvider(String... strings) {
- if (strings == null || strings.length == 0) {
- stringStore = Collections.emptyList();
- } else {
- stringStore = Arrays.asList(strings);
- }
- this.strings = stringStore.iterator();
- }
-
- @Override
- public boolean isInteractive() {
- return true;
- }
-
- @Override
- public boolean supports(CredentialItem... items) {
- return true;
- }
-
- @Override
- public boolean get(URIish uri, CredentialItem... items)
- throws UnsupportedCredentialItem {
- System.out.println("URI: " + uri);
- for (CredentialItem item : items) {
- System.out.println(item.getClass().getSimpleName() + ' '
- + item.getPromptText());
- }
- logItems(uri, items);
- for (CredentialItem item : items) {
- if (item instanceof CredentialItem.InformationalMessage) {
- continue;
- }
- if (item instanceof CredentialItem.YesNoType) {
- ((CredentialItem.YesNoType) item).setValue(true);
- } else if (item instanceof CredentialItem.CharArrayType) {
- if (strings.hasNext()) {
- ((CredentialItem.CharArrayType) item)
- .setValue(strings.next().toCharArray());
- } else {
- return false;
- }
- } else if (item instanceof CredentialItem.StringType) {
- if (strings.hasNext()) {
- ((CredentialItem.StringType) item)
- .setValue(strings.next());
- } else {
- return false;
- }
- } else {
- return false;
- }
- }
- return true;
- }
-
- private List<LogEntry> log = new ArrayList<>();
-
- private void logItems(URIish uri, CredentialItem... items) {
- log.add(new LogEntry(uri, Arrays.asList(items)));
- }
-
- public List<LogEntry> getLog() {
- return log;
- }
- }
-
- protected static class LogEntry {
-
- private URIish uri;
-
- private List<CredentialItem> items;
-
- public LogEntry(URIish uri, List<CredentialItem> items) {
- this.uri = uri;
- this.items = items;
- }
-
- public URIish getURIish() {
- return uri;
- }
-
- public List<CredentialItem> getItems() {
- return items;
- }
- }
-}