Skip to main content

Buried treasure can be found nearly anywhere

Posted by castelaz on July 14, 2004 at 4:30 AM PDT

It started as a typical morning. I was three days behind schedule on a one day project, but hoping to finish it by late afternoon. Of course, I’d no sooner gotten into the code, trying to recapture yesterday’s flow, when the phone rang. The next minute, I was off to my project manager’s office, no doubt to receive yet another reason to delay my current assignment even more.

Now, don’t get me wrong. I’m not complaining. I happen to have a great project manager. He understands that the to-do list is infinitely expandable, but the workday isn’t. He recognizes that if he pulls me from one task to work another, the one left behind isn’t going to magically complete itself. His attitude keeps us both sane. Besides, I like variety, and enjoy having several projects to switch to when I grow stale on one.

Sure enough, I did indeed get a new assignment. I had to write code to login to a web site protected by digest authentication. Fortunalely, I had worked on a fairly large and reasonably sophisticated authentication/authorization component in the past, and was familiar with the various web login methods. While I had never actually implemented digest authentication before, I had some understanding of how it worked. So, after meeting with one of our network administrators, who helped me setup a secured site, we did a bit of packet sniffing of the digest authenticated site we just created. The packet exchange pretty much matched my general understanding of how authentication process worked, and it didn’t look like it would be all that difficult to implement.

Fortunately, before writing any code, my innate laziness asserted itself, if laziness can ever assert itself, and I took a little time to look for something I could use as a starting point. Things were looking pretty grim, until I hit upon Jakarta Commons’ HttpClient. While Simon Brown has already blogged on this same subject, HttpClient - another great Jakarta Commons component, his discussion was limited to the component’s Post method. Additionally, HttpClient is such a useful gem, it bears mentioning again-and-again.

As I just said, HttpClient is part of the Jakarta Commons. The primary goal of the Commons is to create and maintain a repository of reusable Java components which are free and open source. Although I haven't had a wide exposure to all the components the Commons offers, the ones I have used have been a real pleasure. This was particularly true for HttpClient. Unlike a lot of open source, HttpClient has a fairly extensive User Guide, and between it and a few samples, I was able to put together a digest authentication method in relatively short order. Certainly, faster than I would have been able to write a bare-bones, untested implementation myself.

public void access(HttpURL httpURL) throws Exception {
try {
String siteUsername = httpURL.getUser();
String sitePassword = httpURL.getPassword();
HttpClient client = new HttpClient();
if ((siteUsername != null ) && (sitePassword != null)) {
client.getState().setCredentials("Realm", jnlpURL.getHost(),
                            new UsernamePasswordCredentials(siteUsername, sitePassword));
}
HttpMethod method = new GetMethod(httpURL.getURI());
try {
int statusCode = client.executeMethod(method);
String statusStr = HttpStatus.getStatusText(statusCode);
if (statusStr.equalsIgnoreCase("unauthorized")) {
throw new Exception("Not authorized for realm");
}
if (statusStr.equalsIgnoreCase("not found")) {
throw new Exception("Webapp and/or file not found");
}
doSomethingUseful(method.getResponseBodyAsStream());
method.releaseConnection();
}
catch (HttpRecoverableException hre) {
throw new Exception("Exception '" + hre.toString() + "');
}
catch (UnknownHostException uhe) {
throw new Exception("Exception '" + uhe.toString() + "');
}
}
catch (URIException urie) {
throw new Exception("Exception '" + urie.toString() + "');
}
catch (IOException e) {
throw new Exception("Exception '" + e.toString() + "');
}
}

There really isn't much to say about the code. The HttpURL object passed into the access method can be based upon a URL which has an embedded username and password. If you've never seen the syntax for such a URL, http://craig:foobar@host.com/webapp has an embedded username of craig and password of foobar. If the username and password are available, the access method establishes credentials based upon the username and password pulled from the URL. It then performs a standard HTTP GET. This is where the authentication magic occurs. Without going into a lot of detail, the web server detects the presence of the credentials and attempts to authenticate the client. If all goes well, and the credentials are accepted, the client is silently admitted to the protected site. The various status checks and exception catches throughout the access method are there to give you an indication of what can go wrong.

The only warning I need to give regarding the authentication process is that the password needs to be digested prior to being embedded in the URL. Since the site is protected by digest authentication, it stands to reason that the password needs to be digested before being transmitted to the web server. The encryption of the password is typically based the MD5 Digest. A short article explaining Java 2 Security with sample code using MD5 can be found at Java security evolution and concepts, Part 2.

Compared to all that I would have had to write, HttpClient saved me a considerable amount of time and grief. Jakarta Commons offers many other useful components. Check it out !

Related Topics >>