![JAR search and dependency download from the Maven repository](/logo.png)
org.eclipse.jgit.junit.ssh.SshTestBase Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.eclipse.jgit.junit.ssh Show documentation
Show all versions of org.eclipse.jgit.junit.ssh Show documentation
Utility classes to support Ssh based JUnit testing of JGit applications.
The newest version!
/*
* Copyright (C) 2018, 2020 Thomas Wolf 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.junit.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.assertThrows;
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 java.util.concurrent.TimeUnit;
import org.eclipse.jgit.api.errors.TransportException;
import org.eclipse.jgit.errors.CommandFailedException;
import org.eclipse.jgit.transport.CredentialItem;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.SshSupport;
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 SshBasicTestBase {
@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" };
@Test
public void testSshWithoutConfig() throws Exception {
assertThrows(TransportException.class,
() -> cloneWith("ssh://" + TEST_USER + "@localhost:" + testPort
+ "/doesntmatter", defaultCloneDir, null));
}
@Test
public void testSingleCommand() throws Exception {
installConfig("IdentityFile " + privateKey1.getAbsolutePath());
String command = SshTestGitServer.ECHO_COMMAND + " 1 without timeout";
long start = System.nanoTime();
String reply = SshSupport.runSshCommand(
new URIish("ssh://" + TEST_USER + "@localhost:" + testPort),
null, FS.DETECTED, command, 0); // 0 == no timeout
long elapsed = System.nanoTime() - start;
assertEquals(command, reply);
// Now that we have an idea how long this takes on the test
// infrastructure, try again with a timeout.
command = SshTestGitServer.ECHO_COMMAND + " 1 expecting no timeout";
// Still use a generous timeout.
int timeout = 10 * ((int) TimeUnit.NANOSECONDS.toSeconds(elapsed) + 1);
reply = SshSupport.runSshCommand(
new URIish("ssh://" + TEST_USER + "@localhost:" + testPort),
null, FS.DETECTED, command, timeout);
assertEquals(command, reply);
}
@Test
public void testSingleCommandWithTimeoutExpired() throws Exception {
installConfig("IdentityFile " + privateKey1.getAbsolutePath());
String command = SshTestGitServer.ECHO_COMMAND + " 2 EXPECTING TIMEOUT";
CommandFailedException e = assertThrows(CommandFailedException.class,
() -> SshSupport.runSshCommand(new URIish(
"ssh://" + TEST_USER + "@localhost:" + testPort), null,
FS.DETECTED, command, 1));
assertTrue(e.getMessage().contains(command));
assertTrue(e.getMessage().contains("time"));
}
@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 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());
}
private boolean isJsch() {
return getSessionFactory().getType().equals("jsch");
}
@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 (isJsch()) {
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 messages = provider.getLog();
assertFalse("Expected user interaction", messages.isEmpty());
if (isJsch()) {
// 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 (isJsch()) {
// 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 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 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 [email protected],[email protected],[email protected],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(!(isJsch() && (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()));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy