You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ol...@apache.org on 2018/12/14 04:12:37 UTC

[maven-scm] branch master updated: [SCM-832] maven-scm-provider-jgit should support SSH public key auth (#50)

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

olamy 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 9a3daee  [SCM-832]  maven-scm-provider-jgit should support SSH public key auth (#50)
9a3daee is described below

commit 9a3daeeac48a4bf24df73627bc56c45071629834
Author: Martin Kutter <ma...@fen-net.de>
AuthorDate: Fri Dec 14 05:12:32 2018 +0100

    [SCM-832]  maven-scm-provider-jgit should support SSH public key auth (#50)
    
    * Support public key auth for SSH #SCM-832
    
    Adds a TransportConfigCallback to all remote commands, which adds a public/private key based identity for repositories with ssh URLs if configured.
    
    * Updated documentation for #SCM-832
    
    * [SCM-832] Updated documentation
    
    * [SCM-832] Added debug logging
    
    maven-scm-provider-jgit now outputs the private key used when run as mvn -X
---
 .../jgit/command/JGitTransportConfigCallback.java  | 106 +++++++++++++++++++++
 .../scm/provider/git/jgit/command/JGitUtils.java   |  11 ++-
 .../jgit/command/checkout/JGitCheckOutCommand.java |  21 +++-
 .../git/jgit/command/list/JGitListCommand.java     |   6 +-
 .../command/remoteinfo/JGitRemoteInfoCommand.java  |   4 +-
 .../src/site/markdown/index.md.vm                  |  17 +++-
 6 files changed, 153 insertions(+), 12 deletions(-)

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
new file mode 100644
index 0000000..7b13af5
--- /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/JGitTransportConfigCallback.java
@@ -0,0 +1,106 @@
+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 com.jcraft.jsch.JSch;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+import org.apache.maven.scm.log.ScmLogger;
+import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
+import org.eclipse.jgit.api.TransportConfigCallback;
+import org.eclipse.jgit.transport.*;
+import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.StringUtils;
+
+/**
+ * Implementation of {@link TransportConfigCallback} which adds
+ * a public/private key identity to ssh URLs if configured.
+ */
+public class JGitTransportConfigCallback implements TransportConfigCallback {
+    private SshSessionFactory sshSessionFactory = null;
+
+    public JGitTransportConfigCallback(GitScmProviderRepository repo, ScmLogger logger) {
+        if (repo.getFetchInfo().getProtocol().equals("ssh")) {
+            if (!StringUtils.isEmptyOrNull(repo.getPrivateKey()) && repo.getPassphrase() == null) {
+                logger.debug("using private key with passphrase: " + repo.getPrivateKey());
+                sshSessionFactory = new UnprotectedPrivateKeySessionFactory(repo);
+            } else if (!StringUtils.isEmptyOrNull(repo.getPrivateKey()) && repo.getPassphrase() != null) {
+                logger.debug("using private key: " + repo.getPrivateKey());
+                sshSessionFactory = new ProtectedPrivateKeyFileSessionFactory(repo);
+            } else {
+                sshSessionFactory = new SimpleSessionFactory();
+            }
+        }
+    }
+
+    @Override
+    public void configure(Transport transport) {
+        if (transport instanceof SshTransport) {
+            SshTransport sshTransport = (SshTransport) transport;
+            sshTransport.setSshSessionFactory(sshSessionFactory);
+        }
+    }
+
+    static private class SimpleSessionFactory extends JschConfigSessionFactory {
+        @Override
+        protected void configure(OpenSshConfig.Host host, Session session) {
+        }
+    }
+
+    static private abstract class PrivateKeySessionFactory extends SimpleSessionFactory {
+        private final GitScmProviderRepository repo;
+
+        public GitScmProviderRepository getRepo() {
+            return repo;
+        }
+
+        public PrivateKeySessionFactory(GitScmProviderRepository repo) {
+            this.repo = repo;
+        }
+    }
+
+    static private class UnprotectedPrivateKeySessionFactory extends PrivateKeySessionFactory {
+
+        public UnprotectedPrivateKeySessionFactory(GitScmProviderRepository repo) {
+            super(repo);
+        }
+
+        @Override
+        protected JSch createDefaultJSch(FS fs) throws JSchException {
+            JSch defaultJSch = super.createDefaultJSch(fs);
+            defaultJSch.addIdentity(getRepo().getPrivateKey());
+            return defaultJSch;
+        }
+    }
+
+    static private class ProtectedPrivateKeyFileSessionFactory extends PrivateKeySessionFactory {
+
+        public 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 b6900b4..3e3a4f4 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
@@ -28,6 +28,7 @@ import org.apache.maven.scm.util.FilenameUtils;
 import org.codehaus.plexus.util.StringUtils;
 import org.eclipse.jgit.api.AddCommand;
 import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.PushCommand;
 import org.eclipse.jgit.api.Status;
 import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.api.errors.InvalidRemoteException;
@@ -83,7 +84,7 @@ import java.util.Set;
  */
 public class JGitUtils
 {
-    
+
     private JGitUtils()
     {
         // no op
@@ -178,6 +179,8 @@ public class JGitUtils
             return new UsernamePasswordCredentialsProvider( repository.getUser().trim(),
                                                             repository.getPassword().trim() );
         }
+
+
         return null;
     }
 
@@ -185,8 +188,10 @@ public class JGitUtils
         throws GitAPIException, InvalidRemoteException, TransportException
     {
         CredentialsProvider credentials = JGitUtils.prepareSession( logger, git, repo );
-        Iterable<PushResult> pushResultList =
-            git.push().setCredentialsProvider( credentials ).setRefSpecs( refSpec ).call();
+        PushCommand command = git.push().setRefSpecs(refSpec).setCredentialsProvider(credentials)
+                .setTransportConfigCallback(new JGitTransportConfigCallback(repo, logger));
+
+        Iterable<PushResult> pushResultList = command.call();
         for ( PushResult pushResult : pushResultList )
         {
             Collection<RemoteRefUpdate> ru = pushResult.getRemoteUpdates();
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 b89299a..ea1f1dd 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
@@ -30,13 +30,13 @@ import org.apache.maven.scm.command.checkout.CheckOutScmResult;
 import org.apache.maven.scm.command.remoteinfo.RemoteInfoScmResult;
 import org.apache.maven.scm.provider.ScmProviderRepository;
 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.branch.JGitBranchCommand;
 import org.apache.maven.scm.provider.git.jgit.command.remoteinfo.JGitRemoteInfoCommand;
 import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
 import org.codehaus.plexus.util.StringUtils;
-import org.eclipse.jgit.api.CloneCommand;
-import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.*;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.revwalk.RevCommit;
@@ -109,7 +109,13 @@ public class JGitCheckOutCommand
                 CredentialsProvider credentials = JGitUtils.getCredentials( (GitScmProviderRepository) repo );
                 getLogger().info( "cloning [" + branch + "] to " + fileSet.getBasedir() );
                 CloneCommand command = Git.cloneRepository().setURI( repository.getFetchUrl() );
+
                 command.setCredentialsProvider( credentials ).setBranch( branch ).setDirectory( fileSet.getBasedir() );
+
+                TransportConfigCallback transportConfigCallback = new JGitTransportConfigCallback(
+                        (GitScmProviderRepository) repo, getLogger());
+                command.setTransportConfigCallback(transportConfigCallback);
+
                 command.setProgressMonitor( monitor );
                 git = command.call();
             }
@@ -129,6 +135,8 @@ public class JGitCheckOutCommand
             {
                 // git repo exists, so we must git-pull the changes
                 CredentialsProvider credentials = JGitUtils.prepareSession( getLogger(), git, repository );
+                TransportConfigCallback transportConfigCallback = new JGitTransportConfigCallback(
+                        (GitScmProviderRepository) repo, getLogger());
 
                 if ( version != null && StringUtils.isNotEmpty( version.getName() ) && ( version instanceof ScmTag ) )
                 {
@@ -138,12 +146,17 @@ public class JGitCheckOutCommand
                     // In fact, a tag in git may be in multiple branches. This occurs if
                     // you create a branch after the tag has been created
                     getLogger().debug( "fetch..." );
-                    git.fetch().setCredentialsProvider( credentials ).setProgressMonitor( monitor ).call();
+                    FetchCommand command = git.fetch().setCredentialsProvider(credentials).setProgressMonitor(monitor);
+                    command.setTransportConfigCallback(transportConfigCallback);
+                    command.call();
+
                 }
                 else
                 {
                     getLogger().debug( "pull..." );
-                    git.pull().setCredentialsProvider( credentials ).setProgressMonitor( monitor ).call();
+                    PullCommand command = git.pull().setCredentialsProvider(credentials).setProgressMonitor(monitor);
+                    command.setTransportConfigCallback(transportConfigCallback);
+                    command.call();
                 }
             }
 
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 ef86c09..937fa1d 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
@@ -28,6 +28,7 @@ import org.apache.maven.scm.command.list.AbstractListCommand;
 import org.apache.maven.scm.command.list.ListScmResult;
 import org.apache.maven.scm.provider.ScmProviderRepository;
 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.repository.GitScmProviderRepository;
 import org.eclipse.jgit.api.Git;
@@ -61,7 +62,10 @@ public class JGitListCommand
                 JGitUtils.prepareSession( getLogger(), git, (GitScmProviderRepository) repo );
 
             List<ScmFile> list = new ArrayList<ScmFile>();
-            Collection<Ref> lsResult = git.lsRemote().setCredentialsProvider( credentials ).call();
+            Collection<Ref> lsResult = git.lsRemote().setCredentialsProvider( credentials )
+                    .setTransportConfigCallback(
+                            new JGitTransportConfigCallback((GitScmProviderRepository) repo, getLogger()))
+                    .call();
             for ( Ref ref : lsResult )
             {
                 getLogger().debug( ref.getObjectId().getName() + "  " + ref.getTarget().getName() );
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 b521b0b..451be02 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
@@ -26,6 +26,7 @@ import org.apache.maven.scm.command.remoteinfo.AbstractRemoteInfoCommand;
 import org.apache.maven.scm.command.remoteinfo.RemoteInfoScmResult;
 import org.apache.maven.scm.provider.ScmProviderRepository;
 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.repository.GitScmProviderRepository;
 import org.eclipse.jgit.api.Git;
@@ -61,7 +62,8 @@ public class JGitRemoteInfoCommand
             CredentialsProvider credentials = JGitUtils.getCredentials( repo );
 
             LsRemoteCommand lsCommand =
-                git.lsRemote().setRemote( repo.getPushUrl() ).setCredentialsProvider( credentials );
+                git.lsRemote().setRemote( repo.getPushUrl() ).setCredentialsProvider( credentials )
+                        .setTransportConfigCallback(new JGitTransportConfigCallback(repo, getLogger()));
 
             Map<String, String> tag = new HashMap<String, String>();
             Collection<Ref> allTags = lsCommand.setHeads( false ).setTags( true ).call();
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/site/markdown/index.md.vm b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/site/markdown/index.md.vm
index d95a1a6..b64b7af 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/site/markdown/index.md.vm
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/site/markdown/index.md.vm
@@ -20,8 +20,9 @@ under the License.
 maven-scm-provider-jgit
 ===
 
-This scm provider implementation allows the usage of git with the release and scm plugin without having to install a nativ git client. 
-This implementation uses username and password instead of a public/private keys to authenticate the requests to a remote repository like GitHub.
+This scm provider implementation allows the usage of git with the release and scm plugin without having to install a native git client.
+This implementation can use both username and password, or public/private keys to authenticate the requests to a remote
+repository like GitHub. At the moment, public/private keys are only supported for SSH access.
 
 Configuration
 ---
@@ -65,7 +66,17 @@ Usage with the `maven-scm-plugin`
 					</dependency>
 				</dependencies>
 			</plugin>
-			
+
+Public/private key configuration in settings.xml - for use with ssh URLs like ssh://git@github.com/apache/maven-scm
+
+			<servers>
+				<server>
+				    <id>git@github.com</id>
+				    <privateKey>path/to/private/key</privateKey>
+				    <passphrase>private key passphrase</passphrase>
+				</server>
+			<server>
+
 Examples
 ____