Acegi Security in one hour

A concise guide to securing your Java Web applications

Acegi Security has been generating some serious positive buzz among Java enterprise developers, so you might be wondering how it works. In this article, ShriKant Vashishtha walks you through all the steps of a hands-on Acegi Security implementation. First you'll set up form-based authentication and authorization services for a Java-based Web application, then you'll customize Acegi Security for dynamic authorization, as well as integration with proprietary authentication implementations such as LDAP.

Acegi Security is a powerful and flexible security solution for Java enterprise applications built using the Spring framework. Spring-based dependency injection makes Acegi easy to configure and implement in a completely nonintrusive way. This is a boon to organizations that might not want to implement the Spring framework as a whole but still need effective, reusable security for legacy applications.

This article gives you a concise jump-start to implementing Acegi Security for a basic order-processing application. You'll set up authentication and authorization services for the application, and you'll implement those security features in form-based Web pages. After working through the example, you should be able to set up basic form-based security for any Web application in about an hour.

Following a quick introduction to the implementation example, you'll learn about some of the ways you can customize application security using Acegi. You'll see how to set up dynamic role-based authorization based on a database that maps user roles to URLs. Finally, you'll find out how to create a custom Acegi Security authentication implementation that can integrate with existing proprietary authentication implementations.

Environment setup

I wanted to demonstrate Acegi's applicability to a wide range of implementations, not just Spring-based applications. I built the example application using JEE 5, with JavaServer Pages for the presentation layer and SiteMesh for Web layout. The application could just as easily be built using Struts 2, and the Struts 2 infrastructure is already in place in the source code, though not implemented. I used Spring dependency injection to implement Acegi security for the application. See the Resources section to download the application source code. Follow these steps to set up the application environment:

Step 1. Download Acegi, Spring 2, and SiteMesh (see Resources for download links).

Step 2. Create the following folder structure in a Java project:

src - Contains Java source code

test - Contains test cases

config - Any property/XML configuration file that needs to be inside the classpath

web - Contains the Web application

|

decorators - Contains SiteMesh decorators

images - Contains images, if any

scripts - JavaScript files

styles - Cascading Style Sheets (CSS)

WEB-INF

|

jsp - Contains JavaServer Pages files (JSPs)

lib - Contains JARs

Step 3. Copy the following JAR files into the WEB-INF/lib directory:

  • acegi-security-1.0.5.jar - Main classes of the Acegi Security system
  • cglib-2.1.3.jar - Code-generation library used by Spring
  • commons-codec-1.3.jar - Encoders and decoders such as Base64, Hex, Phonetic, and URLs
  • commons-lang-2.1.jar - Helper utilities for java.lang APIs
  • ehcache-1.2.3.jar - Used for basic caching purposes
  • freemarker-2.3.8.jar - Used by the Struts implementation
  • jstl.jar, standard.jar - JavaServer Pages Standard Tag Library (JSTL) tag library
  • log4j-1.2.13.jar - For logging
  • ognl-2.6.11.jar - OGNL library used by the Struts implementation
  • sitemesh-2.3.jar - SiteMesh JAR
  • spring.jar - Spring Framework JAR
  • struts2-core-2.0.8.jar - Struts 2 core JAR
  • xwork-2.0.3.jar - Used by Struts

Changes to web.xml

Because Acegi Security is based on the concept of servlet filters and interceptors, you need to add entries for the FilterToBeanProxy filter to your application's web.xml deployment descriptor, as shown in Listing 1.

Listing 1. Adding servlet filters to web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
  version="2.4">
  <display-name>AcegiTraining</display-name>
  <context-param>

    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext*.xml</param-value>
  </context-param>
  <filter>
    <filter-name>Acegi Filter Chain Proxy</filter-name>

    <filter-class>
      org.acegisecurity.util.FilterToBeanProxy
    </filter-class>
    <init-param>
      <param-name>targetClass</param-name>
      <param-value>

        org.acegisecurity.util.FilterChainProxy
      </param-value>
    </init-param>
  </filter>
  ...
  ...
  <filter-mapping>
    <filter-name>Acegi Filter Chain Proxy</filter-name>

    <url-pattern>/j_acegi_security_check</url-pattern>
  </filter-mapping>
  <filter-mapping>
    <filter-name>Acegi Filter Chain Proxy</filter-name>
    <url-pattern>/j_acegi_logout</url-pattern>

  </filter-mapping>
  <filter-mapping>
    <filter-name>Acegi Filter Chain Proxy</filter-name>
    <url-pattern>*.action</url-pattern>
  </filter-mapping>

  <filter-mapping>
    <filter-name>Acegi Filter Chain Proxy</filter-name>
    <url-pattern>*.jsp</url-pattern>
  </filter-mapping>
  ...

</web-app>

FilterToBeanProxy requires an initialization parameter, targetClass. The targetClass parameter locates the first object of the specified class in the application context. In the configuration in Listing 1, that class is org.acegisecurity.util.FilterChainProxy. The related bean object in the application context is filterChainProxy, shown in Listing 2.

Listing 2. filterChainProxy

<bean id="filterChainProxy"
 class="org.acegisecurity.util.FilterChainProxy">  
  <property name="filterInvocationDefinitionSource">
    <value>
  ...
    </value>

  </property>
</bean>

Notice that Listing 1 defines multiple filter mappings for the Acegi filter. You could instead get away with using a more general filter mapping, as shown in Listing 3.

Listing 3. A general filter mapping

<filter-mapping>
    <filter-name>Acegi Filter Chain Proxy</filter-name>

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

However, if you use the filter mapping in Listing 3, each and every URL is intercepted by the Acegi filter. And the filter now requests authorization details for static resources (JavaScript, CSS, HTML, and images) too, which you may not want to secure. You can avoid this trap by using specific URL patterns.

Order is essential when placing servlet filters. Because the example application uses filters for Acegi, JSP, and SiteMesh, you need to place the Acegi filter first, followed by the JSP and SiteMesh filters, respectively.

1 2 3 4 5 6 7 Page 1