sshj
sshj copied to clipboard
Http Proxy using CustomSocketFactory in SSHJ fails
My Java 7 application needs to connect to a remote SFTP server via HTTPS proxy. As per the depprecated method for connect via proxy in SocketClient, I created a custom javax.net.SocketFactory which creates a Socket(using java.net.Socket#Socket(java.net.Proxy) ) to the remote SFTP server and injected the SocketFactory into the SocketClient.
Code snippet :
SSHClient client = new SSHClient();
client.addHostKeyVerifier(new PromiscuousVerifier());
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort));
Authenticator.setDefault(new Authenticator() {
@Override
public PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(proxyUser, proxyPassword.toCharArray());
}
});
final SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
Socket socket = new Socket(proxy);
SocketAddress socketAddress=new InetSocketAddress(InetAddress.getLoopbackAddress(),0);
// binding the socket with the inetAddress and port number
socket.bind(socketAddress);
// connect() method connects the specified socket to the server
socket.connect(new InetSocketAddress(sftpHost, sftpPort));
factory.createSocket(socket, socket.getInetAddress().getHostName(), socket.getPort(), true);
client.setSocketFactory(factory);
KeyProvider keyProvider = client.loadKeys(sftpPrivateKeyPath, sftpPrivateKeyPassprhase);
client.authPublickey(sftpUser, keyProvider);
I could connect to the remote SFTP server via the proxy but the public key authentication fails with the error that the socket is not connected. Its because the 'socket' instance in SSHClient is not initialised via client.connect(..)
Caused by: java.rmi.RemoteException: ; nested exception is: java.lang.IllegalStateException: Not connected at net.schmizz.sshj.SSHClient.checkConnected(SSHClient.java:823) at net.schmizz.sshj.SSHClient.auth(SSHClient.java:216) at net.schmizz.sshj.SSHClient.authPublickey(SSHClient.java:342) at net.schmizz.sshj.SSHClient.authPublickey(SSHClient.java:360)
I tried to call client.connect(sftpHost, sftpPort) but this is trying to create a new socket using the SocketFactory ignoring the proxy configuration. Could there be some way to inject the 'socket' itself so that the lib uses custom socket with proxy settings?
Many Thanks in advance for a quick feedback!
For an example of how a custom SocketFactory works, have a look at: https://github.com/hierynomus/sshj/commit/fc535a5e76c6a729a191ef7dec5c4bd9aa0006aa
I don't know if this works at all with Java 7, but on the off chance that this will help you (or others), here's a very bare-bones custom SocketFactory that works with Java 8.
import javax.net.SocketFactory;
import java.io.IOException;
import java.net.*;
public class ProxySocketFactory extends SocketFactory {
private Proxy proxy;
public ProxySocketFactory(String proxyHost, int proxyPort) {
this.proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort));
}
@Override
public Socket createSocket() throws IOException {
return new Socket(proxy);
}
@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
throw new UnsupportedOperationException();
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
throw new UnsupportedOperationException();
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
throw new UnsupportedOperationException();
}
}
Using it with SSHJ:
SSHClient client = new SSHClient(config);
if (useProxy) {
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(proxyUser, proxyPassword.toCharArray());
}
});
ProxySocketFactory proxySocketFactory = new ProxySocketFactory(proxyAddress, proxyPort);
client.setSocketFactory(proxySocketFactory);
}
client.connect(hostName, port);