|
|
||
Craig Castelaz's BlogJuly 2004 ArchivesHesitant AcrobatsPosted by castelaz on July 21, 2004 at 12:15 PM | Permalink | Comments (6)
Last week, Daniel Steinberg wrote that he attended a local JUG meeting to hear Bruce Tate speak about his book Better, Faster, Lighter Java. I was fortunate enough to be at the same meeting. Bruce's presentation was interesting, and sparked a fair amount of interaction between him and the audience. Of course, this made the time fly by all too quickly, but Bruce was still able to squeeze in a little time for questions and comments before he had to leave. As Daniel noted in his blog, one of the comments at the end concerned EJB/J2EEs ability to address complex problems. Light-weight techologies are all well-and-good, but complex problems require complex solutions. And in a follow-up remark, the same person held that technologies like Hibernate simply shift complexity, they don't eliminate it. His belief is that it would take it him as long to feel competent with Hibernate as it took him to feel the same with EJBs. Another set of the comments came from a person who identified himself as a maintenance programmer. When something breaks, hes the guy whos responsible for fixing it. In order to do that, he needs access to the code. His primary concern is that technologies such as Hibernate and Spring may hide too much. Hidden code is a barrier to him. He doesnt want to be held responsible for code he cant touch. While I understand and sympathize with these concerns, I believe both sets of comments reflect an all too common desire by programmers to bury themselves in a morass of details. Of course, Im just as guilty as the rest. As I mentioned in my last blog, the first thing I did when I got an assignment to support digest authentication was to sniff the packets going to and from the secured web site. Now, how detail-centric is that? One of the traits of a good programmer is a love of details. but there is a point where it simply gets in the way. Light-weight technologies like JDO, Hibernate, Pico, and Spring are designed to leverage reflection, code generation, and dependency injection. They're intended to not only introduce flexibility into a system, but to also relieve the programmer of a lot of mundane coding. You'll certainly want to dig a bit under the hood to see how they work, but detailed understanding is not required. If you spend too much time examining the giant's shoe size, you'll never have the time to actually climb up to his shoulders. Buried treasure can be found nearly anywherePosted by castelaz on July 14, 2004 at 04:30 AM | Permalink | Comments (4)
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, Id no sooner gotten into the code, trying to recapture yesterdays flow, when the phone rang. The next minute, I was off to my project managers office, no doubt to receive yet another reason to delay my current assignment even more. Now, dont get me wrong. Im not complaining. I happen to have a great project manager. He understands that the to-do list is infinitely expandable, but the workday isnt. He recognizes that if he pulls me from one task to work another, the one left behind isnt 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 didnt 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 components 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 ! | ||
|
|