Submitted by: Robert Anderson <riznob at hotmail dot com> git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274232 13f79535-47bb-0310-9956-ffa450edef68master
@@ -0,0 +1,213 @@ | |||
/* | |||
* The Apache Software License, Version 1.1 | |||
* | |||
* Copyright (c) 2003 The Apache Software Foundation. All rights | |||
* reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions | |||
* are met: | |||
* | |||
* 1. Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* | |||
* 2. Redistributions in binary form must reproduce the above copyright | |||
* notice, this list of conditions and the following disclaimer in | |||
* the documentation and/or other materials provided with the | |||
* distribution. | |||
* | |||
* 3. The end-user documentation included with the redistribution, if | |||
* any, must include the following acknowlegement: | |||
* "This product includes software developed by the | |||
* Apache Software Foundation (http://www.apache.org/)." | |||
* Alternately, this acknowlegement may appear in the software itself, | |||
* if and wherever such third-party acknowlegements normally appear. | |||
* | |||
* 4. The names "Ant" and "Apache Software | |||
* Foundation" must not be used to endorse or promote products derived | |||
* from this software without prior written permission. For written | |||
* permission, please contact apache@apache.org. | |||
* | |||
* 5. Products derived from this software may not be called "Apache" | |||
* nor may "Apache" appear in their names without prior written | |||
* permission of the Apache Group. | |||
* | |||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
* SUCH DAMAGE. | |||
* ==================================================================== | |||
* | |||
* This software consists of voluntary contributions made by many | |||
* individuals on behalf of the Apache Software Foundation. For more | |||
* information on the Apache Software Foundation, please see | |||
* <http://www.apache.org/>. | |||
*/ | |||
package org.apache.tools.ant.taskdefs.optional.ssh; | |||
import com.jcraft.jsch.*; | |||
import java.io.*; | |||
import java.util.List; | |||
import java.util.LinkedList; | |||
import java.util.Iterator; | |||
import java.util.ArrayList; | |||
import org.apache.tools.ant.Task; | |||
import org.apache.tools.ant.BuildException; | |||
import org.apache.tools.ant.DirectoryScanner; | |||
import org.apache.tools.ant.Project; | |||
import org.apache.tools.ant.types.FileSet; | |||
/** | |||
* Base class for Ant tasks using jsch. | |||
* | |||
* @author charliehubbard76@yahoo.com | |||
* @author riznob@hotmail.com | |||
* @since Ant 1.6 | |||
*/ | |||
public abstract class SSHBase extends Task implements LogListener { | |||
private String host; | |||
private String keyfile; | |||
private String knownHosts; | |||
private boolean trust = false; | |||
private int port = 22; | |||
private boolean failOnError = true; | |||
private SSHUserInfo userInfo; | |||
/** | |||
* Constructor for SSHBase. | |||
*/ | |||
public SSHBase() { | |||
super(); | |||
userInfo = new SSHUserInfo(); | |||
} | |||
/** | |||
* Remote host, either DNS name or IP. | |||
* | |||
* @param host The new host value | |||
*/ | |||
public void setHost(String host) { | |||
this.host = host; | |||
} | |||
public void setFailonerror( boolean failure ) { | |||
failOnError = failure; | |||
} | |||
public boolean getFailonerror() { | |||
return failOnError; | |||
} | |||
/** | |||
* Username known to remote host. | |||
* | |||
* @param username The new username value | |||
*/ | |||
public void setUsername(String username) { | |||
userInfo.setName(username); | |||
} | |||
/** | |||
* Sets the password for the user. | |||
* | |||
* @param password The new password value | |||
*/ | |||
public void setPassword(String password) { | |||
userInfo.setPassword(password); | |||
} | |||
/** | |||
* Sets the keyfile for the user. | |||
* | |||
* @param keyfile The new keyfile value | |||
*/ | |||
public void setKeyfile(String keyfile) { | |||
userInfo.setKeyfile(keyfile); | |||
} | |||
/** | |||
* Sets the passphrase for the users key. | |||
* | |||
* @param passphrase The new passphrase value | |||
*/ | |||
public void setPassphrase(String passphrase) { | |||
userInfo.setPassphrase(passphrase); | |||
} | |||
/** | |||
* Sets the path to the file that has the identities of | |||
* all known hosts. This is used by SSH protocol to validate | |||
* the identity of the host. The default is | |||
* <i>${user.home}/.ssh/known_hosts</i>. | |||
* | |||
* @param knownHosts a path to the known hosts file. | |||
*/ | |||
public void setKnownhosts( String knownHosts ) { | |||
this.knownHosts = knownHosts; | |||
} | |||
/** | |||
* Setting this to true trusts hosts whose identity is unknown. | |||
* | |||
* @param yesOrNo if true trust the identity of unknown hosts. | |||
*/ | |||
public void setTrust( boolean yesOrNo ) { | |||
userInfo.setTrust(yesOrNo); | |||
} | |||
/** | |||
* Changes the port used to connect to the remote host. | |||
* | |||
* @param port port number of remote host. | |||
*/ | |||
public void setPort( int port ) { | |||
this.port = port; | |||
} | |||
public int getPort() { | |||
return port; | |||
} | |||
public void init() throws BuildException{ | |||
super.init(); | |||
this.knownHosts = System.getProperty("user.home") + "/.ssh/known_hosts"; | |||
this.trust = false; | |||
this.port = 22; | |||
} | |||
protected Session openSession() throws JSchException { | |||
JSch jsch = new JSch(); | |||
if (null != userInfo.getKeyfile()) { | |||
jsch.addIdentity(userInfo.getKeyfile(), "passphrase"); | |||
} | |||
if( knownHosts != null ) { | |||
log( "Using known hosts: " + knownHosts, Project.MSG_DEBUG ); | |||
jsch.setKnownHosts( knownHosts ); | |||
} | |||
Session session = jsch.getSession( userInfo.getName(), host, port ); | |||
session.setUserInfo(userInfo); | |||
log("Connecting to " + host + ":" + port ); | |||
session.connect(); | |||
return session; | |||
} | |||
protected SSHUserInfo getUserInfo() { | |||
return userInfo; | |||
} | |||
} |
@@ -0,0 +1,208 @@ | |||
/* | |||
* The Apache Software License, Version 1.1 | |||
* | |||
* Copyright (c) 2003 The Apache Software Foundation. All rights | |||
* reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions | |||
* are met: | |||
* | |||
* 1. Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* | |||
* 2. Redistributions in binary form must reproduce the above copyright | |||
* notice, this list of conditions and the following disclaimer in | |||
* the documentation and/or other materials provided with the | |||
* distribution. | |||
* | |||
* 3. The end-user documentation included with the redistribution, if | |||
* any, must include the following acknowlegement: | |||
* "This product includes software developed by the | |||
* Apache Software Foundation (http://www.apache.org/)." | |||
* Alternately, this acknowlegement may appear in the software itself, | |||
* if and wherever such third-party acknowlegements normally appear. | |||
* | |||
* 4. The names "Ant" and "Apache Software | |||
* Foundation" must not be used to endorse or promote products derived | |||
* from this software without prior written permission. For written | |||
* permission, please contact apache@apache.org. | |||
* | |||
* 5. Products derived from this software may not be called "Apache" | |||
* nor may "Apache" appear in their names without prior written | |||
* permission of the Apache Group. | |||
* | |||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
* SUCH DAMAGE. | |||
* ==================================================================== | |||
* | |||
* This software consists of voluntary contributions made by many | |||
* individuals on behalf of the Apache Software Foundation. For more | |||
* information on the Apache Software Foundation, please see | |||
* <http://www.apache.org/>. | |||
*/ | |||
package org.apache.tools.ant.taskdefs.optional.ssh; | |||
import com.jcraft.jsch.UserInfo; | |||
import org.apache.tools.ant.Project; | |||
/** | |||
* @author rhanderson | |||
*/ | |||
public class SSHUserInfo implements UserInfo { | |||
private String name; | |||
private String password = null; | |||
private String keyfile; | |||
private String passphrase = null; | |||
private boolean firstTime = true; | |||
private boolean trustAllCertificates; | |||
public SSHUserInfo() { | |||
super(); | |||
this.trustAllCertificates = true; | |||
} | |||
public SSHUserInfo(String password, boolean trustAllCertificates) { | |||
super(); | |||
this.password = password; | |||
this.trustAllCertificates = trustAllCertificates; | |||
} | |||
/** | |||
* @see com.jcraft.jsch.UserInfo#getName() | |||
*/ | |||
public String getName() { | |||
return name; | |||
} | |||
/** | |||
* @see com.jcraft.jsch.UserInfo#getPassphrase(String) | |||
*/ | |||
public String getPassphrase(String message) { | |||
return passphrase; | |||
} | |||
/** | |||
* @see com.jcraft.jsch.UserInfo#getPassword() | |||
*/ | |||
public String getPassword() { | |||
return password; | |||
} | |||
/** | |||
* @see com.jcraft.jsch.UserInfo#prompt(String) | |||
*/ | |||
public boolean prompt(String str) { | |||
return false; | |||
} | |||
/** | |||
* @see com.jcraft.jsch.UserInfo#retry() | |||
*/ | |||
public boolean retry() { | |||
return false; | |||
} | |||
/** | |||
* Sets the name. | |||
* @param name The name to set | |||
*/ | |||
public void setName(String name) { | |||
this.name = name; | |||
} | |||
/** | |||
* Sets the passphrase. | |||
* @param passphrase The passphrase to set | |||
*/ | |||
public void setPassphrase(String passphrase) { | |||
this.passphrase = passphrase; | |||
} | |||
/** | |||
* Sets the password. | |||
* @param password The password to set | |||
*/ | |||
public void setPassword(String password) { | |||
this.password = password; | |||
} | |||
/** | |||
* Sets the trust. | |||
* @param boolean | |||
*/ | |||
public void setTrust(boolean trust) { | |||
this.trustAllCertificates = trust; | |||
} | |||
/** | |||
* Returns the passphrase. | |||
* @return String | |||
*/ | |||
public String getPassphrase() { | |||
return passphrase; | |||
} | |||
/** | |||
* Returns the keyfile. | |||
* @return String | |||
*/ | |||
public String getKeyfile() { | |||
return keyfile; | |||
} | |||
/** | |||
* Sets the keyfile. | |||
* @param keyfile The keyfile to set | |||
*/ | |||
public void setKeyfile(String keyfile) { | |||
this.keyfile = keyfile; | |||
} | |||
/** | |||
* @see com.jcraft.jsch.UserInfo#promptPassphrase(String) | |||
*/ | |||
public boolean promptPassphrase(String message) { | |||
return true; | |||
} | |||
/** | |||
* @see com.jcraft.jsch.UserInfo#promptPassword(String) | |||
*/ | |||
public boolean promptPassword( String passwordPrompt ) { | |||
//log( passwordPrompt, Project.MSG_DEBUG ); | |||
if( firstTime ) { | |||
firstTime = false; | |||
return true; | |||
} | |||
return firstTime; | |||
} | |||
/** | |||
* @see com.jcraft.jsch.UserInfo#promptYesNo(String) | |||
*/ | |||
public boolean promptYesNo(String message) { | |||
//log( prompt, Project.MSG_DEBUG ); | |||
return trustAllCertificates; | |||
} | |||
/** | |||
* @see com.jcraft.jsch.UserInfo#showMessage(String) | |||
*/ | |||
public void showMessage(String message) { | |||
//log( message, Project.MSG_DEBUG ); | |||
} | |||
} |
@@ -74,19 +74,11 @@ import org.apache.tools.ant.types.FileSet; | |||
* @author charliehubbard76@yahoo.com | |||
* @since Ant 1.6 | |||
*/ | |||
public class Scp extends Task implements LogListener { | |||
public class Scp extends SSHBase { | |||
private String fromUri; | |||
private String toUri; | |||
private String knownHosts; | |||
private boolean trust = false; | |||
private int port = 22; | |||
private List fileSets = null; | |||
private boolean failOnError = true; | |||
public void setFailonerror( boolean failure ) { | |||
failOnError = failure; | |||
} | |||
/** | |||
* Sets the file to be transferred. This can either be a remote | |||
@@ -114,35 +106,7 @@ public class Scp extends Task implements LogListener { | |||
this.toUri = aToUri; | |||
} | |||
/** | |||
* Sets the path to the file that has the identities of | |||
* all known hosts. This is used by SSH protocol to validate | |||
* the identity of the host. The default is | |||
* <i>${user.home}/.ssh/known_hosts</i>. | |||
* @param knownHosts a path to the known hosts file. | |||
*/ | |||
public void setKnownhosts( String knownHosts ) { | |||
this.knownHosts = knownHosts; | |||
} | |||
/** | |||
* Setting this to true trusts hosts whose identity is unknown. | |||
* | |||
* @param yesOrNo if true trust the identity of unknown hosts. | |||
*/ | |||
public void setTrust( boolean yesOrNo ) { | |||
this.trust = yesOrNo; | |||
} | |||
/** | |||
* Changes the port used to connect to the remote host. | |||
* | |||
* @param port port number of remote host. | |||
*/ | |||
public void setPort( int port ) { | |||
this.port = port; | |||
} | |||
/** | |||
* Adds a FileSet tranfer to remote host. NOTE: Either | |||
@@ -161,9 +125,6 @@ public class Scp extends Task implements LogListener { | |||
super.init(); | |||
this.toUri = null; | |||
this.fromUri = null; | |||
this.knownHosts = System.getProperty("user.home") + "/.ssh/known_hosts"; | |||
this.trust = false; | |||
this.port = 22; | |||
this.fileSets = null; | |||
} | |||
@@ -174,12 +135,13 @@ public class Scp extends Task implements LogListener { | |||
if ( fromUri == null && fileSets == null ) { | |||
throw new BuildException("Either the 'file' attribute or one " + | |||
"FileSet is required."); | |||
"FileSet is required."); | |||
} | |||
boolean isFromRemote = false; | |||
if( fromUri != null ) | |||
if( fromUri != null ) { | |||
isFromRemote = isRemoteUri(fromUri); | |||
} | |||
boolean isToRemote = isRemoteUri(toUri); | |||
try { | |||
if (isFromRemote && !isToRemote) { | |||
@@ -194,11 +156,11 @@ public class Scp extends Task implements LogListener { | |||
// not implemented yet. | |||
} else { | |||
throw new BuildException("'todir' and 'file' attributes " + | |||
"must have syntax like the following: " + | |||
"user:password@host:/path"); | |||
"must have syntax like the following: " + | |||
"user:password@host:/path"); | |||
} | |||
} catch (Exception e) { | |||
if( failOnError ) { | |||
if(getFailonerror()) { | |||
throw new BuildException(e); | |||
} else { | |||
log("Caught exception: " + e.getMessage(), Project.MSG_ERR); | |||
@@ -207,20 +169,17 @@ public class Scp extends Task implements LogListener { | |||
} | |||
private void download( String fromSshUri, String toPath ) | |||
throws JSchException, IOException { | |||
String[] fromValues = parseUri(fromSshUri); | |||
throws JSchException, IOException { | |||
String file = parseUri(fromSshUri); | |||
Session session = null; | |||
try { | |||
session = openSession(fromValues[0], | |||
fromValues[1], | |||
fromValues[2], | |||
port ); | |||
session = openSession(); | |||
ScpFromMessage message = new ScpFromMessage( session, | |||
fromValues[3], | |||
new File( toPath ), | |||
fromSshUri.endsWith("*") ); | |||
log("Receiving file: " + fromValues[3] ); | |||
file, | |||
new File( toPath ), | |||
fromSshUri.endsWith("*") ); | |||
log("Receiving file: " + file ); | |||
message.setLogListener( this ); | |||
message.execute(); | |||
} finally { | |||
@@ -230,23 +189,20 @@ public class Scp extends Task implements LogListener { | |||
} | |||
private void upload( List fileSet, String toSshUri ) | |||
throws IOException, JSchException { | |||
String[] toValues = parseUri(toSshUri); | |||
throws IOException, JSchException { | |||
String file = parseUri(toSshUri); | |||
Session session = null; | |||
try { | |||
session = openSession( toValues[0], | |||
toValues[1], | |||
toValues[2], | |||
port ); | |||
session = openSession(); | |||
List list = new ArrayList( fileSet.size() ); | |||
for( Iterator i = fileSet.iterator(); i.hasNext(); ) { | |||
FileSet set = (FileSet) i.next(); | |||
list.add( createDirectory( set ) ); | |||
} | |||
ScpToMessage message = new ScpToMessage( session, | |||
list, | |||
toValues[3] ); | |||
list, | |||
file); | |||
message.setLogListener( this ); | |||
message.execute(); | |||
} finally { | |||
@@ -256,18 +212,15 @@ public class Scp extends Task implements LogListener { | |||
} | |||
private void upload( String fromPath, String toSshUri ) | |||
throws IOException, JSchException { | |||
String[] toValues = parseUri(toSshUri); | |||
throws IOException, JSchException { | |||
String file = parseUri(toSshUri); | |||
Session session = null; | |||
try { | |||
session = openSession( toValues[0], | |||
toValues[1], | |||
toValues[2], | |||
port ); | |||
session = openSession(); | |||
ScpToMessage message = new ScpToMessage( session, | |||
new File( fromPath ), | |||
toValues[3] ); | |||
new File( fromPath ), | |||
file ); | |||
message.setLogListener( this ); | |||
message.execute(); | |||
} finally { | |||
@@ -276,35 +229,32 @@ public class Scp extends Task implements LogListener { | |||
} | |||
} | |||
private Session openSession( String user, String password, | |||
String host, int port ) | |||
throws JSchException { | |||
JSch jsch = new JSch(); | |||
if( knownHosts != null ) { | |||
log( "Using known hosts: " + knownHosts, Project.MSG_DEBUG ); | |||
jsch.setKnownHosts( knownHosts ); | |||
} | |||
Session session = jsch.getSession( user, host, port ); | |||
UserInfo userInfo = new DefaultUserInfo( password, trust ); | |||
session.setUserInfo(userInfo); | |||
log("Connecting to " + host + ":" + port ); | |||
session.connect(); | |||
return session; | |||
} | |||
private String[] parseUri(String uri) { | |||
private String parseUri(String uri) { | |||
int indexOfAt = uri.indexOf('@'); | |||
int indexOfColon = uri.indexOf(':'); | |||
int indexOfPath = uri.indexOf(':', indexOfColon + 1); | |||
if (indexOfColon > -1 && indexOfColon < indexOfAt) { | |||
// user:password@host:/path notation | |||
setUsername(uri.substring(0, indexOfColon)); | |||
setPassword(uri.substring(indexOfColon + 1, indexOfAt)); | |||
} else { | |||
// no password, will require passphrase | |||
setUsername(uri.substring(0, indexOfAt)); | |||
} | |||
String[] values = new String[4]; | |||
values[0] = uri.substring(0, indexOfColon); | |||
values[1] = uri.substring(indexOfColon + 1, indexOfAt); | |||
values[2] = uri.substring(indexOfAt + 1, indexOfPath); | |||
values[3] = uri.substring(indexOfPath + 1); | |||
if (getUserInfo().getPassword() == null | |||
&& getUserInfo().getPassphrase() == null) { | |||
throw new BuildException("neither password nor passphrase for user " | |||
+ getUserInfo().getName() + " has been " | |||
+ "given. Can't authenticate."); | |||
} | |||
return values; | |||
int indexOfPath = uri.indexOf(':', indexOfAt + 1); | |||
if (indexOfPath == -1) { | |||
throw new BuildException("no remote path in " + uri); | |||
} | |||
setHost(uri.substring(indexOfAt + 1, indexOfPath)); | |||
return uri.substring(indexOfPath + 1); | |||
} | |||
private boolean isRemoteUri(String uri) { | |||
@@ -338,46 +288,4 @@ public class Scp extends Task implements LogListener { | |||
return root; | |||
} | |||
public class DefaultUserInfo implements UserInfo { | |||
private String password = null; | |||
private boolean firstTime = true; | |||
private boolean trustAllCertificates; | |||
public DefaultUserInfo(String password, boolean trustAllCertificates) { | |||
this.password = password; | |||
this.trustAllCertificates = trustAllCertificates; | |||
} | |||
public String getPassphrase() { | |||
return null; | |||
} | |||
public String getPassword() { | |||
return password; | |||
} | |||
public boolean promptPassword( String passwordPrompt ) { | |||
log( passwordPrompt, Project.MSG_DEBUG ); | |||
if( firstTime ) { | |||
firstTime = false; | |||
return true; | |||
} | |||
return firstTime; | |||
} | |||
public boolean promptPassphrase( String passPhrasePrompt ) { | |||
return true; | |||
} | |||
public boolean promptYesNo( String prompt ) { | |||
log( prompt, Project.MSG_DEBUG ); | |||
return trustAllCertificates; | |||
} | |||
public void showMessage( String message ) { | |||
log( message, Project.MSG_DEBUG ); | |||
} | |||
} | |||
} |