The first three parts of this article series introduce you to using Acegi Security System to secure Java enterprise applications:
- Part 1 explains how to use Acegi's built-in filters to implement a simple URL-based security system.
- Part 2 shows how to write an access-control policy, store it in an LDAP directory server, and configure Acegi to interact with the LDAP server to implement the policy.
- Part 3 shows how to use Acegi to secure access to Java class instances in your enterprise applications.
This fourth installment demonstrates how to use Acegi to secure JavaServer Faces (JSF) applications that run in a servlet container. This article first explains the features Acegi provides for this purpose and dispels some common misconceptions about using Acegi with JSF. This article then presents a simple web.xml file that you can use to deploy Acegi to secure a JSF application. From there, go deep inside Acegi and JSF components to understand the sequences of events that happen when you deploy the web.xml file and when users access the JSF application. The article concludes by presenting a sample JSF application secured by Acegi.
Think back to this series' first sample Acegi application (see the section "A simple Acegi application" in Part 1). That application uses Acegi to provide the following security features:
- Present a login page whenever an unauthenticated user tries to access a protected resource.
- Redirect an authorized user directly to the required protected resource.
- Present an access-denied page if the user is not authorized to access the protected resource.
Recall that you don't need to write any Java code to get these features. You only need to configure Acegi. You should be able to implement the same features from Acegi in a JSF application without writing any Java code.
Some other writers seem to suggest that integrating Acegi with JSF requires the JSF application to serve the login page (see Resources). This isn't true. It is Acegi's responsibility to serve the login page whenever required. It is also Acegi's responsibility to make sure that the login page is served only once during a secure session. Authenticated and authorized users can then access a protected resource without performing the login procedure repeatedly.
If you use JSF to serve the login page, two main problems occur:
- You don't leverage Acegi's capability to serve the login page whenever
required. You must write Java code to implement all the logic to serve the login
- You must write at least some Java code to hand over user credentials (username and password) from JSF's login page to Acegi.
Acegi is intended to be an alternative to writing Java security code. Using JSF to serve the login page defeats this purpose and initiates a host of other JSF-Acegi integration problems, all of which are due to the fact that Acegi is meant to provide configurable security. If you try to use JSF to do some of Acegi's work, you'll run into trouble.
The rest of this article explains and demonstrates that you can develop JSF applications independently of Acegi and later configure Acegi to secure your JSF applications — without writing any Java code. Let's start by looking at a web.xml file that you can deploy to secure your JSF applications.
Listing 1 shows a web.xml file (often called a deployment descriptor) you can use to deploy Acegi for the purpose of securing JSF applications running inside a servlet container (such as Apache Tomcat):
Listing 1. The web.xml file to deploy Acegi and JSF in a servlet container
<?xml version="1.0"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/acegi-config.xml</param-value> </context-param> <context-param> <param-name>javax.faces.STATE_SAVING_METHOD</param-name> <param-value>server</param-value> </context-param> <context-param> <param-name>javax.faces.CONFIG_FILES</param-name> <param-value>/WEB-INF/faces-config.xml</param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <listener> <listener-class> com.sun.faces.config.ConfigureListener </listener-class> </listener> <!-- Faces Servlet --> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup> 1 </load-on-startup> </servlet> <!-- Faces Servlet Mapping --> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.faces</url-pattern> </servlet-mapping> <!-- Acegi filter configuration --> <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> <!-- Acegi Filter Mapping --> <filter-mapping> <filter-name>Acegi Filter Chain Proxy</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
Note that Listing 1 contains the following tags:
Read on to learn the purpose of each of these tags in a JSF-Acegi application.
<context-param> tag in
Listing 1 defines a parameter that either Acegi or JSF
requires during startup or execution. The first parameter —
— defines the location of Acegi's XML configuration file.
javax.faces.CONFIG_FILES parameters are required by
specifies whether you prefer to store JSF page-view state on the client or the
server. The default behavior of Sun's JSF reference implementation is to store JSF
views on the server.
javax.faces.CONFIG_FILES parameter specifies the
addresses of configuration files that JSF requires. The details of JSF
configuration files are beyond this article's scope. (See
Resources for links to material covering this topic.)
Now look at the two
<listener> tags in
<listener> tags define listener classes
that listen to and handle certain events that occur during the startup and
execution of a JSP or a servlet application. Examples include:
- The servlet container creates a new servlet context while starting a JSP or
servlet application. This event fires every time a JSP or servlet application
- The servlet container creates a new servlet request object. This event occurs
every time the container receives an HTTP request from a client.
- A new HTTP session has been established. This event occurs when a requesting
client establishes an HTTP session with the servlet container.
- A new attribute has been added to servlet context, servlet request, and HTTP
- An existing attribute of the servlet context, servlet request, or HTTP session objects has been modified or deleted.
<listener> tag is like an
extensibility mechanism that allows applications running inside servlet containers
to do processing in conjunction with certain events. The servlet specification
defines several interfaces that listener classes implement in order to handle
For example, the Spring Framework implements a servlet interface named
javax.servlet.ServletContextListener. The spring class
that implements this interface is named
Note that it is the listener class in Listing 1's first
Similarly, JSF implements a class named
implements several event-listening interfaces. You can find the
ConfigureListener class in the second
<listener> tag in
This article later explains the different event-listener interfaces and the processing performed inside Acegi and JSF event-listener classes (see "Starting up a JSF-Acegi application" and "Processing a request for an Acegi-protected JSF page").
Now look at the
<filter> tag in
Listing 1. Servlet applications use filters to pre-process
incoming requests before the requested servlet can process them. Acegi uses
servlet filters to authenticate users before request processing.
Notice from the
<filter> tag in
Listing 1 that its
<filter-class> child specifies a class
FilterToBeanProxy class is part of Acegi. The class
implements an interface named
which is part of the servlet specification. The
javax.servlet.Filter interface has a method named
doFilter(), which the servlet container calls upon
receipt of a request.
Also note that Listing 1's
<filter> tag has another child tag named
<init-param> tag specifies the parameters
required to instantiate the
You can see from Listing 1 that the
FilterToBeanProxy class needs just one parameter, which
is an object of a class named
FilterChainProxy class represents the entire chain of
Acegi filters that discusses in
(see the "Security Filters" section). The
doFilter() method uses the
FilterChainProxy class to execute the chain of Acegi's
<filter-mapping> tag in
Listing 1 specifies the request URLs that invoke Acegi's
FilterToBeanProxy. I have simply mapped all the JSF
pages to Acegi's
FilterToBeanProxy. This means that the
doFilter() method automatically gets control whenever a
user tries to access a JSF page.
<servlet> tag in a web.xml file
specifies the servlet (a JSF servlet, in this case) that you wish to invoke from a
specific URL. The
defines the URL. Almost all JSP or servlet applications contain these two tags, so
there's no need to discuss them here. (See Resources for
links to material that discusses servlet programming in general.)
You've now seen all the tags the web.xml file needs in order to deploy Acegi to secure your JSF applications. You understand how listeners, filters, and servlets coordinate with one another. As you can guess from this discussion, if you deploy the web.xml file in Listing 1 in a servlet container, both Acegi and JSF try to do some processing on two occasions:
- When you start up your application
- When your application receives a request for a JSF page
The next two sections explain the sequence of events that occurs in each of these instances.
Figure 1 shows the sequence of events that happens when a JSF-Acegi application starts up:
Figure 1. Sequence of events when a JSF-Acegi application starts
In detail, the sequence of events shown in Figure 1 is as follows:
- The servlet container instantiates all listeners configured in the web.xml
- The servlet container registers Acegi's
ContextLoaderListeneras a listener class, which implements an interface named
ServletContextListenerinterface contains two important methods:
contextInitialized()method gains control whenever a servlet context is initialized.
- Similarly, the
contextDestroyed()method is called along with destruction of the servlet context when the application exits.
- The servlet container registers JSF's
ConfigureListeneras another listener. JSF's
ConfigureListenerimplements a number of listener interfaces, such as
ServletRequestAttributeListener. You've already seen the
ServletContextListenerinterface's methods. The remaining interfaces are:
ServletContextAttributeListener, which contains three methods:
attributeReplaced(). Respectively, these methods gain control whenever an attribute is added to the servlet context, removed from the servlet context, or replaced by a new attribute. The
attributeReplaced()method gains control in step 8 of the processing a request for an Acegi-protected JSF page sequence.
ServletRequestListener, which contains methods that gain control whenever a new servlet request object is created or deleted. The servlet request object represents and wraps a request from a user.
ServletRequestAttributeListener, which contains methods that gain control whenever an attribute of the request object is added, deleted, or replaced. This article later discusses the processing that JSF's
ConfigureListenerperforms when a new servlet request object is created in step 3 of the processing a request for an Acegi-protected JSF page sequence.
- The servlet container creates a servlet context object, which wraps
application resources (such as JSP pages, Java classes, and application
initialization parameters) and enables the entire application to access the
resources. All other components of your JSF-Acegi application (listeners,
filters, and servlets) store information about application resources in the form
of attributes in the servlet context object.
- The servlet container notifies Acegi's
ContextLoaderListenerthat the servlet context is initialized by calling
contextInitialized()method parses Acegi's configuration file, creates a Web application context for the JSF-Acegi application, and instantiates all the security filters as well as Java beans configured in the Acegi configuration file. These filter objects are later used in authentication and authorization when your JSF application receives a request from a client. (See the discussion of Web application context creation that accompanies Figure 1 in Part 3.)
- The servlet container notifies JSF's
ConfigureListenerabout the initialization of the servlet context by calling its
contextInitialized()method checks all the JSF managed beans configured in JSF configuration files to ensure that the Java classes exist against each of the beans.
- The servlet container checks the web.xml file for any filters configured. For
example, the web.xml file in Listing 1 contains an Acegi
FilterToBeanProxy, which the servlet container instantiates, initializes, and registers as a filter. Acegi is now ready to process incoming requests for authentication and authorization.
- The servlet container instantiates the faces servlet, which starts listening for incoming requests from users.
The next section explains the sequence of events that occurs when your JSF-Acegi application receives a request from a user.
You've learned how to configure Acegi to secure a JSF application. You've also seen the sequence of events that take place when you start up a JSF-Acegi application. This section describes how JSF and Acegi components work within the framework of a servlet container when a user sends a request for an Acegi-secured JSF page.
Figure 2 illustrates the sequence of events that happen when a client sends a request for a JSF page protected by Acegi:
Figure 2. JSF and Acegi working together to serve a JSF page
In detail, the sequence of events shown in Figure 2 is as follows:
- The servlet container creates a servlet request object representing the
- Recall from step 3 of the
starting up a JSF-Acegi application sequence that JSF's
ServletRequestListenerinterface. This means that
ConfigureListenerlistens for events related to the creation and deletion of servlet request objects. Therefore, the servlet container invokes the
requestInitialized()method prepares to execute the JSF life cycle for the request. The preparation includes checking whether a faces context exists for the request. The faces context wraps information about application resources that the faces servlet will later require to execute the JSF life cycle. The faces context is missing if this request is the first of a new session. In this case, the
requestInitialized()method creates a new faces context.
- The servlet container checks whether the user's request accompanies any state
information. If the servlet container finds no state information, it assumes
that the request is the first of a new session and creates an HTTP session
object for the user. If the servlet container finds that the request contains
some state information (such as a cookie or some state information in the URL),
it restores the user's previous session based on the session information it
- The servlet container matches the request URL with the URL pattern contained
<url-pattern>child in the deployment descriptor. If the request URL matches the URL pattern, the servlet container invokes Acegi's
FilterToBeanProxy, registered as a servlet filter in step 9 of Figure 1.
FilterChainProxyclass to execute the entire chain of Acegi's security filters. Acegi's filters automatically check the HTTP session object created in step 4 to see whether the requesting client is already authenticated. If Acegi finds that the user is not authenticated, it serves the login page. Otherwise it goes directly through the authorization process that described in the "Configuring the interceptor" section of Part 2.
- Acegi updates the servlet context with session information for the
- The servlet container notifies the
attributeReplaced()method of JSF's
ConfigureListenerthat the servlet context has been updated. The
ConfigureListenerchecks if any of JSF's beans have been changed. If it finds any changes, it updates the faces context accordingly. However, in this case, Acegi does not change any of JSF's managed beans during authentication, so
ConfigureListenerdoes no processing during this call.
- If the authorization process succeeds, control is transferred to the faces servlet, which executes the JSF life cycle and serves a response back to the user.
Now that you know how JSF and Acegi work together to serve a JSF request, it's time to see JSF and Acegi in action.
The download included with this article (see Download) contains a sample JSF-Acegi application named JSFAcegiSample that demonstrates simple integration of Acegi with JSF. The sample application uses the web.xml file in Listing 1.
To deploy the sample application, follow the two steps in the "Deploy and run the application" section of Part 1. You also need to download and unzip jsf-1_1_01.zip from Sun's JSF site (see Resources). Copy all the files you find in jsf-1.1.X.zip into the WEB-INF/lib folder of your JSFAcegiSample application.
You can invoke the sample application by accessing http://localhost:8080/JSFAcegiSample from your browser. The JSFAcegiSample application displays an index page that contains links to protected resources and a login page. All protected pages are developed using JSF components, whereas Acegi serves the login page and performs authentication and authorization.
In this article, you've learned how to configure Acegi to secure JSF applications. You've also learned in detail how JSF and Acegi components work together within the framework of a servlet container. Finally, you tried running a sample JSF-Acegi application.
There's still some more ground to cover on the subject of implementing Acegi security for JSF applications. The next article in this series will demonstrate how to use Acegi to secure access to JSF's managed beans.
|Source code for this article||j-acegi4-source.zip||15KB||HTTP|
Java applications with
Acegi series: Get an introduction to using Acegi Security System to secure Java
- "Securing Java applications with Acegi, Part 1: Architectural overview and security filters" (Bilal Siddiqui, developerWorks, March 2007): This article introduces you to the architecture and components of Acegi Security System.
- "Securing Java applications with Acegi, Part 2: Working with an LDAP directory server" (Bilal Siddiqui, developerWorks, May 2007): This article demonstrates the working of directory servers with Acegi.
- "Securing Java applications with Acegi, Part 3: Access control for Java objects" (Bilal Siddiqui, developerWorks, September 2007): This article demonstrates access control for Java objects.
Acegi Security System: The Acegi Web
site is your first stop for reference documentation.
"JSF and Acegi": This
entry on MyFaces WIKI on JSF-Acegi integration talks about using JSF beans to
secure JSF applications.
"Another Faces in your Face: Acegi/JSF solution addendum"
(Tony L. Kerz, Fair Trade Java Stack Blog, February 2006) and
"Integrating Acegi with JSF"
(Victor Tatai, sometimes i feel like screaming..., October 2005): Blog entries
that discuss strategy for integrating Acegi with JSF.
"ACEGI JSF Components hit the stores"
(Cagatay Civici's Weblog, January 2006): This blog entry discusses developing JSF
components for authentication and authorization using Acegi.
Apache MyFaces forum:
See the discussion thread about the use of custom JSF tags for JSF-Acegi
"Story of a Servlet: An Instant Tutorial"
(Mark Andrews, java.sun.com): Learn servlet programming.
"Getting started with JavaServer Faces 1.2"
(Richard Hightower, developerWorks, December 2007 and January 2008): Get up to
speed quickly with the latest JSF version in this two-part tutorial.
"Acegi Security System for Spring Framework, Part 1"
Security System for Spring Framework, Part 2":
Check out this presentation on Acegi security.
"Using JSF technology for XForms applications"
(Faheem Khan, developerWorks, February 2005): This tutorial explains the JSF life
cycle in detail.
- Browse the
for books on these and other technical topics.
developerWorks Java technology zone:
Find hundreds of articles about every aspect of Java programming.
Get products and technologies
JavaServer Faces Technology:
Download the JSF implementation from Sun's Web site.
Acegi Security System:
Bilal Siddiqui is an electronics engineer, an XML consultant, and the co-founder of WaxSys, a company focused on simplifying e-business. After graduating in 1995 with a degree in electronics engineering from the University of Engineering and Technology, Lahore, he began designing software solutions for industrial control systems. Later, he turned to XML and used his experience programming in C++ to build Web- and Wap-based XML processing tools, server-side parsing solutions, and service applications. Bilal is a technology evangelist and a frequently-published technical author.