bodewig 2003/03/11 05:00:31
Modified: src/main/org/apache/tools/ant/taskdefs/optional/ssh Scp.java Added: src/main/org/apache/tools/ant/taskdefs/optional/ssh SSHBase.java SSHUserInfo.java Log: Add key based authentication to scp. Submitted by: Robert Anderson <riznob at hotmail dot com> Revision Changes Path 1.4 +48 -140 ant/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Scp.java Index: Scp.java =================================================================== RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Scp.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- Scp.java 10 Mar 2003 10:05:43 -0000 1.3 +++ Scp.java 11 Mar 2003 13:00:31 -0000 1.4 @@ -74,19 +74,11 @@ * @author [EMAIL PROTECTED] * @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 @@ 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 @@ 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 @@ 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 @@ // not implemented yet. } else { throw new BuildException("'todir' and 'file' attributes " + - "must have syntax like the following: " + - "user:[EMAIL PROTECTED]:/path"); + "must have syntax like the following: " + + "user:[EMAIL PROTECTED]:/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 @@ } 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 @@ } 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 @@ } 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 @@ } } - 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); - - 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); - - return values; + if (indexOfColon > -1 && indexOfColon < indexOfAt) { + // user:[EMAIL PROTECTED]:/path notation + setUsername(uri.substring(0, indexOfColon)); + setPassword(uri.substring(indexOfColon + 1, indexOfAt)); + } else { + // no password, will require passphrase + setUsername(uri.substring(0, indexOfAt)); + } + + if (getUserInfo().getPassword() == null + && getUserInfo().getPassphrase() == null) { + throw new BuildException("neither password nor passphrase for user " + + getUserInfo().getName() + " has been " + + "given. Can't authenticate."); + } + + 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) { @@ -337,47 +287,5 @@ } 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 ); - } } } 1.1 ant/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHBase.java Index: SSHBase.java =================================================================== /* * 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 [EMAIL PROTECTED] * * 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 [EMAIL PROTECTED] * @author [EMAIL PROTECTED] * @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; } } 1.1 ant/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHUserInfo.java Index: SSHUserInfo.java =================================================================== /* * 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 [EMAIL PROTECTED] * * 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 ); } }