Search code examples
javarsasftpjsch

SFTP Connection through OPENSSH IdentityFile in Java


I'm developing a Java application that has to store data inside an SFTP.

The test environment has a password authentication, meanwhile the production environment has an authorized OPENSSH key (the standard id_rsa) used as IdentityFile. This means that I have to keep both authentication methods in the same code.

That's how I handled it. Basically, if the identityFile path is not set, it will leverage the password login. Note that all variables come from application.properties:

JSch jsch = new JSch();
jsch.setKnownHosts(knownHosts);

if (!identityFile.equals("")) {
    jsch.addIdentity(identityFile, passphrase);
}
Session jschSession = jsch.getSession(user, host, port);
jschSession.setConfig("StrictHostKeyChecking", "no");

if (identityFile.equals("")) {
    jschSession.setPassword(pass);
    jschSession.setConfig("PreferredAuthentications", "password");
} else {
    jschSession.setConfig("PreferredAuthentications", "publickey");
}
jschSession.connect();
ChannelSftp channelSftp = (ChannelSftp) jschSession.openChannel("sftp");
channelSftp.connect();

I can connect to the test environment but cannot connect to the production SFTP, so I instantiated an SFTP on a development server with (hopefully) the same configurations. I followed this guide.

Connecting to the development SFTP through shell and FileZilla, specifying the IdentityFile, works fine. Connecting to the test SFTP through Java, shell and FileZilla with password, works fine.

Java won't connect using IdentityFile. All I keep getting is com.jcraft.jsch.SftpException: Auth fail on jschSession.connect(), if I use an RSA private key.

Production environment uses an OPENSSH private key, so I cannot convert it. If I use the OPENSSH key, I get invalid privatekey: [B@48c76607 error, on jsch.addIdentity(identityFile). As I've read here, JSch doesn't like OPENSSH keys.

This means that JSch wants an RSA key, but it doesn't connect either. I will think about converting the OPENSSH to RSA later.

I tried running the jar on both Windows and an Ubuntu dockerized VM. The id_rsa file has the right permissions on both systems.

The version of JSch I'm using is jsch-0.1.55.jar. I'm running Java 8.

These are the JSch logs after connecting with an RSA key.

Connecting to <HOST> port <PORT>
Connection established
Remote version string: SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.3
Local version string: SSH-2.0-JSCH-0.1.54
CheckCiphers: aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,3des-ctr,arcfour,arcfour128,arcfour256
CheckKexes: diffie-hellman-group14-sha1,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521
CheckSignatures: ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521
SSH_MSG_KEXINIT sent
SSH_MSG_KEXINIT received
kex: server: curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,sntrup761x25519-sha512@openssh.com,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256
kex: server: rsa-sha2-512,rsa-sha2-256,ecdsa-sha2-nistp256,ssh-ed25519
kex: server: chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com
kex: server: chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com
kex: server: umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1
kex: server: umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1
kex: server: none,zlib@openssh.com
kex: server: none,zlib@openssh.com
kex: server: 
kex: server: 
kex: client: ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1
kex: client: ssh-rsa,ssh-dss,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521
kex: client: aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc,aes192-ctr,aes192-cbc,aes256-ctr,aes256-cbc
kex: client: aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc,aes192-ctr,aes192-cbc,aes256-ctr,aes256-cbc
kex: client: hmac-md5,hmac-sha1,hmac-sha2-256,hmac-sha1-96,hmac-md5-96
kex: client: hmac-md5,hmac-sha1,hmac-sha2-256,hmac-sha1-96,hmac-md5-96
kex: client: none
kex: client: none
kex: client: 
kex: client: 
kex: server->client aes128-ctr hmac-sha1 none
kex: client->server aes128-ctr hmac-sha1 none
SSH_MSG_KEX_ECDH_INIT sent
expecting SSH_MSG_KEX_ECDH_REPLY
Host '<HOST>' is known and matches the ECDSA host key
SSH_MSG_NEWKEYS sent
SSH_MSG_NEWKEYS received
SSH_MSG_SERVICE_REQUEST sent
SSH_MSG_SERVICE_ACCEPT received
Authentications that can continue: publickey
Next authentication method: publickey
Disconnecting from <HOST> port <PORT>

Realistically, there is something missing in my SSH/SFTP configuration, since my app can't connect to SSH on the same server either.

Any help is highly appreciated!


Solution

  • Thanks to @MartinPrikryl and this linked thread, I found a solution. Looks like someone forked the original jsch library and solved these kind of problems. Swapping the Maven dependency from

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

    to

    <dependency>
        <groupId>com.github.mwiede</groupId>
        <artifactId>jsch</artifactId>
        <version>0.2.13</version>
    </dependency>
    

    was enough to solve it. Absolutely no need to refactor code.

    Some considerations

    This library is a thid-party, independent fork from the original jsch. This means it may still have some flaws and they could stop supporting it anytime (just like com.jcraft). Personally, I would have preferred an actual fix, but solving it was too urgent. Plus, this fork allows me to use an OPENSSH key. Using a converted RSA key could have been a problem, since I would avoid touching any of the production environment configurations.