Inconsistency between Servlet specification implementations
I’ve been playing around with the various implementations of the security features in Servlet 2.3 compatible web containers. If you’ve ever built secure web applications, you’ll know that there are a handful of fairly useful methods on the HttpServletRequest interface. For example, the getUserPrincipal() method allows you to get access to the authenticated principal, as described by the following Javadoc.
Returns a java.security.Principal object containing the name of the current authenticated user. If the user has not been authenticated, the method returns null.
The reason that I've been looking into all this in detail is that I'm trying to get my open source blogging software (Pebble) to work consistently between vendor implementations. In the webapp, I have a collection of unsecured pages and a collection of secured pages that are defined to fall within a security constraint that is declared in the
web.xml file. As stated the by Servlet specification, trying access a secured resource will force the user to be authenticate themselves. The problem that I've come across is that those security methods that I mentioned before work inconsistently between implementations.
For example, on Tomcat and Resin, a call to the
getUserPrincipal() method returns a non-null
Principal instance at any time after authentication, regardless of whether a request has been made for a secured or unsecured resource. However, with other implementations such as JBoss and Jetty, the
getUserPrincipal() method only returns a non-null instance if the request is for a secured resource. What this means is that after authentication, you cannot consistently tell from that method whether the current user has been authenticated or not. Tomcat/Resin will report yes, while JBoss/Jetty will report no.
This issue first came up because a few people have deployed my blogging webapp onto JBoss and were reporting that they could not see some of the "admin" links that appear on the top of every page after logging in. Having delved through the Servlet specification and accompanying Javadoc, I'm still not sure who has correctly implemented this particular feature. A workaround to this is fairly straightforward, and just requires that the user's credentials are saved away in the session, using something like the following:
// some J2EE web containers don't allow programmatic access to the
// principal information from resources that don't fall under a
// security constraint - for this reason this information is placed into
// the user's session
AuthenticatedUser user = new AuthenticatedUser();
Regardless of the workaround, this does present some interesting questions. Which implementation is correct? What happens when the specification is unclear? Are the Javadocs considered as a part of the specification? After all, they are a programming contract and included in the specification itself. In this case, my opinion is that Tomcat and Resin are correct because the important point is that the user has been authenticated. What do you think, and what do you think would happen if all the implementations were put through the J2EE compatibility tests? Deploying to a certified implementation is my next step and should guarantee consistency. Perhaps making the compatibilty test kits free to open source implementations would help in situations like this, removing doubt as to what is correct.