diff options
author | Thomas Wolf <thomas.wolf@paranor.ch> | 2021-11-02 18:48:25 +0100 |
---|---|---|
committer | Matthias Sohn <matthias.sohn@sap.com> | 2021-11-03 23:46:54 +0100 |
commit | 634302d2da74226cff9f78e121ad5b8216c476e6 (patch) | |
tree | 29b6a8b1fb07f00fd5926ed79bbf06758fa753db /org.eclipse.jgit.ssh.apache | |
parent | 68017a029cb6b8648b29ae695c9e614d1f7a9770 (diff) | |
download | jgit-634302d2da74226cff9f78e121ad5b8216c476e6.tar.gz jgit-634302d2da74226cff9f78e121ad5b8216c476e6.zip |
sshd: add support for ssh-agent
Add a simple SSH agent connector using JNA. Include com.sum.jna and
com.sun.jna.platform in the target platform.
JNA is used to communicate through Unix domain sockets with ssh-agent,
and if on Windows, to communicate via shared memory with Pageant.
The new bundle o.e.j.ssh.apache.agent is an OSGi fragment so that
the java.util.ServiceLoader can find the provided factory without
further ado in OSGi environments.
Adapt both maven and bazel builds to include the new bundle.
Manually tested on OS X, CentOS 7, and Win10 with Pageant 0.76. Tested
by installing JGit built from this change into freshly downloaded
Eclipse 2021-12 M1, and then doing git fetches via SSH with different
~/.ssh/config settings (explicit IdentityFile, without any but a key in
the agent, with no keys and a key in the agent and IdentitiesOnly=yes
(must fail)).
Bug: 541274
Bug: 541275
Change-Id: I34e85467293707dbad1eb44d1f40fc2e70ba3622
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
Diffstat (limited to 'org.eclipse.jgit.ssh.apache')
5 files changed, 72 insertions, 6 deletions
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 index 08da18f5aa..c082a9a963 100644 --- 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 @@ -12,8 +12,12 @@ 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.Iterator; import java.util.List; +import java.util.NoSuchElementException; +import org.apache.sshd.client.auth.pubkey.KeyAgentIdentity; +import org.apache.sshd.client.auth.pubkey.PublicKeyIdentity; import org.apache.sshd.client.auth.pubkey.UserAuthPublicKey; import org.apache.sshd.client.config.hosts.HostConfigEntry; import org.apache.sshd.client.session.ClientSession; @@ -38,7 +42,7 @@ public class JGitPublicKeyAuthentication extends UserAuthPublicKey { throw new IllegalStateException("Wrong session type: " //$NON-NLS-1$ + rawSession.getClass().getCanonicalName()); } - JGitClientSession session = ((JGitClientSession) rawSession); + JGitClientSession session = (JGitClientSession) rawSession; HostConfigEntry hostConfig = session.getHostConfigEntry(); // Set signature algorithms for public key authentication String pubkeyAlgos = hostConfig.getProperty(PUBKEY_ACCEPTED_ALGORITHMS); @@ -60,5 +64,48 @@ public class JGitPublicKeyAuthentication extends UserAuthPublicKey { // If we don't set signature factories here, the default ones from the // session will be used. super.init(session, service); + // In sshd 2.7.0, we end up now with a key iterator that uses keys + // provided by an ssh-agent even if IdentitiesOnly is true. So if + // needed, filter out any KeyAgentIdentity. + if (hostConfig.isIdentitiesOnly()) { + Iterator<PublicKeyIdentity> original = keys; + // The original iterator will already have gotten the identities + // from the agent. Unfortunately there's nothing we can do about + // that; it'll have to be fixed upstream. (As will, ultimately, + // respecting isIdentitiesOnly().) At least we can simply not + // use the keys the agent provided. + // + // See https://issues.apache.org/jira/browse/SSHD-1218 + keys = new Iterator<>() { + + private PublicKeyIdentity value; + + @Override + public boolean hasNext() { + if (value != null) { + return true; + } + PublicKeyIdentity next = null; + while (original.hasNext()) { + next = original.next(); + if (!(next instanceof KeyAgentIdentity)) { + value = next; + return true; + } + } + return false; + } + + @Override + public PublicKeyIdentity next() { + if (hasNext()) { + PublicKeyIdentity result = value; + value = null; + return result; + } + throw new NoSuchElementException(); + } + }; + } } } 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 da99f56cb8..3364180099 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 @@ -63,6 +63,7 @@ import org.eclipse.jgit.transport.SshConfigStore; import org.eclipse.jgit.transport.SshConstants; import org.eclipse.jgit.transport.SshSessionFactory; import org.eclipse.jgit.transport.URIish; +import org.eclipse.jgit.transport.sshd.agent.Connector; import org.eclipse.jgit.transport.sshd.agent.ConnectorFactory; import org.eclipse.jgit.util.FS; @@ -105,9 +106,9 @@ public class SshdSessionFactory extends SshSessionFactory implements Closeable { /** * Creates a new {@link SshdSessionFactory} using the given {@link KeyCache} - * and {@link ProxyDataFactory}. The {@code keyCache} is used for all sessions - * created through this session factory; cached keys are destroyed when the - * session factory is {@link #close() closed}. + * and {@link ProxyDataFactory}. The {@code keyCache} is used for all + * sessions created through this session factory; cached keys are destroyed + * when the session factory is {@link #close() closed}. * <p> * Caching ssh keys in memory for an extended period of time is generally * considered bad practice, but there may be circumstances where using a @@ -117,13 +118,21 @@ public class SshdSessionFactory extends SshSessionFactory implements Closeable { * to use a {@link #createKeyPasswordProvider(CredentialsProvider) * KeyPasswordProvider} that has access to some secure storage and can save * and retrieve passwords from there without user interaction. Another - * approach is to use an ssh agent. + * approach is to use an SSH agent. * </p> * <p> * Note that the underlying ssh library (Apache MINA sshd) may or may not * keep ssh keys in memory for unspecified periods of time irrespective of * the use of a {@link KeyCache}. * </p> + * <p> + * By default, the factory uses the {@link java.util.ServiceLoader} to find + * a {@link ConnectorFactory} for creating a {@link Connector} to connect to + * a running SSH agent. If it finds one, the SSH agent is used in publickey + * authentication. If there is none, no SSH agent will ever be contacted. + * Note that one can define {@code IdentitiesOnly yes} for a host entry in + * the {@code ~/.ssh/config} file to bypass the SSH agent in any case. + * </p> * * @param keyCache * {@link KeyCache} to use for caching ssh keys, or {@code null} diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/agent/Connector.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/agent/Connector.java index b6da0866a0..d8dfbfc94d 100644 --- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/agent/Connector.java +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/agent/Connector.java @@ -16,6 +16,7 @@ import java.io.IOException; * Simple interface for connecting to something and making RPC-style * request-reply calls. * + * @see ConnectorFactory * @since 6.0 */ public interface Connector extends Closeable { diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/agent/ConnectorFactory.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/agent/ConnectorFactory.java index fa725ab858..b351d89ef5 100644 --- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/agent/ConnectorFactory.java +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/agent/ConnectorFactory.java @@ -15,7 +15,10 @@ import java.io.IOException; import org.eclipse.jgit.annotations.NonNull; /** - * A factory for creating {@link Connector}s. + * A factory for creating {@link Connector}s. This is a service provider + * interface; implementations are discovered via the + * {@link java.util.ServiceLoader}, or can be set explicitly on a + * {@link org.eclipse.jgit.transport.sshd.SshdSessionFactory}. * * @since 6.0 */ diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/agent/package-info.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/agent/package-info.java new file mode 100644 index 0000000000..71ca43f3d5 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/agent/package-info.java @@ -0,0 +1,6 @@ +/** + * Service provider interfaces for connecting to an SSH agent. Implementations + * are discovered via the {@link java.util.ServiceLoader}, or can be set + * explicitly on a {@link org.eclipse.jgit.transport.sshd.SshdSessionFactory}. + */ +package org.eclipse.jgit.transport.sshd.agent; |