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 ddb475dc1..1ac8faaa4 100644 --- a/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF @@ -12,6 +12,7 @@ Import-Package: org.apache.sshd.client.config.hosts;version="[2.7.0,2.8.0)", org.apache.sshd.common.auth;version="[2.7.0,2.8.0)", org.apache.sshd.common.config.keys;version="[2.7.0,2.8.0)", org.apache.sshd.common.helpers;version="[2.7.0,2.8.0)", + org.apache.sshd.common.kex;version="[2.7.0,2.8.0)", org.apache.sshd.common.keyprovider;version="[2.7.0,2.8.0)", org.apache.sshd.common.session;version="[2.7.0,2.8.0)", org.apache.sshd.common.signature;version="[2.7.0,2.8.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 c56d2307c..c1f5fef3c 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 @@ -34,13 +34,18 @@ import org.apache.sshd.client.config.hosts.KnownHostEntry; import org.apache.sshd.client.config.hosts.KnownHostHashValue; +import org.apache.sshd.common.NamedFactory; import org.apache.sshd.common.config.keys.AuthorizedKeyEntry; import org.apache.sshd.common.config.keys.KeyUtils; import org.apache.sshd.common.config.keys.PublicKeyEntry; import org.apache.sshd.common.config.keys.PublicKeyEntryResolver; +import org.apache.sshd.common.kex.BuiltinDHFactories; +import org.apache.sshd.common.kex.DHFactory; +import org.apache.sshd.common.kex.KeyExchangeFactory; import org.apache.sshd.common.session.Session; import org.apache.sshd.common.util.net.SshdSocketAddress; import org.apache.sshd.server.ServerAuthenticationManager; +import org.apache.sshd.server.ServerBuilder; import org.apache.sshd.server.SshServer; import org.apache.sshd.server.forward.StaticDecisionForwardingFilter; import org.eclipse.jgit.api.Git; @@ -702,4 +707,42 @@ public void testConnectAuthSshRsa() throws Exception { session.disconnect(); } } + + /** + * Tests that one can log in at an even poorer server that also only has the + * SHA1 KEX methods available. Apparently this is the case for at least some + * Microsoft TFS instances. The user has to enable the poor KEX methods in + * the ssh config explicitly; we don't enable them by default. + * + * @throws Exception + * on failure + */ + @Test + public void testConnectOnlyRsaSha1() throws Exception { + try (SshServer oldServer = createServer(TEST_USER, publicKey1)) { + oldServer.setSignatureFactoriesNames("ssh-rsa"); + List sha1Factories = BuiltinDHFactories + .parseDHFactoriesList( + "diffie-hellman-group1-sha1,diffie-hellman-group14-sha1") + .getParsedFactories(); + assertEquals(2, sha1Factories.size()); + List kexFactories = NamedFactory + .setUpTransformedFactories(true, sha1Factories, + ServerBuilder.DH2KEX); + oldServer.setKeyExchangeFactories(kexFactories); + oldServer.start(); + registerServer(oldServer); + installConfig("Host server", // + "HostName localhost", // + "Port " + oldServer.getPort(), // + "User " + TEST_USER, // + "IdentityFile " + privateKey1.getAbsolutePath(), // + "KexAlgorithms +diffie-hellman-group1-sha1"); + RemoteSession session = getSessionFactory().getSession( + new URIish("ssh://server/doesntmatter"), null, FS.DETECTED, + 10000); + assertNotNull(session); + session.disconnect(); + } + } } diff --git a/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties b/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties index 5bc086767..defcbdcfc 100644 --- a/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties +++ b/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties @@ -8,6 +8,7 @@ configInvalidProxyJump=Ssh config, host ''{0}'': Cannot parse ProxyJump ''{1}'' configNoKnownAlgorithms=Ssh config ''{0}'' ''{1}'' resulted in empty list (none known, or all known removed); using default. configProxyJumpNotSsh=Non-ssh URI in ProxyJump ssh config configProxyJumpWithPath=ProxyJump ssh config: jump host specification must not have a path +configUnknownAlgorithm=Ssh config {0}: ignoring unknown algorithm ''{1}'' in {2} {3} ftpCloseFailed=Closing the SFTP channel failed gssapiFailure=GSS-API error for mechanism OID {0} gssapiInitFailure=GSS-API initialization failure for mechanism {0} diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java index 7656fe8d0..066cec38b 100644 --- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018, 2019 Thomas Wolf and others + * Copyright (C) 2018, 2021 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 @@ -29,17 +29,26 @@ import java.util.Objects; import java.util.Set; +import org.apache.sshd.client.ClientBuilder; import org.apache.sshd.client.ClientFactoryManager; import org.apache.sshd.client.config.hosts.HostConfigEntry; import org.apache.sshd.client.keyverifier.ServerKeyVerifier; import org.apache.sshd.client.session.ClientSessionImpl; import org.apache.sshd.common.AttributeRepository; import org.apache.sshd.common.FactoryManager; +import org.apache.sshd.common.NamedResource; import org.apache.sshd.common.PropertyResolver; import org.apache.sshd.common.config.keys.KeyUtils; import org.apache.sshd.common.io.IoSession; import org.apache.sshd.common.io.IoWriteFuture; +import org.apache.sshd.common.kex.BuiltinDHFactories; +import org.apache.sshd.common.kex.DHFactory; import org.apache.sshd.common.kex.KexProposalOption; +import org.apache.sshd.common.kex.KeyExchangeFactory; +import org.apache.sshd.common.kex.extension.KexExtensionHandler; +import org.apache.sshd.common.kex.extension.KexExtensions; +import org.apache.sshd.common.signature.BuiltinSignatures; +import org.apache.sshd.common.kex.extension.KexExtensionHandler.AvailabilityPhase; import org.apache.sshd.common.util.Readable; import org.apache.sshd.common.util.buffer.Buffer; import org.eclipse.jgit.errors.InvalidPatternException; @@ -70,6 +79,8 @@ public class JGitClientSession extends ClientSessionImpl { */ private static final int DEFAULT_MAX_IDENTIFICATION_SIZE = 64 * 1024; + private static final AttributeKey INITIAL_KEX_DONE = new AttributeKey<>(); + private HostConfigEntry hostConfig; private CredentialsProvider credentialsProvider; @@ -219,6 +230,32 @@ protected Map setNegotiationResult( return result; } + Set getAllAvailableSignatureAlgorithms() { + Set allAvailable = new HashSet<>(); + BuiltinSignatures.VALUES.forEach(s -> allAvailable.add(s.getName())); + BuiltinSignatures.getRegisteredExtensions() + .forEach(s -> allAvailable.add(s.getName())); + return allAvailable; + } + + private void setNewFactories(Collection defaultFactories, + Collection finalFactories) { + // If new factory names were added make sure we actually have factories + // for them all. + // + // But add new ones at the end: we don't want to change the order for + // pubkey auth, and any new ones added here were not included in the + // default set for some reason, such as being deprecated or weak. + // + // The order for KEX is determined by the order in the proposal string, + // but the order in pubkey auth is determined by the order in the + // factory list (possibly overridden via ssh config + // PubkeyAcceptedAlgorithms; see JGitPublicKeyAuthentication). + Set resultSet = new LinkedHashSet<>(defaultFactories); + resultSet.addAll(finalFactories); + setSignatureFactoriesNames(resultSet); + } + @Override protected String resolveAvailableSignaturesProposal( FactoryManager manager) { @@ -229,16 +266,17 @@ protected String resolveAvailableSignaturesProposal( .getProperty(SshConstants.HOST_KEY_ALGORITHMS); if (!StringUtils.isEmptyOrNull(algorithms)) { List result = modifyAlgorithmList(defaultSignatures, - algorithms, SshConstants.HOST_KEY_ALGORITHMS); + getAllAvailableSignatureAlgorithms(), algorithms, + SshConstants.HOST_KEY_ALGORITHMS); if (!result.isEmpty()) { if (log.isDebugEnabled()) { log.debug(SshConstants.HOST_KEY_ALGORITHMS + ' ' + result); } + setNewFactories(defaultSignatures, result); return String.join(",", result); //$NON-NLS-1$ } log.warn(format(SshdText.get().configNoKnownAlgorithms, - SshConstants.HOST_KEY_ALGORITHMS, - algorithms)); + SshConstants.HOST_KEY_ALGORITHMS, algorithms)); } // No HostKeyAlgorithms; using default -- change order to put existing // keys first. @@ -261,6 +299,10 @@ protected String resolveAvailableSignaturesProposal( if (log.isDebugEnabled()) { log.debug(SshConstants.HOST_KEY_ALGORITHMS + ' ' + reordered); } + // Make sure we actually have factories for them all. + if (reordered.size() > defaultSignatures.size()) { + setNewFactories(defaultSignatures, reordered); + } return String.join(",", reordered); //$NON-NLS-1$ } if (log.isDebugEnabled()) { @@ -270,15 +312,87 @@ protected String resolveAvailableSignaturesProposal( return String.join(",", defaultSignatures); //$NON-NLS-1$ } + private List determineKexProposal() { + List kexFactories = getKeyExchangeFactories(); + List defaultKexMethods = NamedResource + .getNameList(kexFactories); + HostConfigEntry config = resolveAttribute( + JGitSshClient.HOST_CONFIG_ENTRY); + String algorithms = config.getProperty(SshConstants.KEX_ALGORITHMS); + if (!StringUtils.isEmptyOrNull(algorithms)) { + Set allAvailable = new HashSet<>(); + BuiltinDHFactories.VALUES + .forEach(s -> allAvailable.add(s.getName())); + BuiltinDHFactories.getRegisteredExtensions() + .forEach(s -> allAvailable.add(s.getName())); + List result = modifyAlgorithmList(defaultKexMethods, + allAvailable, algorithms, SshConstants.KEX_ALGORITHMS); + if (!result.isEmpty()) { + // If new ones were added, update the installed factories + Set configuredKexMethods = new HashSet<>( + defaultKexMethods); + List newKexFactories = new ArrayList<>(); + result.forEach(name -> { + if (!configuredKexMethods.contains(name)) { + DHFactory factory = BuiltinDHFactories + .resolveFactory(name); + if (factory == null) { + // Should not occur here + if (log.isDebugEnabled()) { + log.debug( + "determineKexProposal({}) unknown KEX algorithm {} ignored", //$NON-NLS-1$ + this, name); + } + } else { + newKexFactories + .add(ClientBuilder.DH2KEX.apply(factory)); + } + } + }); + if (!newKexFactories.isEmpty()) { + newKexFactories.addAll(kexFactories); + setKeyExchangeFactories(newKexFactories); + } + return result; + } + log.warn(format(SshdText.get().configNoKnownAlgorithms, + SshConstants.KEX_ALGORITHMS, algorithms)); + } + return defaultKexMethods; + } + + @Override + protected String resolveSessionKexProposal(String hostKeyTypes) + throws IOException { + String kexMethods = String.join(",", determineKexProposal()); //$NON-NLS-1$ + Boolean isRekey = getAttribute(INITIAL_KEX_DONE); + if (isRekey == null || !isRekey.booleanValue()) { + // First time + KexExtensionHandler extHandler = getKexExtensionHandler(); + if (extHandler != null && extHandler.isKexExtensionsAvailable(this, + AvailabilityPhase.PROPOSAL)) { + if (kexMethods.isEmpty()) { + kexMethods = KexExtensions.CLIENT_KEX_EXTENSION; + } else { + kexMethods += ',' + KexExtensions.CLIENT_KEX_EXTENSION; + } + } + setAttribute(INITIAL_KEX_DONE, Boolean.TRUE); + } + if (log.isDebugEnabled()) { + log.debug(SshConstants.KEX_ALGORITHMS + ' ' + kexMethods); + } + return kexMethods; + } + /** * Modifies a given algorithm list according to a list from the ssh config, - * including remove ('-') and reordering ('^') operators. Addition ('+') is - * not handled since we have no way of adding dynamically implementations, - * and the defaultList is supposed to contain all known implementations - * already. + * including add ('+'), remove ('-') and reordering ('^') operators. * * @param defaultList * to modify + * @param allAvailable + * all available values * @param fromConfig * telling how to modify the {@code defaultList}, must not be * {@code null} or empty @@ -288,22 +402,22 @@ protected String resolveAvailableSignaturesProposal( * set */ public List modifyAlgorithmList(List defaultList, - String fromConfig, String overrideKey) { + Set allAvailable, String fromConfig, String overrideKey) { Set defaults = new LinkedHashSet<>(); defaults.addAll(defaultList); switch (fromConfig.charAt(0)) { case '+': - // Additions make not much sense -- it's either in - // defaultList already, or we have no implementation for - // it. No point in proposing it. - return defaultList; + List newSignatures = filteredList(allAvailable, overrideKey, + fromConfig.substring(1)); + defaults.addAll(newSignatures); + return new ArrayList<>(defaults); case '-': // This takes wildcard patterns! removeFromList(defaults, overrideKey, fromConfig.substring(1)); return new ArrayList<>(defaults); case '^': // Specified entries go to the front of the default list - List allSignatures = filteredList(defaults, + List allSignatures = filteredList(allAvailable, overrideKey, fromConfig.substring(1)); Set atFront = new HashSet<>(allSignatures); for (String sig : defaults) { @@ -315,7 +429,7 @@ public List modifyAlgorithmList(List defaultList, default: // Default is overridden -- only accept the ones for which we do // have an implementation. - return filteredList(defaults, fromConfig); + return filteredList(allAvailable, overrideKey, fromConfig); } } @@ -342,11 +456,15 @@ private void removeFromList(Set current, String key, } } - private List filteredList(Set known, String values) { + private List filteredList(Set known, String key, + String values) { List newNames = new ArrayList<>(); for (String newValue : values.split("\\s*,\\s*")) { //$NON-NLS-1$ if (known.contains(newValue)) { newNames.add(newValue); + } else { + log.warn(format(SshdText.get().configUnknownAlgorithm, this, + newValue, key, values)); } } return newNames; diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthFactory.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthFactory.java new file mode 100644 index 000000000..0e3e24dcf --- /dev/null +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthFactory.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2018, 2021 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.internal.transport.sshd; + +import java.io.IOException; + +import org.apache.sshd.client.auth.pubkey.UserAuthPublicKey; +import org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyFactory; +import org.apache.sshd.client.session.ClientSession; + +/** + * A customized authentication factory for public key user authentication. + */ +public class JGitPublicKeyAuthFactory extends UserAuthPublicKeyFactory { + + /** The singleton {@link JGitPublicKeyAuthFactory}. */ + public static final JGitPublicKeyAuthFactory FACTORY = new JGitPublicKeyAuthFactory(); + + private JGitPublicKeyAuthFactory() { + super(); + } + + @Override + public UserAuthPublicKey createUserAuth(ClientSession session) + throws IOException { + return new JGitPublicKeyAuthentication(getSignatureFactories()); + } +} diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java new file mode 100644 index 000000000..08da18f5a --- /dev/null +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2018, 2021 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.internal.transport.sshd; + +import static java.text.MessageFormat.format; +import static org.eclipse.jgit.transport.SshConstants.PUBKEY_ACCEPTED_ALGORITHMS; + +import java.util.List; + +import org.apache.sshd.client.auth.pubkey.UserAuthPublicKey; +import org.apache.sshd.client.config.hosts.HostConfigEntry; +import org.apache.sshd.client.session.ClientSession; +import org.apache.sshd.common.NamedFactory; +import org.apache.sshd.common.signature.Signature; +import org.eclipse.jgit.util.StringUtils; + +/** + * Custom {@link UserAuthPublicKey} implementation for handling SSH config + * PubkeyAcceptedAlgorithms. + */ +public class JGitPublicKeyAuthentication extends UserAuthPublicKey { + + JGitPublicKeyAuthentication(List> factories) { + super(factories); + } + + @Override + public void init(ClientSession rawSession, String service) + throws Exception { + if (!(rawSession instanceof JGitClientSession)) { + throw new IllegalStateException("Wrong session type: " //$NON-NLS-1$ + + rawSession.getClass().getCanonicalName()); + } + JGitClientSession session = ((JGitClientSession) rawSession); + HostConfigEntry hostConfig = session.getHostConfigEntry(); + // Set signature algorithms for public key authentication + String pubkeyAlgos = hostConfig.getProperty(PUBKEY_ACCEPTED_ALGORITHMS); + if (!StringUtils.isEmptyOrNull(pubkeyAlgos)) { + List signatures = session.getSignatureFactoriesNames(); + signatures = session.modifyAlgorithmList(signatures, + session.getAllAvailableSignatureAlgorithms(), pubkeyAlgos, + PUBKEY_ACCEPTED_ALGORITHMS); + if (!signatures.isEmpty()) { + if (log.isDebugEnabled()) { + log.debug(PUBKEY_ACCEPTED_ALGORITHMS + ' ' + signatures); + } + setSignatureFactoriesNames(signatures); + } else { + log.warn(format(SshdText.get().configNoKnownAlgorithms, + PUBKEY_ACCEPTED_ALGORITHMS, pubkeyAlgos)); + } + } + // If we don't set signature factories here, the default ones from the + // session will be used. + super.init(session, service); + } +} diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java index 071e1979d..ae12c2028 100644 --- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018, 2020 Thomas Wolf and others + * Copyright (C) 2018, 2021 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 @@ -267,24 +267,6 @@ private JGitClientSession createSession(IoSession ioSession, session.setUsername(username); session.setConnectAddress(address); session.setHostConfigEntry(hostConfig); - // Set signature algorithms for public key authentication - String pubkeyAlgos = hostConfig - .getProperty(SshConstants.PUBKEY_ACCEPTED_ALGORITHMS); - if (!StringUtils.isEmptyOrNull(pubkeyAlgos)) { - List signatures = getSignatureFactoriesNames(); - signatures = session.modifyAlgorithmList(signatures, pubkeyAlgos, - SshConstants.PUBKEY_ACCEPTED_ALGORITHMS); - if (!signatures.isEmpty()) { - if (log.isDebugEnabled()) { - log.debug(SshConstants.PUBKEY_ACCEPTED_ALGORITHMS + ' ' - + signatures); - } - session.setSignatureFactoriesNames(signatures); - } else { - log.warn(format(SshdText.get().configNoKnownAlgorithms, - SshConstants.PUBKEY_ACCEPTED_ALGORITHMS, pubkeyAlgos)); - } - } if (session.getCredentialsProvider() == null) { session.setCredentialsProvider(getCredentialsProvider()); } diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java index 73c2288cc..c0f571962 100644 --- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java @@ -28,6 +28,7 @@ public static SshdText get() { /***/ public String configNoKnownAlgorithms; /***/ public String configProxyJumpNotSsh; /***/ public String configProxyJumpWithPath; + /***/ public String configUnknownAlgorithm; /***/ public String ftpCloseFailed; /***/ public String gssapiFailure; /***/ public String gssapiInitFailure; diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java index d52e24adf..cad959c90 100644 --- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java @@ -32,7 +32,6 @@ import org.apache.sshd.client.SshClient; import org.apache.sshd.client.auth.UserAuthFactory; import org.apache.sshd.client.auth.keyboard.UserAuthKeyboardInteractiveFactory; -import org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyFactory; import org.apache.sshd.client.config.hosts.HostConfigEntryResolver; import org.apache.sshd.common.NamedFactory; import org.apache.sshd.common.SshException; @@ -49,6 +48,7 @@ import org.eclipse.jgit.internal.transport.sshd.CachingKeyPairProvider; import org.eclipse.jgit.internal.transport.sshd.GssApiWithMicAuthFactory; import org.eclipse.jgit.internal.transport.sshd.JGitPasswordAuthFactory; +import org.eclipse.jgit.internal.transport.sshd.JGitPublicKeyAuthFactory; import org.eclipse.jgit.internal.transport.sshd.JGitServerKeyVerifier; import org.eclipse.jgit.internal.transport.sshd.JGitSshClient; import org.eclipse.jgit.internal.transport.sshd.JGitSshConfig; @@ -577,7 +577,7 @@ private List getUserAuthFactories() { // Password auth doesn't have this problem. return Collections.unmodifiableList( Arrays.asList(GssApiWithMicAuthFactory.INSTANCE, - UserAuthPublicKeyFactory.INSTANCE, + JGitPublicKeyAuthFactory.FACTORY, JGitPasswordAuthFactory.INSTANCE, UserAuthKeyboardInteractiveFactory.INSTANCE)); }