4

I have a Java application that is trying to access a web service via http proxy. The Java app is 3rd party app for which we don't have access to source code.

Its launch can be configured by passing Java launch parameters among other things. I am wondering what are the java properties that one can pass so that the app can use the logged in user's NTLM credentials to authenticate proxy connections?

When I passed https.proxyHost and https.proxyPort (i.e. -Dhttps.proxyHost=abcd ... to jvm command line), I do see difference in the logs. Now it fails with message below.

[WrapperSimpleAppMain] [AuthChallengeProcessor] ntlm authentication scheme selected 
INFO   | jvm 5    | 2015/06/03 14:49:25 | 2015-06-03 14:49:25,380 
INFO [WrapperSimpleAppMain] [HttpMethodDirector] No credentials available for NTLM <any realm>@proxy.ins.dell.com:80 
INFO  | jvm 5    | 2015/06/03 14:49:25 | Exiting due to fatal exception. 
INFO   | jvm 5    | 2015/06/03 14:49:25 | com.atlassian.bamboo.agent.bootstrap.RemoteAgentHttpException: HTTP status code 407 received in response to fingerprint request

I tried passing http.proxyUser and http.proxyPassword. That didn't work. I am wondering what the right configuration is to make a Java app transparently use proxy info without having to make code changes.

Thanks

videoguy
  • 1,732
  • 2
  • 24
  • 49

3 Answers3

5

Finally I figured out by trial and error. Passing java.net.useSystemProxies=true along with https.proxyPort, https.proxyHost resolved this.

Basically the java vm command line got

-Djava.net.useSystemProxies=true -Dhttps.proxyPort=80 -Dhttps.proxyHost=proxyserver.mycompany.com

I didn't have to pass https.proxyUser, https.proxyPassword. I believe proxy authentication used the same credentials as my login NTLM credentials.

videoguy
  • 1,732
  • 2
  • 24
  • 49
  • Using only `-Djava.net.useSystemProxies=true` was sufficient for me. The proxy's host and port where read from the enviroment. – ixe013 Oct 06 '17 at 16:38
  • 1
    ADDITIONALLY: Keep an eye on changes done between jdk 1.8.0_025 and jdk 1.8.0_144! If your proxy uses basic authentication it seems as if you have to set the property `jdk.http.auth.tunneling.disabledSchemes` to an empty string - or remove "basic" from it! The jdk default is to NOT USE basic authentication here! Just add something like `-Djdk.http.auth.tunneling.disabledSchemes=""` as a jvm-option to allow (all) authentication types. – eventhorizon Jan 23 '18 at 12:01
3

One also needs to specify NT domain for NTLM authnetication to work.

-Dhttp.proxyUser=MyDomain/username

or by setting

-Dhttp.auth.ntlm.domain=MyDomain

And you also MUST explicitly instruct HttpClient to take system properties into account, which it does not do by default

 CloseableHttpClient client = HttpClients.createSystem();

or

 CloseableHttpClient client = HttpClients.custom()
     .useSystemProperties()
     .build();
ok2c
  • 26,450
  • 5
  • 63
  • 71
  • I tried all those properties. It didn't work. I don't have access to the source code of the tool to force it to use system properties. – videoguy Jun 18 '15 at 19:03
  • Settings all these properties has no effect if the client has not been explicitly instructed to take them into account (as shown above). If the application in question does not provide you with a way to customize HttpClient configuration you are out of luck – ok2c Jun 19 '15 at 08:49
2

A working example with Apache HttpClient 4.5.*

Note: It does not work unless you use HttpClients.custom().useSystemProperties().build();

System.setProperty("http.proxyHost" , "myhost");
System.setProperty("http.proxyPort" , "myport");
System.setProperty("http.proxyUser" , "myuser");
System.setProperty("http.proxyPassword" , "mypassword");

CloseableHttpClient httpclient = HttpClients.custom().useSystemProperties().build();

try {

HttpGet httpGet = new HttpGet("http://www.google.com");

CloseableHttpResponse httpResponse = httpclient.execute(httpGet);

    try {
        System.out.println(httpResponse.getStatusLine());
        for (Header header : response.getAllHeaders()) {
            System.out.println("header " + header.getName() + " - " + header.getValue());
        }

        String responseString = EntityUtils.toString(httpResponse.getEntity());
        System.out.println("responseString :" + responseString);

    } finally {
        response.close();
    }
} catch (Exception exception) {
    exception.printStackTrace();
} finally {
    httpclient.close();
}

Instead of using System.setProperty you can set the properties with

-Dhttp.proxyHost="myhost" -Dhttp.proxyPort="myport" -Dhttp.proxyUser=myuser -Dhttp.proxyPassword="mypassword"

Important: If you try to access a HTTPS service you have to change the properties to https It also does not work if you use https.* properties and you access a http URL

System.setProperty("https.proxyHost" , "myhost");
System.setProperty("https.proxyPort" , "myport");
System.setProperty("https.proxyUser" , "myuser");
System.setProperty("https.proxyPassword" , "mypassword");

CloseableHttpClient httpclient = HttpClients.custom().useSystemProperties().build();

try {
    HttpGet httpGet = new HttpGet("https://www.google.com");

API: https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/

Pure Java - without Apache HttpClient

You can set the same https.proxyHost etc properties if you use the java.net.HttpURLConnection class

Always respect using https.proxyHost etc for https://... connections and http.proxyHost etc for http://... connections!

String uri = "https://www.google.com/";
HttpURLConnection connection = (HttpURLConnection) new URL(uri).openConnection();

InputStream response = connection.getInputStream();

BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));

String inputLine; int x = 0;

while ((inputLine = in.readLine()) != null) {
    System.out.println(inputLine);
    x++; if (x > 4) { break;}
}
in.close();
response.close();
Andreas Panagiotidis
  • 2,763
  • 35
  • 32