Getting through a firewall via proxy
Bear Giles | October 1, 2010Corporate firewalls. sigh. But sometimes our applications have to get past a firewall. How do you do it?
The best solution is to let somebody else do it. If you’re using HttpComponents (HttpClient was renamed with version 4) it already has support for proxies in the HostConfiguration object. The library is designed to work it so you should just set up the configuration and be done with it.
Sometimes you can’t let somebody else do it. For instance you could be reading a naked stream. This isn’t HTTP at all but these services often sit on port 80 since that port is let through firewalls. A library like HttpComponents/HttpClient might look tempting but it’s not the answer.
So how do you get through the proxy firewall yourself?
The first step is to identify the type of proxy firewall you’re dealing with. All require that you connect to the proxy, most require you to also authenticate yourself. But you might get lucky and only need to solve the first half of the problem.
Proxy connection
The easiest way to set up a proxy connection is to set two (or three) System properties:
- http.proxyHost
- http.proxyPort
- http.nonProxyHosts (‘|’ separated list with ‘*’ wildcards)
You can set these properties programmatically or via the command line. You can only have one default proxy though – something that may not be acceptable to you.
- System.setProperty("http.proxyHost", proxyHost);
- System.setProperty("http.proxyPort", proxyPort);
- URL url = new URL(destination);
- URLConnection conn = url.openConnection();
- conn.connect();
System.setProperty("http.proxyHost", proxyHost); System.setProperty("http.proxyPort", proxyPort); URL url = new URL(destination); URLConnection conn = url.openConnection(); conn.connect();
A slightly more difficult approach is to create a Proxy object that is passed to the URL connection.
- Proxy proxy = new Proxy(Proxy.Type.HTTP,
- new InetSocketAddress(proxyHost, proxyPort));
- URL url = new URL(destination);
- URLConnection conn = url.openConnection(proxy);
- conn.connect();
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort)); URL url = new URL(destination); URLConnection conn = url.openConnection(proxy); conn.connect();
This approach begs a question – where do you create the Proxy? There’s a solution to this since Java 5 – the ProxySelector class. It provides a list of Proxies for a specified URL. You need to create your own ProxySelector and register it as the default ProxyServer but that should be straightforward.
The application code must still know to retrieve a Proxy from the selector but there is no longer a need for that code to know the details of that Proxy.
- Proxy proxy = ProxySelector.getDefault().select(url.toURI());
- URLConnection conn = url.openConnection(proxy);
- conn.connect();
Proxy proxy = ProxySelector.getDefault().select(url.toURI()); URLConnection conn = url.openConnection(proxy); conn.connect();
Authentication
The classic way to handle http proxy firewall authentication is to set a request header.
- Proxy proxy = ProxySelector.getDefault().select(url.toURI());
- HttpURLConnection conn = (HttpURLConnection) url.openConnection(proxy);
- conn.connect();
- String encodedUserPwd = Base64.encodeBase64String("user:password".getBytes();
- conn.setRequestProxy("Proxy-Authorization", "Basic " +_ encodedUserPwd);
- InputStream is = conn.getInputStream();
Proxy proxy = ProxySelector.getDefault().select(url.toURI()); HttpURLConnection conn = (HttpURLConnection) url.openConnection(proxy); conn.connect(); String encodedUserPwd = Base64.encodeBase64String("user:password".getBytes(); conn.setRequestProxy("Proxy-Authorization", "Basic " +_ encodedUserPwd); InputStream is = conn.getInputStream();
A second approach is to provide a default authenticator that will be used on all connections.
- Authenticator.setDefault(new Authenticator() {
- protected PasswordAuthentication getPasswordAuthentication() {
- return new PasswordAuthentication(username, password.toCharArray());
- }
- });
Authenticator.setDefault(new Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(username, password.toCharArray()); } });
If we need to provide multiple authentications we must provide a local implementation of Authenticator that overrides the various static methods to
More info: http://www.rgagnon.com/javadetails/java-0085.html