Simple Ssh Connect with Jsch

Simple SSH connect with JSch

You have to execute that code in another thread so you don't hang the UI thread is what that exception means. If the UI thread is executing a network call it can't repaint the UI so your users sees a frozen UI that doesn't respond to them while the app is waiting on the network call to finish. Android wants to avoid bad user experiences like this so it prevents you from doing things like this by throwing this exception.

Your onCreate() method should invoke another thread (I'd suggest using an AsyncTask over a raw thread) to perform the SSH connection. Then when it's done it can post the results back to the UI thread and safely update your application's UI from the UI thread.

http://developer.android.com/reference/android/os/AsyncTask.html

Basic SSH connection via JSCH on android

Ok here we go,
your code is okay, but some little errors are in.. let me correct this,
you have to implement the button right and some little changes and it will work:

MainActivity:

    import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;

public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Button btn = (Button) view.findViewById(R.id.button);
btn.setOnClickListener(new View.OnClickListener() {
//start execution of ssh commands
@Override
public void onClick(View v){
new AsyncTask<Integer, Void, Void>(){
@Override
protected Void doInBackground(Integer... params) {
try {
executeSSHcommand();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}.execute(1);
}
});
}

public void executeSSHcommand(){
String user = "xxx";
String password = "xxx";
String host = "192.168.xxx.xxx";
int port=22;
try{

JSch jsch = new JSch();
Session session = jsch.getSession(user, host, port);
session.setPassword(password);
session.setConfig("StrictHostKeyChecking", "no");
session.setTimeout(10000);
session.connect();
ChannelExec channel = (ChannelExec)session.openChannel("exec");
channel.setCommand("your ssh command here");
channel.connect();
channel.disconnect();
// show success in UI with a snackbar alternatively use a toast
Snackbar.make(getActivity().findViewById(android.R.id.content),
"Success!", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
catch(JSchException e){
// show the error in the UI
Snackbar.make(getActivity().findViewById(android.R.id.content),
"Check WIFI or Server! Error : "+e.getMessage(),
Snackbar.LENGTH_LONG)
.setDuration(20000).setAction("Action", null).show();
}
}
}

additional you can delete the line " android:onClick="onCLick" " in your layout.xml

at my project this is working just fine even without the delay. of curse you need internet permission in manifest file. but i think this permission will grantet immediately on start of the application.

hope it helps, sometimes little things make a difference.

kind regards

chwzr

Connecting to server via SSH using Java - JSch and issuing shell commands

If you want to implement an interactive shell, you need to use SSH "shell" channel.

JSch has a simple example showing how to do that:

http://www.jcraft.com/jsch/examples/Shell.java.html

Though note that fully implementing an interactive shell is an immense work. So you will likely find out that a simple implementation like above will not work as you might hope.

For some background, see also:

What is the difference between the 'shell' channel and the 'exec' channel in JSch

Run a command over SSH with JSch

The following code example written in Java will allow you to execute any command on a foreign computer through SSH from within a java program. You will need to include the com.jcraft.jsch jar file.

  /* 
* SSHManager
*
* @author cabbott
* @version 1.0
*/
package cabbott.net;

import com.jcraft.jsch.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;

public class SSHManager
{
private static final Logger LOGGER =
Logger.getLogger(SSHManager.class.getName());
private JSch jschSSHChannel;
private String strUserName;
private String strConnectionIP;
private int intConnectionPort;
private String strPassword;
private Session sesConnection;
private int intTimeOut;

private void doCommonConstructorActions(String userName,
String password, String connectionIP, String knownHostsFileName)
{
jschSSHChannel = new JSch();

try
{
jschSSHChannel.setKnownHosts(knownHostsFileName);
}
catch(JSchException jschX)
{
logError(jschX.getMessage());
}

strUserName = userName;
strPassword = password;
strConnectionIP = connectionIP;
}

public SSHManager(String userName, String password,
String connectionIP, String knownHostsFileName)
{
doCommonConstructorActions(userName, password,
connectionIP, knownHostsFileName);
intConnectionPort = 22;
intTimeOut = 60000;
}

public SSHManager(String userName, String password, String connectionIP,
String knownHostsFileName, int connectionPort)
{
doCommonConstructorActions(userName, password, connectionIP,
knownHostsFileName);
intConnectionPort = connectionPort;
intTimeOut = 60000;
}

public SSHManager(String userName, String password, String connectionIP,
String knownHostsFileName, int connectionPort, int timeOutMilliseconds)
{
doCommonConstructorActions(userName, password, connectionIP,
knownHostsFileName);
intConnectionPort = connectionPort;
intTimeOut = timeOutMilliseconds;
}

public String connect()
{
String errorMessage = null;

try
{
sesConnection = jschSSHChannel.getSession(strUserName,
strConnectionIP, intConnectionPort);
sesConnection.setPassword(strPassword);
// UNCOMMENT THIS FOR TESTING PURPOSES, BUT DO NOT USE IN PRODUCTION
// sesConnection.setConfig("StrictHostKeyChecking", "no");
sesConnection.connect(intTimeOut);
}
catch(JSchException jschX)
{
errorMessage = jschX.getMessage();
}

return errorMessage;
}

private String logError(String errorMessage)
{
if(errorMessage != null)
{
LOGGER.log(Level.SEVERE, "{0}:{1} - {2}",
new Object[]{strConnectionIP, intConnectionPort, errorMessage});
}

return errorMessage;
}

private String logWarning(String warnMessage)
{
if(warnMessage != null)
{
LOGGER.log(Level.WARNING, "{0}:{1} - {2}",
new Object[]{strConnectionIP, intConnectionPort, warnMessage});
}

return warnMessage;
}

public String sendCommand(String command)
{
StringBuilder outputBuffer = new StringBuilder();

try
{
Channel channel = sesConnection.openChannel("exec");
((ChannelExec)channel).setCommand(command);
InputStream commandOutput = channel.getInputStream();
channel.connect();
int readByte = commandOutput.read();

while(readByte != 0xffffffff)
{
outputBuffer.append((char)readByte);
readByte = commandOutput.read();
}

channel.disconnect();
}
catch(IOException ioX)
{
logWarning(ioX.getMessage());
return null;
}
catch(JSchException jschX)
{
logWarning(jschX.getMessage());
return null;
}

return outputBuffer.toString();
}

public void close()
{
sesConnection.disconnect();
}

}

For testing.

  /**
* Test of sendCommand method, of class SSHManager.
*/
@Test
public void testSendCommand()
{
System.out.println("sendCommand");

/**
* YOU MUST CHANGE THE FOLLOWING
* FILE_NAME: A FILE IN THE DIRECTORY
* USER: LOGIN USER NAME
* PASSWORD: PASSWORD FOR THAT USER
* HOST: IP ADDRESS OF THE SSH SERVER
**/
String command = "ls FILE_NAME";
String userName = "USER";
String password = "PASSWORD";
String connectionIP = "HOST";
SSHManager instance = new SSHManager(userName, password, connectionIP, "");
String errorMessage = instance.connect();

if(errorMessage != null)
{
System.out.println(errorMessage);
fail();
}

String expResult = "FILE_NAME\n";
// call sendCommand for each command and the output
//(without prompts) is returned
String result = instance.sendCommand(command);
// close only after all commands are sent
instance.close();
assertEquals(expResult, result);
}

How to SSH to a server behind another SSH server using JSch?

To connect to a second server behind a firewall, there are in principle two options.

The naive one would be to call ssh on the first server (from an exec channel), indicating the right server. This would need agent forwarding with JSch, and also doesn't provide the JSch API to access the second server, only the ssh command line.

The better one would be to use the connection to the first server to build up a TCP Tunnel, and use this tunnel to connect to the second server. The JSch Wiki contains a ProxySSH class (together with some example code) which allows to use a JSch session as a tunnel for a second JSch session. (Disclaimer: This class was written mainly by me, with some support from the JSch author.)

When you have your connection to the second server, use either a shell channel or a series of exec channels to execute your commands. (See Shell, Exec or Subsystem Channel in the JSch Wiki for an overview, and the Javadocs for details.)


For your unknown-host-key problem:

The secure version would be to collect all host keys (in a secure way) before and put them in the known_hosts file. (If you simply trust the key which is presented to you, you are vulnerable to a man-in-the-middle attack. If these are of no concern in your network, since it is physically secured, good for you.)

The convenient version is setting the configuration option StrictHostKeyChecking to no - this will add unknown host keys to the host keys file:

JSch.setConfig("StrictHostKeyChecking", "no");

(You can also set it individually on the sessions, if you only want to set it for the proxied sessions and not for the tunnel session. Or override it for the tunnel session with yesor ask - there the MITM danger might be greater.)

A middle way would be to enable actually asking the user (which then should compare the fingerprints to some list) - for this, implement the UserInfo interface and provide the object to the session. (The JSch Wiki contains an example implementation using Swing JOptionPanes, which you can simply use if your client program runs on a system with GUI.)

For the saving of accepted host keys to work, you must use the JSch.setKnownHosts method with a file name argument, not the one with an InputStream argument - else your accepting will have to be repeated for each restart of your client.

Using JSch to ssh to a remote server but got stuck in dealing with the message prompt

What you are seeing is most probably SSH authentication banner.

By default JSch handles that by passing it to showMessage method of your implementation of UserInfo interface.

Your implementation of the method is most probably what displays the prompt. Change the implementation the way you like. Though make sure you still handle the message reasonably, like logging it. As the method is used for other important messages.

Another possibility is that you are seeing a keyboard-interactive message with no prompts. That message is handled by UIKeyboardInteractive interface and its UIKeyboardInteractive.promptKeyboardInteractive method.

Both these methods are implemented by your MyUserInfo class to show some GUI.

For details, see How to read the SSH key-sig pair banner (for generating SSH password) after connecting to host in java?



Related Topics



Leave a reply



Submit