This is an automated email from the ASF dual-hosted git repository. lgoldstein pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mina-sshd.git
The following commit(s) were added to refs/heads/master by this push: new f5c63a87d [GH-429] Support GIT protocol-v2 f5c63a87d is described below commit f5c63a87d46ca5820e17af00b4e65a43288b58c7 Author: =?UTF-8?q?Pavel=20Fla=C5=A1ka?= <pavel.fla...@oracle.com> AuthorDate: Mon Dec 11 18:58:20 2023 +0200 [GH-429] Support GIT protocol-v2 --- CHANGES.md | 10 +++++----- .../java/org/apache/sshd/git/GitModuleProperties.java | 7 +++++++ .../java/org/apache/sshd/git/pack/GitPackCommand.java | 15 ++++++++++++++- .../org/apache/sshd/git/transport/GitSshdSession.java | 16 +++++++++++++++- .../org/apache/sshd/git/pack/GitPackCommandTest.java | 13 +++++++++++++ 5 files changed, 54 insertions(+), 7 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 97f72b924..800246c46 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -32,9 +32,11 @@ ## New Features -# Behavioral changes and enhancements +* [GH-429](https://github.com/apache/mina-sshd/issues/429) Support GIT protocol-v2 -## New `ScpTransferEventListener` callback method +## Behavioral changes and enhancements + +### New `ScpTransferEventListener` callback method Following [GH-428/GH-392](https://github.com/apache/mina-sshd/issues/428) a new `handleReceiveCommandAckInfo` method has been added to enable users to inspect acknowledgements of a `receive` related command. The user is free to inspect the command that was attempted as well as the response code and decide how @@ -43,7 +45,5 @@ an exception if so. ## Potential compatibility issues -### Server-side SFTP file handle encoding - -### Major Code Re-factoring +## Major Code Re-factoring diff --git a/sshd-git/src/main/java/org/apache/sshd/git/GitModuleProperties.java b/sshd-git/src/main/java/org/apache/sshd/git/GitModuleProperties.java index e3339a3c1..7ede9b42a 100644 --- a/sshd-git/src/main/java/org/apache/sshd/git/GitModuleProperties.java +++ b/sshd-git/src/main/java/org/apache/sshd/git/GitModuleProperties.java @@ -50,6 +50,13 @@ public final class GitModuleProperties { public static final Property<Duration> CHANNEL_OPEN_TIMEOUT = Property.duration("git-ssh-channel-open-timeout", Duration.ofSeconds(7L)); + /** + * Property used to configure the SSHD {@link org.apache.sshd.common.FactoryManager} with the {@code GIT_PROTOCOL} + * environment variable. The default is not specified and therefore original (v0) protocol is used. + */ + public static final Property<String> GIT_PROTOCOL_VERSION + = Property.string("git-ssh-protocol-version"); + private GitModuleProperties() { // private } diff --git a/sshd-git/src/main/java/org/apache/sshd/git/pack/GitPackCommand.java b/sshd-git/src/main/java/org/apache/sshd/git/pack/GitPackCommand.java index bd102014b..ef77012d7 100644 --- a/sshd-git/src/main/java/org/apache/sshd/git/pack/GitPackCommand.java +++ b/sshd-git/src/main/java/org/apache/sshd/git/pack/GitPackCommand.java @@ -20,15 +20,20 @@ package org.apache.sshd.git.pack; import java.io.IOException; import java.nio.file.Path; +import java.util.Collections; import java.util.List; +import java.util.Map; import org.apache.sshd.common.util.GenericUtils; +import org.apache.sshd.common.util.MapEntryUtils; import org.apache.sshd.common.util.ValidateUtils; import org.apache.sshd.common.util.threads.CloseableExecutorService; import org.apache.sshd.git.AbstractGitCommand; import org.apache.sshd.git.GitLocationResolver; +import org.apache.sshd.server.Environment; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.RepositoryCache; +import org.eclipse.jgit.transport.GitProtocolConstants; import org.eclipse.jgit.transport.ReceivePack; import org.eclipse.jgit.transport.RemoteConfig; import org.eclipse.jgit.transport.UploadPack; @@ -77,7 +82,15 @@ public class GitPackCommand extends AbstractGitCommand { Repository db = key.open(true /* must exist */); String subCommand = args[0]; if (RemoteConfig.DEFAULT_UPLOAD_PACK.equals(subCommand)) { - new UploadPack(db).upload(getInputStream(), getOutputStream(), getErrorStream()); + UploadPack uploadPack = new UploadPack(db); + Environment environment = getEnvironment(); + Map<String, String> envVars = environment.getEnv(); + String protocol = MapEntryUtils.isEmpty(envVars) + ? null : envVars.get(GitProtocolConstants.PROTOCOL_ENVIRONMENT_VARIABLE); + if (GenericUtils.isNotBlank(protocol)) { + uploadPack.setExtraParameters(Collections.singleton(protocol)); + } + uploadPack.upload(getInputStream(), getOutputStream(), getErrorStream()); } else if (RemoteConfig.DEFAULT_RECEIVE_PACK.equals(subCommand)) { new ReceivePack(db).receive(getInputStream(), getOutputStream(), getErrorStream()); } else { diff --git a/sshd-git/src/main/java/org/apache/sshd/git/transport/GitSshdSession.java b/sshd-git/src/main/java/org/apache/sshd/git/transport/GitSshdSession.java index 091c434ae..639f12e52 100644 --- a/sshd-git/src/main/java/org/apache/sshd/git/transport/GitSshdSession.java +++ b/sshd-git/src/main/java/org/apache/sshd/git/transport/GitSshdSession.java @@ -19,6 +19,9 @@ package org.apache.sshd.git.transport; import java.io.IOException; +import java.util.Collections; +import java.util.Map; +import java.util.Optional; import org.apache.sshd.client.SshClient; import org.apache.sshd.client.channel.ChannelExec; @@ -28,6 +31,7 @@ import org.apache.sshd.common.util.logging.AbstractLoggingBean; import org.apache.sshd.git.GitModuleProperties; import org.eclipse.jgit.transport.CredentialItem; import org.eclipse.jgit.transport.CredentialsProvider; +import org.eclipse.jgit.transport.GitProtocolConstants; import org.eclipse.jgit.transport.RemoteSession; import org.eclipse.jgit.transport.URIish; import org.eclipse.jgit.util.FS; @@ -128,7 +132,17 @@ public class GitSshdSession extends AbstractLoggingBean implements RemoteSession log.trace("exec({}) session={}, timeout={} sec.", commandName, session, timeout); } - ChannelExec channel = session.createExecChannel(commandName); + ChannelExec channel; + Optional<String> protocolVer = GitModuleProperties.GIT_PROTOCOL_VERSION.get(session); + String protocol = protocolVer.orElse(null); + if (GenericUtils.isNotBlank(protocol)) { + Map<String, String> env = Collections.singletonMap( + GitProtocolConstants.PROTOCOL_ENVIRONMENT_VARIABLE, protocol); + channel = session.createExecChannel(commandName, null, env); + } else { + channel = session.createExecChannel(commandName); + } + if (traceEnabled) { log.trace("exec({}) session={} - open channel", commandName, session); } diff --git a/sshd-git/src/test/java/org/apache/sshd/git/pack/GitPackCommandTest.java b/sshd-git/src/test/java/org/apache/sshd/git/pack/GitPackCommandTest.java index bfee4a395..ea6f00879 100644 --- a/sshd-git/src/test/java/org/apache/sshd/git/pack/GitPackCommandTest.java +++ b/sshd-git/src/test/java/org/apache/sshd/git/pack/GitPackCommandTest.java @@ -24,8 +24,11 @@ import java.util.Collections; import com.jcraft.jsch.JSch; import org.apache.sshd.client.SshClient; +import org.apache.sshd.common.PropertyResolver; +import org.apache.sshd.common.PropertyResolverUtils; import org.apache.sshd.common.util.OsUtils; import org.apache.sshd.git.GitLocationResolver; +import org.apache.sshd.git.GitModuleProperties; import org.apache.sshd.git.transport.GitSshdSessionFactory; import org.apache.sshd.server.SshServer; import org.apache.sshd.server.auth.password.AcceptAllPasswordAuthenticator; @@ -36,6 +39,7 @@ import org.apache.sshd.util.test.JSchLogger; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.transport.CredentialsProvider; +import org.eclipse.jgit.transport.GitProtocolConstants; import org.eclipse.jgit.transport.SshSessionFactory; import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; import org.junit.Assume; @@ -108,6 +112,15 @@ public class GitPackCommandTest extends BaseTestSupport { git.pull().setRebase(true).call(); assertTrue("Client not started after rebase", client.isStarted()); + + PropertyResolver useProtocolV2 = PropertyResolverUtils + .toPropertyResolver( + Collections.singletonMap(GitModuleProperties.GIT_PROTOCOL_VERSION.getName(), + GitProtocolConstants.VERSION_2_REQUEST)); + client.setParentPropertyResolver(useProtocolV2); + git.fetch().call(); + assertTrue("Client not started after fetch using GIT_PROTOCOL='version=2' env. variable", + client.isStarted()); } finally { client.stop(); }