Acegi security is a natural choice for many enterprise applications built using the Spring framework. JSF (JavaServer Faces) is a Java-based Web application framework that facilitates rapid application development by assembling reusable UI components. As you will learn in this article, it is not hard to secure your JSF applications with Acegi. In fact, you can address most details of authentication and authorization in a Spring application context file.
I'll present a simple Web application example based on the Apache MyFaces JSF implementation. I'll then show you how to use the Spring application context to integrate Acegi's authentication and authorization functionality into the JSF application. You'll see how to implement Acegi's URL-level role-based authorization, and you'll also learn how to implement Acegi's business-layer security using Java 5 annotations.
Note that this article is intended for Java developers already familiar with JavaServer Faces, Acegi, and Spring-based application development. You will be introduced to securing JSF applications with Acegi.
About the sample application
The sample application used for this discussion presents a login page to the user. If the user attempts to log in with the correct user name and password, he is redirected to a page where he may make a purchase. We will use the Acegi security framework to configure the security details that ensure the user's ID has been authenticated, and that his presence on the purchase page is authorized. The user can visit the purchase page if has the role
ROLE_URLACCESS. But making a purchase is a secure business method, so the user will only be able to access the purchase page if he has the role
The application utilizes Acegi's support for Java 5 security annotations, so Java 5 is a pre-requisite for following the example. You will need the JAR files of Acegi, MyFaces, and Spring in your
WEB-INF/lib folder if you want to run the application.
Now let us see how we go about configuring the Spring application context to integrate Acegi and JSF.
Integrating Acegi and JSF
Before attempting to integrate Acegi with JSF, it is important to understand how Acegi works in the Web layer. Acegi uses servlet filters for authentication and authorization. The filters can be chosen and configured in the order in which they need to be executed. The appropriate filter fetches authentication request information such as username and password, and passes this information to Acegi's authentication manager, which is configured as a Spring bean.
The authentication manager contacts an authentication provider to get a
UserDetails object from a
UserDetailsService. If authentication is successful, the user's granted authorities (application-wide permissions) are populated in the returned
UserDetails object. This information is used to build the authentication object, which is then stored in Acegi's security context (which is created by yet another filter). The security context is associated with the current execution thread by the security context holder. The security context is stored as a session attribute and used for authorization checks by Acegi in the Web layer.
I assume you are familiar with basic JSF application development, and so will not describe the steps involved in configuring a JSF application, such as defining the JSF servlet and providing the servlet mapping. I also assume, for the sake of this example, that we have already registered a
ContextLoaderListener to load the Spring application context when the application starts up. Download the sample application code for details.
Assuming that the above configurations are complete, the first step toward integrating Acegi with JSF is to configure Acegi's filters and direct all requests and forwards to be routed through them.
Enabling the Acegi filter chain in web.xml
Instead of registering all the Acegi filters individually in web.xml, you can use Acegi's security filter chain proxy. The Acegi filter chain invokes the filters added to its property list in the Spring context file. Acegi's
FilterToBeanProxy class implements the
javax.servlet.Filter interface; hence its
doFilter() method is invoked by the servlet container when the request for a JSF page is received. This object delegates filter requests to a Spring-managed bean of type
FilterChainProxy that is defined in the Spring bean context.
The configuration in web.xml is as shown in Listing 1.
Listing 1. Configuring the Acegi filter chain
<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>
The mapping in Listing 2 causes the requests and forwards to be routed through Acegi's filter chain proxy.
Listing 2. Mapping requests and forwards to the filter
<filter-mapping> <filter-name>Acegi Filter Chain Proxy</filter-name> <url-pattern>/*</url-pattern> <dispatcher>FORWARD</dispatcher> <dispatcher>REQUEST</dispatcher> </filter-mapping>