diff options
author | Thomas Wolf <thomas.wolf@paranor.ch> | 2021-10-27 14:03:10 +0200 |
---|---|---|
committer | Thomas Wolf <thomas.wolf@paranor.ch> | 2021-11-10 13:57:01 -0500 |
commit | e7838b9c080011817ddb59c53298237a9c24a7a6 (patch) | |
tree | 885bd217ebe1f0226c156aa2676272cfa1e9cc43 /org.eclipse.jgit.ssh.apache/src/org | |
parent | b84738c3693081d3ed9e8e1ba4a5db6e5ac3abf8 (diff) | |
download | jgit-e7838b9c080011817ddb59c53298237a9c24a7a6.tar.gz jgit-e7838b9c080011817ddb59c53298237a9c24a7a6.zip |
[sshd agent] Introduce ConnectorDescriptor
Once a factory supports different SSH agents on the same platform,
which is planned for Windows once we use Apache MINA sshd 2.8.0,
client code may need to have a way to specify which SSH agent shall
be used when the SSH config doesn't define anything.
Add a mechanism by which a ConnectorFactory can tell what Connectors
it may provide. Client code can use this to set the identityAgent
parameter of ConnectorFactory.create() to the wanted default if it
would be null otherwise.
A ConnectorDescriptor is a pair of strings: an internal name, and a
display name. The latter is included because client code might want to
communicate agent names to the user, be it in error messages or in some
chooser dialog where a user could define which of several alternative
SSH agents should be used as default. The internal name is intended to
be used in the IdentityAgent directive in ~/.ssh/config.
Also make the ConnectorFactory discovered via the ServiceLoader
accessible and overrideable. Provide static get/setDefault() methods,
similar to the SshSessionFactory itself.
Change-Id: Ie3d077395d32dfddc72bc8627e92b23636938182
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
Diffstat (limited to 'org.eclipse.jgit.ssh.apache/src/org')
3 files changed, 136 insertions, 12 deletions
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/agent/ConnectorFactoryProvider.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/agent/ConnectorFactoryProvider.java index 9984f99763..aba7a76459 100644 --- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/agent/ConnectorFactoryProvider.java +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/agent/ConnectorFactoryProvider.java @@ -19,7 +19,7 @@ import org.eclipse.jgit.transport.sshd.agent.ConnectorFactory; */ public final class ConnectorFactoryProvider { - private static final ConnectorFactory FACTORY = loadDefaultFactory(); + private static volatile ConnectorFactory INSTANCE = loadDefaultFactory(); private static ConnectorFactory loadDefaultFactory() { ServiceLoader<ConnectorFactory> loader = ServiceLoader @@ -35,17 +35,27 @@ public final class ConnectorFactoryProvider { } - private ConnectorFactoryProvider() { - // No instantiation - } - /** - * Retrieves the default {@link ConnectorFactory} obtained via the - * {@link ServiceLoader}. + * Retrieves the currently set default {@link ConnectorFactory}. * * @return the {@link ConnectorFactory}, or {@code null} if none. */ public static ConnectorFactory getDefaultFactory() { - return FACTORY; + return INSTANCE; + } + + /** + * Sets the default {@link ConnectorFactory}. + * + * @param factory + * {@link ConnectorFactory} to use, or {@code null} to use the + * factory discovered via the {@link ServiceLoader}. + */ + public static void setDefaultFactory(ConnectorFactory factory) { + INSTANCE = factory == null ? loadDefaultFactory() : factory; + } + + private ConnectorFactoryProvider() { + // No instantiation } } 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 3364180099..58cf8e1ddd 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 @@ -56,7 +56,6 @@ import org.eclipse.jgit.internal.transport.sshd.JGitUserInteraction; import org.eclipse.jgit.internal.transport.sshd.OpenSshServerKeyDatabase; import org.eclipse.jgit.internal.transport.sshd.PasswordProviderWrapper; import org.eclipse.jgit.internal.transport.sshd.SshdText; -import org.eclipse.jgit.internal.transport.sshd.agent.ConnectorFactoryProvider; import org.eclipse.jgit.internal.transport.sshd.agent.JGitSshAgentFactory; import org.eclipse.jgit.transport.CredentialsProvider; import org.eclipse.jgit.transport.SshConfigStore; @@ -456,12 +455,15 @@ public class SshdSessionFactory extends SshSessionFactory implements Closeable { /** * Gets a {@link ConnectorFactory}. If this returns {@code null}, SSH agents * are not supported. + * <p> + * The default implementation uses {@link ConnectorFactory#getDefault()} + * </p> * * @return the factory, or {@code null} if no SSH agent support is desired * @since 6.0 */ protected ConnectorFactory getConnectorFactory() { - return ConnectorFactoryProvider.getDefaultFactory(); + return ConnectorFactory.getDefault(); } /** 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 b351d89ef5..da98ea7fe0 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 @@ -11,8 +11,10 @@ package org.eclipse.jgit.transport.sshd.agent; import java.io.File; import java.io.IOException; +import java.util.Collection; import org.eclipse.jgit.annotations.NonNull; +import org.eclipse.jgit.internal.transport.sshd.agent.ConnectorFactoryProvider; /** * A factory for creating {@link Connector}s. This is a service provider @@ -25,13 +27,44 @@ import org.eclipse.jgit.annotations.NonNull; public interface ConnectorFactory { /** + * Retrieves the currently set default {@link ConnectorFactory}. This is the + * factory that is used unless overridden by the + * {@link org.eclipse.jgit.transport.sshd.SshdSessionFactory}. + * + * @return the current default factory; may be {@code null} if none is set + * and the {@link java.util.ServiceLoader} cannot find any suitable + * implementation + */ + static ConnectorFactory getDefault() { + return ConnectorFactoryProvider.getDefaultFactory(); + } + + /** + * Sets a default {@link ConnectorFactory}. This is the factory that is used + * unless overridden by the + * {@link org.eclipse.jgit.transport.sshd.SshdSessionFactory}. + * <p> + * If no default factory is set programmatically, an implementation is + * discovered via the {@link java.util.ServiceLoader}. + * </p> + * + * @param factory + * {@link ConnectorFactory} to set, or {@code null} to revert to + * the default behavior of using the + * {@link java.util.ServiceLoader}. + */ + static void setDefault(ConnectorFactory factory) { + ConnectorFactoryProvider.setDefaultFactory(factory); + } + + /** * Creates a new {@link Connector}. * * @param identityAgent * identifies the wanted agent connection; if {@code null}, the * factory is free to provide a {@link Connector} to a default - * agent. The value will typically come from the IdentityAgent - * setting in ~/.ssh/config. + * agent. The value will typically come from the + * {@code IdentityAgent} setting in {@code ~/.ssh/config}. * @param homeDir * the current local user's home directory as configured in the * {@link org.eclipse.jgit.transport.sshd.SshdSessionFactory} @@ -58,4 +91,83 @@ public interface ConnectorFactory { */ String getName(); + /** + * {@link ConnectorDescriptor}s describe available {@link Connector}s a + * {@link ConnectorFactory} may provide. + * <p> + * A {@link ConnectorFactory} may support connecting to different SSH + * agents. Agents are identified by name; a user can choose a specific agent + * for instance via the {@code IdentityAgent} setting in + * {@code ~/.ssh/config}. + * </p> + * <p> + * OpenSSH knows two built-in names: "none" for not using any agent, and + * "SSH_AUTH_SOCK" for using an agent that communicates over a Unix domain + * socket given by the value of environment variable {@code SSH_AUTH_SOCK}. + * Other agents can be specified in OpenSSH by specifying the socket file + * directly. (The "standard" OpenBSD OpenSSH knows only this communication + * mechanism.) "SSH_AUTH_SOCK" is also the default in OpenBSD OpenSSH if + * nothing is configured. + * </p> + * <p> + * A particular {@link ConnectorFactory} may support more communication + * mechanisms or different agents. For instance, a factory on Windows might + * support Pageant, Win32-OpenSSH, or even git bash ssh-agent, and might + * accept internal names like "pageant", "openssh", "SSH_AUTH_SOCK" in + * {@link ConnectorFactory#create(String, File)} to choose among them. + * </p> + * The {@link ConnectorDescriptor} interface and the + * {@link ConnectorFactory#getSupportedConnectors()} and + * {@link ConnectorFactory#getDefaultConnector()} methods provide a way for + * code using a {@link ConnectorFactory} to learn what the factory supports + * and thus implement some way by which a user can influence the default + * behavior if {@code IdentityAgent} is not set or + * {@link ConnectorFactory#create(String, File)} is called with + * {@code identityAgent == null}. + */ + interface ConnectorDescriptor { + + /** + * Retrieves the internal name of a supported {@link Connector}. The + * internal name is the one a user can specify for instance in the + * {@code IdentityAgent} setting in {@code ~/.ssh/config} to select the + * connector. + * + * @return the internal name; not empty + */ + @NonNull + String getIdentityAgent(); + + /** + * Retrieves a display name for a {@link Connector}, suitable for + * showing in a UI. + * + * @return the display name; properly localized and not empty + */ + @NonNull + String getDisplayName(); + } + + /** + * Tells which kinds of SSH agents this {@link ConnectorFactory} supports. + * <p> + * An implementation of this method should document the possible values it + * returns. + * </p> + * + * @return an immutable collection of {@link ConnectorDescriptor}s, + * including {@link #getDefaultConnector()} and not including a + * descriptor for internal name "none" + */ + @NonNull + Collection<ConnectorDescriptor> getSupportedConnectors(); + + /** + * Tells what kind of {@link Connector} this {@link ConnectorFactory} + * creates if {@link ConnectorFactory#create(String, File)} is called with + * {@code identityAgent == null}. + * + * @return a {@link ConnectorDescriptor} for the default connector + */ + ConnectorDescriptor getDefaultConnector(); } |