summaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit.junit.ssh/src
diff options
context:
space:
mode:
authorThomas Wolf <thomas.wolf@paranor.ch>2020-06-27 15:01:01 +0200
committerThomas Wolf <thomas.wolf@paranor.ch>2020-07-26 20:44:03 +0200
commiteb67862cbaf8f77a7ebb6e01a0d43366d3a223f0 (patch)
tree3283539072404253f15c588e765373aff51c4ade /org.eclipse.jgit.junit.ssh/src
parentd35f0ffb7c33a11f8192ec64da5a736827ab472d (diff)
downloadjgit-eb67862cbaf8f77a7ebb6e01a0d43366d3a223f0.tar.gz
jgit-eb67862cbaf8f77a7ebb6e01a0d43366d3a223f0.zip
Remove dependency on JSch from SSH test framework
Use standard java.security to generate test keys, use sshd to write public key files, and write PKCS#8 PEM files for our non-encrypted test private keys. This is a format that both JSch and Apache MINA sshd can read. Change-Id: I6ec55cfd7346b672a7fb6139d51abfb06d81a394 Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
Diffstat (limited to 'org.eclipse.jgit.junit.ssh/src')
-rw-r--r--org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestGitServer.java71
-rw-r--r--org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestHarness.java87
2 files changed, 115 insertions, 43 deletions
diff --git a/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestGitServer.java b/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestGitServer.java
index 9aa4afcef1..1862b07603 100644
--- a/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestGitServer.java
+++ b/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestGitServer.java
@@ -91,8 +91,7 @@ public class SshTestGitServer {
* @param testUser
* user name of the test user
* @param testKey
- * <em>private</em> key file of the test user; the server will
- * only user the public key from it
+ * public key file of the test user
* @param repository
* to serve
* @param hostKey
@@ -103,17 +102,54 @@ public class SshTestGitServer {
public SshTestGitServer(@NonNull String testUser, @NonNull Path testKey,
@NonNull Repository repository, @NonNull byte[] hostKey)
throws IOException, GeneralSecurityException {
+ this(testUser, readPublicKey(testKey), repository,
+ readKeyPair(hostKey));
+ }
+
+ /**
+ * Creates a ssh git <em>test</em> server. It serves one single repository,
+ * and accepts public-key authentication for exactly one test user.
+ *
+ * @param testUser
+ * user name of the test user
+ * @param testKey
+ * public key file of the test user
+ * @param repository
+ * to serve
+ * @param hostKey
+ * the unencrypted private key to use as host key
+ * @throws IOException
+ * @throws GeneralSecurityException
+ * @since 5.9
+ */
+ public SshTestGitServer(@NonNull String testUser, @NonNull Path testKey,
+ @NonNull Repository repository, @NonNull KeyPair hostKey)
+ throws IOException, GeneralSecurityException {
+ this(testUser, readPublicKey(testKey), repository, hostKey);
+ }
+
+ /**
+ * Creates a ssh git <em>test</em> server. It serves one single repository,
+ * and accepts public-key authentication for exactly one test user.
+ *
+ * @param testUser
+ * user name of the test user
+ * @param testKey
+ * the {@link PublicKey} of the test user
+ * @param repository
+ * to serve
+ * @param hostKey
+ * the {@link KeyPair} to use as host key
+ * @since 5.9
+ */
+ public SshTestGitServer(@NonNull String testUser,
+ @NonNull PublicKey testKey, @NonNull Repository repository,
+ @NonNull KeyPair hostKey) {
this.testUser = testUser;
setTestUserPublicKey(testKey);
this.repository = repository;
server = SshServer.setUpDefaultServer();
- // Set host key
- try (ByteArrayInputStream in = new ByteArrayInputStream(hostKey)) {
- SecurityUtils.loadKeyPairIdentities(null, null, in, null)
- .forEach((k) -> hostKeys.add(k));
- } catch (IOException | GeneralSecurityException e) {
- // Ignore.
- }
+ hostKeys.add(hostKey);
server.setKeyPairProvider((session) -> hostKeys);
configureAuthentication();
@@ -135,6 +171,20 @@ public class SshTestGitServer {
});
}
+ private static PublicKey readPublicKey(Path key)
+ throws IOException, GeneralSecurityException {
+ return AuthorizedKeyEntry.readAuthorizedKeys(key).get(0)
+ .resolvePublicKey(null, PublicKeyEntryResolver.IGNORING);
+ }
+
+ private static KeyPair readKeyPair(byte[] keyMaterial)
+ throws IOException, GeneralSecurityException {
+ try (ByteArrayInputStream in = new ByteArrayInputStream(keyMaterial)) {
+ return SecurityUtils.loadKeyPairIdentities(null, null, in, null)
+ .iterator().next();
+ }
+ }
+
private static class FakeUserAuthGSS extends UserAuthGSS {
@Override
protected Boolean doAuth(Buffer buffer, boolean initial)
@@ -343,8 +393,7 @@ public class SshTestGitServer {
*/
public void setTestUserPublicKey(Path key)
throws IOException, GeneralSecurityException {
- this.testKey = AuthorizedKeyEntry.readAuthorizedKeys(key).get(0)
- .resolvePublicKey(null, PublicKeyEntryResolver.IGNORING);
+ this.testKey = readPublicKey(key);
}
/**
diff --git a/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestHarness.java b/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestHarness.java
index 43f9dc4b24..7970685436 100644
--- a/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestHarness.java
+++ b/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestHarness.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ * Copyright (C) 2018, 2020 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
@@ -9,27 +9,31 @@
*/
package org.eclipse.jgit.junit.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.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Base64;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
+import org.apache.sshd.common.config.keys.PublicKeyEntry;
import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.PushCommand;
@@ -48,9 +52,6 @@ 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
@@ -104,50 +105,71 @@ public abstract class SshTestHarness extends RepositoryTestCase {
File serverDir = new File(getTemporaryDirectory(), "srv");
assertTrue(serverDir.mkdir());
// Create two key pairs. Let's not call them "id_rsa".
+ KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
+ generator.initialize(2048);
privateKey1 = new File(sshDir, "first_key");
privateKey2 = new File(sshDir, "second_key");
- publicKey1 = createKeyPair(privateKey1);
- createKeyPair(privateKey2);
- ByteArrayOutputStream publicHostKey = new ByteArrayOutputStream();
+ publicKey1 = createKeyPair(generator.generateKeyPair(), privateKey1);
+ createKeyPair(generator.generateKeyPair(), privateKey2);
+ // Create a host key
+ KeyPair hostKey = generator.generateKeyPair();
// Start a server with our test user and the first key.
server = new SshTestGitServer(TEST_USER, publicKey1.toPath(), db,
- createHostKey(publicHostKey));
+ hostKey);
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())));
+ StringBuilder knownHostsLine = new StringBuilder();
+ knownHostsLine.append("[localhost]:").append(testPort).append(' ');
+ PublicKeyEntry.appendPublicKeyEntry(knownHostsLine,
+ hostKey.getPublic());
+ Files.write(knownHosts.toPath(),
+ Collections.singleton(knownHostsLine.toString()));
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);
+ private static File createKeyPair(KeyPair newKey, File privateKeyFile)
+ throws Exception {
+ // Write PKCS#8 PEM unencrypted. Both JSch and sshd can read that.
+ PrivateKey privateKey = newKey.getPrivate();
+ String format = privateKey.getFormat();
+ if (!"PKCS#8".equalsIgnoreCase(format)) {
+ throw new IOException("Cannot write " + privateKey.getAlgorithm()
+ + " key in " + format + " format");
+ }
+ try (BufferedWriter writer = Files.newBufferedWriter(
+ privateKeyFile.toPath(), StandardCharsets.US_ASCII)) {
+ writer.write("-----BEGIN PRIVATE KEY-----");
+ writer.newLine();
+ write(writer, privateKey.getEncoded(), 64);
+ writer.write("-----END PRIVATE KEY-----");
+ writer.newLine();
}
File publicKeyFile = new File(privateKeyFile.getParentFile(),
privateKeyFile.getName() + ".pub");
+ StringBuilder builder = new StringBuilder();
+ PublicKeyEntry.appendPublicKeyEntry(builder, newKey.getPublic());
+ builder.append(' ').append(TEST_USER);
try (OutputStream out = new FileOutputStream(publicKeyFile)) {
- pair.writePublicKey(out, TEST_USER);
+ out.write(builder.toString().getBytes(StandardCharsets.US_ASCII));
}
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();
+ private static void write(BufferedWriter out, byte[] bytes, int lineLength)
+ throws IOException {
+ String data = Base64.getEncoder().encodeToString(bytes);
+ int last = data.length();
+ for (int i = 0; i < last; i += lineLength) {
+ if (i + lineLength <= last) {
+ out.write(data.substring(i, i + lineLength));
+ } else {
+ out.write(data.substring(i));
+ }
+ out.newLine();
}
+ Arrays.fill(bytes, (byte) 0);
}
/**
@@ -167,7 +189,8 @@ public abstract class SshTestHarness extends RepositoryTestCase {
*/
protected static String createKnownHostsFile(File file, String host,
int port, File publicKey) throws IOException {
- List<String> lines = Files.readAllLines(publicKey.toPath(), UTF_8);
+ List<String> lines = Files.readAllLines(publicKey.toPath(),
+ StandardCharsets.UTF_8);
assertEquals("Public key has too many lines", 1, lines.size());
String pubKey = lines.get(0);
// Strip off the comment.