You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by mi...@apache.org on 2022/07/21 21:37:24 UTC

[maven-scm] branch master updated: [SCM-993] Add tests for SSH private key-based authentication during checkout (clone)

This is an automated email from the ASF dual-hosted git repository.

michaelo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-scm.git


The following commit(s) were added to refs/heads/master by this push:
     new b7f2a58ce [SCM-993] Add tests for SSH private key-based authentication during checkout (clone)
b7f2a58ce is described below

commit b7f2a58ceb4acd486b126e1a7caed1f910cf7f12
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Fri Jul 8 08:44:28 2022 +0200

    [SCM-993] Add tests for SSH private key-based authentication during checkout (clone)
    
    This closes #155
---
 .../main/java/org/apache/maven/scm/ScmFileSet.java |   2 +-
 .../maven/scm/manager/AbstractScmManager.java      |   3 +-
 .../scm/provider/git/gitexe/GitExeScmProvider.java |  20 ++-
 .../git/gitexe/command/GitCommandLineUtils.java    |  21 ++-
 .../gitexe/command/checkin/GitCheckInCommand.java  |  28 ++-
 .../command/checkout/GitCheckOutCommand.java       |  16 +-
 .../command/remoteinfo/GitRemoteInfoCommand.java   |  13 +-
 .../checkout/GitExeSshCheckOutCommandTckTest.java  |  71 ++++++++
 .../maven-scm-provider-gittest/pom.xml             |  28 +++
 .../checkout/GitSshCheckOutCommandTckTest.java     | 187 +++++++++++++++++++++
 .../maven-scm-provider-jgit/pom.xml                |   5 +
 .../scm/provider/git/jgit/JGitTestScmProvider.java | 104 ++++++++++++
 .../checkout/JGitSshCheckOutCommandTckTest.java    | 148 ++++++++++++++++
 .../src/test/resources/ssh-keypairs/README         |   4 +
 .../src/test/resources/ssh-keypairs/sample_rsa     |  50 ++++++
 .../src/test/resources/ssh-keypairs/sample_rsa.pub |   1 +
 pom.xml                                            |   7 +
 17 files changed, 691 insertions(+), 17 deletions(-)

diff --git a/maven-scm-api/src/main/java/org/apache/maven/scm/ScmFileSet.java b/maven-scm-api/src/main/java/org/apache/maven/scm/ScmFileSet.java
index 28d0022b3..8401c844b 100644
--- a/maven-scm-api/src/main/java/org/apache/maven/scm/ScmFileSet.java
+++ b/maven-scm-api/src/main/java/org/apache/maven/scm/ScmFileSet.java
@@ -43,7 +43,7 @@ public class ScmFileSet
     private static final long serialVersionUID = -5978597349974797556L;
 
     private static final String DELIMITER = ",";
-    
+
     /** @see DirectoryScanner#DEFAULTEXCLUDES */
     private static final String DEFAULT_EXCLUDES = StringUtils.join( DirectoryScanner.DEFAULTEXCLUDES, DELIMITER );
 
diff --git a/maven-scm-api/src/main/java/org/apache/maven/scm/manager/AbstractScmManager.java b/maven-scm-api/src/main/java/org/apache/maven/scm/manager/AbstractScmManager.java
index 343dce5ee..8514a1bb9 100644
--- a/maven-scm-api/src/main/java/org/apache/maven/scm/manager/AbstractScmManager.java
+++ b/maven-scm-api/src/main/java/org/apache/maven/scm/manager/AbstractScmManager.java
@@ -79,7 +79,8 @@ public abstract class AbstractScmManager
     {
         requireNonNull( providers );
         this.scmProviders.clear();
-        providers.forEach( this::setScmProvider );
+        // first provider must not be overwritten by subsequent ones if they are registered for the same key
+        providers.forEach( this.scmProviders::putIfAbsent );
     }
 
     /**
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/GitExeScmProvider.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/GitExeScmProvider.java
index 50943c12f..1b3948441 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/GitExeScmProvider.java
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/GitExeScmProvider.java
@@ -23,6 +23,8 @@ import javax.inject.Named;
 import javax.inject.Singleton;
 
 import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.apache.maven.scm.ScmException;
 import org.apache.maven.scm.ScmFileSet;
@@ -54,6 +56,13 @@ import org.apache.maven.scm.repository.ScmRepositoryException;
 public class GitExeScmProvider
     extends AbstractGitScmProvider
 {
+    private final Map<String, String> environmentVariables;
+
+    public GitExeScmProvider()
+    {
+        environmentVariables = new HashMap<>();
+    }
+
     /** {@inheritDoc} */
     protected GitCommand getAddCommand()
     {
@@ -75,13 +84,13 @@ public class GitExeScmProvider
     /** {@inheritDoc} */
     protected GitCommand getCheckInCommand()
     {
-        return new GitCheckInCommand();
+        return new GitCheckInCommand( environmentVariables );
     }
 
     /** {@inheritDoc} */
     protected GitCommand getCheckOutCommand()
     {
-        return new GitCheckOutCommand();
+        return new GitCheckOutCommand( environmentVariables );
     }
 
     /** {@inheritDoc} */
@@ -141,7 +150,7 @@ public class GitExeScmProvider
     /** {@inheritDoc} */
     protected GitCommand getRemoteInfoCommand()
     {
-        return new GitRemoteInfoCommand();
+        return new GitRemoteInfoCommand( environmentVariables );
     }
 
     /** {@inheritDoc} */
@@ -162,4 +171,9 @@ public class GitExeScmProvider
 
         return result.getInfoItems().get( 0 ).getURL();
     }
+
+    public void setEnvironmentVariable( String key, String value )
+    {
+        environmentVariables.put( key, value );
+    }
 }
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/GitCommandLineUtils.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/GitCommandLineUtils.java
index 0d9a0e5b4..2dc908b9e 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/GitCommandLineUtils.java
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/GitCommandLineUtils.java
@@ -33,7 +33,9 @@ import org.slf4j.LoggerFactory;
 
 import java.io.File;
 import java.io.IOException;
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Command line construction utility.
@@ -87,15 +89,30 @@ public final class GitCommandLineUtils
         }
     }
 
+   /**
+    *
+    * @param workingDirectory
+    * @param command
+    * @return TODO
+    */
+   public static Commandline getBaseGitCommandLine( File workingDirectory, String command )
+   {
+       return getBaseGitCommandLine( workingDirectory, command, Collections.emptyMap() );
+   }
+
     /**
      *
      * @param workingDirectory
      * @param command
+     * @param environment
      * @return TODO
      */
-    public static Commandline getBaseGitCommandLine( File workingDirectory, String command )
+    public static Commandline getBaseGitCommandLine( File workingDirectory, String command,
+                                                     Map<String, String> environment )
     {
-        return getAnonymousBaseGitCommandLine( workingDirectory, command );
+        Commandline cl = getAnonymousBaseGitCommandLine( workingDirectory, command );
+        environment.forEach( cl::addEnvironment );
+        return cl;
     }
 
     /**
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/checkin/GitCheckInCommand.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/checkin/GitCheckInCommand.java
index 0e42d6ab9..09cbdb8a2 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/checkin/GitCheckInCommand.java
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/checkin/GitCheckInCommand.java
@@ -47,6 +47,7 @@ import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 
 /**
  * @author <a href="mailto:struberg@yahoo.de">Mark Struberg</a>
@@ -57,6 +58,14 @@ public class GitCheckInCommand
     extends AbstractCheckInCommand
     implements GitCommand
 {
+    private final Map<String, String> environmentVariables;
+
+    public GitCheckInCommand( Map<String, String> environmentVariables )
+    {
+        super();
+        this.environmentVariables = environmentVariables;
+    }
+
     /** {@inheritDoc} */
     protected CheckInScmResult executeCheckInCommand( ScmProviderRepository repo, ScmFileSet fileSet, String message,
                                                       ScmVersion version )
@@ -145,7 +154,7 @@ public class GitCheckInCommand
                 return new CheckInScmResult( null, statusConsumer.getChangedFiles() );
             }
 
-            Commandline clCommit = createCommitCommandLine( repository, fileSet, messageFile );
+            Commandline clCommit = createCommitCommandLine( repository, fileSet, messageFile, environmentVariables );
 
             exitCode = GitCommandLineUtils.execute( clCommit, stdout, stderr );
             if ( exitCode != 0 )
@@ -211,11 +220,12 @@ public class GitCheckInCommand
     //
     // ----------------------------------------------------------------------
 
-    public static Commandline createPushCommandLine( GitScmProviderRepository repository,
-                                                     ScmFileSet fileSet, ScmVersion version )
+    public Commandline createPushCommandLine( GitScmProviderRepository repository,
+                                              ScmFileSet fileSet, ScmVersion version )
         throws ScmException
     {
-        Commandline cl = GitCommandLineUtils.getBaseGitCommandLine( fileSet.getBasedir(), "push" );
+        Commandline cl = GitCommandLineUtils.getBaseGitCommandLine( fileSet.getBasedir(), "push",
+                environmentVariables );
 
         String branch = GitBranchCommand.getCurrentBranch( repository, fileSet );
 
@@ -235,7 +245,15 @@ public class GitCheckInCommand
                                                        File messageFile )
         throws ScmException
     {
-        Commandline cl = GitCommandLineUtils.getBaseGitCommandLine( fileSet.getBasedir(), "commit" );
+        return createCommitCommandLine( repository, fileSet, messageFile, Collections.emptyMap() );
+    }
+
+    public static Commandline createCommitCommandLine( GitScmProviderRepository repository, ScmFileSet fileSet,
+                                                       File messageFile, Map<String, String> environmentVariables )
+        throws ScmException
+    {
+        Commandline cl = GitCommandLineUtils.getBaseGitCommandLine( fileSet.getBasedir(), "commit",
+                environmentVariables );
 
         cl.createArg().setValue( "--verbose" );
 
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/checkout/GitCheckOutCommand.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/checkout/GitCheckOutCommand.java
index 2f9e7c0dc..915810651 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/checkout/GitCheckOutCommand.java
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/checkout/GitCheckOutCommand.java
@@ -20,6 +20,7 @@ package org.apache.maven.scm.provider.git.gitexe.command.checkout;
  */
 
 import java.io.File;
+import java.util.Map;
 
 import org.apache.maven.scm.CommandParameter;
 import org.apache.maven.scm.CommandParameters;
@@ -52,6 +53,14 @@ public class GitCheckOutCommand
     extends AbstractCheckOutCommand
     implements GitCommand
 {
+    private final Map<String, String> environmentVariables;
+
+    public GitCheckOutCommand( Map<String, String> environmentVariables )
+    {
+        super();
+        this.environmentVariables = environmentVariables;
+    }
+
     /**
      * 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,
@@ -104,7 +113,7 @@ public class GitCheckOutCommand
             lastCommandLine = clClone.toString();
         }
 
-        GitRemoteInfoCommand gitRemoteInfoCommand = new GitRemoteInfoCommand();
+        GitRemoteInfoCommand gitRemoteInfoCommand = new GitRemoteInfoCommand( environmentVariables );
 
         RemoteInfoScmResult result = gitRemoteInfoCommand.executeRemoteInfoCommand( repository, null, null );
 
@@ -173,7 +182,8 @@ public class GitCheckOutCommand
     private Commandline createCloneCommand( GitScmProviderRepository repository, File workingDirectory,
                                             ScmVersion version, boolean binary, boolean shallow )
     {
-        Commandline cl = GitCommandLineUtils.getBaseGitCommandLine( workingDirectory.getParentFile(), "clone" );
+        Commandline cl = GitCommandLineUtils.getBaseGitCommandLine( workingDirectory.getParentFile(), "clone",
+                environmentVariables );
 
         forceBinary( cl, binary );
 
@@ -240,7 +250,7 @@ public class GitCheckOutCommand
         }
         else
         {
-            cl = GitCommandLineUtils.getBaseGitCommandLine( workingDirectory, "pull" );
+            cl = GitCommandLineUtils.getBaseGitCommandLine( workingDirectory, "pull", environmentVariables );
 
             cl.createArg().setValue( repository.getFetchUrl() );
             cl.createArg().setValue( "master" );
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/remoteinfo/GitRemoteInfoCommand.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/remoteinfo/GitRemoteInfoCommand.java
index c97d5a3f3..87b207920 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/remoteinfo/GitRemoteInfoCommand.java
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/remoteinfo/GitRemoteInfoCommand.java
@@ -19,6 +19,8 @@ package org.apache.maven.scm.provider.git.gitexe.command.remoteinfo;
  * under the License.
  */
 
+import java.util.Map;
+
 import org.apache.maven.scm.CommandParameters;
 import org.apache.maven.scm.ScmException;
 import org.apache.maven.scm.ScmFileSet;
@@ -38,6 +40,13 @@ public class GitRemoteInfoCommand
     extends AbstractRemoteInfoCommand
     implements GitCommand
 {
+    private final Map<String, String> environmentVariables;
+
+    public GitRemoteInfoCommand( Map<String, String> environmentVariables )
+    {
+        super();
+        this.environmentVariables = environmentVariables;
+    }
 
     @Override
     public RemoteInfoScmResult executeRemoteInfoCommand( ScmProviderRepository repository, ScmFileSet fileSet,
@@ -65,9 +74,9 @@ public class GitRemoteInfoCommand
     //
     // ----------------------------------------------------------------------
 
-    public static Commandline createCommandLine( GitScmProviderRepository repository )
+    public Commandline createCommandLine( GitScmProviderRepository repository )
     {
-        Commandline cl = GitCommandLineUtils.getBaseGitCommandLine( null, "ls-remote" );
+        Commandline cl = GitCommandLineUtils.getBaseGitCommandLine( null, "ls-remote", environmentVariables );
 
         cl.setWorkingDirectory( System.getProperty( "java.io.tmpdir" ) );
 
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/test/java/org/apache/maven/scm/provider/git/gitexe/command/checkout/GitExeSshCheckOutCommandTckTest.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/test/java/org/apache/maven/scm/provider/git/gitexe/command/checkout/GitExeSshCheckOutCommandTckTest.java
new file mode 100644
index 000000000..f83d0488d
--- /dev/null
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/test/java/org/apache/maven/scm/provider/git/gitexe/command/checkout/GitExeSshCheckOutCommandTckTest.java
@@ -0,0 +1,71 @@
+package org.apache.maven.scm.provider.git.gitexe.command.checkout;
+
+/*
+ * 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.nio.file.Files;
+import java.nio.file.Path;
+import java.security.GeneralSecurityException;
+
+import org.apache.commons.io.FilenameUtils;
+import org.apache.maven.scm.provider.git.command.checkout.GitSshCheckOutCommandTckTest;
+import org.apache.maven.scm.provider.git.gitexe.GitExeScmProvider;
+import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
+import org.apache.maven.scm.repository.ScmRepository;
+
+/**
+ *
+ */
+public class GitExeSshCheckOutCommandTckTest
+    extends GitSshCheckOutCommandTckTest
+{
+    private Path knownHostsFile;
+
+    public static final String VARIABLE_GIT_SSH_COMMAND = "GIT_SSH_COMMAND"; // https://git-scm.com/docs/git#Documentation/git.txt-codeGITSSHCOMMANDcode, requires git 2.3.0 or newer
+
+    public GitExeSshCheckOutCommandTckTest() throws GeneralSecurityException
+    {
+        super();
+    }
+
+    @Override
+    protected String getScmProvider()
+    {
+        return "git";
+    }
+
+    @Override
+    public void configureCredentials( ScmRepository repository, String passphrase ) throws Exception
+    {
+        super.configureCredentials( repository, passphrase );
+        GitScmProviderRepository providerRepository = (GitScmProviderRepository) repository.getProviderRepository();
+        GitExeScmProvider provider = (GitExeScmProvider) getScmManager().getProviderByRepository( getScmRepository() );
+        knownHostsFile = Files.createTempFile( "known-hosts", null );
+        provider.setEnvironmentVariable( VARIABLE_GIT_SSH_COMMAND, "ssh -o UserKnownHostsFile=" + knownHostsFile +
+                " -o StrictHostKeyChecking=no -o IdentitiesOnly=yes -i " + FilenameUtils.separatorsToUnix( providerRepository.getPrivateKey() ) );
+    }
+
+    @Override
+    public void removeRepo() throws Exception
+    {
+        super.removeRepo();
+        Files.deleteIfExists( knownHostsFile );
+    }
+
+}
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gittest/pom.xml b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gittest/pom.xml
index 728c1582f..2d5257682 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gittest/pom.xml
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gittest/pom.xml
@@ -33,6 +33,10 @@
   <name>Maven SCM Git Provider TCK Tests</name>
   <description>Tests library for SCM Git Provider.</description>
 
+  <properties>
+    <minaSshdVersion>2.8.0</minaSshdVersion>
+  </properties>
+
   <dependencies>
     <dependency>
       <groupId>org.apache.maven.scm</groupId>
@@ -46,6 +50,30 @@
       <groupId>org.codehaus.plexus</groupId>
       <artifactId>plexus-utils</artifactId>
     </dependency>
+    <!-- for testing SSH authentication -->
+    <dependency>
+      <groupId>org.apache.sshd</groupId>
+      <artifactId>sshd-git</artifactId>
+      <version>${minaSshdVersion}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.sshd</groupId>
+      <artifactId>sshd-common</artifactId>
+      <version>${minaSshdVersion}</version>
+      <type>test-jar</type>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.sshd</groupId>
+      <artifactId>sshd-core</artifactId>
+      <version>${minaSshdVersion}</version>
+      <type>test-jar</type>
+    </dependency>
+    <!-- for creating SSH keypairs dynamically -->
+    <dependency>
+      <groupId>org.bouncycastle</groupId>
+      <artifactId>bcpkix-jdk15on</artifactId>
+      <version>1.70</version>
+    </dependency>
     <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gittest/src/main/java/org/apache/maven/scm/provider/git/command/checkout/GitSshCheckOutCommandTckTest.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gittest/src/main/java/org/apache/maven/scm/provider/git/command/checkout/GitSshCheckOutCommandTckTest.java
new file mode 100644
index 000000000..376d8acf2
--- /dev/null
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gittest/src/main/java/org/apache/maven/scm/provider/git/command/checkout/GitSshCheckOutCommandTckTest.java
@@ -0,0 +1,187 @@
+package org.apache.maven.scm.provider.git.command.checkout;
+
+/*
+ * 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.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.nio.file.FileSystem;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.PosixFilePermissions;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.maven.scm.provider.ScmProviderRepositoryWithHost;
+import org.apache.maven.scm.provider.git.GitScmTestUtils;
+import org.apache.maven.scm.repository.ScmRepository;
+import org.apache.maven.scm.tck.command.checkout.CheckOutCommandTckTest;
+import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.config.keys.writer.openssh.OpenSSHKeyEncryptionContext;
+import org.apache.sshd.common.config.keys.writer.openssh.OpenSSHKeyPairResourceWriter;
+import org.apache.sshd.git.GitLocationResolver;
+import org.apache.sshd.git.pack.GitPackCommandFactory;
+import org.apache.sshd.server.SshServer;
+import org.apache.sshd.server.auth.pubkey.KeySetPublickeyAuthenticator;
+import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator;
+import org.apache.sshd.server.session.ServerSession;
+import org.apache.sshd.util.test.CommonTestSupportUtils;
+import org.apache.sshd.util.test.CoreTestSupportUtils;
+import org.bouncycastle.openssl.PKCS8Generator;
+import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
+import org.bouncycastle.openssl.jcajce.JcaPKCS8Generator;
+import org.bouncycastle.util.io.pem.PemObject;
+import org.junit.Assume;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+/**
+ *
+ */
+public abstract class GitSshCheckOutCommandTckTest
+    extends CheckOutCommandTckTest
+{
+    protected final SshServer sshServer;
+    protected final KeyPair keyPair;
+    protected final List<PublicKey> acceptedPublicKeys;
+
+    @Rule
+    public TemporaryFolder tmpDirectory = new TemporaryFolder();
+
+    protected GitSshCheckOutCommandTckTest() throws GeneralSecurityException
+    {
+         sshServer = CoreTestSupportUtils.setupTestServer( getClass() );
+         keyPair = CommonTestSupportUtils.generateKeyPair( KeyUtils.RSA_ALGORITHM, 2048 );
+         acceptedPublicKeys = new ArrayList<>();
+         acceptedPublicKeys.add( keyPair.getPublic() );
+         PublickeyAuthenticator authenticator = new KeySetPublickeyAuthenticator( "onlykey",
+                  acceptedPublicKeys );
+         sshServer.setPublickeyAuthenticator( authenticator );
+    }
+
+    void writePrivateKeyAsPkcs8( Path file, String passphrase )
+            throws IOException, GeneralSecurityException
+    {
+        // encryption only optional
+        if ( passphrase != null )
+        {
+            // encryption with format outlined in https://dnaeon.github.io/openssh-private-key-binary-format/
+            OpenSSHKeyPairResourceWriter writer = new OpenSSHKeyPairResourceWriter();
+            OpenSSHKeyEncryptionContext context = new OpenSSHKeyEncryptionContext();
+            context.setCipherType( "192" );
+            context.setPassword( passphrase );
+            try ( OutputStream output = Files.newOutputStream( file ) )
+            {
+                writer.writePrivateKey( keyPair, "comment", context, output );
+            }
+        }
+        else
+        {
+            // wrap unencrypted private key as regular PKCS8 private key
+            PKCS8Generator pkcs8Generator = new JcaPKCS8Generator( keyPair.getPrivate(), null );
+            PemObject pemObject = pkcs8Generator.generate();
+
+            try ( Writer writer = Files.newBufferedWriter( file );
+                            JcaPEMWriter pw = new JcaPEMWriter( writer ) )
+            {
+                pw.writeObject( pemObject );
+            }
+        }
+
+        if ( file.getFileSystem().supportedFileAttributeViews().contains( "posix" ) )
+        {
+            // must only be readable/writeable by me
+            Files.setPosixFilePermissions( file, PosixFilePermissions.fromString( "rwx------" ) );
+        }
+    }
+
+    protected abstract String getScmProvider();
+
+    /** {@inheritDoc} */
+    public String getScmUrl()
+        throws Exception
+    {
+        return "scm:" + getScmProvider() + ":ssh://localhost:" + sshServer.getPort() + "/repository";
+    }
+
+    public void configureCredentials( ScmRepository repository, String passphrase )
+        throws Exception
+    {
+        ScmProviderRepositoryWithHost providerRepository =
+             ScmProviderRepositoryWithHost.class.cast( repository.getProviderRepository() );
+        // store as file
+        Path privateKeyFile = tmpDirectory.newFile().toPath();
+        writePrivateKeyAsPkcs8( privateKeyFile, passphrase );
+        providerRepository.setPrivateKey( privateKeyFile.toString() );
+        providerRepository.setPassphrase( passphrase ); // may be null
+    }
+
+    /** {@inheritDoc} */
+    public void initRepo()
+        throws Exception
+    {
+        GitScmTestUtils.initRepo( "src/test/resources/repository/", getRepositoryRoot(), getWorkingDirectory() );
+
+        GitLocationResolver gitLocationResolver = new GitLocationResolver()
+        {
+            @Override
+            public Path resolveRootDirectory( String command, String[] args, ServerSession session, FileSystem fs )
+                throws IOException
+            {
+                return getRepositoryRoot().getParentFile().toPath();
+            }
+        };
+        sshServer.setCommandFactory( new GitPackCommandFactory( gitLocationResolver ) );
+        sshServer.start();
+
+        // as checkout also already happens in setup() make sure to configure credentials here as well
+        configureCredentials( getScmRepository(), null );
+    }
+
+    @Override
+    public void removeRepo() throws Exception
+    {
+        sshServer.stop();
+        super.removeRepo();
+    }
+
+    @Override
+    @Test
+    public void testCheckOutCommandTest()
+        throws Exception
+    {
+        configureCredentials( getScmRepository(), null );
+        super.testCheckOutCommandTest();
+    }
+
+    @Test
+    public void testCheckOutCommandWithPassphraseTest() throws Exception
+    {
+        // TODO: currently no easy way to pass passphrase in gitexe
+        Assume.assumeTrue( "Ignore test with passphrase for provider " + getScmProvider(),
+                           "jgit".equals( getScmProvider() ) );
+        configureCredentials( getScmRepository(), "mySecret" );
+        super.testCheckOutCommandTest();
+    }
+}
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 d343e513a..9f15c4c56 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
@@ -98,6 +98,11 @@
       <artifactId>slf4j-simple</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <build>
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/test/java/org/apache/maven/scm/provider/git/jgit/JGitTestScmProvider.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/test/java/org/apache/maven/scm/provider/git/jgit/JGitTestScmProvider.java
new file mode 100644
index 000000000..befeffb1c
--- /dev/null
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/test/java/org/apache/maven/scm/provider/git/jgit/JGitTestScmProvider.java
@@ -0,0 +1,104 @@
+package org.apache.maven.scm.provider.git.jgit;
+
+/*
+ * 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 javax.annotation.Priority;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.function.Consumer;
+
+import org.apache.maven.scm.provider.ScmProvider;
+import org.apache.maven.scm.provider.git.command.GitCommand;
+import org.apache.maven.scm.provider.git.jgit.command.checkin.JGitCheckInCommand;
+import org.apache.maven.scm.provider.git.jgit.command.checkout.JGitCheckOutCommand;
+import org.apache.maven.scm.provider.git.jgit.command.remoteinfo.JGitRemoteInfoCommand;
+import org.codehaus.plexus.components.interactivity.Prompter;
+import org.eclipse.jgit.api.TransportCommand;
+
+/**
+ * Allows to register callbacks for all commands leveraging {@link TransportCommand}.
+ */
+@Singleton
+@Named( "jgit" )
+@Priority( 1 ) // must have higher priority than default JGitScmProvider
+public class JGitTestScmProvider
+    extends JGitScmProvider implements ScmProvider
+{
+    private Consumer<JGitCheckInCommand> checkInCommandCallback;
+    private Consumer<JGitCheckOutCommand> checkOutCommandCallback;
+    private Consumer<JGitRemoteInfoCommand> remoteInfoCommandCallback;
+
+    @Inject
+    public JGitTestScmProvider( Prompter prompter )
+    {
+        super( prompter );
+    }
+
+    public void registerCheckInCommandCallback( Consumer<JGitCheckInCommand> gitCommandConsumer )
+    {
+        checkInCommandCallback = gitCommandConsumer;
+    }
+
+    public void registerCheckOutCommandCallback( Consumer<JGitCheckOutCommand> gitCommandConsumer )
+    {
+        checkOutCommandCallback = gitCommandConsumer;
+    }
+
+    public void registerRemoteInfoCommandCallback( Consumer<JGitRemoteInfoCommand> gitCommandConsumer )
+    {
+        remoteInfoCommandCallback = gitCommandConsumer;
+    }
+
+    @Override
+    protected GitCommand getCheckInCommand()
+    {
+        JGitCheckInCommand command = (JGitCheckInCommand) super.getCheckInCommand();
+        if ( checkInCommandCallback != null )
+        {
+            checkInCommandCallback.accept( command );
+        }
+        return command;
+    }
+
+    @Override
+    protected GitCommand getCheckOutCommand()
+    {
+        JGitCheckOutCommand command = (JGitCheckOutCommand) super.getCheckOutCommand();
+        if ( checkOutCommandCallback != null )
+        {
+            checkOutCommandCallback.accept( command );
+        }
+        return command;
+    }
+
+    @Override
+    protected GitCommand getRemoteInfoCommand()
+    {
+        JGitRemoteInfoCommand command = (JGitRemoteInfoCommand) super.getRemoteInfoCommand();
+        if ( remoteInfoCommandCallback != null )
+        {
+            remoteInfoCommandCallback.accept( command );
+        }
+        return command;
+    }
+
+}
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/checkout/JGitSshCheckOutCommandTckTest.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/test/java/org/apache/maven/scm/provider/git/jgit/command/checkout/JGitSshCheckOutCommandTckTest.java
new file mode 100644
index 000000000..faaea591f
--- /dev/null
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/test/java/org/apache/maven/scm/provider/git/jgit/command/checkout/JGitSshCheckOutCommandTckTest.java
@@ -0,0 +1,148 @@
+package org.apache.maven.scm.provider.git.jgit.command.checkout;
+
+/*
+ * 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.io.InputStream;
+import java.net.InetSocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.security.GeneralSecurityException;
+import java.security.PublicKey;
+import java.util.function.Consumer;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.maven.scm.provider.ScmProviderRepositoryWithHost;
+import org.apache.maven.scm.provider.git.command.checkout.GitSshCheckOutCommandTckTest;
+import org.apache.maven.scm.provider.git.jgit.JGitTestScmProvider;
+import org.apache.maven.scm.provider.git.jgit.command.ScmProviderAwareSshdSessionFactory;
+import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
+import org.apache.maven.scm.repository.ScmRepository;
+import org.apache.sshd.common.config.keys.PublicKeyEntry;
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.internal.transport.sshd.OpenSshServerKeyDatabase;
+import org.eclipse.jgit.transport.CredentialsProvider;
+import org.eclipse.jgit.transport.sshd.ServerKeyDatabase;
+import org.eclipse.jgit.util.FileUtils;
+import org.junit.Test;
+import org.slf4j.Logger;
+
+/** @author <a href="mailto:struberg@yahoo.de">Mark Struberg</a> */
+public class JGitSshCheckOutCommandTckTest
+    extends GitSshCheckOutCommandTckTest
+{
+
+    public JGitSshCheckOutCommandTckTest() throws GeneralSecurityException, IOException
+    {
+        super();
+    }
+
+    @Override
+    protected String getScmProvider()
+    {
+        return "jgit";
+    }
+
+    @Override
+    public void initRepo() throws Exception
+    {
+        super.initRepo();
+        JGitTestScmProvider provider = (JGitTestScmProvider) getScmManager().getProviderByRepository( getScmRepository() );
+        // accept all hosts
+        provider.registerCheckOutCommandCallback( new Consumer<JGitCheckOutCommand>()
+        {
+            @Override
+            public void accept( JGitCheckOutCommand command )
+            {
+                command.setSshSessionFactorySupplier( AcceptAllHostsSshdSessionFactory::new );
+            }
+
+        } );
+    }
+
+    private static final class AcceptAllHostsSshdSessionFactory extends ScmProviderAwareSshdSessionFactory
+    {
+        public AcceptAllHostsSshdSessionFactory( GitScmProviderRepository repo, Logger logger )
+        {
+            super( repo, logger );
+        }
+
+        @Override
+        protected ServerKeyDatabase createServerKeyDatabase( File homeDir, File sshDir )
+        {
+            return new OpenSshServerKeyDatabase( false, null )
+            {
+                @Override
+                public boolean accept( @NonNull String connectAddress,
+                        @NonNull InetSocketAddress remoteAddress,
+                        @NonNull PublicKey serverKey,
+                        @NonNull Configuration config, CredentialsProvider provider )
+                {
+                    return true;
+                }
+            };
+        }
+    }
+
+    @Override
+    protected void deleteDirectory( File directory )
+        throws IOException
+    {
+        if ( directory.exists() )
+        {
+            FileUtils.delete( directory, FileUtils.RECURSIVE | FileUtils.RETRY );
+        }
+    }
+
+    @Test
+    public void testCheckOutCommandWithPregeneratedKeysTest()
+        throws Exception
+    {
+        // test key pairs being generated with ssh-keygen (they have a slighly different format than the ones tested
+        // in testCheckOutCommandWithPassphraseTest and testCheckOutCommandTest)
+        configureKeypairFromClasspathResource( getScmRepository(), "sample_rsa", "mySecret");
+        super.testCheckOutCommandTest();
+    }
+
+    private void configureKeypairFromClasspathResource( ScmRepository repository, String resourceName, String passphrase )
+        throws IOException, GeneralSecurityException
+    {
+        // accept public key
+        try ( InputStream publicKeyInputStream = this.getClass().getResourceAsStream( "/ssh-keypairs/" + resourceName + ".pub" ) )
+        {
+            PublicKey publicKey = PublicKeyEntry.parsePublicKeyEntry( IOUtils.toString( publicKeyInputStream, StandardCharsets.US_ASCII ) ).resolvePublicKey( null, null, null );
+            acceptedPublicKeys.add( publicKey );
+        }
+        Path privateKeyFile = Files.createTempFile( "privateKey", null );
+        // private key into tmp file
+        try ( InputStream privateKeyInputStream = this.getClass().getResourceAsStream( "/ssh-keypairs/" + resourceName ) )
+        {
+            Files.copy( privateKeyInputStream, privateKeyFile, StandardCopyOption.REPLACE_EXISTING );
+        }
+        // configure provider repository with private key details
+        ScmProviderRepositoryWithHost providerRepository =
+                        ScmProviderRepositoryWithHost.class.cast( repository.getProviderRepository() );
+        providerRepository.setPassphrase( passphrase ); // may be null
+        providerRepository.setPrivateKey( privateKeyFile.toString() );
+    }
+}
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/test/resources/ssh-keypairs/README b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/test/resources/ssh-keypairs/README
new file mode 100644
index 000000000..ea832c158
--- /dev/null
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/test/resources/ssh-keypairs/README
@@ -0,0 +1,4 @@
+The keys in here have only been created via "ssh-keygen" for testing purposes,
+they are not usable in other context, especially they don't grant access to any server.
+
+For all private keys which are encrypted, they have the passphrase "mySecret".
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/test/resources/ssh-keypairs/sample_rsa b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/test/resources/ssh-keypairs/sample_rsa
new file mode 100644
index 000000000..5307fdbd5
--- /dev/null
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/test/resources/ssh-keypairs/sample_rsa
@@ -0,0 +1,50 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+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
+CFHN0oAR6VHE53faIMez2A0XY=
+-----END OPENSSH PRIVATE KEY-----
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/test/resources/ssh-keypairs/sample_rsa.pub b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/test/resources/ssh-keypairs/sample_rsa.pub
new file mode 100644
index 000000000..e2cf1d628
--- /dev/null
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/test/resources/ssh-keypairs/sample_rsa.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC8e3gqfjzieCzdozP2XLd5H0TyGmT7lRckFcwbOuudArJ/cQrN2JpK0Kze+Y+1uT7eB2bITmA+yntnPcqjSD7OyS+xGhw4XevvHZiKSsNqbS98Woxlop6z6HyuXeIeKCMsx1YXrGrej12uMEHHx1Qyq5kN2nECip+LlXIY25PCPQcj1F0x25Rl3x819QpRi9eIwnyclyeq381eefn7sJS0rpHC2uN6PtmuDP4oDJ59HYuQfRQNkjubGTKCd0Zi+aJy5tRYBUnLEQ3ZIbmoXnA8uiIkSZoX5q5w9lxarMp4jkiaLdKzNLZInSQpn1Pw9NiZqgrH83xyVgusr9id22lNf2PqFQbEi2tcYHbH2DBaysh0azNkWdBlTmjY1KuqzL8a3Cw8vCxccBvYKMRQNrzAmPO7Tg7fq4qAlhF64nk4PEFbsD+gLTDmbsn4dE9cXLIrxF9G [...]
diff --git a/pom.xml b/pom.xml
index 122a94d8f..3ffa4873c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -300,6 +300,13 @@
             </excludes>
           </configuration>
         </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-surefire-plugin</artifactId>
+          <configuration>
+            <trimStackTrace>false</trimStackTrace>
+          </configuration>
+        </plugin>
       </plugins>
     </pluginManagement>
     <plugins>