From acb585f9f1e0b3c0fd5b77394dfc89bd008b3dcc Mon Sep 17 00:00:00 2001 From: Konrad Windszus Date: Fri, 8 Jul 2022 08:44:28 +0200 Subject: [PATCH] [SCM-995] Upgrade JGit to 5.13.1 and leverage Apache Mina SSHD instead of JSch This closes #153 --- .../maven-scm-provider-jgit/pom.xml | 16 ++-- .../command/JGitTransportConfigCallback.java | 89 +----------------- .../provider/git/jgit/command/JGitUtils.java | 4 +- .../ScmProviderAwareSshdSessionFactory.java | 92 +++++++++++++++++++ .../command/checkout/JGitCheckOutCommand.java | 38 +++++--- .../jgit/command/list/JGitListCommand.java | 19 +++- .../remoteinfo/JGitRemoteInfoCommand.java | 20 +++- ...tCheckInCommandCommitterAuthorTckTest.java | 6 ++ 8 files changed, 178 insertions(+), 106 deletions(-) create mode 100644 maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/ScmProviderAwareSshdSessionFactory.java diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/pom.xml b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/pom.xml index f5aab7b1a..29efbf3b6 100644 --- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/pom.xml +++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/pom.xml @@ -35,6 +35,9 @@ see http://eclipse.org/jgit/ + + 5.13.1.202206130422-r + javax.inject @@ -47,13 +50,12 @@ org.eclipse.jgit org.eclipse.jgit - 4.5.4.201711221230-r - - - commons-logging - commons-logging - - + ${jgitVersion} + + + org.eclipse.jgit + org.eclipse.jgit.ssh.apache + ${jgitVersion} org.slf4j diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/JGitTransportConfigCallback.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/JGitTransportConfigCallback.java index 033779346..7c8c72726 100644 --- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/JGitTransportConfigCallback.java +++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/JGitTransportConfigCallback.java @@ -19,19 +19,10 @@ * under the License. */ -import com.jcraft.jsch.JSch; -import com.jcraft.jsch.JSchException; -import com.jcraft.jsch.Session; -import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository; import org.eclipse.jgit.api.TransportConfigCallback; -import org.eclipse.jgit.transport.JschConfigSessionFactory; -import org.eclipse.jgit.transport.OpenSshConfig; -import org.eclipse.jgit.transport.SshSessionFactory; import org.eclipse.jgit.transport.SshTransport; import org.eclipse.jgit.transport.Transport; -import org.eclipse.jgit.util.FS; -import org.eclipse.jgit.util.StringUtils; -import org.slf4j.Logger; +import org.eclipse.jgit.transport.sshd.SshdSessionFactory; /** * Implementation of {@link TransportConfigCallback} which adds @@ -39,27 +30,11 @@ */ public class JGitTransportConfigCallback implements TransportConfigCallback { - private SshSessionFactory sshSessionFactory = null; + private final SshdSessionFactory sshSessionFactory; - public JGitTransportConfigCallback( GitScmProviderRepository repo, Logger logger ) + public JGitTransportConfigCallback( SshdSessionFactory sshSessionFactory ) { - if ( repo.getFetchInfo().getProtocol().equals( "ssh" ) ) - { - if ( !StringUtils.isEmptyOrNull( repo.getPrivateKey() ) && repo.getPassphrase() == null ) - { - logger.debug( "using private key: " + repo.getPrivateKey() ); - sshSessionFactory = new UnprotectedPrivateKeySessionFactory( repo ); - } - else if ( !StringUtils.isEmptyOrNull( repo.getPrivateKey() ) && repo.getPassphrase() != null ) - { - logger.debug( "using private key with passphrase: " + repo.getPrivateKey() ); - sshSessionFactory = new ProtectedPrivateKeyFileSessionFactory( repo ); - } - else - { - sshSessionFactory = new SimpleSessionFactory(); - } - } + this.sshSessionFactory = sshSessionFactory; } @Override @@ -72,60 +47,4 @@ public void configure( Transport transport ) } } - private static class SimpleSessionFactory extends JschConfigSessionFactory - { - @Override - protected void configure( OpenSshConfig.Host host, Session session ) - { - } - } - - private abstract static class PrivateKeySessionFactory extends SimpleSessionFactory - { - private final GitScmProviderRepository repo; - - GitScmProviderRepository getRepo() - { - return repo; - } - - PrivateKeySessionFactory( GitScmProviderRepository repo ) - { - this.repo = repo; - } - } - - private static class UnprotectedPrivateKeySessionFactory extends PrivateKeySessionFactory - { - - UnprotectedPrivateKeySessionFactory( GitScmProviderRepository repo ) - { - super( repo ); - } - - @Override - protected JSch createDefaultJSch( FS fs ) throws JSchException - { - JSch defaultJSch = super.createDefaultJSch( fs ); - defaultJSch.addIdentity( getRepo().getPrivateKey() ); - return defaultJSch; - } - } - - private static class ProtectedPrivateKeyFileSessionFactory extends PrivateKeySessionFactory - { - - ProtectedPrivateKeyFileSessionFactory( GitScmProviderRepository repo ) - { - super( repo ); - } - - @Override - protected JSch createDefaultJSch( FS fs ) throws JSchException - { - JSch defaultJSch = super.createDefaultJSch( fs ); - defaultJSch.addIdentity( getRepo().getPrivateKey(), getRepo().getPassphrase() ); - return defaultJSch; - } - } } diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/JGitUtils.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/JGitUtils.java index 8bfb2ecfd..81dc26aa9 100644 --- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/JGitUtils.java +++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/JGitUtils.java @@ -193,7 +193,9 @@ public static Iterable push( Git git, GitScmProviderRepository repo, { CredentialsProvider credentials = prepareSession( git, repo ); PushCommand command = git.push().setRefSpecs( refSpec ).setCredentialsProvider( credentials ) - .setTransportConfigCallback( new JGitTransportConfigCallback( repo, LOGGER ) ); + .setTransportConfigCallback( + new JGitTransportConfigCallback( new ScmProviderAwareSshdSessionFactory( repo, LOGGER ) ) + ); Iterable pushResultList = command.call(); for ( PushResult pushResult : pushResultList ) diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/ScmProviderAwareSshdSessionFactory.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/ScmProviderAwareSshdSessionFactory.java new file mode 100644 index 000000000..b5d247243 --- /dev/null +++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/ScmProviderAwareSshdSessionFactory.java @@ -0,0 +1,92 @@ +package org.apache.maven.scm.provider.git.jgit.command; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.List; + +import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository; +import org.eclipse.jgit.transport.CredentialsProvider; +import org.eclipse.jgit.transport.URIish; +import org.eclipse.jgit.transport.sshd.IdentityPasswordProvider; +import org.eclipse.jgit.transport.sshd.KeyPasswordProvider; +import org.eclipse.jgit.transport.sshd.SshdSessionFactory; +import org.eclipse.jgit.util.StringUtils; +import org.slf4j.Logger; + +/** + * {@link SshdSessionFactory} considering the settings from {@link GitScmProviderRepository}. + * + */ +public class ScmProviderAwareSshdSessionFactory extends SshdSessionFactory +{ + private final GitScmProviderRepository repo; + private final Logger logger; + + public ScmProviderAwareSshdSessionFactory( GitScmProviderRepository repo, Logger logger ) + { + this.repo = repo; + this.logger = logger; + } + + @Override + protected List getDefaultIdentities( File sshDir ) + { + if ( !StringUtils.isEmptyOrNull( repo.getPrivateKey() ) ) + { + logger.debug( "Using private key at {}", repo.getPrivateKey() ); + return Collections.singletonList( Paths.get( repo.getPrivateKey() ) ); + } + else + { + return super.getDefaultIdentities( sshDir ); + } + } + + @Override + protected KeyPasswordProvider createKeyPasswordProvider( CredentialsProvider provider ) + { + if ( repo.getPassphrase() != null ) + { + return new IdentityPasswordProvider( provider ) + { + @Override + public char[] getPassphrase( URIish uri, int attempt ) throws IOException + { + if ( attempt > 0 ) + { + throw new IOException( "Passphrase was not correct in first attempt, " + + "canceling further attempts!" ); + } + logger.debug( "Using stored passphrase" ); + return repo.getPassphrase().toCharArray(); + } + }; + } + else + { + return super.createKeyPasswordProvider( provider ); + } + } +} \ No newline at end of file diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/checkout/JGitCheckOutCommand.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/checkout/JGitCheckOutCommand.java index d7646fda8..a701ccd91 100644 --- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/checkout/JGitCheckOutCommand.java +++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/checkout/JGitCheckOutCommand.java @@ -19,6 +19,13 @@ * under the License. */ + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.function.BiFunction; + import org.apache.maven.scm.ScmException; import org.apache.maven.scm.ScmFile; import org.apache.maven.scm.ScmFileSet; @@ -32,6 +39,7 @@ import org.apache.maven.scm.provider.git.command.GitCommand; import org.apache.maven.scm.provider.git.jgit.command.JGitTransportConfigCallback; import org.apache.maven.scm.provider.git.jgit.command.JGitUtils; +import org.apache.maven.scm.provider.git.jgit.command.ScmProviderAwareSshdSessionFactory; import org.apache.maven.scm.provider.git.jgit.command.branch.JGitBranchCommand; import org.apache.maven.scm.provider.git.jgit.command.remoteinfo.JGitRemoteInfoCommand; import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository; @@ -48,11 +56,7 @@ import org.eclipse.jgit.storage.file.WindowCacheConfig; import org.eclipse.jgit.transport.CredentialsProvider; import org.eclipse.jgit.treewalk.TreeWalk; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; +import org.slf4j.Logger; /** * @author Mark Struberg @@ -63,6 +67,19 @@ public class JGitCheckOutCommand extends AbstractCheckOutCommand implements GitCommand { + private BiFunction sshSessionFactorySupplier; + + public JGitCheckOutCommand() + { + sshSessionFactorySupplier = ScmProviderAwareSshdSessionFactory::new; + } + + public void setSshSessionFactorySupplier( + BiFunction sshSessionFactorySupplier ) + { + this.sshSessionFactorySupplier = sshSessionFactorySupplier; + } + /** * For git, the given repository is a remote one. We have to clone it first if the working directory does not * contain a git repo yet, otherwise we have to git-pull it. @@ -94,6 +111,9 @@ protected CheckOutScmResult executeCheckOutCommand( ScmProviderRepository repo, branch = Constants.MASTER; } + TransportConfigCallback transportConfigCallback = new JGitTransportConfigCallback( + sshSessionFactorySupplier.apply( (GitScmProviderRepository) repo, logger ) ); + logger.debug( "try checkout of branch: " + branch ); if ( !fileSet.getBasedir().exists() || !( new File( fileSet.getBasedir(), ".git" ).exists() ) ) @@ -116,8 +136,6 @@ protected CheckOutScmResult executeCheckOutCommand( ScmProviderRepository repo, command.setCredentialsProvider( credentials ).setBranch( branch ).setDirectory( fileSet.getBasedir() ); - TransportConfigCallback transportConfigCallback = new JGitTransportConfigCallback( - (GitScmProviderRepository) repo, logger ); command.setTransportConfigCallback( transportConfigCallback ); command.setProgressMonitor( monitor ); @@ -125,7 +143,7 @@ protected CheckOutScmResult executeCheckOutCommand( ScmProviderRepository repo, } JGitRemoteInfoCommand remoteInfoCommand = new JGitRemoteInfoCommand(); - + remoteInfoCommand.setSshSessionFactorySupplier( sshSessionFactorySupplier ); RemoteInfoScmResult result = remoteInfoCommand.executeRemoteInfoCommand( repository, fileSet, null ); if ( git == null ) @@ -133,14 +151,12 @@ protected CheckOutScmResult executeCheckOutCommand( ScmProviderRepository repo, // deliberately not using JGitUtils.openRepo(), the caller told us exactly where to checkout git = Git.open( fileSet.getBasedir() ); } - + if ( fileSet.getBasedir().exists() && new File( fileSet.getBasedir(), ".git" ).exists() && result.getBranches().size() > 0 ) { // git repo exists, so we must git-pull the changes CredentialsProvider credentials = JGitUtils.prepareSession( git, repository ); - TransportConfigCallback transportConfigCallback = new JGitTransportConfigCallback( - (GitScmProviderRepository) repo, logger ); if ( version != null && StringUtils.isNotEmpty( version.getName() ) && ( version instanceof ScmTag ) ) { diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/list/JGitListCommand.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/list/JGitListCommand.java index 2b85b8d4b..234ab018b 100644 --- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/list/JGitListCommand.java +++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/list/JGitListCommand.java @@ -30,14 +30,17 @@ import org.apache.maven.scm.provider.git.command.GitCommand; import org.apache.maven.scm.provider.git.jgit.command.JGitTransportConfigCallback; import org.apache.maven.scm.provider.git.jgit.command.JGitUtils; +import org.apache.maven.scm.provider.git.jgit.command.ScmProviderAwareSshdSessionFactory; import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.transport.CredentialsProvider; +import org.slf4j.Logger; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.function.BiFunction; /** * @author Dominik Bartholdi (imod) @@ -48,6 +51,19 @@ public class JGitListCommand implements GitCommand { + private BiFunction sshSessionFactorySupplier; + + public JGitListCommand() + { + sshSessionFactorySupplier = ScmProviderAwareSshdSessionFactory::new; + } + + public void setSshSessionFactorySupplier( + BiFunction sshSessionFactorySupplier ) + { + this.sshSessionFactorySupplier = sshSessionFactorySupplier; + } + @Override protected ListScmResult executeListCommand( ScmProviderRepository repo, ScmFileSet fileSet, boolean recursive, ScmVersion scmVersion ) @@ -64,7 +80,8 @@ protected ListScmResult executeListCommand( ScmProviderRepository repo, ScmFileS List list = new ArrayList<>(); Collection lsResult = git.lsRemote().setCredentialsProvider( credentials ) .setTransportConfigCallback( - new JGitTransportConfigCallback( (GitScmProviderRepository) repo, logger ) ) + new JGitTransportConfigCallback( + sshSessionFactorySupplier.apply( (GitScmProviderRepository) repo, logger ) ) ) .call(); for ( Ref ref : lsResult ) { diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/remoteinfo/JGitRemoteInfoCommand.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/remoteinfo/JGitRemoteInfoCommand.java index 833822fd4..62b64a9a3 100644 --- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/remoteinfo/JGitRemoteInfoCommand.java +++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/remoteinfo/JGitRemoteInfoCommand.java @@ -28,16 +28,19 @@ import org.apache.maven.scm.provider.git.command.GitCommand; import org.apache.maven.scm.provider.git.jgit.command.JGitTransportConfigCallback; import org.apache.maven.scm.provider.git.jgit.command.JGitUtils; +import org.apache.maven.scm.provider.git.jgit.command.ScmProviderAwareSshdSessionFactory; import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.LsRemoteCommand; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.transport.CredentialsProvider; +import org.slf4j.Logger; import java.util.Collection; import java.util.HashMap; import java.util.Map; +import java.util.function.BiFunction; /** * @author Dominik Bartholdi (imod) @@ -48,6 +51,19 @@ public class JGitRemoteInfoCommand implements GitCommand { + private BiFunction sshSessionFactorySupplier; + + public JGitRemoteInfoCommand() + { + sshSessionFactorySupplier = ScmProviderAwareSshdSessionFactory::new; + } + + public void setSshSessionFactorySupplier( + BiFunction sshSessionFactorySupplier ) + { + this.sshSessionFactorySupplier = sshSessionFactorySupplier; + } + @Override public RemoteInfoScmResult executeRemoteInfoCommand( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters ) @@ -63,7 +79,9 @@ public RemoteInfoScmResult executeRemoteInfoCommand( ScmProviderRepository repos LsRemoteCommand lsCommand = git.lsRemote().setRemote( repo.getPushUrl() ).setCredentialsProvider( credentials ) - .setTransportConfigCallback( new JGitTransportConfigCallback( repo, logger ) ); + .setTransportConfigCallback( + new JGitTransportConfigCallback( sshSessionFactorySupplier.apply( repo, logger ) ) + ); Map tag = new HashMap<>(); Collection allTags = lsCommand.setHeads( false ).setTags( true ).call(); diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/test/java/org/apache/maven/scm/provider/git/jgit/command/checkin/JGitCheckInCommandCommitterAuthorTckTest.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/test/java/org/apache/maven/scm/provider/git/jgit/command/checkin/JGitCheckInCommandCommitterAuthorTckTest.java index 1f4cd44dd..5c56c25f8 100644 --- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/test/java/org/apache/maven/scm/provider/git/jgit/command/checkin/JGitCheckInCommandCommitterAuthorTckTest.java +++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/test/java/org/apache/maven/scm/provider/git/jgit/command/checkin/JGitCheckInCommandCommitterAuthorTckTest.java @@ -361,6 +361,12 @@ public int getTimezone( long when ) { return reader.getTimezone( when ); } + + @Override + public FileBasedConfig openJGitConfig( Config config, FS fs ) + { + return reader.openJGitConfig( config, fs ); + } } }