All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.cloudslang.content.rft.remote_copy.ScpCopier Maven / Gradle / Ivy

/*
 * (c) Copyright 2021 Micro Focus
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Apache License v2.0 which accompany this distribution.
 *
 * The Apache License is available 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.
 */
package io.cloudslang.content.rft.remote_copy;
/**
 * 

Copies a file to/from/between two remote hosts using SCP. */ import com.hp.oo.content.commons.util.Address; import com.iconclude.dharma.commons.exception.DharmaException; import com.iconclude.dharma.commons.security.ssh.DefaultSSHSessionCreator; import com.iconclude.dharma.commons.security.ssh.SSHChannelProcessor; import com.iconclude.dharma.commons.security.ssh.SSHOperation; import com.iconclude.dharma.commons.security.ssh.SSHOperationResult; import com.iconclude.dharma.commons.util.StringUtils; import com.jcraft.jsch.ChannelExec; import com.jcraft.jsch.JSchException; import com.jcraft.jsch.Session; import java.io.*; import java.util.HashMap; import java.util.Map; public class ScpCopier extends SimpleCopier { String sourceFileName; private String host; private int port; private String username; private String password; private String privateKeyFile; //Collection tickets; public ScpCopier() { } protected void getFile(String source, File getFile) throws Exception { SCPLocalOperationGet scpOp = new SCPLocalOperationGet(source, host, port, username, password, privateKeyFile, getFile, this, connectionTimeout * 1000); SSHOperationResult raw = scpOp.exec(); //contains a call to bindOperation() if (raw.isTimedOut()) { throw new Exception("SCP Operation timed out"); } if (raw.getCodeInt() != 0) { throw new Exception("SCP Operation failed: " + raw.getError() + "\n" + raw.getException()); } if (sourceFileName == null) sourceFileName = getSimpleFileName(source); } protected IReader getFile(String source) throws Exception { File getFile; getFile = File.createTempFile("SCPCopy", ".tmp"); getFile(source, getFile); return new SimpleReader(sourceFileName, getFile); } protected void putFile(IReader sourceFile, String destination) throws Exception { LocalSCPOperationPut scpOp = new LocalSCPOperationPut(sourceFile.getFile(), destination, host, port, username, password, privateKeyFile, sourceFile.getFileName(), connectionTimeout * 1000); SSHOperationResult raw = scpOp.exec(); //contains a call to bindOperation() if (raw.isTimedOut()) { throw new Exception("SCP Operation timed out"); } if (raw.getCodeInt() != 0) throw new Exception("SCP Operation failed: " + raw.getError() + "\n" + raw.getException()); } @Override public void setCredentials(String host, int port, String username, String password) throws UnsupportedOperationException { Address address = new Address(host, port); this.host = address.getBareHost(); this.port = address.getPort(); this.username = username; this.password = password; } @Override public void setCredentials(String host, int port, String username, String password, String privateKeyFile) throws UnsupportedOperationException { setCredentials(host, port, username, password); this.privateKeyFile = privateKeyFile; } public void setCustomArgument(complexArgument name, Object value) { switch (name) { //case kerberosTickets: tickets = ActionRequestUtils.collectKerberosTicketsFromPassword((ActionRequest)value); break; default: throw new UnsupportedOperationException(getProtocolName() + " does not allow " + name.name() + " to be set"); } } public String getProtocolName() { return CopierFactory.copiers.scp.name(); } } class SCPLocalOperationGet extends SSHOperation { private String srcHost; private int port; private String srcUsername; private String srcPassword; private String srcPrivateKeyFile; private int connectionTimeout; public SCPLocalOperationGet(String srcPath, String srcHost, int port, String srcUsername, String srcPassword, String srcPrivateKeyFile, File dest, ScpCopier exec, int timeout) { this(new DefaultSSHSessionCreator(), new SCPLocalProcessor(srcPath, dest, exec, timeout)); Address address = new Address(srcHost, port); this.srcHost = address.getBareHost(); this.port = address.getPort(); this.srcUsername = srcUsername; this.srcPassword = srcPassword; this.srcPrivateKeyFile = srcPrivateKeyFile; this.connectionTimeout = timeout; } protected SCPLocalOperationGet(DefaultSSHSessionCreator sessCreator, SCPLocalProcessor channelProc) { super(sessCreator, channelProc); } @SuppressWarnings("unchecked") @Override protected Map bindOperation() { Map result = new HashMap(); if (StringUtils.isEmpty(srcHost)) { throw new DharmaException(SSHOperation.HOST + " not specified"); } result.put(SSHOperation.HOST, srcHost); result.put(Address.INTEGER_PORT, port); if (StringUtils.isBlank(srcUsername)) { throw new DharmaException("userName not specified"); } result.put(SSHOperation.USERNAME, srcUsername); result.put(SSHOperation.PASSWORD, srcPassword); if (!StringUtils.isBlank(srcPrivateKeyFile)) { result.put(SSHOperation.PK_FILE, srcPrivateKeyFile); } result.put(SSHOperation.TIMEOUT, String.valueOf(connectionTimeout)); return result; } } class SCPLocalProcessor extends SSHChannelProcessor { public static final String CHANNELTYPE = "exec"; protected ChannelExec channel; protected int connectionTimeout; OutputStream out; InputStream in; ScpCopier parent; private String srcPath; private File dest; public SCPLocalProcessor(String srcPath, File dest, ScpCopier parent, int connectionTimeout) { this.srcPath = srcPath; this.dest = dest; this.parent = parent; this.connectionTimeout = connectionTimeout; // small hack to handle the input name change from privateKey to privateKeyFile } @SuppressWarnings("unchecked") //@Override public void createChannel(Session session, Map bindings) throws JSchException { channel = (ChannelExec) session.openChannel(CHANNELTYPE); } private String getSourceFile() { return srcPath; } private File getDestinationFile() { return dest; } @Override public SSHOperationResult process() throws JSchException { try { try { in = channel.getInputStream(); out = channel.getOutputStream(); } catch (Exception e) { return fail("Unable to read SSH session's IO streams.\n" + e.toString()); } channel.setCommand("scp -f " + getSourceFile()); // connect channel to host channel.connect(connectionTimeout); // run the shell simulator (this basically is sending a batch of commands to the ssh server) return copyFrom(); } finally { if (channel.isConnected()) channel.disconnect(); } } private SSHOperationResult copyFrom() { FileOutputStream fos = null; try { byte[] buf = new byte[1024]; // send '\0' buf[0] = 0; out.write(buf, 0, 1); out.flush(); boolean processed = false; File destFile = getDestinationFile(); while (true) { int c = checkAck(in); if (c != 'C') { if (!processed) return fail("Received incorrect ack response for secure copy command"); else break; } processed = true; // read '0644 ' in.read(buf, 0, 5); long filesize = 0L; while (true) { if (in.read(buf, 0, 1) < 0) { return fail("Read of file stream from remote host failed."); } if (buf[0] == ' ') break; filesize = filesize * 10L + (long) (buf[0] - '0'); } for (int i = 0; ; i++) { in.read(buf, i, 1); if (buf[i] == (byte) 0x0a) { parent.sourceFileName = new String(buf, 0, i); break; } } // send '\0' buf[0] = 0; out.write(buf, 0, 1); out.flush(); // read a content of lfile fos = new FileOutputStream(destFile); int foo; while (true) { if (buf.length < filesize) foo = buf.length; else foo = (int) filesize; foo = in.read(buf, 0, foo); if (foo < 0) { // error break; } fos.write(buf, 0, foo); filesize -= foo; if (filesize == 0L) break; } fos.close(); fos = null; if (checkAck(in) != 0) { return fail("No ack received"); } // send '\0' buf[0] = 0; out.write(buf, 0, 1); out.flush(); } SSHOperationResult result = new SSHOperationResult(); result.setOutput(destFile.getAbsolutePath()); result.setCodeInt(0); result.setException(""); result.setError(""); return result; } catch (Exception e) { System.out.println(e); try { if (fos != null) fos.close(); return fail(e.toString()); } catch (Exception ee) { return fail(ee.toString() + "\n" + e.toString()); } } } private SSHOperationResult fail(String reason) { SSHOperationResult result = new SSHOperationResult(); result.setOutput(reason); result.setCodeInt(-1); result.setException(reason); result.setError(reason); return result; } private int checkAck(InputStream in) throws IOException { int b = in.read(); // b may be 0 for success, // 1 for error, // 2 for fatal error, // -1 if (b == 0) return b; if (b == -1) return b; if (b == 1 || b == 2) { StringBuffer sb = new StringBuffer(); int c; do { c = in.read(); sb.append((char) c); } while (c != '\n'); if (b == 1) { // error System.out.print(sb.toString()); throw new IOException("Error: " + sb.toString()); } if (b == 2) { // fatal error System.out.print(sb.toString()); throw new IOException("Fatal Error: " + sb.toString()); } } return b; } } class LocalSCPProcessor extends SSHChannelProcessor { public static final String CHANNELTYPE = "exec"; protected ChannelExec channel; OutputStream out; InputStream in; String sourceFileName; private int connectionTimeout; private File tmp; private String destPath; public LocalSCPProcessor(File tmp, String destPath, String sourceFileName, int connectionTimeout) { this.tmp = tmp; this.destPath = destPath; this.sourceFileName = sourceFileName; this.connectionTimeout = connectionTimeout; } @SuppressWarnings("unchecked") @Override public void createChannel(Session session, Map bindings) throws JSchException { channel = (ChannelExec) session.openChannel(CHANNELTYPE); } private String getDestinationName() { if (destPath.lastIndexOf('/') == destPath.length() - 1) return sourceFileName; else if (destPath.contains("/")) return destPath.substring(destPath.lastIndexOf("/") + 1); else return destPath; } private String getDestinationPath() { if (destPath.lastIndexOf('/') == destPath.length() - 1) return destPath + sourceFileName; else return destPath; } @Override public SSHOperationResult process() throws JSchException { try { try { in = channel.getInputStream(); out = channel.getOutputStream(); } catch (Exception e) { return fail("Unable to read SSH session's IO streams.\n" + e.toString()); } channel.setCommand("scp -p -t " + getDestinationPath()); // connect channel to host channel.connect(connectionTimeout); // run the shell simulator (this basically is sending a batch of commands to the ssh server) return copyTo(); } finally { if (channel.isConnected()) channel.disconnect(); } } private SSHOperationResult copyTo() { try { SSHOperationResult result = new SSHOperationResult(); if (checkAck(in) != 0) { return fail("No ack received"); } // send "C0644 filesize filename", where filename should not // include '/' long filesize = (tmp).length(); String command = "C0644 " + filesize + " "; command += getDestinationName(); command += "\n"; out.write(command.getBytes()); out.flush(); if (checkAck(in) != 0) { return fail("No ack received"); } // send a content of lfile FileInputStream fis = new FileInputStream(tmp); byte[] buf = new byte[1024]; try { while (true) { int len = fis.read(buf, 0, buf.length); if (len <= 0) break; out.write(buf, 0, len); out.flush(); } } finally { fis.close(); } // send '\0' buf[0] = 0; out.write(buf, 0, 1); out.flush(); if (checkAck(in) != 0) { return fail("No ack received"); } result.setOutput(destPath); result.setCodeInt(0); result.setException(""); result.setError(""); return result; } catch (Exception e) { return fail(e.toString()); } } private SSHOperationResult fail(String reason) { SSHOperationResult result = new SSHOperationResult(); result.setOutput(reason); result.setCodeInt(-1); result.setException(reason); result.setError(reason); return result; } private int checkAck(InputStream in) throws IOException { int b = in.read(); // b may be 0 for success, // 1 for error, // 2 for fatal error, // -1 if (b == 0) return b; if (b == -1) return b; if (b == 1 || b == 2) { StringBuffer sb = new StringBuffer(); int c; do { c = in.read(); sb.append((char) c); } while (c != '\n'); if (b == 1) { // error System.out.print(sb.toString()); throw new IOException("Error: " + sb.toString()); } if (b == 2) { // fatal error System.out.print(sb.toString()); throw new IOException("Fatal Error: " + sb.toString()); } } return b; } } class LocalSCPOperationPut extends SSHOperation { private String destHost; private int port; private String destUsername; private String destPassword; private String destPrivateKeyFile; private int connectionTimeout; public LocalSCPOperationPut(File tmp, String destPath, String destHost, int port, String destUsername, String destPassword, String destPrivateKeyFile, String sourceFileName, int timeout) { this(new DefaultSSHSessionCreator(), new LocalSCPProcessor(tmp, destPath, sourceFileName, timeout)); Address address = new Address(destHost, port); this.destHost = address.getBareHost(); this.port = address.getPort(); this.destUsername = destUsername; this.destPassword = destPassword; this.destPrivateKeyFile = destPrivateKeyFile; this.connectionTimeout = timeout; } protected LocalSCPOperationPut(DefaultSSHSessionCreator sessCreator, LocalSCPProcessor channelProc) { super(sessCreator, channelProc); } @SuppressWarnings("unchecked") @Override protected Map bindOperation() { Map result = new HashMap(); if (StringUtils.isEmpty(destHost)) { throw new DharmaException(SSHOperation.HOST + " not specified"); } result.put(SSHOperation.HOST, destHost); result.put(Address.INTEGER_PORT, port); if (StringUtils.isBlank(destUsername)) { throw new DharmaException("userName not specified"); } result.put(SSHOperation.USERNAME, destUsername); result.put(SSHOperation.PASSWORD, destPassword); if (!StringUtils.isBlank(destPrivateKeyFile)) { result.put(SSHOperation.PK_FILE, destPrivateKeyFile); } result.put(SSHOperation.TIMEOUT, String.valueOf(connectionTimeout)); // Kerberos support: deserialize tickets and place them in the binding map /*if (!CollectionUtils.isEmpty(tickets)) { result.put(SSHOperation.KRBTICKETS, tickets); }*/ return result; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy