diff --git a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF index acc81018e..f79287d75 100644 --- a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF @@ -51,6 +51,7 @@ Import-Package: org.apache.sshd.agent;version="[2.0.0,2.1.0)", org.apache.sshd.common.digest;version="[2.0.0,2.1.0)", org.apache.sshd.common.forward;version="[2.0.0,2.1.0)", org.apache.sshd.common.future;version="[2.0.0,2.1.0)", + org.apache.sshd.common.helpers;version="[2.0.0,2.1.0)", org.apache.sshd.common.io;version="[2.0.0,2.1.0)", org.apache.sshd.common.kex;version="[2.0.0,2.1.0)", org.apache.sshd.common.keyprovider;version="[2.0.0,2.1.0)", 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 98d4e3e5e..2d8a6361c 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 @@ -82,6 +82,12 @@ import org.eclipse.jgit.transport.sshd.KeyCache; */ public class JGitSshClient extends SshClient { + /** + * An attribute key for the comma-separated list of default preferred + * authentication mechanisms. + */ + public static final AttributeKey PREFERRED_AUTHENTICATIONS = new AttributeKey<>(); + private KeyCache keyCache; private CredentialsProvider credentialsProvider; @@ -109,10 +115,24 @@ public class JGitSshClient extends SshClient { userName + '@' + address, null); SshFutureListener listener = createConnectCompletionListener( connectFuture, userName, address, hostConfig); + // sshd needs some entries from the host config already in the + // constructor of the session. Put those as properties on this client, + // where it will find them. We can set the host config only once the + // session object has been created. + copyProperty( + hostConfig.getProperty(SshConstants.PREFERRED_AUTHENTICATIONS, + getAttribute(PREFERRED_AUTHENTICATIONS)), + PREFERRED_AUTHS); connector.connect(address).addListener(listener); return connectFuture; } + private void copyProperty(String value, String key) { + if (value != null && !value.isEmpty()) { + getProperties().put(key, value); + } + } + private SshFutureListener createConnectCompletionListener( ConnectFuture connectFuture, String username, InetSocketAddress address, HostConfigEntry hostConfig) { 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 862b5590e..62fa6afdf 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 @@ -217,6 +217,12 @@ public class SshdSessionFactory extends SshSessionFactory implements Closeable { JGitSshClient jgitClient = (JGitSshClient) client; jgitClient.setKeyCache(getKeyCache()); jgitClient.setCredentialsProvider(credentialsProvider); + String defaultAuths = getDefaultPreferredAuthentications(); + if (defaultAuths != null) { + jgitClient.setAttribute( + JGitSshClient.PREFERRED_AUTHENTICATIONS, + defaultAuths); + } // Other things? return client; }); @@ -433,4 +439,17 @@ public class SshdSessionFactory extends SshSessionFactory implements Closeable { UserAuthKeyboardInteractiveFactory.INSTANCE, UserAuthPasswordFactory.INSTANCE)); } + + /** + * Gets the list of default preferred authentication mechanisms. If + * {@code null} is returned the openssh default list will be in effect. If + * the ssh config defines {@code PreferredAuthentications} the value from + * the ssh config takes precedence. + * + * @return a comma-separated list of algorithm names, or {@code null} if + * none + */ + protected String getDefaultPreferredAuthentications() { + return null; + } } diff --git a/org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestBase.java b/org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestBase.java index 2f623e330..3b5aa5adb 100644 --- a/org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestBase.java +++ b/org.eclipse.jgit.test/src/org/eclipse/jgit/transport/ssh/SshTestBase.java @@ -572,6 +572,29 @@ public abstract class SshTestBase extends SshTestHarness { "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"); + } + @Theory public void testSshKeys(String keyName) throws Exception { // JSch fails on ECDSA 384/521 keys. Compare