This series of articles is an introduction to using Acegi Security System to secure Java enterprise applications. Part 1 of this series introduced Acegi and explained how to use its built-in security filters to implement a simple, URL-based security system. Part 2 showed you how to write an access control policy and store it in an LDAP directory server, as well as how to configure Acegi to interact with the directory server to implement your access control policy. This third article in the series demonstrates how to use Acegi to secure access to Java class instances in your enterprise applications.
I'll start by briefly explaining when you might need to secure access to your Java classes, including a couple of typical enterprise application scenarios for reference. For further background, I explain how Spring's inversion of control (IOC) framework creates instances of Java classes, which are accessible from your JSPs or servlets. I also introduce the important concept of bean proxies, which Spring uses to filter access to Java objects. Finally, I will show you how to configure Acegi's method security interceptor to control access to your Java classes. I continue with this article in the series by enhancing the sample application from Part 2 to incorporate support for secure Java objects.
Because this discussion builds on the previous two articles in the series, I frequently reference the discussion and examples from Part 1 and Part 2. It may be helpful to open these installments in additional browser windows before you continue.
Use cases for securing Java classes
You might recall that I talked briefly about enterprise application security at the beginning of this series. In that introductory discussion, I mentioned a scenario in which URL security would not be enough:
Consider a PDF document containing the data about a particular product manufactured by the manufacturing company. Part of the document contains design data meant to be edited and updated by the company's design department. Another part of the document contains production data, which production managers will use. For a scenario like this one, you would need to implement more fine-grained security applying different access rights to different portions of the document.
Before moving on, let's consider a couple more application scenarios that might require you to secure individual classes in addition to implementing URL security.
Workflows in business automation applications consist of processes. For example, the workflow of performing a blood test in a pathology laboratory could consist of a number of steps, with each step being considered a business process:
- A staff member collects the blood sample from a patient and assigns an ID number to the sample.
- A laboratory technician performs the required test on the sample and prepares the test results.
- A qualified pathologist writes a test report based on the prepared test results.
You can clearly see that each process is executed by a separate user who is authorized to execute the process. Someone who is not authorized to perform a process should not be able to execute the process. For example, the lab technician should only prepare test results and should not be able to write the test report.
Authorized business processes are common to almost all business automation applications. Normally, you would implement each business process as a Java class, and all the classes would need to be secured by means of an appropriate access control policy.
Business-to-business integration
Business-to-business (B2B) integration refers to the common scenario where two business entities need to expose specific functionality to each other. For example, a hotel might expose its room reservation functionality to a tour operator, who could then use it to reserve an available hotel room for a tourist. As a partner, the tour operator might also have a special room reservation rate. In this case, the hotel's reservation system would have to authenticate the operator before allowing access to the selected classes for reserving rooms at the special rate.
Creating Java objects in Spring
Now you have an idea of why it's important to be able to secure access to Java class instances. Before introducing Acegi's functionality for this advanced level of security, I want to refresh your memory about some of the key features of the Spring framework, which you need to understand to follow the upcoming examples.
Let's start by configuring some Java classes and instantiating them. As you might
recall from
Part
1,
Java classes are configured in Spring's XML configuration file. Configuring a Java
class in a Spring configuration file is exactly the same as configuring an Acegi
filter, so I won't explain this step. Instead, just take a look at Listing 1,
which shows the configuration for a bean named
publicCatalog:
Listing 1. Acegi XML configuration file
<beans>
<bean id="publicCatalog"
class="com.catalog.PublicCatalog" />
<!--Other bean tags -->
<beans>
|
It's important that you understand how Spring's IOC framework reads information
about your Java classes from the XML configuration file and instantiates them. You
might recall that in the
first article
of this series, I used a web.xml file to configure a
<listener> tag pointing to a class named
ContextLoaderListener. The
ContextLoaderListener loads Spring's IOC framework and
creates Java objects. You can see all this by referring back to
Part 1, Listing
8.
It is also depicted in Figure 1:
Figure 1. Loading Spring's IOC framework and creating Java objects

Now let's consider those steps in detail:
- When you initiate your Acegi application, the servlet container (in this case
Apache Tomcat) creates a servlet context, which holds information about
application resources such as JSP pages and classes.
- The servlet container notifies the
ContextLoaderListenerclass that your application is being started. - The
ContextLoaderListenerclass creates a Web application context to hold information about the Spring-specific resources of your application. With the Spring's IOC framework, you can load your own custom application context. To create an application context, it uses a context loader class namedContextLoader, which loads the application context. - In case the application does not want to define its own application context,
it can use a class named
XMLWebApplicationContext, which is part of the Spring framework and provides functionality to process Spring's XML configuration files. Acegi applications use Spring's XML configuration file, so this article discusses only the application context represented by theXMLWebApplicationContextclass. In the case of this example, the context loader instantiates theXMLWebApplicationContextclass, which represents the application context for your Acegi application. The context loader also sets a reference of the servlet context (created in Step 1) into the Web application context. - The
XMLWebApplicationContextclass parses your XML configuration file for information about your Java classes and loads the information into its internal objects. - The
XMLWebApplicationContextclass instantiates all the Java classes specified in your XML configuration file. TheXMLWebApplicationContextclass checks whether a Java bean configured in the XML configuration file depends on some other Java objects. If so, theXMLWebApplicationContextclass first instantiates the beans on which other beans depend. In this way, theXMLWebApplicationContextclass creates instances of all the beans defined in the XML configuration file. (Note that Step 6 assumes that none of the beans configured in the XML configuration file need to be secured. A later section explains the additional steps that have occurred between Step 5 and Step 6 to secure access to Java beans created here.) - The
XMLWebApplicationContextclass stores all beans in an array.
You've seen how to load bean definitions from an XML configuration file and create instances of Java classes. Next, I'll introduce you to the Spring bean proxy and explain its importance when securing access to Java class instances.
The previous section discussed how Spring's IOC framework instantiates Java objects. In order to secure access to your Java objects, Spring's IOC framework uses the concept of bean proxies. This section first shows you how to configure a bean proxy and then demonstrates how Spring's IOC framework creates the proxy object.
Configuring a proxy for a Java object
If you want to create a proxy bean, the Spring IOC framework requires you to
configure an instance of a proxy creator bean. Spring's IOC framework uses the
proxy creator to create proxy objects. Listing 2 is the configuration file for the
proxy creator bean, used to secure a Java object named
privateCatalog:
Listing 2. Proxy bean configuration
<bean id="proxyCreator"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>privateCatalog</value>
<!--Names of other beans to be proxied -->
</list>
</property>
<property name="interceptorNames">
<list>
<value>privateCatalogSecurityInterceptor</value>
</list>
</property>
</bean>
|
As you can see in Listing 2, the <bean>
tag has a class attribute whose value is
org.springframework.aop.framework.autoproxy.
BeanNameAutoProxyCreator.
The BeanNameAutoProxyCreator class is part of the
Spring IOC framework and automatically creates bean proxies. The Spring framework
provides an interface named BeanPostProcessor, which
represents an extensibility mechanism to allow applications to write their own
logic to create bean proxies. Spring's
BeanNameAutoProxyCreator class implements the
BeanPostProcessor interface and provides all the proxy
creation logic that you need to secure your Java classes. Therefore, you don't
need to implement the BeanPostProcessor interface for
the purpose of this article.
While creating bean proxies, the
BeanNameAutoProxyCreator class creates proxies for all
the beans defined by the beanNames property (see the
first <property> child of the
<bean> tag in
Listing 2). The beanNames
property takes a list of bean names in a
<list> tag. In
Listing 2, I have configured only one bean named
privateCatalog for which I want to create a proxy.
Now look at the second <property> child
of the <bean> tag in
Listing
2. It specifies a property named
interceptorNames, which wraps the names of one or more
interceptors. I will discuss the concept of interceptors in detail later in the
article. For the moment, just note that an interceptor can intercept a user's
request and implement an access control policy before allowing the user to access
the bean.
Now you've seen how to configure proxy for the beans that you want to protect. Next, you'll learn how Spring's IOC framework internally creates proxy objects for the beans of your application.
In Step 5 and Step 6 of "Creating Java objects in Spring"
you saw how the XMLWebApplicationContext class reads
bean definitions from an XML configuration file and then creates bean instances.
Before creating a bean instance, the
XMLWebApplicationContext class checks whether the XML
configuration file contains any proxy creator bean configuration (that is, a bean
that implements the BeanPostProcessor interface). If it
finds one, it asks the proxy creator to create bean proxies for the beans that you
wish to secure.
Now consider how the proxy creator internally creates proxy objects:
- The proxy creator (that is, the
BeanNameAutoProxyCreatorclass) loads all the bean names specified in thebeanNamesproperty file that you configured in Listing 2. - The proxy creator uses the bean names to load their respective Java classes
using the
classattribute of each bean definition. - The proxy creator creates an instance of the interceptor specified in the
interceptorNamesproperty shown in Listing 2. - Finally, the proxy creator creates an instance of a class named
Cglib2AopProxy, passing all the bean names (from Step 2) and the interceptor (from Step 3) to theCglib2AopProxyclass. TheCglib2AopProxyclass is part of the Spring framework and is used to generate dynamic proxy objects. In this case, theCglib2AopProxyclass creates the proxy objects you will need to control access to your secure beans.
The Cglib2AopProxy class implements two interfaces
named AOPProxy and
MethodInterceptor. The
AOPProxy interface is part of the Spring framework and
represents the actual bean that you want to proxy, so it exposes the same methods
that your bean exposes. The MethodInterceptor
interface, also part of the AOP specification, has methods that receive control
whenever a user tries to access the bean that you have proxied. This means the
MethodInterceptor interface handles requests from users
to access a proxied bean. Given that the Cglib2AopProxy
class implements both AOPProxy and
MethodInterceptor interfaces, you can guess that it
offers the complete functionality of representing a proxied bean as well as
handling user requests to access a proxied bean. (See the
Resources section for links to articles that discuss
AOP.)
After executing the previous steps, you have the required proxy objects. So the
XMLWebApplicationContext class stores the proxies of
secure beans (instead of the actual beans) in the same array that you saw in Step
7 of "Creating Java objects in Spring."
Accessing proxied Java objects
In the previous sections, you learned how Spring creates public beans and private beans. For the purpose of this article, you can think of public beans as unsecured and private ones as being secured by proxy. Now let's look at the sequence of steps a client application must follow to access public and private beans.
Listing 3 shows the XML configurations for two beans named
publicCatalog and
privateCatalog. The
publicCatalog bean is meant for public access so it
does not need a bean proxy. The privateCatalog bean is
meant to be accessed only by designated users, so it must be secured. I have
included a bean proxy configuration for the
privateCatalog bean in Listing 3:
Listing 3. XML configuration for publicCatalog and privateCatalog beans
<beans>
<bean id="publicCatalog" class="sample.PublicCatalog"/>
<bean id="privateCatalog" class="sample.PrivateCatalog"/>
<!-- proxy configuration for privateCatalog bean -->
<bean id="proxyCreator"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>privateCatalog</value>
<!--Names of other beans to be proxied -->
</list>
</property>
<property name="interceptorNames">
<list>
<value>privateCatalogSecurityInterceptor</value>
</list>
</property>
</bean>
<beans>
|
Listing 4 shows the code that an application could use to access the
publicCatalog and
privateCatalog Java beans configured in Listing 3. Note
that the Java code shown in Listing 4 could exist in a JSP page or in another bean
contributing to a server-side Java application.
Listing 4. Client application code to access secure and insecure Java beans
//Step 1: Fetching an instance of the application context
XMLWebApplicationContext applicationCtx =
WebApplicationContextUtils.getWebApplicationContext(
this.getServletConfig().getServletContext());
//Step 2: Fetching an insecure bean from the application context
PublicCatalog publicCatalog =
(PublicCatalog) applicationCtx.getBean("publicCatalog");
//Step 3: Calling a method of the insecure bean
String publicData = publicCatalog.getData();
//Step 4: Fetching a secure bean from the application context
PrivateCatalog privateCatalog =
(PrivateCatalog) applicationCtx.getBean("privateCatalog");
//Step 5: Calling a method of the secure bean
String privateData = privateCatalog.getData();
|
Consider the steps in Listing 4 in greater detail:
- Step 1: Fetching an instance of the application context
When an application wants to access a Java bean configured in an XML configuration file, it has to fetch theXMLWebApplicationContextobject that you saw earlier in Step 4 of "Creating Java objects in Spring." TheXMLWebApplicationContextobject contains references to all the Java beans configured in the XML configuration file. - Step 2: Fetching an insecure bean from the application context
You now have a reference to theXMLWebApplicationContextobject. TheXMLWebApplicationContextclass exposes a method namedgetBean(), which takes the name of a bean and finds the bean in the array it prepared in Step 7 of "Creating Java objects in Spring." In this case, the bean ispublicCatalog(which is not proxied), so theXMLWebApplicationContextreturns the actual bean. - Step 3: Calling a method of the insecure bean
Now you can call any method of thepublicCatalogbean you got in Step 2. For example, thegetData()method call shown in Listing 4 executes without any access control and returns the catalog data to the application. - Step 4: Fetching a secure bean from the application context
Fetching a secure bean is similar to fetching insecure beans. The only difference is that when you try to fetch a secure bean by calling thegetBean()method, you get a proxy of the secure object instead of the actual object. The proxy is the same object created by the Spring framework that I explained in Step 4 of "Spring IOC takes over." - Step 5: Calling a method of the secure bean
When you call a method of a secure bean, the proxy object that you got in Step 4 dispatches a method invocation request to the interceptor. The interceptor processes the method invocation request by checking if the user trying to access the method has appropriate access rights.
You should have a clear picture now of how the Spring framework creates Java objects and how client applications interact with them. With this background, it will be easier to understand and utilize Acegi's method security interceptor, which is the topic of the next section.
Configuring Acegi's method security interceptor
Whenever an application tries to access a method of a bean secured using Acegi Security System, the request is automatically transferred to Acegi's method security interceptor. The purpose of the method security interceptor is to control access to methods of secure Java beans. The interceptor uses Acegi's authentication and authorization framework to confirm whether a user is authorized to call a method of the secure Java bean, and then responds accordingly.
Listing 5 is a sample configuration of Acegi's method security interceptor:
Listing 5. Configuration of Acegi's method security interceptor
<bean id="privateCatalogSecurityInterceptor"
class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager">
<ref bean="authenticationManager"/>
</property>
<property name="accessDecisionManager">
<ref bean="accessDecisionManager"/>
</property>
<property name="objectDefinitionSource">
<value>
sample.PrivateCatalog.getData=ROLE_HEAD_OF_ENGINEERING
<!-- Roles required by other beans -->
</value>
</property>
</bean>
|
The interceptor configuration shown in Listing 5 contains three properties that
you need to configure in order to secure access to your Java beans:
authenticationManager,
accessDecisionManager, and
objectDefinitionSource.
Recall that you configured the authenticationManager
property while
configuring the authentication processing filter
in the first article of this series. The purpose of the
authenticationManager property is to authenticate a
user.
You learned about the
accessDecisionManager
property in the second article in this series. The access decision manager is
responsible for making authorization decisions. The method security interceptor
uses the authenticationManager and
accessDecisionManager properties to authenticate and
authorize a user before allowing access to a secure bean.
Now look at the objectDefinitionSource property
configured in Listing 5. It is similar to the
objectDefinitionSource
property shown in Part 1. Whereas the original
objectDefinitionSource
contained URLs like /protected/* and
/**, the
objectDefinitionSource property in Listing 5 specifies
class and method names; for instance,
sample.PrivateCatalog is the name of a class that you
proxied earlier and getData is the name of a method to
which you want to control user's access.
Whenever the user accesses the getData() method of the
PrivateCatalog bean, control is automatically
transferred to the interceptor. The interceptor uses the Acegi framework to check
whether the user's business role is
ROLE_HEAD_OF_ENGINEERING (in this example). If it is,
the interceptor allows access to the getData() method.
If interceptor finds that the user does not have the
ROLE_HEAD_OF_ENGINEERING, it denies access.
The next section looks at a sample Acegi application that implements the concepts you have learned so far.
The source code download for this article contains a sample application called AcegiMethodSecurity, which you can configure and deploy as follows:
- Populate your LDAP server with user information. The
sample application download contains an LDIF file that
has user information ready to be loaded into your LDAP server. See
"Populating the server"
in Part 2 for a refresher on importing the LDIF file into your LDAP server. Note
that this application features the same users (
alice,bob, andspecialUser) that you worked with in Part 2. - Copy the acegiMethodSecurity.war file from the source code download of this
article into the webapps directory of your Tomcat installation.
- Copy Acegi's jar files into the WEB-INF/lib folder of the sample application.
(See
"Deploy and run the application"
from Part 1 for a refresher on this.)
- Download the cglib-full-2.0.2.jar file and copy it in WEB-INF/lib folder of the sample application.
Start Tomcat and you should be all set to try the sample application.
Get to know the sample application
You can invoke the sample application by accessing the http://localhost:8080/acegiMethodSecurity URL from your browser. The AcegiMethodSecurity application displays an index page that contains two links (Catalog and Login), as shown in Figure 2:
Figure 2. Main page of the sample application

When you click on the application's Catalog link, it will ask you to log
in. If you log in as alice or
specialUser, the sample application serves you the
complete catalog, including both public and private data. That's because
back in Listing 5, you configured the method security
interceptor to allow users having
ROLE_HEAD_OF_ENGINEERING to access the private catalog,
and both alice and
specialUser have that access. On the other hand, if you
log in as bob, the sample application shows you only
public data.
Assigning additional roles to authenticated users
This section demonstrates an enhanced version of the sample application. The enhanced version shows how Acegi lets you temporarily assign additional roles to an authenticated user at runtime.
You might need additional roles whenever a secure bean (such as the
privateCatalog bean of
Listing 3) needs to access a remote resource. As an
example, you might consider that your secure bean needs to access a remote
application through Java's Remote Method Invocation (RMI) framework or a Web
service. The user accessing your secure bean will not possess the business role
that the remote application expects from a user trying to access it.
In this case, Acegi first checks whether the user is authorized to access the secure bean. After checking, Acegi allows the user to access the secure bean. When the secure bean attempts to access the remote service, it will need additional business roles. If the user who accessed the secure bean does not have the additional role(s), the secure bean will not be able to successfully access the remote service.
The run-as-replacement mechanism
The Acegi framework provides a simple mechanism called run-as-replacement that allows you to configure one or more additional roles for an authenticated user only for the duration of a method invocation call. You can use the run-as replacement to configure additional roles for a secure bean to access remote applications. This means whenever the secure bean needs to access a remote application, Acegi will load additional roles for the user, thus allowing the secure bean to access the remote application.
Listing 6 shows an enhanced configuration of the method security interceptor that you saw earlier in Listing 5. The enhanced version uses the run-as-replacement mechanism.
Listing 6. Enhanced configuration of Acegi's method security interceptor
<bean id="privateCatalogSecurityInterceptor"
class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager">
<ref bean="authenticationManager"/>
</property>
<property name="accessDecisionManager">
<ref bean="accessDecisionManager"/>
</property>
<property name="runAsManager"> <bean id="runAsManager"
class="org.acegisecurity.runas.RunAsManagerImpl"> <property name="key"> <value>myKeyPass</value> </property> </bean> </property>
<property name="objectDefinitionSource">
<value>
sample.PrivateCatalog.getData=ROLE_HEAD_OF_ENGINEERING,RUN_AS_MANAGER
</value>
</property>
</bean>
|
You can see two enhancements in Listing 6 (as compared to
Listing 5) shown in bold. The first enhancement is a
property named runAsManager. The purpose of the
runAsManager property is to add support for dynamically
adding roles to the authenticated user. For this purpose, the
runAsManager property contains the definition of a bean
named RunAsManagerImpl. The
RunAsManagerImpl bean becomes active only when it finds
a role with RUN_AS_ prefix in the role definitions of a
method in objectDefinitionSource. For example, the role
definition of the PrivateCatalog.getData() method (the
second bold enhancement in Listing 6) has a
RUN_AS_MANAGER role.
The RunAsManagerImpl bean contains a property named
key, which wraps a cryptographic key used to ensure
that the additional role can only be generated as part of the run-as-replacement
procedure.
When a user calls the getData() method, the
RunAsManagerImpl bean becomes active and creates an
additional role named RUN_AS_MANAGER, thus enabling the
getData() method to access the remote application.
This article's source code download includes a sample
application named EnhancedAcegiMethodSecurity, which
demonstrates the run-as-replacement mechanism and procedure. The application
displays an index page with a Catalog link. If you click the Catalog link,
you will be asked to log in.
Once you have logged in, the
EnhancedAcegiMethodSecurity application will provide
you with the complete information about the logged-in user and that user's roles.
For instance, if you log in as alice or
specialUser, you will be shown all the business roles
of the user including the additional temporary
RUN_AS_MANAGER role.
In this series of articles, I introduced you to using Acegi Security System to enforce both URL-based security and method-based security. You learned how to design access control policies and host them in a directory server, how to configure Acegi to communicate with a directory service, and how to make authentication and authorization decisions based on the access control policies hosted there.
This article focused on using method-based security to protect Java class instances. It also explained how Acegi and Spring internally create and proxy Java objects and how bean proxies work to implement access control. The article includes a couple of sample applications that you can use to further explore the concepts you have learned in this series. See the Resources section to learn more about securing Java applications with Acegi.
| Description | Name | Size | Download method |
|---|---|---|---|
| Source code for this article | j-acegi3-source.zip | 36KB | HTTP |
Information about download methods
Learn
- Securing
Java applications with
Acegi series: Get an introduction to using Acegi Security System to secure Java
enterprise applications.
- "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 4: Protecting JSF applications" (Bilal Siddiqui, developerWorks, February 2008): This article helps you configure JSF and Acegi to work together in a servlet container and explores how JSF and Acegi components cooperate with one another.
- The Acegi Security System home page:
Get reference documentation and download Acegi.
- Acegi Security System for Spring, Part 1:
A presentation on URL-based security.
- Acegi Security System for Spring, Part 2:
A presentation on method-based security.
- Download cglib-full-2.0.2.jar:
Used by Acegi Security System to create proxies.
- The AOP alliance home page:
Hosted on SourceForge.net.
-
"Aspect Oriented Programming with Spring:
Learn more about Spring AOP.
- AOP@Work
series
(developerWorks, February 2005 - April 2006): Practical, hands-on articles
featuring AOP techniques that you can use today.
- developerWorks Java technology zone:
Hundreds of articles about every aspect of Java programming.
Discuss
- developerWorks
blogs: Get
involved in the
developerWorks community.
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.





