Appium

Tuesday 24 January 2017

Connect SSH tunnel and upload the files through JSch shell channel

Recently, I came across the problem where tunnel is key-based authentication so I did some workaround and finally able to logged into the tunnel.

It was really challenging task for me to connect the tunnel where the private key is loaded on to the client machine and all the communication would be user based. So decided to use JSch library, it allows us to connect the SSH to the remote host.

Maven dependency for JSch (check the updated version in maven site):

<dependency>
    <groupId>com.jcraft</groupId>
    <artifactId>jsch</artifactId>
    <version>0.1.54</version>
</dependency>

To connect the tunnel programmatically, first we need to make the connection with remote host. here is the code to connect the session:

public static Session getSession(String host, String user, int port,String privateKey,String passphrase)
{
try {
JSch jsch = new JSch();
jsch.addIdentity(privateKey, passphrase);
session = jsch.getSession(user, host, port);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");//if you want to skip host-key check
session.setConfig(config);
session.connect();
} catch (Exception e) {
                       System.out.println("Issue in creating the Session---->"+e);
}
return session;
}

once connected to the session, we need to open the 'shell' channel using connected session and then execute the command in the shell to connect to the tunnel.

The following function can be used to connect the tunnel and upload the files:

public static void tunnelConnectionAndFileUpload(Session sshSession,String tunnelConCmd,String localLocation, String tunnelLocation, String[] fileName) throws IOException, JSchException{
try {
String tunnelCommand=tunnelConCmd+"\r";
String localLoc="lcd "+localLocation+"\r";
String tunnelLoc="cd "+tunnelLocation+"\r";
for(String value:fileName){
String fName="put "+value+"\r";
Channel channel = sshSession.openChannel("shell");
        OutputStream inputstream_for_the_channel = channel.getOutputStream();
PrintStream commander = new PrintStream(inputstream_for_the_channel, true);
ByteArrayOutputStream out = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(out);
channel.setOutputStream(ps);
channel.connect();
System.out.println("-----------Connecting to the tunnel--------------");
commander.write(tunnelCommand.getBytes());
waitForText(out,"authorized");//you can change the condition 
System.out.println(out.toString());
out.reset();
System.out.println("-------Navigating to the local folder---------");
commander.write(localLoc.getBytes());
waitForText(out,"lcd");
System.out.println(out.toString());
out.reset();
System.out.println("-------Navigating to the tunnel folder---------");
commander.write(tunnelLoc.getBytes());   
waitForText(out,"cd");
System.out.println(out.toString());
out.reset();
System.out.println("-------Uploading file to the tunnel---------");
commander.write(fName.getBytes());  
waitForText(out,"100%");
System.out.println(out.toString());
out.reset();
}
}
catch (Exception e) {
System.out.println("Issue in creating the tunnel Session---->"+e);
}


In the above function we need to provide the following parameters:

sshSession: pass the active session
tunnelConCmd: pass the command to connect tunnel session
localLocation: pass the location from where we need to upload the file (it will be first session location)
tunnelLocation: pass the tunnel Location
fileName: provide the files name to be uploaded

The another very important task that we need to make sure whether tunnel command execution completed or not, for this we need to implement the wait for until command completely executed.

The following function can be used to wait for command execution:

public static void waitForText(ByteArrayOutputStream text, String condition) throws InterruptedException{
while (System.nanoTime() < System.nanoTime()+TimeUnit.NANOSECONDS.convert(5L, TimeUnit.MINUTES)){
 Thread.sleep(2000);
 if(text.toString().contains(condition)){
 break;
 }
}
}

this function will wait for maximum 5 min to make sure whether command is completely executed or not.
At last we need to terminate the session:

public static void terminateSession(Session session){
try {
if(session.isConnected()){
   session.disconnect();
}
} catch (Exception e) {
System.out.println("Exception in disconnecting the Session---->"+e);
}
}

Now, we can easily upload the files to the tunnel (Y)
Above functions can be used like this:

public static void main(String[] args) throws IOException, JSchException {
String tunnelCommand="sftp -oPort=22 -oIdentityFile=/home/manoj/.ssh/id_dsa abc@xyz.example.com";
String tunnelLoc="var/upload";
String localFolderLoc="/home/manoj/files";
String privateKeyFile = "provide private key location";
Session session=getSession("xxx@example.com", "manoj", 22, privateKeyFile, "pass@123");
tunnelConnectionAndFileUpload(session, tunnelCommand,localFolderLoc, tunnelLoc, new String[]{"pqr_test.xml"});
terminateSession(session);
}

Keep Coding! :)


No comments:

Post a Comment