I am testing simple Apache Mina SSHD server using Jsch library. Junit test looks like:
package com.ssh;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.sshd.SshServer;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.server.PasswordAuthenticator;
import org.apache.sshd.server.UserAuth;
import org.apache.sshd.server.auth.UserAuthPassword;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.apache.sshd.server.session.ServerSession;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.ssh.util.EchoShellFactory;
public class SshServiceTest {
@Rule
public TemporaryFolder testFolder = new TemporaryFolder();
private static final String USERNAME = "username";
private static final String PASSWORD = "password";
private static final String HOSTNAME = "localhost";
private SshServer sshd;
@Before
public void prepare() throws IOException {
setupSSHServer();
}
private void setupSSHServer() throws IOException {
sshd = SshServer.setUpDefaultServer();
sshd.setPort(22);
sshd.setKeyPairProvider(
new SimpleGeneratorHostKeyProvider(testFolder.newFile("hostkey.ser").getAbsolutePath()));
List<NamedFactory<UserAuth>> userAuthFactories = new ArrayList<NamedFactory<UserAuth>>();
userAuthFactories.add(new UserAuthPassword.Factory());
sshd.setUserAuthFactories(userAuthFactories);
sshd.setPasswordAuthenticator(new PasswordAuthenticator() {
public boolean authenticate(String username, String password, ServerSession session) {
return USERNAME.equals(username) && PASSWORD.equals(password);
}
});
sshd.setShellFactory(new EchoShellFactory());
sshd.start();
}
@Test
public void testConnection() throws Exception {
System.out.println("test started");
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
JSch jsch = new JSch();
Session session = jsch.getSession(USERNAME, HOSTNAME, 22);
session.setPassword(PASSWORD);
session.setConfig(config);
session.connect();
System.out.println("Connected");
Channel channel = session.openChannel("exec");
((ChannelExec) channel).setCommand("pwd");
((ChannelExec) channel).setErrStream(System.err);
InputStream in = channel.getInputStream();
channel.connect();
byte[] tmp = new byte[1024];
while (true) {
while (in.available() > 0) {
int i = in.read(tmp, 0, 1024);
if (i < 0)
break;
System.out.print(new String(tmp, 0, i));
}
if (channel.isClosed()) {
System.out.println("exit-status: " + channel.getExitStatus());
break;
}
try {
Thread.sleep(1000);
} catch (Exception ee) {
}
}
channel.disconnect();
session.disconnect();
System.out.println("DONE");
}
@After
public void cleanup() throws InterruptedException {
try {
sshd.stop(true);
} catch (Exception e) {
System.out.println(e);
}
}
}
And my shell factory looks like:
package com.ssh.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import org.apache.sshd.common.Factory;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.Environment;
import org.apache.sshd.server.ExitCallback;
public class EchoShellFactory implements Factory<Command> {
public Command create() {
return new EchoShell();
}
public static class EchoShell implements Command, Runnable {
private InputStream in;
private OutputStream out;
private OutputStream err;
private ExitCallback callback;
private Environment environment;
private Thread thread;
public InputStream getIn() {
return in;
}
public OutputStream getOut() {
return out;
}
public OutputStream getErr() {
return err;
}
public Environment getEnvironment() {
return environment;
}
public void setInputStream(InputStream in) {
this.in = in;
}
public void setOutputStream(OutputStream out) {
this.out = out;
}
public void setErrorStream(OutputStream err) {
this.err = err;
}
public void setExitCallback(ExitCallback callback) {
this.callback = callback;
}
public void start(Environment env) throws IOException {
environment = env;
thread = new Thread(this, "EchoShell");
thread.start();
}
public void destroy() {
thread.interrupt();
}
public void run() {
BufferedReader r = new BufferedReader(new InputStreamReader(in));
try {
for (;;) {
String s = r.readLine();
if (s == null) {
return;
}
out.write(("executed " + s + "\r\n").getBytes());
out.flush();
if ("exit".equals(s)) {
return;
}
}
} catch (InterruptedIOException e) {
// Ignore
} catch (Exception e) {
System.out.println("Error executing EchoShell...");
} finally {
if (r != null) {
try {
r.close();
} catch (IOException e) {
// ignore
}
}
callback.onExit(0);
}
}
}
}
In this case value of in.available() is always "0" and while look runs forever. I have to stop the process manually. When SSHD server is up, I can connect to it through putty and execute dummy commands. Only when I try to connect to this server using Jsch lib, input stream as shown above is always 0. I searched at many places, but couldn't find whats wrong. Please let me know, if you have any idea on how to make it work.
Thanks in advance.