Authenticated HTTP proxy with Java

206,675

Solution 1

(EDIT: As pointed out by the OP, the using a java.net.Authenticator is required too. I'm updating my answer accordingly for the sake of correctness.)

(EDIT#2: As pointed out in another answer, in JDK 8 it's required to remove basic auth scheme from jdk.http.auth.tunneling.disabledSchemes property)

For authentication, use java.net.Authenticator to set proxy's configuration and set the system properties http.proxyUser and http.proxyPassword.

final String authUser = "user";
final String authPassword = "password";
Authenticator.setDefault(
  new Authenticator() {
    @Override
    public PasswordAuthentication getPasswordAuthentication() {
      return new PasswordAuthentication(authUser, authPassword.toCharArray());
    }
  }
);

System.setProperty("http.proxyUser", authUser);
System.setProperty("http.proxyPassword", authPassword);

System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");

Solution 2

You're almost there, you just have to append:

-Dhttp.proxyUser=someUserName
-Dhttp.proxyPassword=somePassword

Solution 3

http://rolandtapken.de/blog/2012-04/java-process-httpproxyuser-and-httpproxypassword says:

Other suggest to use a custom default Authenticator. But that's dangerous because this would send your password to anybody who asks.

This is relevant if some http/https requests don't go through the proxy (which is quite possible depending on configuration). In that case, you would send your credentials directly to some http server, not to your proxy.

He suggests the following fix.

// Java ignores http.proxyUser. Here come's the workaround.
Authenticator.setDefault(new Authenticator() {
    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
        if (getRequestorType() == RequestorType.PROXY) {
            String prot = getRequestingProtocol().toLowerCase();
            String host = System.getProperty(prot + ".proxyHost", "");
            String port = System.getProperty(prot + ".proxyPort", "80");
            String user = System.getProperty(prot + ".proxyUser", "");
            String password = System.getProperty(prot + ".proxyPassword", "");

            if (getRequestingHost().equalsIgnoreCase(host)) {
                if (Integer.parseInt(port) == getRequestingPort()) {
                    // Seems to be OK.
                    return new PasswordAuthentication(user, password.toCharArray());  
                }
            }
        }
        return null;
    }  
});

I haven't tried it yet, but it looks good to me.

I modified the original version slightly to use equalsIgnoreCase() instead of equals(host.toLowerCase()) because of this: http://mattryall.net/blog/2009/02/the-infamous-turkish-locale-bug and I added "80" as the default value for port to avoid NumberFormatException in Integer.parseInt(port).

Solution 4

Most of the answer is in existing replies, but for me not quite. This is what works for me with java.net.HttpURLConnection (I have tested all the cases with JDK 7 and JDK 8). Note that you do not have to use the Authenticator class.

Case 1 : Proxy without user authentication, access HTTP resources

-Dhttp.proxyHost=myproxy -Dhttp.proxyPort=myport

Case 2 : Proxy with user authentication, access HTTP resources

-Dhttp.proxyHost=myproxy -Dhttp.proxyPort=myport -Dhttps.proxyUser=myuser -Dhttps.proxyPassword=mypass

Case 3 : Proxy without user authentication, access HTTPS resources (SSL)

-Dhttps.proxyHost=myproxy -Dhttps.proxyPort=myport 

Case 4 : Proxy with user authentication, access HTTPS resources (SSL)

-Dhttps.proxyHost=myproxy -Dhttps.proxyPort=myport -Dhttps.proxyUser=myuser -Dhttps.proxyPassword=mypass

Case 5 : Proxy without user authentication, access both HTTP and HTTPS resources (SSL)

-Dhttp.proxyHost=myproxy -Dhttp.proxyPort=myport -Dhttps.proxyHost=myproxy -Dhttps.proxyPort=myport 

Case 6 : Proxy with user authentication, access both HTTP and HTTPS resources (SSL)

-Dhttp.proxyHost=myproxy -Dhttp.proxyPort=myport -Dhttp.proxyUser=myuser -Dhttp.proxyPassword=mypass -Dhttps.proxyHost=myproxy -Dhttps.proxyPort=myport -Dhttps.proxyUser=myuser -Dhttps.proxyPassword=mypass

You can set the properties in the with System.setProperty("key", "value) too.

To access HTTPS resource you may have to trust the resource by downloading the server certificate and saving it in a trust store and then using that trust store. ie

 System.setProperty("javax.net.ssl.trustStore", "c:/temp/cert-factory/my-cacerts");
 System.setProperty("javax.net.ssl.trustStorePassword", "changeit");

Solution 5

For Java 1.8 and higher you must set

-Djdk.http.auth.tunneling.disabledSchemes=

to make proxies with Basic Authorization working with https along with Authenticator as mentioned in accepted answer

Share:
206,675
Andre Pastore
Author by

Andre Pastore

Computer Scientist Distributed Systems Architect & Engineer Software Engineer python, java, javascript, perl, bash, ... developer former-CTO Event Driven mindset Functional teams seeker Looking for diverse and multicultural leadership

Updated on February 17, 2020

Comments

  • Andre Pastore
    Andre Pastore about 4 years

    How can I configure the username and password to authenticate a http proxy server using Java?

    I just found the following configuration parameters:

    http.proxyHost=<proxyAddress>
    http.proxyPort=<proxyPort>
    https.proxyHost=<proxyAddress>
    https.proxyPort=<proxyPort>
    

    But, my proxy server requires authentication. How can I configure my app to use the proxy server?

  • divinedragon
    divinedragon over 11 years
    I too got the response with the code snippet. But when I set the wrong values for password, if the request went through the proxy, it should say Connection refused. I got the output in that case as well. How can I verify if the requests are being sent via the proxy???
  • Carl Smotricz
    Carl Smotricz over 10 years
    @Pascal: I think you meant those last 2 lines to set proxyHost and proxyPort, not proxyUser and proxyPassword, as the latter are already established by the Authenticator. Or am I missing something?
  • user207421
    user207421 about 10 years
    @divinedragon It shouldn't say 'connection refused'. It's not even possible. The connection was accepted by TCP, to the proxy, which then failed your authentication. At that point it is impossible for the proxy to generate a connection refusal.
  • Andreas Panagiotidis
    Andreas Panagiotidis over 7 years
    You do not have to add the Authenticator. For me, with Java 7 and Java 8 it enough to set the http.* properties.
  • Michael Paesold
    Michael Paesold about 7 years
    I can confirm that using the Authenticator class is not required on JDK 7 or 8. Just use -D<proto>.proxyUser= and -D<proto>.proxyPassword=.
  • R. Karlus
    R. Karlus almost 7 years
    The properties "http.proxyUser" and "http.proxyPassword" are not obligatory. You're specifying the Authenticator for the JVM. So, you can remove those configurations.
  • Stefan Haberl
    Stefan Haberl almost 5 years
    For 2019 (JDK7+) this is the correct answer. The only thing missing to be totally complete is the no-proxy settings: To bypass your proxy for certain domains use -Dhttp.nonProxyHosts=*.mydomain.com|localhost. Note, that this setting is used for both HTTP and HTTPS. More info at the official documentation
  • Lonzak
    Lonzak almost 5 years
    And the schemes must be empty?
  • Youssef NAIT
    Youssef NAIT over 4 years
    Isn't it better to create the PasswordAuthentication outside of the anonymous class and return it in getPasswordAuthentication, this will prevent creating a new object each time the proxy authentication is required.
  • jonenst
    jonenst about 4 years
    It doesn't work on linux using oracle jdk 'ava version "1.8.0_231"' or "java version "11.0.5" 2019-10-15 LTS" Downvoted as I suppose that something else is happening during the reported working tests. (is it something windows specific?)
  • dimeros
    dimeros over 3 years
    Correct, the basic authentication is introduced after java8_111 by default installation. In this case, the Authenticator is needed.
  • Hokkyokusei
    Hokkyokusei about 3 years
    Mannn, this really saved my day. Thanks for posting this amazing answer. God Bless you.
  • res
    res almost 2 years
    This answer made me realize something obvious but that I wasn't seeing, nor was finding in other answers: http.proxyHost and https.proxyHost are different things!!! setting a "HTTP proxy" does not work with a "HTTPS URL call"