]> source.dussan.org Git - jgit.git/commitdiff
ssh: Prefer algorithms of the known host keys 02/130402/5
authorSaša Živkov <sasa.zivkov@sap.com>
Thu, 4 Oct 2018 12:08:41 +0000 (14:08 +0200)
committerSaša Živkov <sasa.zivkov@sap.com>
Thu, 18 Oct 2018 09:59:16 +0000 (11:59 +0200)
JSch prefers ssh-rsa key type. When the remote server supports ssh-rsa
key type then this key type will be used even if the known_hosts file
contains a host key for that host, but with different key type.
This caused an unexpected UnknownHostKey error.

To fix the issue first scan the known_hosts, the HostKeyRepository in
JSch API, for any already existing host keys for the target host and
modify the default session settings to prefer their algorithms. However,
do this only if there is no HostKeyAlgorithms setting active.

Change-Id: I236df2a860ddd9289a0a820ddf09c2dea3673d36

org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java

index eab3b3c0ccd9c4dedf3c90b5d50c7d36cfafe0fd..4e712a55677c1d5db446708594ca1389d7a72f42 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2018, Sasa Zivkov <sasa.zivkov@sap.com>
  * Copyright (C) 2016, Mark Ingram <markdingram@gmail.com>
  * Copyright (C) 2009, Constantine Plotnikov <constantine.plotnikov@gmail.com>
  * Copyright (C) 2008-2009, Google Inc.
 
 package org.eclipse.jgit.transport;
 
+import static java.util.stream.Collectors.joining;
+import static java.util.stream.Collectors.toList;
+import static org.eclipse.jgit.transport.OpenSshConfig.SSH_PORT;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
@@ -59,9 +64,11 @@ import java.net.ConnectException;
 import java.net.UnknownHostException;
 import java.text.MessageFormat;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Stream;
 
 import org.eclipse.jgit.errors.TransportException;
 import org.eclipse.jgit.internal.JGitText;
@@ -71,6 +78,8 @@ import org.slf4j.LoggerFactory;
 
 import com.jcraft.jsch.ConfigRepository;
 import com.jcraft.jsch.ConfigRepository.Config;
+import com.jcraft.jsch.HostKey;
+import com.jcraft.jsch.HostKeyRepository;
 import com.jcraft.jsch.JSch;
 import com.jcraft.jsch.JSchException;
 import com.jcraft.jsch.Session;
@@ -224,6 +233,9 @@ public abstract class JschConfigSessionFactory extends SshSessionFactory {
                                        credentialsProvider));
                }
                safeConfig(session, hc.getConfig());
+               if (hc.getConfig().getValue("HostKeyAlgorithms") == null) { //$NON-NLS-1$
+                       setPreferredKeyTypesOrder(session);
+               }
                configure(hc, session);
                return session;
        }
@@ -239,6 +251,36 @@ public abstract class JschConfigSessionFactory extends SshSessionFactory {
                                "CheckSignatures"); //$NON-NLS-1$
        }
 
+       private static void setPreferredKeyTypesOrder(Session session) {
+               HostKeyRepository hkr = session.getHostKeyRepository();
+               List<String> known = Stream.of(hkr.getHostKey(hostName(session), null))
+                               .map(HostKey::getType)
+                               .collect(toList());
+
+               if (!known.isEmpty()) {
+                       String serverHostKey = "server_host_key"; //$NON-NLS-1$
+                       String current = session.getConfig(serverHostKey);
+                       if (current == null) {
+                               session.setConfig(serverHostKey, String.join(",", known)); //$NON-NLS-1$
+                               return;
+                       }
+
+                       String knownFirst = Stream.concat(
+                                                       known.stream(),
+                                                       Stream.of(current.split(",")) //$NON-NLS-1$
+                                                                       .filter(s -> !known.contains(s)))
+                                       .collect(joining(",")); //$NON-NLS-1$
+                       session.setConfig(serverHostKey, knownFirst);
+               }
+       }
+
+       private static String hostName(Session s) {
+               if (s.getPort() == SSH_PORT) {
+                       return s.getHost();
+               }
+               return String.format("[%s]:%d", s.getHost(), s.getPort()); //$NON-NLS-1$
+       }
+
        private void copyConfigValueToSession(Session session, Config cfg,
                        String from, String to) {
                String value = cfg.getValue(from);