Showing posts with label Servlet. Show all posts
Showing posts with label Servlet. Show all posts

Sunday, November 7, 2010

Logging HttpServletRequests

Motivation

Whereas observing ServletResponses is non-trivial, Sun Oracle makes it much easier to observe HTTP requests via the ServletRequestListener interface. ServletRequestListeners are awesome; they make it super easy to record and log requests, thereby improving the undestandability of your web applications. Recording and logging ServletRequests with a listener is preferable to doing that same work in the requested resource (Servlet, JSP, etc.) since the former strategy achieves an improved separation of concerns.

Implementation

Big-Oh Software's CommonWeb Framework provides RequestObserverListener, an abstract implementation of the ServletRequestListener interface that can be extended to observe ServletRequests in myriad meaningful ways. That abstract implementation of the listener interface collaborates with the ObservedHttpServletRequest class, which adapts an original ServletRequest into an object that is more easily observed, recorded and logged.

An Example: Servlet Request Logging

Using the RequestObserverListener to log incoming Servlet requests is shamefully easy. Only a few lines of Java and XML are needed:

package foo.bar;

import net.big_oh.common.web.listener.request.*;

public class MyRequestLoggerListener extends RequestObserverListener
{

 @Override
 protected void doOnServletRequestInitialized(ObservedServletRequest observedServletRequest)
 {
  System.out.println(observedServletRequest);
 }

}
... and ...
<!-- web.xml snippet -->

<listener>
  <listener-class>foo.bar.RequestLoggerListener</listener-class>
</listener>

By applying the above logging listener to a web application, you'll see that new ServletRequests are logged in this format:
Received a HTTP/1.1 request from localhost (127.0.0.1) for resource http://127.0.0.1:8080/CommonWeb/ (GET) -- jSessionId: B46435C89F9FABCE571AF701E0BC6820 -- userName: unknown

Sunday, October 17, 2010

Observing HttpServletResponses

Motivation

Filters are a great way to observe (or even modify) the response generated for an HTTP request. This post will present a handy application of the observer pattern from within a Java web Filter, allowing developers to monitor responses to HTTP requests as they are constructed.

Implementation

The response observer filter I want to describe is part of Big-Oh Software's CommonWeb Framework. That framework defines a ResponseObserver interface that models the events that transpire while constructing the response to an HTTP request. A simple, abstract filter class, ResponseObserverFilter, serves as the base class for (potentially) many filters that observe those events.

An Example: Response Size Monitor Filter

Because the abstract ResponseObserverFilter utilizes the observer pattern, we can use it to define many useful, concrete filters without having to write much code. For example, it is quite easy to create a ResponseSizeMonitorFilter that announces the size of the response generated for an HTTP request.

Applying the ResponseSizeMonitorFilter to the servlets in your web application is a simple matter of including the snippet below in your web.xml file:

<!-- web.xml snippet -->

<filter>
  <filter-name>ResponseSizeMonitorFilter</filter-name>
  <filter-class>net.big_oh.common.web.impl.ResponseSizeMonitorFilter</filter-class>
</filter>

<filter-mapping>
  <filter-name>ResponseSizeMonitorFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

The ResponseSizeMonitorFilter will now log the size of HTTP responses in the following format:
The response for the requested url (http://127.0.0.1:8080/CommonWeb/ImageServlet) contained about 4.09 kilobytes.

Sunday, August 1, 2010

Declarative Container Managed Authentication

Motivation

For web applications that provide dynamic content tailored to individual users, authentication is an important concern. Authentication confirms that a user is, indeed, who they claim to be. As a result, (web) applications employ authentication to confirm the identities of users and protect privileged resources.

The Java Servlet specification supports declarative authentication, which eases the implementation of a web application's authentication strategy. By using declarative authentication, web developers simply declare that some or all of the application's resources are protected. Web developers are liberated from the burden of writing code that describes how those security constraints are enforced.

This tutorial provides a quick overview for web developers who want to take advantage of the Servlet specification's support of declarative authentication. The tutorial covers both container-agnostic elements of the web.xml file that support declarative authentication, as well as some authentication-related features of the Tomcat servlet container.

Securing Web Resources Declaratively

The web.xml file is the first stop on the way to adding declarative authentication to a web application. In that file, we'll want to declare what type of authentication should be used. By appropriately configuring a <login-config> element, we can tell the servlet container what query method should be used when authenticating users. Several options are available, though form-based authentication is the most common.

<login-config>
  <auth-method>FORM</auth-method>
  <form-login-config>
    <form-login-page>
      /WEB-INF/pages/login.jsp?info=login
    </form-login-page>
    <form-error-page>
      /WEB-INF/pages/login.jsp?info=login_failed
    </form-error-page>
  </form-login-config>
</login-config>

The <login-config> element above tells the servlet container how it should authenticate users for the related web application. Next we need to tell the servlet container which resources in the web application require that the user be authenticated.

<security-constraint>
  <web-resource-collection>
    <web-resource-name>Secured Resources</web-resource-name>
    <description>
      Only logged in users should be able to visit the 
      resources in this collection.
    </description>
    <url-pattern>/command/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
    <role-name>user</role-name>
  </auth-constraint>
  <user-data-constraint>
    <transport-guarantee>NONE</transport-guarantee>
  </user-data-constraint>
</security-constraint>

<security-role>
    <role-name>user</role-name>
</security-role>

The <security-constraint> element above provides a trivial example in which all URLs that map to the pattern "/command/*" are secured so that they may only be accessed by authenticated users in the "user" role.

Defining a JDBCRealm

All of the authentication-related configuration that we did above in the web.xml file is highly portable since that file will be packaged and deployed with our web application. Notice, however, that the configuration work we did in web.xml isn't sufficient by itself to support declarative authentication. Specifically, we've not yet told the Servlet container where and how to access the web application's list of valid users with related passwords.

This is where we have to delve into some container-specific details. By default, the Tomcat servlet container will attempt to authenticate by reading the user names and passwords defined in its $CATALINA_HOME/conf/tomcat-users.xml file. Obviously, this is not very convenient if we intend to use a relational database to store information about our web application's users.

Thankfully, it's easy to configure Tomcat to read from a relational database instead of the tomcat-users.xml file when authenticating users. To do so, we'll need to configure a new Realm, which is Tomcat's generic term for a collection of information about users.

<Realm 
    className="org.apache.catalina.realm.JDBCRealm"
    driverName="org.postgresql.Driver"
    connectionURL="jdbc:postgresql://localhost:5432/YourDatabaseName"
    connectionName="your_db_username" 
    connectionPassword="your_db_password"
    userTable="user_table_name" 
    userNameCol="user_name_column_name" 
    userCredCol="user_password_column_name"
    userRoleTable="uesr_role_table_name" 
    roleNameCol="role_name_column_name" />

The <Realm> element defined above tells Tomcat how it can use a relational database to authenticate users.

Configuring Web Application Context

In the section above we saw how to define a <Realm> element that instructs Tomcat to employ our relational database when authenticating users. One final consideration remains: where should we place that <Realm> definition? A single Tomcat server can host multiple web applications. Presumably each of those web applications may want to use a different database to authenticate its users. As a result, we should locate our <Realm> element within the <Context> element for our web application so that the Realm applies only to our web application.

A good way to include a <Realm> element within the web application's <Context> is to include a META-INF/context.xml file in our web application. By defining a <Realm> element within such a file, we can ensure that the application will use the appropriate relational database for authentication, regardless of which Tomcat server it is deployed to.

Granting Security Privileges

One final, useful note is that we may need to augment the security constraints for our application server if we want it to use an external relational database for user authentication. For the Tomcat Servlet container, we can add an entry to the $CATALINA_HOME/config/catalina.policy file.

grant {
    permission java.net.SocketPermission "localhost:5432", 
    "connect,resolve";
};    

The above statement grants permission for any class in the servlet container to lookup and connect to our database, which runs on the localhost at port 5432.