aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit.ssh.apache.test
diff options
context:
space:
mode:
authorMatthias Sohn <matthias.sohn@sap.com>2019-09-04 02:42:51 +0200
committerMatthias Sohn <matthias.sohn@sap.com>2019-09-04 02:43:03 +0200
commit4d7821567383ea5e431dca623ab865ae96fffa4c (patch)
tree37d897bc7baf7cea7eeef41f95988879bbcc040e /org.eclipse.jgit.ssh.apache.test
parent2f751c34e132cf86d51271255f92cdbc105c18d2 (diff)
parent8f742b9d3058cc5d4266194bf9a8bf21e7b34e16 (diff)
downloadjgit-4d7821567383ea5e431dca623ab865ae96fffa4c.tar.gz
jgit-4d7821567383ea5e431dca623ab865ae96fffa4c.zip
Merge branch 'stable-5.5'
* stable-5.5: Prepare 5.4.4-SNAPSHOT builds JGit v5.4.3.201909031940-r Prepare 5.3.6-SNAPSHOT builds JGit v5.3.5.201909031855-r Prepare 5.1.12-SNAPSHOT builds JGit v5.1.11.201909031202-r Prepare 4.11.10-SNAPSHOT builds JGit v4.11.9.201909030838-r Bazel: Update bazlets to the latest master revision Bazel: Remove FileTreeIteratorWithTimeControl from BUILD file BatchRefUpdate: repro racy atomic update, and fix it Delete unused FileTreeIteratorWithTimeControl Fix RacyGitTests#testRacyGitDetection Change RacyGitTests to create a racy git situation in a stable way Silence API warnings sshd: fix proxy connections with the DefaultProxyDataFactory sshd: support the HashKnownHosts configuration sshd: configurable server key verification sshd: allow setting a null ssh config sshd: simplify OpenSshServerKeyVerifier sshd: simplify ServerKeyLookup interface Use https in update site URLs Change-Id: Icd21a8fcccffd56bfedbd037e48028308db6d13b Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
Diffstat (limited to 'org.eclipse.jgit.ssh.apache.test')
-rw-r--r--org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF10
-rw-r--r--org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java53
-rw-r--r--org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/NoFilesSshTest.java221
3 files changed, 282 insertions, 2 deletions
diff --git a/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
index b863bf3fe9..4bae3d9b6e 100644
--- a/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
@@ -7,7 +7,15 @@ Bundle-Version: 5.6.0.qualifier
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.eclipse.jgit.api.errors;version="[5.6.0,5.7.0)",
+Import-Package: org.apache.sshd.client.config.hosts;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.auth;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.config.keys;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.keyprovider;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.session;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.util.net;version="[2.2.0,2.3.0)",
+ org.apache.sshd.common.util.security;version="[2.2.0,2.3.0)",
+ org.eclipse.jgit.api.errors;version="[5.6.0,5.7.0)",
org.eclipse.jgit.internal.transport.sshd.proxy;version="[5.6.0,5.7.0)",
org.eclipse.jgit.junit;version="[5.6.0,5.7.0)",
org.eclipse.jgit.junit.ssh;version="[5.6.0,5.7.0)",
diff --git a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java
index df0b832a0f..b9b7353d3e 100644
--- a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java
+++ b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java
@@ -42,16 +42,22 @@
*/
package org.eclipse.jgit.transport.sshd;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.apache.sshd.client.config.hosts.KnownHostEntry;
import org.eclipse.jgit.api.errors.TransportException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.transport.SshSessionFactory;
import org.eclipse.jgit.transport.ssh.SshTestBase;
-import org.eclipse.jgit.transport.sshd.SshdSessionFactory;
import org.eclipse.jgit.util.FS;
import org.junit.Test;
import org.junit.experimental.theories.Theories;
@@ -102,6 +108,51 @@ public class ApacheSshTest extends SshTestBase {
}
@Test
+ public void testHashedKnownHosts() throws Exception {
+ assertTrue("Failed to delete known_hosts", knownHosts.delete());
+ // 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, //
+ "HashKnownHosts yes", //
+ "Host localhost", //
+ "HostName localhost", //
+ "Port " + testPort, //
+ "User " + TEST_USER, //
+ "IdentityFile " + privateKey1.getAbsolutePath());
+ List<LogEntry> messages = provider.getLog();
+ assertFalse("Expected user interaction", messages.isEmpty());
+ assertEquals(
+ "Expected to be asked about the key, and the file creation", 2,
+ messages.size());
+ assertTrue("~/.ssh/known_hosts should exist now", knownHosts.exists());
+ // Let's 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());
+ // Check that the first line contains neither "localhost" nor
+ // "127.0.0.1", but does contain the expected hash.
+ List<String> lines = Files.readAllLines(knownHosts.toPath()).stream()
+ .filter(s -> s != null && s.length() >= 1 && s.charAt(0) != '#'
+ && !s.trim().isEmpty())
+ .collect(Collectors.toList());
+ assertEquals("Unexpected number of known_hosts lines", 1, lines.size());
+ String line = lines.get(0);
+ assertFalse("Found host in line", line.contains("localhost"));
+ assertFalse("Found IP in line", line.contains("127.0.0.1"));
+ assertTrue("Hash not found", line.contains("|"));
+ KnownHostEntry entry = KnownHostEntry.parseKnownHostEntry(line);
+ assertTrue("Hash doesn't match localhost",
+ entry.isHostMatch("localhost", testPort)
+ || entry.isHostMatch("127.0.0.1", testPort));
+ }
+
+ @Test
public void testPreamble() throws Exception {
// Test that the client can deal with strange lines being sent before
// the server identification string.
diff --git a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/NoFilesSshTest.java b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/NoFilesSshTest.java
new file mode 100644
index 0000000000..c0dc2cf20e
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/NoFilesSshTest.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2019 Thomas Wolf <thomas.wolf@paranor.ch>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.transport.sshd;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.net.InetSocketAddress;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.PublicKey;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.keyprovider.KeyIdentityProvider;
+import org.apache.sshd.common.session.SessionContext;
+import org.apache.sshd.common.util.net.SshdSocketAddress;
+import org.apache.sshd.common.util.security.SecurityUtils;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.transport.CredentialsProvider;
+import org.eclipse.jgit.transport.SshSessionFactory;
+import org.eclipse.jgit.transport.ssh.SshTestHarness;
+import org.eclipse.jgit.util.FS;
+import org.junit.After;
+import org.junit.Test;
+
+/**
+ * Test for using the SshdSessionFactory without files in ~/.ssh but with an
+ * in-memory setup.
+ */
+public class NoFilesSshTest extends SshTestHarness {
+
+
+ private PublicKey testServerKey;
+
+ private KeyPair testUserKey;
+
+ @Override
+ protected SshSessionFactory createSessionFactory() {
+ SshdSessionFactory result = new SshdSessionFactory(new JGitKeyCache(),
+ null) {
+
+ @Override
+ protected File getSshConfig(File dir) {
+ return null;
+ }
+
+ @Override
+ protected ServerKeyDatabase getServerKeyDatabase(File homeDir,
+ File dir) {
+ return new ServerKeyDatabase() {
+
+ @Override
+ public List<PublicKey> lookup(String connectAddress,
+ InetSocketAddress remoteAddress,
+ Configuration config) {
+ return Collections.singletonList(testServerKey);
+ }
+
+ @Override
+ public boolean accept(String connectAddress,
+ InetSocketAddress remoteAddress,
+ PublicKey serverKey, Configuration config,
+ CredentialsProvider provider) {
+ return KeyUtils.compareKeys(serverKey, testServerKey);
+ }
+
+ };
+ }
+
+ @Override
+ protected Iterable<KeyPair> getDefaultKeys(File dir) {
+ // This would work for this simple test case:
+ // return Collections.singletonList(testUserKey);
+ // But let's see if we can check the host and username that's used.
+ // For that, we need access to the sshd SessionContext:
+ return new KeyAuthenticator();
+ }
+
+ @Override
+ protected String getDefaultPreferredAuthentications() {
+ return "publickey";
+ }
+ };
+
+ // The home directory is mocked at this point!
+ result.setHomeDirectory(FS.DETECTED.userHome());
+ result.setSshDirectory(sshDir);
+ return result;
+ }
+
+ private class KeyAuthenticator implements KeyIdentityProvider, Iterable<KeyPair> {
+
+ @Override
+ public Iterator<KeyPair> iterator() {
+ // Should not be called. The use of the Iterable interface in
+ // SshdSessionFactory.getDefaultKeys() made sense in sshd 2.0.0,
+ // but sshd 2.2.0 added the SessionContext, which although good
+ // (without it we couldn't check here) breaks the Iterable analogy.
+ // But we're stuck now with that interface for getDefaultKeys, and
+ // so this override throwing an exception is unfortunately needed.
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Iterable<KeyPair> loadKeys(SessionContext session)
+ throws IOException, GeneralSecurityException {
+ if (!TEST_USER.equals(session.getUsername())) {
+ return Collections.emptyList();
+ }
+ SshdSocketAddress remoteAddress = SshdSocketAddress
+ .toSshdSocketAddress(session.getRemoteAddress());
+ switch (remoteAddress.getHostName()) {
+ case "localhost":
+ case "127.0.0.1":
+ return Collections.singletonList(testUserKey);
+ default:
+ return Collections.emptyList();
+ }
+ }
+ }
+
+ @After
+ public void cleanUp() {
+ testServerKey = null;
+ testUserKey = null;
+ }
+
+ @Override
+ protected void installConfig(String... config) {
+ File configFile = new File(sshDir, Constants.CONFIG);
+ if (config != null) {
+ try {
+ Files.write(configFile.toPath(), Arrays.asList(config));
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+ }
+
+ private KeyPair load(Path path) throws Exception {
+ try (InputStream in = Files.newInputStream(path)) {
+ return SecurityUtils
+ .loadKeyPairIdentities(null,
+ NamedResource.ofName(path.toString()), in, null)
+ .iterator().next();
+ }
+ }
+
+ @Test
+ public void testCloneWithBuiltInKeys() throws Exception {
+ // This test should fail unless our in-memory setup is taken: no
+ // known_hosts file, and a config that specifies a non-existing key.
+ File newHostKey = new File(getTemporaryDirectory(), "newhostkey");
+ copyTestResource("id_ed25519", newHostKey);
+ server.addHostKey(newHostKey.toPath(), true);
+ testServerKey = load(newHostKey.toPath()).getPublic();
+ assertTrue(newHostKey.delete());
+ testUserKey = load(privateKey1.getAbsoluteFile().toPath());
+ assertNotNull(testServerKey);
+ assertNotNull(testUserKey);
+ cloneWith(
+ "ssh://" + TEST_USER + "@localhost:" + testPort
+ + "/doesntmatter",
+ new File(getTemporaryDirectory(), "cloned"), null, //
+ "Host localhost", //
+ "IdentityFile "
+ + new File(sshDir, "does_not_exist").getAbsolutePath());
+ }
+
+}