Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Securing Java applications with Acegi, Part 4: Protecting JSF applications

Configurable security for JavaServer Faces applications

Bilal Siddiqui (xml4java@yahoo.co.uk), Freelance consultant, WaxSys
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.

Summary:  Bilal Siddiqui continues his series by showing you how to use Acegi to secure Java™Server Faces (JSF) applications. Configure JSF and Acegi to work together in a servlet container, and explore how JSF and Acegi components cooperate with one another.

View more content in this series

Date:  19 Feb 2008
Level:  Intermediate PDF:  A4 and Letter (295 KB)Get Adobe® Reader®
Also available in:   Chinese  Russian

Activity:  23256 views
Comments:  

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.

Adding security without writing Java code

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.

Clearing up misconceptions

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 page.

  • 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.


Deploying Acegi to secure a JSF application

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:

  • Three <context-param> tags
  • Two <listener> tags
  • A <filter> tag
  • A <servlet> tag
  • A <servlet-mapping> tag
  • A <filter-mapping> tag

Read on to learn the purpose of each of these tags in a JSF-Acegi application.

Supplying context parameters to Acegi and JSF

Each <context-param> tag in Listing 1 defines a parameter that either Acegi or JSF requires during startup or execution. The first parameter — contextConfigLocation — defines the location of Acegi's XML configuration file.

The javax.faces.STATE_SAVING_METHOD and javax.faces.CONFIG_FILES parameters are required by JSF. The javax.faces.STATE_SAVING_METHOD parameter 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.

The 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.)

Configuring listeners for Acegi and JSF

Now look at the two <listener> tags in Listing 1. <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 starts.

  • 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 session objects.

  • An existing attribute of the servlet context, servlet request, or HTTP session objects has been modified or deleted.

The <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 events.

For example, the Spring Framework implements a servlet interface named javax.servlet.ServletContextListener. The spring class that implements this interface is named org.springframework.web.context.ContextLoaderListener. Note that it is the listener class in Listing 1's first <listener> tag.

Similarly, JSF implements a class named com.sun.faces.config.ConfigureListener, which implements several event-listening interfaces. You can find the ConfigureListener class in the second <listener> tag in Listing 1.

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").

Configuring and mapping servlet filters

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 named org.acegisecurity.util.FilterToBeanProxy. The FilterToBeanProxy class is part of Acegi. The class implements an interface named javax.servlet.Filter, 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>. The <init-param> tag specifies the parameters required to instantiate the FilterToBeanProxy class. You can see from Listing 1 that the FilterToBeanProxy class needs just one parameter, which is an object of a class named FilterChainProxy. The FilterChainProxy class represents the entire chain of Acegi filters that discusses in Part 1 (see the "Security Filters" section). The FilterToBeanProxy class's doFilter() method uses the FilterChainProxy class to execute the chain of Acegi's security filters.

The <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 FilterChainProxy doFilter() method automatically gets control whenever a user tries to access a JSF page.

Configuring the JSF servlet

The <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 <servlet-mapping> tag 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.


Starting up a JSF-Acegi application

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
Sequence of events when a JSF-Acegi application starts


In detail, the sequence of events shown in Figure 1 is as follows:

  1. The servlet container instantiates all listeners configured in the web.xml file.

  2. The servlet container registers Acegi's ContextLoaderListener as a listener class, which implements an interface named javax.servlet.ServletContextListener. The ServletContextListener interface contains two important methods: contextInitialized() and contextDestroyed():
    • The 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.

  3. The servlet container registers JSF's ConfigureListener as another listener. JSF's ConfigureListener implements a number of listener interfaces, such as ServletContextListener, ServletContextAttributeListener, ServletRequestListener, and ServletRequestAttributeListener. You've already seen the ServletContextListener interface's methods. The remaining interfaces are:
    • ServletContextAttributeListener, which contains three methods: attributeAdded(), attributeRemoved(), and 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 ConfigureListener performs when a new servlet request object is created in step 3 of the processing a request for an Acegi-protected JSF page sequence.

  4. 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.

  5. The servlet container notifies Acegi's ContextLoaderListener that the servlet context is initialized by calling ContextLoaderListener's contextInitializated() method.

  6. The 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.)

  7. The servlet container notifies JSF's ConfigureListener about the initialization of the servlet context by calling its contextInitialized() method.

  8. The 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.

  9. The servlet container checks the web.xml file for any filters configured. For example, the web.xml file in Listing 1 contains an Acegi filter named FilterToBeanProxy, which the servlet container instantiates, initializes, and registers as a filter. Acegi is now ready to process incoming requests for authentication and authorization.

  10. 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.


Processing a request for an Acegi-protected JSF page

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
JSF and Acegi working together to serve a JSF page


In detail, the sequence of events shown in Figure 2 is as follows:

  1. The servlet container creates a servlet request object representing the user's request.

  2. Recall from step 3 of the starting up a JSF-Acegi application sequence that JSF's ConfigureListener implements the ServletRequestListener interface. This means that ConfigureListener listens for events related to the creation and deletion of servlet request objects. Therefore, the servlet container invokes the ConfigureListener class's requestInitialized() method.

  3. 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.

  4. 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 maintains.

  5. The servlet container matches the request URL with the URL pattern contained inside the <filter-mapping> tag's <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.

  6. Acegi's FilterToBeanProxy uses the FilterChainProxy class 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.

  7. Acegi updates the servlet context with session information for the authenticated user.

  8. The servlet container notifies the attributeReplaced() method of JSF's ConfigureListener that the servlet context has been updated. The ConfigureListener checks 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 ConfigureListener does no processing during this call.

  9. 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.


A sample JSF-Acegi application

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.


Conclusion

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.



Download

DescriptionNameSizeDownload method
Source code for this articlej-acegi4-source.zip15KBHTTP

Information about download methods


Resources

Learn

Get products and technologies

Discuss

About the author

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.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology, Web development
ArticleID=290556
ArticleTitle=Securing Java applications with Acegi, Part 4: Protecting JSF applications
publish-date=02192008