You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@ant.apache.org by ja...@apache.org on 2019/10/25 08:17:58 UTC

[ant] branch master updated: Support the SSH configuration file (~/.ssh/config) in the sshexec, sshsession and scp tasks

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

jaikiran pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ant.git


The following commit(s) were added to refs/heads/master by this push:
     new b6143ef  Support the SSH configuration file (~/.ssh/config) in the sshexec, sshsession and scp tasks
b6143ef is described below

commit b6143efab2f45ff11c980438c60d79f6db0da868
Author: Emmanuel Bourg <eb...@apache.org>
AuthorDate: Thu Oct 24 17:00:21 2019 +0200

    Support the SSH configuration file (~/.ssh/config) in the sshexec, sshsession and scp tasks
    
    This closes #106 pull request at github/apache/ant repo
---
 WHATSNEW                                           |  4 ++
 manual/Tasks/scp.html                              |  8 ++++
 manual/Tasks/sshexec.html                          |  8 ++++
 manual/Tasks/sshsession.html                       |  8 ++++
 .../tools/ant/taskdefs/optional/ssh/SSHBase.java   | 55 ++++++++++++++++++++++
 .../tools/ant/taskdefs/optional/ssh/SSHExec.java   |  3 ++
 .../ant/taskdefs/optional/ssh/SSHSession.java      |  3 ++
 .../tools/ant/taskdefs/optional/ssh/Scp.java       | 17 ++++---
 8 files changed, 99 insertions(+), 7 deletions(-)

diff --git a/WHATSNEW b/WHATSNEW
index ad4ac9e..29dedcf 100644
--- a/WHATSNEW
+++ b/WHATSNEW
@@ -14,6 +14,10 @@ Fixed bugs:
    files.
    Bugzilla Report 63874
 
+ * sshexec, sshsession and scp now support a new sshConfig parameter.
+   It specified the SSH configuration file (typically ${user.home}/.ssh/config)
+   defining the username and keyfile to be used per host.
+
 Other changes:
 --------------
 
diff --git a/manual/Tasks/scp.html b/manual/Tasks/scp.html
index c353879..a9a95a1 100644
--- a/manual/Tasks/scp.html
+++ b/manual/Tasks/scp.html
@@ -143,6 +143,14 @@ information.  This task has been tested with <code>jsch-0.1.2</code> and later.<
     <td>No; defaults to an empty string</td>
   </tr>
   <tr>
+    <td>sshConfig</td>
+    <td>Location of the file holding the OpenSSH style configuration (e.g. <code>${user.home}/.ssh/config</code>).
+        The username and the key file are read from the configuration file,
+        unless they are already specified in the task parameters.
+        <em>since Ant 1.10.8</em></td>
+    <td>No</td>
+  </tr>
+  <tr>
     <td>verbose</td>
     <td>Determines whether SCP outputs verbosely to the user. Currently this means outputting
       dots/stars showing the progress of a file transfer.  <em>since Ant 1.6.2</em></td>
diff --git a/manual/Tasks/sshexec.html b/manual/Tasks/sshexec.html
index c30b4a5..6437b46 100644
--- a/manual/Tasks/sshexec.html
+++ b/manual/Tasks/sshexec.html
@@ -105,6 +105,14 @@ JSCh earlier than 0.1.28.</p>
     <td>No; defaults to an empty string</td>
   </tr>
   <tr>
+    <td>sshConfig</td>
+    <td>Location of the file holding the OpenSSH style configuration (e.g. <code>${user.home}/.ssh/config</code>).
+        The username and the key file are read from the configuration file,
+        unless they are already specified in the task parameters.
+        <em>since Ant 1.10.8</em></td>
+    <td>No</td>
+  </tr>
+  <tr>
     <td>suppresssystemout</td>
     <td>Whether to suppress system out. <em>since Ant 1.9.0</em></td>
     <td>No; defaults to <q>false</q></td>
diff --git a/manual/Tasks/sshsession.html b/manual/Tasks/sshsession.html
index bf8d80a..6f557bb 100644
--- a/manual/Tasks/sshsession.html
+++ b/manual/Tasks/sshsession.html
@@ -111,6 +111,14 @@ JSCh earlier than 0.1.28.</p>
     <td>No; defaults to an empty string</td>
   </tr>
   <tr>
+    <td>sshConfig</td>
+    <td>Location of the file holding the OpenSSH style configuration (e.g. <code>${user.home}/.ssh/config</code>).
+        The username and the key file are read from the configuration file,
+        unless they are already specified in the task parameters.
+        <em>since Ant 1.10.8</em></td>
+    <td>No</td>
+  </tr>
+  <tr>
     <td>timeout</td>
     <td>Give up if the connection cannot be established within the specified time (given in
       milliseconds).</td>
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHBase.java b/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHBase.java
index 338a11a..edee9a8 100644
--- a/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHBase.java
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHBase.java
@@ -18,6 +18,11 @@
 
 package org.apache.tools.ant.taskdefs.optional.ssh;
 
+import java.io.File;
+import java.io.IOException;
+
+import com.jcraft.jsch.ConfigRepository;
+import com.jcraft.jsch.OpenSSHConfig;
 import org.apache.tools.ant.BuildException;
 import org.apache.tools.ant.Project;
 import org.apache.tools.ant.Task;
@@ -42,6 +47,7 @@ public abstract class SSHBase extends Task implements LogListener {
     private boolean failOnError = true;
     private boolean verbose;
     private final SSHUserInfo userInfo;
+    private String sshConfig;
     private int serverAliveCountMax = 3;
     private int serverAliveIntervalSeconds = 0;
 
@@ -107,6 +113,24 @@ public abstract class SSHBase extends Task implements LogListener {
     }
 
     /**
+     * Get the OpenSSH config file (~/.ssh/config).
+     * @return the OpenSSH config file
+     * @since Ant 1.10.8
+     */
+    public String getSshConfig() {
+        return sshConfig;
+    }
+
+    /**
+     * Set the OpenSSH config file (~/.ssh/config).
+     * @param sshConfig the OpenSSH config file
+     * @since Ant 1.10.8
+     */
+    public void setSshConfig(String sshConfig) {
+        this.sshConfig = sshConfig;
+    }
+
+    /**
      * Set the serverAliveCountMax value.
      * @param countMax int
      * @since Ant 1.9.7
@@ -236,6 +260,37 @@ public abstract class SSHBase extends Task implements LogListener {
     }
 
     /**
+     * Load the SSH configuration file.
+     * @throws BuildException on error
+     */
+    protected void loadSshConfig() throws BuildException {
+        if (sshConfig != null && (userInfo.getName() == null || userInfo.getKeyfile() == null)) {
+            if (!new File(sshConfig).exists()) {
+                throw new BuildException("The SSH configuration file specified doesn't exist: " + sshConfig);
+            }
+            
+            log("Loading SSH configuration file " + sshConfig, Project.MSG_DEBUG);
+            ConfigRepository.Config config = null;
+            try {
+                config = OpenSSHConfig.parseFile(sshConfig).getConfig(host);
+            } catch (IOException e) {
+                throw new BuildException("Failed to load the SSH configuration file " + sshConfig, e);
+            }
+            
+            host = config.getHostname();
+            
+            if (userInfo.getName() == null) {
+                userInfo.setName(config.getUser());
+            }
+            
+            if (userInfo.getKeyfile() == null) {
+                log("Using SSH key file " + config.getValue("IdentityFile") + " for host " + host, Project.MSG_INFO);
+                userInfo.setKeyfile(config.getValue("IdentityFile"));
+            }
+        }
+    }
+
+    /**
      * Open an ssh session.
      * @return the opened session
      * @throws JSchException on error
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHExec.java b/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHExec.java
index 1cd273b..17dd431 100644
--- a/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHExec.java
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHExec.java
@@ -284,6 +284,9 @@ public class SSHExec extends SSHBase {
         if (getHost() == null) {
             throw new BuildException("Host is required.");
         }
+        
+        loadSshConfig();
+        
         if (getUserInfo().getName() == null) {
             throw new BuildException("Username is required.");
         }
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHSession.java b/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHSession.java
index 6b7c33e..5c52246 100644
--- a/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHSession.java
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHSession.java
@@ -132,6 +132,9 @@ public class SSHSession extends SSHBase {
         if (getHost() == null) {
             throw new BuildException("Host is required.");
         }
+        
+        loadSshConfig();
+        
         if (getUserInfo().getName() == null) {
             throw new BuildException("Username is required.");
         }
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Scp.java b/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Scp.java
index f954a72..3d181d3 100644
--- a/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Scp.java
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Scp.java
@@ -435,19 +435,22 @@ public class Scp extends SSHBase {
             throw new BuildException("no username was given.  Can't authenticate.");
         }
 
-        if (getUserInfo().getPassword() == null
-            && getUserInfo().getKeyfile() == null) {
-            throw new BuildException(
-                "neither password nor keyfile for user %s has been given.  Can't authenticate.",
-                getUserInfo().getName());
-        }
-
         final int indexOfPath = uri.indexOf(':', indexOfAt + 1);
         if (indexOfPath == -1) {
             throw new BuildException("no remote path in %s", uri);
         }
 
         setHost(uri.substring(indexOfAt + 1, indexOfPath));
+        
+        loadSshConfig();
+        
+        if (getUserInfo().getPassword() == null
+            && getUserInfo().getKeyfile() == null) {
+            throw new BuildException(
+                "neither password nor keyfile for user %s has been given.  Can't authenticate.",
+                getUserInfo().getName());
+        }
+        
         String remotePath = uri.substring(indexOfPath + 1);
         if (remotePath.isEmpty()) {
             remotePath = ".";