Java Web Programming with Eclipse contents
Last modified February 06, 2011 01:47 am

back next

Web Application Security (continued)

Security Filter

Video

Overview

The purpose of the security filter is to enforce authorization policies for the web application. In other words, the security filter makes sure that users only access the resources for which they are authorized.

A servlet filter is a component that is configured to pre-process and post-process requests that are processed by servlets. By placing security code in a servlet filter, we separate security-related code from code that implements application functionality, which adheres to the separation of concerns principle.

Deployment Descriptor

Add the contents of the following code to the deployment descriptor (web.xml).

   <security-constraint>
      <web-resource-collection>
         <web-resource-name>publisher</web-resource-name>
         <url-pattern>/login</url-pattern>
      </web-resource-collection>
      <user-data-constraint> 
         <transport-guarantee>CONFIDENTIAL</transport-guarantee>
      </user-data-constraint>
   </security-constraint>

   <filter>
      <filter-name>security-filter</filter-name>
      <filter-class>publisher.web.SecurityFilter</filter-class>
   </filter>
   <filter-mapping>
      <filter-name>security-filter</filter-name>
      <url-pattern>/*</url-pattern>
   </filter-mapping>

The security-constraint element ensures that access to the login servlet is done over https. (Https is the standard mechanism for providing confidentiality.) The filter element tells the servlet container to pass all requests to the application through the security filter rather than to the target servlet. The security filter then decides whether to pass the request message to the target servlet or redirect the user to the login page.

The Security Filter Class

In the publisher.web package, create a java class called SecurityFilter with the contents of the the following code.

package publisher.web;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;

public class SecurityFilter implements Filter 
{
   private Logger logger = Logger.getLogger(this.getClass());
   public void init(FilterConfig filterConfig) throws ServletException
   {
   }

   public void destroy() 
   {
   }

   public void doFilter(
         ServletRequest request, 
         ServletResponse response,
         FilterChain chain) 
   throws IOException, ServletException 
   {
      logger.debug("doFilter()");
      HttpServletResponse resp = (HttpServletResponse) response;
      HttpServletRequest req = (HttpServletRequest) request;
      String servletPath = req.getServletPath();

      // Allow access to login functionality.
      if (servletPath.equals("/login"))
      {
         chain.doFilter(req, resp);
         return;
      }
      // Allow access to news feed.
      if (servletPath.equals("/news.rss")) {
	chain.doFilter(req, resp);
	return;
      }
      // All other functionality requires authentication.
      HttpSession session = req.getSession();
      Long userId = (Long) session.getAttribute("userId");
      if (userId != null)
      {
         // User is logged in.
         chain.doFilter(req, resp);
         return;
      }
      
      // Request is not authorized.
      resp.sendRedirect("login");
   }   
}

The init method implemented above does nothing but is needed in the code because the it is a method in the Filter interface. All methods in interfaces must be implemented, so we provide a empty method. Similary, we provide an empty implementation of the destroy method.

The web.xml code given earlier configure this filter to process all requests that come into this application. If the user is not logged in, then we will send the user to the login page. In this way, users can not access any application functionality other than the login page until they authenticate themselves to the system.

The doFilter method of the above filter is called for every requested resource. The first thing we do is check to see if the requested resource is for the login page. Requests for the login page should always be honored, so in this case, we permit the request to be processed by the servlet attached to the incoming request by calling doFilter on the chain object. The chain object represents the chain of processors that will be used for the incoming requests. After calling doFilter on the chain object, we return because at this point, the login servlet would have processed the request.

In addition to login requests, we also want to permit requests for the news feed. This allows anyone to view the news feed. What we want to restrict is access to the functionality that allows users to create, edit and delete news items.

If the request is not for login and not for the news feed, then we need to check to see if the user is logged in. We do this be looking to see if the user's id is stored in the session. If the user's id is in the session, we allow the request to be processed by calling doFilter on the chain object. If the user's id is not in the session, then we redirect the browser to the login page.

Test

Stop and start the publisher application and then perform the following tests with a fresh browser instance.

  1. Verify that login and logout functions work correctly.
  2. After doing a logout, try to access a protected resource without logging in. For instance, try to access http://localhost:8080/publisher/home. Verify that the application redirects you to the login page rather than sending you the home page. If it appears that you can still access a protected resource, then the browser is presenting to you a cached version of the web page. To see that this is the case, click on the reload button of the browser and see that you are redirected to the login page.

back next

Copyright 2007-2009 David Turner and Jinseok Chae. All rights reserved.