跳到主要內容

SFTP/SSH in JAVA

It is relatively hard to find code examples in Internet regarding SFTP and SSH in java.

Here I have written an example to demonstrate its usage.

Key points

  • I make use of J2SSH v0.2.2
  • The demonstration program is capable of
    • acting as a ssh mini shell
    • run a batch of simple sftp commands stored in a specified file
    • run a batch of simple ssh command stored in a specified file (not yet finished)

Remark:

  • Please note that the crew who made J2SSH has already totally rewritten all of its functions and make it available at commercial market
  • Please do test the speed of the prototype before you decide on whether to use this package. We have tested that it is generally at least 10% slower than sftp version in Unix.

Usage

Application :Sftp/SSH client
Author :Edmund Ng
last update :2009-11-05
version :v0.9a
help :
Example:
This list examples of usage


1.java -jar sftp.jar --help
This starts a ssh mini client
2.java -jar sftp.jar
This makes sftp execute a list of ssh commands stored in batch.txt
3.java -jar sftp.jar -s batch.txt
This makes sftp execute a list of sftp commands stored in batch.txt
4.java -jar sftp.jar -f batch.txt
The username,password and host are stored in config.ini

Code snippet

Mini Shell Code Segment

public static void miniShell()
{
try {
// JDK > 1.4 ONLY
/*Handler fh = new FileHandler("example.log");
fh.setFormatter(new SimpleFormatter());
Logger.getLogger("com.sshtools").setUseParentHandlers(false);
Logger.getLogger("com.sshtools").addHandler(fh);
Logger.getLogger("com.sshtools").setLevel(Level.ALL);*/
// Configure J2SSH (This will attempt to install the bouncycastle provider
// under jdk 1.3.1)

ConfigurationLoader.initialize(false);
BufferedReader reader =
new BufferedReader(new InputStreamReader(System.in));
System.out.print("Connect to host? ");
String hostname = reader.readLine();
// Make a client connection
SshClient ssh = new SshClient();
ssh.setSocketTimeout(30000);
SshConnectionProperties properties = new SshConnectionProperties();
properties.setHost(hostname);
properties.setPrefPublicKey("ssh-dss");
// Connect to the host
ssh.connect(properties);
// Create a password authentication instance
PasswordAuthenticationClient pwd = new PasswordAuthenticationClient();
// Get the users name
System.out.print("Username? ");
// Read the password
String username = reader.readLine();
pwd.setUsername(username);
// Get the password
System.out.print("Password? ");
String password = reader.readLine();
pwd.setPassword(password);
// Try the authentication
int result = ssh.authenticate(pwd);
// Evaluate the result
if (result == AuthenticationProtocolState.COMPLETE) {
System.out.println("Successful login");
// The connection is authenticated we can now do some real work!
SessionChannelClient session = ssh.openSessionChannel();
if(!session.requestPseudoTerminal("ANSI", 80, 24, 0, 0, ""))
System.out.println("Failed to allocate a pseudo terminal");
if (session.startShell()) {
System.out.println("Shell started");
IOStreamConnector input =
new IOStreamConnector();
IOStreamConnector output =
new IOStreamConnector();
IOStreamConnector error =
new IOStreamConnector();
output.setCloseOutput(false);
input.setCloseInput(false);
error.setCloseOutput(false);
input.connect(System.in, session.getOutputStream());

//FileOutputStream fos1=new FileOutputStream("mylog1.log");
//FileOutputStream fos2=new FileOutputStream("mylog2.log");

output.connect(session.getInputStream(), System.out);
//output.connect(session.getInputStream(), fos1);
error.connect(session.getStderrInputStream(), System.out);
//error.connect(session.getStderrInputStream(), fos2);
session.getState().waitForState(ChannelState.CHANNEL_CLOSED);
}else
System.out.println("Failed to start the users shell");
ssh.disconnect();

} else
{
System.out.println("Authentication fail");
} //end if
}
catch (Exception e) {
e.printStackTrace();
}

Connect to SFTP

public static SshClient getSSHClient(String _host,String username,String password)
{
try
{
ConfigurationLoader.initialize(false);
String hostname = _host;
SshClient ssh = new SshClient();
ssh.connect(hostname,new AlwaysAllowingConsoleKnownHostsKeyVerification());
PasswordAuthenticationClient pwd = new PasswordAuthenticationClient();
pwd.setUsername(username);
pwd.setPassword(password);
// Try the authentication
int result = ssh.authenticate(pwd);
// Evaluate the result
if (result == AuthenticationProtocolState.COMPLETE)
{
return ssh;
}else
{
return null;
}
} catch(Exception ex)
{
System.out.println(ex.getMessage());
return null;
}
}//end function

public static void batchSFTP(String filename) throws Exception
{
SshClient ssh=getSSHClient(host,username,password);
if(ssh==null)
{
System.out.println("Authentication fail");
return;
}
SftpClient sftp=ssh.openSftpClient();
if(sftp==null)
{
System.out.println("Connection fail or no such service!");
return;
}
File file=new File(".");
String current_path=file.getCanonicalPath();
sftp.lcd(current_path);
//Read the command list in filename
Vector vLine=HF.readLine(filename);
for(int i=0;i<vLine.size();i++)
{
String command=(String)vLine.get(i);
System.out.println("The command is:"+command);
CommandParser.runCommand(command,sftp);
}//end for
sftp.quit();
ssh.disconnect();
System.out.println("Finished");
//determine the current path
/*
File file=new File(".");
String current_path=file.getCanonicalPath();
sftp.lcd(current_path);
//sftp.put("run.bat");
sftp.put("cron.rar");
sftp.quit();
ssh.disconnect();
System.out.println("Finished");
*/

}//end function

Full class code of AlwaysAllowingConsoleKnownHostsKeyVerification

I think this part is a bit tricky and it takes me sometimes to figure it out in Internet that we can actually override the class to password the interactive login

package net;

import com.sshtools.j2ssh.transport.ConsoleKnownHostsKeyVerification;
import com.sshtools.j2ssh.transport.InvalidHostFileException;
import com.sshtools.j2ssh.transport.publickey.SshPublicKey;

public class AlwaysAllowingConsoleKnownHostsKeyVerification extends
ConsoleKnownHostsKeyVerification {

public AlwaysAllowingConsoleKnownHostsKeyVerification()
throws InvalidHostFileException {
super();
// Don't not do anything else
}

@Override
public void onHostKeyMismatch(String s, SshPublicKey sshpublickey,
SshPublicKey sshpublickey1) {
try
{
System.out.println("The host key supplied by " + s + " is: " + sshpublickey1.getFingerprint());
System.out.println("The current allowed key for " + s + " is: " + sshpublickey.getFingerprint());
System.out.println("~~~Using Custom Key verification, allowing to pass through~~~");
allowHost(s, sshpublickey, false);
}
catch(Exception exception)
{
exception.printStackTrace();
}
}

@Override
public void onUnknownHost(String s, SshPublicKey sshpublickey) {
try
{
System.out.println("The host " + s + " is currently unknown to the system");
System.out.println("The host key fingerprint is: " + sshpublickey.getFingerprint());
System.out.println("~~~Using Custom Key verification, allowing to pass through~~~");
allowHost(s, sshpublickey, false);
}
catch(Exception exception)
{
exception.printStackTrace();
}
}
}

Download:

Full source code with build script can be downloaded at

http://www.iedmund.com/dbwizard/sshsftp.zip

留言

這個網誌中的熱門文章

Setup Tomcat HTTPS (with JDK 8 to Java 15) in 2 mins

  Setup Tomcat 9 HTTPS/SSL To have a quick view, you may see the video(s): https://www.youtube.com/watch?v=WDGoF13vhZU 1. Generate Keystore I am using JDK 15 to generate the keystore. But the steps are similar with Tomcat 6 + openjdk 8(as I have tried it before writing this doc) Use “keytool” command to create a self-signed certificate. During the keystore creation process, you need to assign a password and fill in the certificate’s details. D:\apache-tomcat-9.0.38\conf>keytool -genkey -alias tomcatks -keyalg RSA -keystore D:\apache-tomcat-9.0.38\conf\tomcatks When enter the passwords during generation, please make sure the two passwords you entered are the SAME. This is the requirement of Tomcat. Here is the abstract from Tomcat installation  Finally, you will be prompted for the key password , which is the password specifically for this Certificate (as opposed to any other Certificates stored in the same keystore file). You MUST use the same password here as was used f...

全港乒乓球錦標賽 09 甲組賽事

今天換個輕鬆一點的題目,看看精彩的乒乓球 我在這裏介紹有個Channel有很清晰的乒乓球比賽片段,是全港乒乓球錦標賽甲組的賽事,其中有高澤禮在香港比賽的最新的片段 ,我相信這種場面很少有機會見到,因為,第一是業餘對專業,我在電視中都未看過,是認真比賽的那一種,不是國家隊奧運完結之後派冠軍來的表演賽,大家放軟手腳逗下逗下的那一種,可觀性高很多,第二,拍攝很有現場感,就算電視台都很少見到這樣的角度,就像親臨現場一樣。 雖然高禮澤貴為國際頂級球員,但落到這場地區賽事的時候都非常認真;雖然他技術高幾班,但認真程度從有球滴死對手時,球証看不清楚,而他正領先下,他都幫忙指証便可看出。 他是港隊中又有善又認真的專業球員,希望給年輕球員有認真對陣高水準球員的機會。 http://www.youtube.com/watch?v=nSo6Kg0vEus (這幾局可能是平均分數最接近的比賽) http://www.youtube.com/watch?v=LTJuYI906AI 還有很多其他攝錄質素很高的片段 謝嘉俊(港隊代表) vs 趙頌熙(港隊少年代表,在港有乒乓神童之稱,曾在11歲時贏得中國全國兒童賽冠軍) http://www.youtube.com/watch?v=zNEG2CzrDMI 謝嘉俊(港隊代表) vs 王德龍 09全港公開乒乓球單項錦標賽 Part 1 http://www.youtube.com/watch?v=OIeSo9V5V-0 趙頌熙(青少年港隊代表) 對 陳嘉耀 09全港公開乒乓球單項錦標賽 決勝局 Part 1 http://www.youtube.com/watch?v=jpaXjLL1bT4 陳文鋒 對 蔡鎮滔 2009全港公開乒乓球單項錦標賽 Part 2 http://www.youtube.com/watch?v=ZdcG8-I0buw&feature=channel_page 或者可以直接溜灠這個channel頻道 http://www.youtube.com/ppball

Files sharing problem between Windows 2003 server host and virtual machine

Regarding VMServer 1.08, when I copy files between a Windows 2003 host and a vm(no matter it is Windows XP or Windows 2003 Server), the following error prompted out arbitrarily, usually for copying large files. First I thought I had solved it by disabling the Jumbo frame and any kind of flow control in network card advance setting. It corrected the problem for most of the cases until I came across a situation to copy a 600MB file, the captioned error "network name is no longer available " prompted out after 10 to 20 seconds. It was not easy to find the solution as there are many cases, with different reasons, having the same symptom, thus I jot it down for a record. 1. Disable Jumbo frame, or any kind of flow control (try disabling Jumbo frame first) 2. Disable Denial of service attack in Windows 2003. Microsoft had acknowledged it has problem by itself in some cases. VMWare Server and "...network name is no longer available..." Did you ever receive following erro...