sshj icon indicating copy to clipboard operation
sshj copied to clipboard

Http Proxy using CustomSocketFactory in SSHJ fails

Open PriyankaSureshMS opened this issue 3 years ago • 2 comments
trafficstars

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!

PriyankaSureshMS avatar Nov 15 '22 14:11 PriyankaSureshMS

For an example of how a custom SocketFactory works, have a look at: https://github.com/hierynomus/sshj/commit/fc535a5e76c6a729a191ef7dec5c4bd9aa0006aa

hierynomus avatar Nov 15 '22 21:11 hierynomus

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);

quantumferret avatar Jan 06 '23 11:01 quantumferret