Friday, March 14, 2008

SFTP in Java with JSch Using Private Key Authentication

JSch is an excellent library for ssh in Java. One bad thing is that there is no real documentation - or rather, the source itself is the documentation. And the good news is of course that the source code is available along with a nice collection of examples.

I recently had to use SFTP from a Java application and it did take some source-diving to figure out exactly how it works (specifically to get the parameters for JSch.addIdentity right). It turned out to be rather straight-forward:

...

private void execute() throws JSchException, SftpException {
JSch jSch = new JSch();
final byte[] prvkey = readMyPrivateKeyFromFile(); // Private key must be byte array
final byte[] emptyPassPhrase = new byte[0]; // Empty passphrase for now, get real passphrase from MyUserInfo

jSch.addIdentity(
"myusername", // String userName
prvkey, // byte[] privateKey
null, // byte[] publicKey
emptyPassPhrase // byte[] passPhrase
);
Session session = jSch.getSession("myusername", "hostname.com", 22);
UserInfo ui = new MyUserInfo(); // MyUserInfo implements UserInfo
session.setUserInfo(ui);
session.connect();
Channel channel = session.openChannel("sftp");
ChannelSftp sftp = (ChannelSftp) channel;
sftp.connect();

final Vector files = sftp.ls(".");
for (Object obj : files) {
// Do stuff with files
}
sftp.disconnect();
session.disconnect();
}

...

The MyUserInfo class must implement the UserInfo interface. There are a number of good examples of this in the jsch distribution.

17 comments:

Unknown said...

Another handy SFTP applet in Java is Loelink. It used JScape. [www.loelink.com] A big advantage is that I don't have to install anything!

Niels Sthen Hansen said...

Hi T,

It actually looks like a really neat sftp client!

The application I was working on was server side with no gui so in our case jsch was more appropriate. But thank you for your comment and for the link.

Unknown said...

Hi, Can you post the contents of readMyPrivateKeyFromFile(). I am having trouble passing the byte stream to the addIdentity. Keep coming back with java.lang.ArrayIndexOutOfBoundsException. I am using jsch-0.1.42.

Niels Sthen Hansen said...

Hi RaviShankar,

Its been a while since I posted this and I seem to have misplaced the original source from back then.

As far as I remember readMyPrivateKeyFile() simply used FileUtils.readFileToByteArray() (from commons-io, http://commons.apache.org/io/).

Do you get the exception when reading the file or when you are passing it to jsch? Also, have you verified that the key file works, e.g. by using it from a command line ssh -i keyfile user@host ?

Andi said...

removing files on the sftp-server does not work. Also renaming files does not work too.

Any ideas please???

Andy

Niels Sthen Hansen said...

Hi Andy
Have you made sure that your sftp user has sufficient permissions to remove the file? Also, what kind of error message/exception are you getting ?

Unknown said...

Hi,
I'm getting "invalid private key" error when I use

jSch.addIdentity( "myusername",prvkey,null,emptyPassPhrase);

I have both private & public keys available and even pass both but still same error.

What I would like to understand is the purpose of "myusername". Is this the actual username used to connect to server, right? B'cos I checked the code & it is just used to report error.

I'm able to SCP file from command prompt, but from code I can't even connect to remote server.

I don't have password. All I have is User Id, Host, Private & Public keys (generated using Putty).

Can you please help me in resolving this issue?

Niels Sthen Hansen said...

Hi Geminine

It is true that the "myusername" in addIdentity is never sent to server. It is used only in reporting and as an identifier in the internal IdentifyFile collection in JSch.

The "myusername" in jSch.getSession("myusername", "hostname.com", 22) is the one that is being used in the authentication.

It is quite puzzling that you cannot even connect to the server from your code.

The things that I can think of off the top of my head (which you probably already thought of yourself, but anyway...) are:
- Do you use the correct username/host in jSch.getSession ?
- Is your ssh server using port 22 ?
- How are you reading the private key file? Is the private key at any point being converted to a java.lang.String ?
- Do you have a passphrase on your private key? And if so, how are you passing it to jsch (read from file, String constant in code or something else?)

Unknown said...

Hi

I am tryint to SFTP a file programmatically without any prompt.
I have the following credentials
servername,username and password.
However when I try connecting, the programs stops for a while and then gives the error as follows
11:12:55,356 ERROR [GSIFTPFeedTransporter] JSchException occured...
com.jcraft.jsch.JSchException: connection is closed by foreign host

Any inputs into this.
Thanks in advance!

Ansu

Niels Sthen Hansen said...

Hi AJ

It looks like a socket timeout. Can you connect to the server with command line ssh/sftp from the same machine ?

Unknown said...

Hi
I am trying to use Jsch for SFTP ing a file to a server. Following is the code:
JSch jsch = new JSch();
Session session = jsch.getSession(getUsername(), getServerName(), getPort());

UserInfo ui = new FTPUserInfo(getPassword());

Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);

session.setUserInfo(ui);
session.connect();

However i get the following error

com.jcraft.jsch.JSchException: Auth cancel


Any ideas why its happening?

Thanks

Unknown said...

Hi Niels,
I am working on the JSch SFTP implementation in Java with authentication using public and private key pair.
I am getting the error of invalid private key which I see most of the Jsch SFTP users have reported.I see that Jsch library cannot handle private key of the format extension .ppk(putty private key).
Looks like .ppk format is the general format of private key.
Do you have any solution in using .ppk extension file.
Please respond soon if possible.

Thanks.

Regards,
Sandeep

Niels Sthen Hansen said...

Hi Sandeep,

I believe that PuTTYgen can convert a .ppk file to OpenSSH format (http://the.earth.li/~sgtatham/putty/0.60/htmldoc/Chapter8.html#pubkey-puttygen). Have you tried to do this ?

I think the main (only?) difference in the .ppk and openssh is a set of header lines above the encoded key content, so it should not be too difficult to write a converter if you need to be able to use arbitrary .ppk files on the fly.

Sharath said...

Hi Sandeep,
do not use a *.ppk for SFTP; use a *.key file generated for your private key (*.ppk).

Try this it may help.

Unknown said...

Thanks! Useful post.

Unknown said...

Hi,

I am unable to get .ZIP files from a sftp server. The get method is throwing the error but it just gives java.lang.exception 4:

Any idea what could be the issue?

Thanks,
Sandeep

RockIng on Life said...

if ur getting auth fail error,
then take the putty gen private key and convert it to open ssh format by using import functionality of putty gen.Then use this open ssh format file in java code instead of private key. and also use pass phrase by putting in a file and read as byte array. use it in addIdentity(String,bytearrayof ssh format file,null,byte array of passphrase file)

use proper userid,hostname and port no


This is working