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!
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.
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.