Skip to content

Commit acb585f

Browse files
kwinmichael-o
authored andcommitted
[SCM-995] Upgrade JGit to 5.13.1 and leverage Apache Mina SSHD instead of JSch
This closes #153
1 parent 07d51d3 commit acb585f

File tree

8 files changed

+178
-106
lines changed

8 files changed

+178
-106
lines changed

maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/pom.xml

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
see http://eclipse.org/jgit/
3636
</description>
3737

38+
<properties>
39+
<jgitVersion>5.13.1.202206130422-r</jgitVersion><!-- version 6+ requires Java 11 -->
40+
</properties>
3841
<dependencies>
3942
<dependency>
4043
<groupId>javax.inject</groupId>
@@ -47,13 +50,12 @@
4750
<dependency>
4851
<groupId>org.eclipse.jgit</groupId>
4952
<artifactId>org.eclipse.jgit</artifactId>
50-
<version>4.5.4.201711221230-r</version>
51-
<exclusions>
52-
<exclusion>
53-
<groupId>commons-logging</groupId>
54-
<artifactId>commons-logging</artifactId>
55-
</exclusion>
56-
</exclusions>
53+
<version>${jgitVersion}</version>
54+
</dependency>
55+
<dependency>
56+
<groupId>org.eclipse.jgit</groupId>
57+
<artifactId>org.eclipse.jgit.ssh.apache</artifactId>
58+
<version>${jgitVersion}</version>
5759
</dependency>
5860
<dependency>
5961
<groupId>org.slf4j</groupId>

maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/JGitTransportConfigCallback.java

Lines changed: 4 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -19,47 +19,22 @@
1919
* under the License.
2020
*/
2121

22-
import com.jcraft.jsch.JSch;
23-
import com.jcraft.jsch.JSchException;
24-
import com.jcraft.jsch.Session;
25-
import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
2622
import org.eclipse.jgit.api.TransportConfigCallback;
27-
import org.eclipse.jgit.transport.JschConfigSessionFactory;
28-
import org.eclipse.jgit.transport.OpenSshConfig;
29-
import org.eclipse.jgit.transport.SshSessionFactory;
3023
import org.eclipse.jgit.transport.SshTransport;
3124
import org.eclipse.jgit.transport.Transport;
32-
import org.eclipse.jgit.util.FS;
33-
import org.eclipse.jgit.util.StringUtils;
34-
import org.slf4j.Logger;
25+
import org.eclipse.jgit.transport.sshd.SshdSessionFactory;
3526

3627
/**
3728
* Implementation of {@link TransportConfigCallback} which adds
3829
* a public/private key identity to ssh URLs if configured.
3930
*/
4031
public class JGitTransportConfigCallback implements TransportConfigCallback
4132
{
42-
private SshSessionFactory sshSessionFactory = null;
33+
private final SshdSessionFactory sshSessionFactory;
4334

44-
public JGitTransportConfigCallback( GitScmProviderRepository repo, Logger logger )
35+
public JGitTransportConfigCallback( SshdSessionFactory sshSessionFactory )
4536
{
46-
if ( repo.getFetchInfo().getProtocol().equals( "ssh" ) )
47-
{
48-
if ( !StringUtils.isEmptyOrNull( repo.getPrivateKey() ) && repo.getPassphrase() == null )
49-
{
50-
logger.debug( "using private key: " + repo.getPrivateKey() );
51-
sshSessionFactory = new UnprotectedPrivateKeySessionFactory( repo );
52-
}
53-
else if ( !StringUtils.isEmptyOrNull( repo.getPrivateKey() ) && repo.getPassphrase() != null )
54-
{
55-
logger.debug( "using private key with passphrase: " + repo.getPrivateKey() );
56-
sshSessionFactory = new ProtectedPrivateKeyFileSessionFactory( repo );
57-
}
58-
else
59-
{
60-
sshSessionFactory = new SimpleSessionFactory();
61-
}
62-
}
37+
this.sshSessionFactory = sshSessionFactory;
6338
}
6439

6540
@Override
@@ -72,60 +47,4 @@ public void configure( Transport transport )
7247
}
7348
}
7449

75-
private static class SimpleSessionFactory extends JschConfigSessionFactory
76-
{
77-
@Override
78-
protected void configure( OpenSshConfig.Host host, Session session )
79-
{
80-
}
81-
}
82-
83-
private abstract static class PrivateKeySessionFactory extends SimpleSessionFactory
84-
{
85-
private final GitScmProviderRepository repo;
86-
87-
GitScmProviderRepository getRepo()
88-
{
89-
return repo;
90-
}
91-
92-
PrivateKeySessionFactory( GitScmProviderRepository repo )
93-
{
94-
this.repo = repo;
95-
}
96-
}
97-
98-
private static class UnprotectedPrivateKeySessionFactory extends PrivateKeySessionFactory
99-
{
100-
101-
UnprotectedPrivateKeySessionFactory( GitScmProviderRepository repo )
102-
{
103-
super( repo );
104-
}
105-
106-
@Override
107-
protected JSch createDefaultJSch( FS fs ) throws JSchException
108-
{
109-
JSch defaultJSch = super.createDefaultJSch( fs );
110-
defaultJSch.addIdentity( getRepo().getPrivateKey() );
111-
return defaultJSch;
112-
}
113-
}
114-
115-
private static class ProtectedPrivateKeyFileSessionFactory extends PrivateKeySessionFactory
116-
{
117-
118-
ProtectedPrivateKeyFileSessionFactory( GitScmProviderRepository repo )
119-
{
120-
super( repo );
121-
}
122-
123-
@Override
124-
protected JSch createDefaultJSch( FS fs ) throws JSchException
125-
{
126-
JSch defaultJSch = super.createDefaultJSch( fs );
127-
defaultJSch.addIdentity( getRepo().getPrivateKey(), getRepo().getPassphrase() );
128-
return defaultJSch;
129-
}
130-
}
13150
}

maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/JGitUtils.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,9 @@ public static Iterable<PushResult> push( Git git, GitScmProviderRepository repo,
193193
{
194194
CredentialsProvider credentials = prepareSession( git, repo );
195195
PushCommand command = git.push().setRefSpecs( refSpec ).setCredentialsProvider( credentials )
196-
.setTransportConfigCallback( new JGitTransportConfigCallback( repo, LOGGER ) );
196+
.setTransportConfigCallback(
197+
new JGitTransportConfigCallback( new ScmProviderAwareSshdSessionFactory( repo, LOGGER ) )
198+
);
197199

198200
Iterable<PushResult> pushResultList = command.call();
199201
for ( PushResult pushResult : pushResultList )
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package org.apache.maven.scm.provider.git.jgit.command;
2+
3+
/*
4+
* Licensed to the Apache Software Foundation (ASF) under one
5+
* or more contributor license agreements. See the NOTICE file
6+
* distributed with this work for additional information
7+
* regarding copyright ownership. The ASF licenses this file
8+
* to you under the Apache License, Version 2.0 (the
9+
* "License"); you may not use this file except in compliance
10+
* with the License. You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing,
15+
* software distributed under the License is distributed on an
16+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17+
* KIND, either express or implied. See the License for the
18+
* specific language governing permissions and limitations
19+
* under the License.
20+
*/
21+
22+
import java.io.File;
23+
import java.io.IOException;
24+
import java.nio.file.Path;
25+
import java.nio.file.Paths;
26+
import java.util.Collections;
27+
import java.util.List;
28+
29+
import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
30+
import org.eclipse.jgit.transport.CredentialsProvider;
31+
import org.eclipse.jgit.transport.URIish;
32+
import org.eclipse.jgit.transport.sshd.IdentityPasswordProvider;
33+
import org.eclipse.jgit.transport.sshd.KeyPasswordProvider;
34+
import org.eclipse.jgit.transport.sshd.SshdSessionFactory;
35+
import org.eclipse.jgit.util.StringUtils;
36+
import org.slf4j.Logger;
37+
38+
/**
39+
* {@link SshdSessionFactory} considering the settings from {@link GitScmProviderRepository}.
40+
*
41+
*/
42+
public class ScmProviderAwareSshdSessionFactory extends SshdSessionFactory
43+
{
44+
private final GitScmProviderRepository repo;
45+
private final Logger logger;
46+
47+
public ScmProviderAwareSshdSessionFactory( GitScmProviderRepository repo, Logger logger )
48+
{
49+
this.repo = repo;
50+
this.logger = logger;
51+
}
52+
53+
@Override
54+
protected List<Path> getDefaultIdentities( File sshDir )
55+
{
56+
if ( !StringUtils.isEmptyOrNull( repo.getPrivateKey() ) )
57+
{
58+
logger.debug( "Using private key at {}", repo.getPrivateKey() );
59+
return Collections.singletonList( Paths.get( repo.getPrivateKey() ) );
60+
}
61+
else
62+
{
63+
return super.getDefaultIdentities( sshDir );
64+
}
65+
}
66+
67+
@Override
68+
protected KeyPasswordProvider createKeyPasswordProvider( CredentialsProvider provider )
69+
{
70+
if ( repo.getPassphrase() != null )
71+
{
72+
return new IdentityPasswordProvider( provider )
73+
{
74+
@Override
75+
public char[] getPassphrase( URIish uri, int attempt ) throws IOException
76+
{
77+
if ( attempt > 0 )
78+
{
79+
throw new IOException( "Passphrase was not correct in first attempt, "
80+
+ "canceling further attempts!" );
81+
}
82+
logger.debug( "Using stored passphrase" );
83+
return repo.getPassphrase().toCharArray();
84+
}
85+
};
86+
}
87+
else
88+
{
89+
return super.createKeyPasswordProvider( provider );
90+
}
91+
}
92+
}

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

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@
1919
* under the License.
2020
*/
2121

22+
23+
import java.io.File;
24+
import java.util.ArrayList;
25+
import java.util.List;
26+
import java.util.Set;
27+
import java.util.function.BiFunction;
28+
2229
import org.apache.maven.scm.ScmException;
2330
import org.apache.maven.scm.ScmFile;
2431
import org.apache.maven.scm.ScmFileSet;
@@ -32,6 +39,7 @@
3239
import org.apache.maven.scm.provider.git.command.GitCommand;
3340
import org.apache.maven.scm.provider.git.jgit.command.JGitTransportConfigCallback;
3441
import org.apache.maven.scm.provider.git.jgit.command.JGitUtils;
42+
import org.apache.maven.scm.provider.git.jgit.command.ScmProviderAwareSshdSessionFactory;
3543
import org.apache.maven.scm.provider.git.jgit.command.branch.JGitBranchCommand;
3644
import org.apache.maven.scm.provider.git.jgit.command.remoteinfo.JGitRemoteInfoCommand;
3745
import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
@@ -48,11 +56,7 @@
4856
import org.eclipse.jgit.storage.file.WindowCacheConfig;
4957
import org.eclipse.jgit.transport.CredentialsProvider;
5058
import org.eclipse.jgit.treewalk.TreeWalk;
51-
52-
import java.io.File;
53-
import java.util.ArrayList;
54-
import java.util.List;
55-
import java.util.Set;
59+
import org.slf4j.Logger;
5660

5761
/**
5862
* @author <a href="mailto:[email protected]">Mark Struberg</a>
@@ -63,6 +67,19 @@ public class JGitCheckOutCommand
6367
extends AbstractCheckOutCommand
6468
implements GitCommand
6569
{
70+
private BiFunction<GitScmProviderRepository, Logger, ScmProviderAwareSshdSessionFactory> sshSessionFactorySupplier;
71+
72+
public JGitCheckOutCommand()
73+
{
74+
sshSessionFactorySupplier = ScmProviderAwareSshdSessionFactory::new;
75+
}
76+
77+
public void setSshSessionFactorySupplier(
78+
BiFunction<GitScmProviderRepository, Logger, ScmProviderAwareSshdSessionFactory> sshSessionFactorySupplier )
79+
{
80+
this.sshSessionFactorySupplier = sshSessionFactorySupplier;
81+
}
82+
6683
/**
6784
* For git, the given repository is a remote one. We have to clone it first if the working directory does not
6885
* contain a git repo yet, otherwise we have to git-pull it.
@@ -94,6 +111,9 @@ protected CheckOutScmResult executeCheckOutCommand( ScmProviderRepository repo,
94111
branch = Constants.MASTER;
95112
}
96113

114+
TransportConfigCallback transportConfigCallback = new JGitTransportConfigCallback(
115+
sshSessionFactorySupplier.apply( (GitScmProviderRepository) repo, logger ) );
116+
97117
logger.debug( "try checkout of branch: " + branch );
98118

99119
if ( !fileSet.getBasedir().exists() || !( new File( fileSet.getBasedir(), ".git" ).exists() ) )
@@ -116,31 +136,27 @@ protected CheckOutScmResult executeCheckOutCommand( ScmProviderRepository repo,
116136

117137
command.setCredentialsProvider( credentials ).setBranch( branch ).setDirectory( fileSet.getBasedir() );
118138

119-
TransportConfigCallback transportConfigCallback = new JGitTransportConfigCallback(
120-
(GitScmProviderRepository) repo, logger );
121139
command.setTransportConfigCallback( transportConfigCallback );
122140

123141
command.setProgressMonitor( monitor );
124142
git = command.call();
125143
}
126144

127145
JGitRemoteInfoCommand remoteInfoCommand = new JGitRemoteInfoCommand();
128-
146+
remoteInfoCommand.setSshSessionFactorySupplier( sshSessionFactorySupplier );
129147
RemoteInfoScmResult result = remoteInfoCommand.executeRemoteInfoCommand( repository, fileSet, null );
130148

131149
if ( git == null )
132150
{
133151
// deliberately not using JGitUtils.openRepo(), the caller told us exactly where to checkout
134152
git = Git.open( fileSet.getBasedir() );
135153
}
136-
154+
137155
if ( fileSet.getBasedir().exists() && new File( fileSet.getBasedir(), ".git" ).exists()
138156
&& result.getBranches().size() > 0 )
139157
{
140158
// git repo exists, so we must git-pull the changes
141159
CredentialsProvider credentials = JGitUtils.prepareSession( git, repository );
142-
TransportConfigCallback transportConfigCallback = new JGitTransportConfigCallback(
143-
(GitScmProviderRepository) repo, logger );
144160

145161
if ( version != null && StringUtils.isNotEmpty( version.getName() ) && ( version instanceof ScmTag ) )
146162
{

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

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,17 @@
3030
import org.apache.maven.scm.provider.git.command.GitCommand;
3131
import org.apache.maven.scm.provider.git.jgit.command.JGitTransportConfigCallback;
3232
import org.apache.maven.scm.provider.git.jgit.command.JGitUtils;
33+
import org.apache.maven.scm.provider.git.jgit.command.ScmProviderAwareSshdSessionFactory;
3334
import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
3435
import org.eclipse.jgit.api.Git;
3536
import org.eclipse.jgit.lib.Ref;
3637
import org.eclipse.jgit.transport.CredentialsProvider;
38+
import org.slf4j.Logger;
3739

3840
import java.util.ArrayList;
3941
import java.util.Collection;
4042
import java.util.List;
43+
import java.util.function.BiFunction;
4144

4245
/**
4346
* @author Dominik Bartholdi (imod)
@@ -48,6 +51,19 @@ public class JGitListCommand
4851
implements GitCommand
4952
{
5053

54+
private BiFunction<GitScmProviderRepository, Logger, ScmProviderAwareSshdSessionFactory> sshSessionFactorySupplier;
55+
56+
public JGitListCommand()
57+
{
58+
sshSessionFactorySupplier = ScmProviderAwareSshdSessionFactory::new;
59+
}
60+
61+
public void setSshSessionFactorySupplier(
62+
BiFunction<GitScmProviderRepository, Logger, ScmProviderAwareSshdSessionFactory> sshSessionFactorySupplier )
63+
{
64+
this.sshSessionFactorySupplier = sshSessionFactorySupplier;
65+
}
66+
5167
@Override
5268
protected ListScmResult executeListCommand( ScmProviderRepository repo, ScmFileSet fileSet, boolean recursive,
5369
ScmVersion scmVersion )
@@ -64,7 +80,8 @@ protected ListScmResult executeListCommand( ScmProviderRepository repo, ScmFileS
6480
List<ScmFile> list = new ArrayList<>();
6581
Collection<Ref> lsResult = git.lsRemote().setCredentialsProvider( credentials )
6682
.setTransportConfigCallback(
67-
new JGitTransportConfigCallback( (GitScmProviderRepository) repo, logger ) )
83+
new JGitTransportConfigCallback(
84+
sshSessionFactorySupplier.apply( (GitScmProviderRepository) repo, logger ) ) )
6885
.call();
6986
for ( Ref ref : lsResult )
7087
{

0 commit comments

Comments
 (0)