[SalesForce] SOAP API Connection through proxy with authentication [407 – Proxy Authentication required]

I am following the documentation to connect to SOAP API through a proxy.

String proxyUsername = "";
String proxyPassword = "";
String username = "";
String password = "";
String endpoint = "https://test.salesforce.com/services/Soap/u/37.0";
String proxyHost = "";
int proxyPort = 0;

System.setProperty("http.proxyHost", proxyHost);
System.setProperty("http.proxyPort", Integer.toString(proxyPort));
System.setProperty("https.proxyHost", proxyHost);
System.setProperty("https.proxyPort", Integer.toString(proxyPort));
Authenticator.setDefault(new Authenticator() {
    @Override
    public PasswordAuthentication getPasswordAuthentication()
    {
        return new PasswordAuthentication(proxyUsername, proxyPassword.toCharArray());
    }
});
ConnectorConfig partnerConfig = new ConnectorConfig();
partnerConfig.setUsername(username);
partnerConfig.setPassword(password);
partnerConfig.setAuthEndpoint(endpoint);
partnerConfig.setProxy(proxyHost, proxyPort);
partnerConfig.setProxyUsername(proxyUsername);
partnerConfig.setProxyPassword(proxyPassword);
PartnerConnection partner = new PartnerConnection(partnerConfig);

This has thrown:

com.sforce.ws.ConnectionException: Failed to send request to
https://test.salesforce.com/services/Soap/u/37.0 at
com.sforce.ws.transport.SoapConnection.send(SoapConnection.java:121)
at
com.sforce.soap.partner.PartnerConnection.login(PartnerConnection.java:770)
Caused by: java.io.IOException: Unable to tunnel through proxy. Proxy
returns "HTTP/1.0 407 Proxy Authentication Required" at
sun.net.www.protocol.http.HttpURLConnection.doTunneling(Unknown
Source) at
sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown
Source) at
sun.net.www.protocol.http.HttpURLConnection.getOutputStream0(Unknown
Source) at
sun.net.www.protocol.http.HttpURLConnection.getOutputStream(Unknown
Source) at
sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(Unknown
Source) at
com.sforce.ws.transport.JdkHttpTransport.connectRaw(JdkHttpTransport.java:136)
at
com.sforce.ws.transport.JdkHttpTransport.connectLocal(JdkHttpTransport.java:100)
at
com.sforce.ws.transport.JdkHttpTransport.connectLocal(JdkHttpTransport.java:95)
at
com.sforce.ws.transport.JdkHttpTransport.connect(JdkHttpTransport.java:91)
at
com.sforce.ws.transport.SoapConnection.send(SoapConnection.java:95)

I debugged the JdkHttpTransport class on Salesforce and it seems to set the proxy but this throws such an exception. I am able to connect through the Rest API though. The soap trace clearly states that it is setting the properties:

WSC: Creating a new connection to
https://test.salesforce.com/services/Soap/u/37.0 Proxy = HTTP @
/x.x.x.x:portname username username

Has anyone found a solution to this issue?

Best Answer

This is quite messy as force-wsc is supposed to handle the authenticated proxy but unfortunately it doesn't. Much worse fact is that dataloader - a similar tool for Apex written in Java works with proxy while wsc is riddled with issues and bugs for proxies. A workaround would be to incorporate a class similar to HttpClientTransport from the dataloader repository and add this line if proxy is enabled:

partnerConfig.setTransport(HttpClientTransport.class);

This should be handling authenticated proxy. However, the need is authenticated proxy for all the API connections (SOAP, Bulk, Metadata, etc.) but this covers only for SOAP. The bulk connection is not equipped with authenticated proxy as it uses HttpURLConnection class. I verified this fact with the dataloader.

For Bulk connection, there isn't much of a choice than to rewrite the BulkConnection class. Extend the class and overwrite the doHttpGet() method. Recommended way is to use Apache's HttpClient libraries instead of the HttpURLConnection class. I haven't analyzed the same solution for Metadata connection yet.

It is appalling that a library that is widely used is broken with respect to a feature for so many years.