Acegi Security for Dummies

Erik Kerkhoven 21

Probably this post is one of many Acegi Security Getting Started’s
to be found on the web. However we at Amis just recently went thru it. Here
is our step-by-step guide how to set up basic authentication and web request authorization.
We used a bit older version of the frameworks. However after going thru
the steps described below, you’ll end up with a basic understanding of this security system.

downloading the lab you’ll find an application that contains all layers
of the Spring framework: a basic Spring MVC tier and service tier that
uses Spring JDBC.
Acegi Security logo

1. Getting Up and Running

We are going to add security measures to an existing fully insecure
application created with the Spring framework. This application can be downloaded here: Before you can go ahead with implementing security on this application, you should perform the following steps:

  • Install Maven on the project
  • Install database schema
  • Prepare Tomcat
  • Import project into Eclipse

Install Maven on the project

Install Maven 2 ( Start up DOS prompt. Navigate to directory where project is located (e.g.
../projects/acegi-lab). Issue command:

>mvn install

should see the Maven log message that says that pallas-0.1.war has
installed into local .m2/repository; and you should see the message:
successful. Next, create Eclipse project by issuing command

>mvn eclipse:eclipse

you should see the message that says that Eclipse project has been
to local directory ../projects/acegi-lab. When you look in your local
project directory you’ll notice that the files .classpath, .project,
.wtpmodules and  a
directory called target has been added.

Install database schema

Install Oracle XE database (  Create user PALLAS/PALLAS. Grant
DBA privilege. Create objects and test data by running script
acegi-lab/src/main/sql/create_schema.sql . Modify data source URL
jdbc:oracle:thin:@localhost:1521:XE that is defined in file
acegi-lab/src/main/webapp/META-INF/context.xml. Change the SID XE into
you own SID.

Prepare Tomcat

Install Tomcat 5.5 ( and add the following jar files to CATALINA_HOME/common/lib:

  • commons-pool-1.2.jar
  • commons-dbcp-1.2.1.jar
  • commons-collections-3.1.jar
  • ojdbc14.jar

Import project into Eclipse

Install Eclipse 3.1. and start it. Go to
Window>Preferences>Server>Install Runtimes and add Tomcat. Go
to file>import and select Existing Projects into
Workspace. Select the project home (directory acegi-lab), and click
Finish. It can
be that Eclipse complains about missing directory .deployables and
shows a building
error. This can be ignored. Restart Eclipse are you are fine. Select
src>main>webapp>index.html. Choose from Right-click menu:
Run As>Run on Server. The application welcome page should appear.

2. Implementing Authentication

The first step in building up the security for this application is
providing authentication. In Acegi the authentication is performed by
the AuthenticationManager. Therefore we need to create this class. As
for most objects in Spring this is done by wiring it in the application
context. So we have to go to the context configuration file of our
project. For convenience reasons this file is split into multiple files
that contain bean definitions grouped according to their role within
the application (could be any division). If we go to
src>main>webapp>WEB-INF, we see:

  • pallas-servlet.xml
  • dataAccessContext.xml
  • businessContext.xml
  • webContext.xml

Now we are going to add yet another one to this list, named:
securityContext.xml. Please add file securityContext.xml to directory
src>main>webapp>WEB-INF. This file should have the following

<?xml version="1.0" encoding="UTF-8"?>

As you can see this file expects a couple of bean definitions. After
completion of this lab we’ll have added the beans that are represented
in the figure below. An arrow denotes a dependency that a bean has on
another bean:

Security beans

First we start with adding three filters:

<bean id="filterChainProxy" class="net.sf.acegisecurity.util.FilterChainProxy">
  <property name="filterInvocationDefinitionSource">

The order in which the filters are listed above, defines the order
in which they are run. Next we add the bean definitions for the filters:

<bean id="httpSessionContextIntegrationFilter" class="net.sf.acegisecurity.context.HttpSessionContextIntegration Filter">
  <property name="context" value="" />

<bean id="authenticationProcessingFilter" class="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
  <property name="authenticationManager">
    <ref bean="authenticationManager" />
  <property name="authenticationFailureUrl" value="/login.html?error=1" />
  <property name="defaultTargetUrl" value="/" />
  <property name="filterProcessesUrl" value="/j_acegi_security_check" />
<bean id="securityEnforcementFilter" class="net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter">
  <property name="filterSecurityInterceptor" ref="filterSecurityInterceptor" />
  <property name="authenticationEntryPoint" ref="authenticationEntryPoint" />

Into these filters other beans are injected. We start with the AuthenticationManager, the bean that does the authentication:

<bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
  <property name="providers">
      <ref local="daoAuthenticationProvider" />

In its turn the AuthenticationManager depends on one (or more)
providers. We inject the DaoAuthenticationProvider, that is defined by:

<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
  <property name="authenticationDao">
    <ref local="memoryAuthenticationDao" />

Next we choose to inject a MemoryAuthenticationDao into the DaoAuthentiactionProvider, that on its turn is defined by:

<bean id="memoryAuthenticationDao" class="net.sf.acegisecurity.providers.dao.memory.InMemoryDaoImpl">
  <property name="userMap">

A list of principals and their credentials are stored in memory.
Next we need to wire a couple of beans to finish this context file:

<bean id="filterSecurityInterceptor" class="net.sf.acegisecurity.intercept.web.FilterSecurityInterceptor">
  <property name="authenticationManager"
    ref="authenticationManager" />
  <property name="accessDecisionManager"
    ref="httpRequestAccessDecisionManager" />
  <property name="objectDefinitionSource">

The FilterSecurityInterceptor also uses the AuthenticationManager.
Furthermore an AccessDecisionManager is wired into it, that makes use
of a RoleVoter:

<bean id="httpRequestAccessDecisionManager" class="">
  <property name="allowIfAllAbstainDecisions" value="false" />
  <property name="decisionVoters">
    <bean class="" />

Finally we need to wire a AuthenticationEntryPoint into the SecurityEnforcementFilter:

<bean id="authenticationEntryPoint" class="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
  <property name="loginFormUrl" value="/login.html" />
  <property name="forceHttps" value="false" />

Please save file securityContext.xml. In order to use this
securityContext, we need to add it to the list of context configuration
locations in web.xml. Please go ahead. For help see solution #1 below.

Next we need to register the FilterChainProxy bean in web.xml. In order to do so, add the following two XML elements to web.xml:

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

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

This should be placed before the servlet element. Now it’s time to
create a logon HTML page. Remember that in the AuthenticationEntryPoint
bean above, the loginFormUrl is defined as login.html. Now we add a
login.jsp to src>main>webapp>WEB-INF>jsp, defined something

<%@ page session="false"%>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ include file="taglibs.jsp"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
    <%@ include file="banner.jsp"%>
    <c:if test="${model.errorTxtKey != null}">
      Invalid Username / Password
    <form action="<c:url value="j_acegi_security_check"/>" method="POST">
	  <td>Username :</td>
	  <td><input name="j_username" /></td>
          <td>Password :</td>
	  <td><input type="password" name="j_password" /></td>
	  <td><input type="submit" value="Login" /></td>

Still, at this point of our building process, the authentication
entry point, called login.html is not yet mapped to this login.jsp. In
order to get this mapping right, we need to add a new URL mapping in
context configuration XML file, called pallas-servlet.xml. Please add
the mapping of login.html to loginController. For help see solution #2.

As you can see the path /login.html that enters the DispatcherServlet
is routed to a new controller, called LoginController. This controller
does not yet exist in our project, so we need to create it. Now we
switch to the Java classes. Please open package nl.amis.pallas.web.
This package contains controllers that are part of Spring MVC. Create
Java file, and add the following code to it:

package nl.amis.pallas.web;

import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.bind.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.*;

public class LoginController extends AbstractController {

	protected final Log logger = LogFactory.getLog(getClass());

	public ModelAndView handleRequestInternal(HttpServletRequest request,
			HttpServletResponse response) throws ServletRequestBindingException {
		String errorTxtKey = null;
		if (RequestUtils.getIntParameter(request, "error") != null) {
			errorTxtKey = "err.incorrect_usr_pwd";

		// use pk to find model data
		Map<String, Object> model = new HashMap<String, Object>();
		model.put("errorTxtKey", errorTxtKey);

		return new ModelAndView("login", "model", model);

In Spring, creating a new Java class is not sufficient. What do we need to do next?

Yep, we need to wire it in a context configuration file. In this
case, we need to add the LoginController bean to the XML file
webContext.xml. Please try to add this bean to webContext.xml. For help
see solution #3 below.

When we run the application, we notice that authentication is not taken place. What would be the reason for this?

Indeed, we still miss a mapping of a URI pattern to a role, in order to
trigger the authentication. In order to facilitate this pattern
mapping, we will put URIs that we want to secure in a virtual path,
called secure/. Please modify the following files:


Finally, we need to add a URI filter pattern to the
FilterSecurityInterceptor bean that is defined in XML file
securityContext.xml. Please go ahead and adapt the value of the
ObjectDefinitionSource attribute of this Interceptor, below
PATTERN_TYPE_APACHE_ANT in the XML element below:

<bean id="filterSecurityInterceptor"
  <property name="authenticationManager"
    ref="authenticationManager" />
  <property name="accessDecisionManager"
    ref="httpRequestAccessDecisionManager" />
  <property name="objectDefinitionSource">

For help see solution #4.

3. Authorization

So far we have succeeded to get the authentication to work. During
this process we implemented authorization too, namely principals with
the granted authorities employee and manager are allowed to enter the
application and all of its (secure) pages. Now we will modify the
authorization by implementing the requirement that only managers are
allowed to add new employees. Please implement this requirement by
modifying the ObjectDefinitionSource attribute of the
FilterSecurityInterception. One way to do this is adding the following
line above the existing pattern:


This should be above the existing pattern because the patterns are evaluated from specific to more generic. So this results in:


This must of course be complemented by modifying the paths located in the following files:

  • employee_list.jsp : manager/add_employee.html
  • pallas-servlet.xml : /secure/manager/add_employee.html

Please implement this authorization requirement and test the changes by
logging as manager with username = piet, and password = hup. The Acegi
tag library offers the possibility to test the granted authorities of
principals. So next we want to display the link to Add Employee page
only when the user is a manager. This can be accomplished by embedding
the link in employee_list.jsp into the tag:

<authz:authorize ifAnyGranted="ROLE_MANAGER">

Please go ahead and try it out.

4. Authentication thru JDBC

Often the authentication repository is located in a database that
contains a list of principals and their granted authorities. Therefore
we will build this in this lab. In our datasource PALLASDS there exists
a minimal authentication repository in the form of some extra columns


the type of the DaoAuthenticationProvider demonstrates the power of
Spring. Because all we need to do is modify beans that are wired in the
securityContext.xml, and to provide the Java class that corresponds
with the new bean that will be wired into the DaoAuthenticationProvider


  1. Open
    securityContext.xml and remove the MemoryAuthenticationDao element and
    the existing DaoAuthenticationProvider bean definition.
  2. Inject the new DaoAuthenticationProvider bean by adding to securityContext.xml:
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
  <property name="authenticationDao" ref="authenticationDao"/>
  <property name="userCache">
    <bean id="userCache" class="net.sf.acegisecurity.providers.dao.cache.EhCacheBasedUserCache">
      <property name="cache">
        <bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
          <property name="cacheManager" ref="cacheManager"/>
	    <property name="cacheName" value="userCache"/>

<bean id="authenticationDao" class="">
  <property name="dataSource" ref="dataSource"/>

<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" />

you can see, we’ll use a custom AuthenticationDao, that is implemented
as a new class located in package Therefore
we need to add the class to our project. Create a new package and add class,
for example as follows:

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;

import javax.sql.DataSource;

import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.GrantedAuthorityImpl;
import net.sf.acegisecurity.UserDetails;
import net.sf.acegisecurity.providers.dao.User;
import net.sf.acegisecurity.providers.dao.UsernameNotFoundException;
import net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.object.MappingSqlQuery;

public class AuthenticationJdbcDaoImpl extends JdbcDaoImpl {

	protected final Log logger = LogFactory.getLog(getClass());

	private Long depId;

	private String empName;

	private Long empId;

	protected void initMappingSqlQueries() {
		super.setUsersByUsernameQuery("select username, password, is_account_enabled, department_id, name, id from employee where username = lower(?)");
		super.setAuthoritiesByUsernameQuery("select role from employee where username = lower(?)");
		this.setUsersByUsernameMapping(new CustomUsersByUsernameMapping(this.getDataSource()));
		this.setAuthoritiesByUsernameMapping(new CustomAuthoritiesByUsernameMapping(
						this.getDataSource()));"query users = " + getUsersByUsernameQuery());"query authorities = " + getAuthoritiesByUsernameQuery());

	public UserDetails loadUserByUsername(String username) {
		try {
			// is instance of User and is not a CustomUser, as I would expect...
			UserDetails u = super.loadUserByUsername(username);
			CustomUser cu = new CustomUser(u, depId, empName, empId);

			String str = "load user " + cu.getUsername() + ", "
					+ cu.isEnabled() + ", " + cu.getDepartmentId() + ", "
					+ cu.getEmployeeName() + ", " + cu.getEmployeeId();
			GrantedAuthority[] roles = cu.getAuthorities();
			for (int i = 0; i < roles.length; i++) {
				str += "\n - " + roles[i].getAuthority();
			return cu;
		} catch (UsernameNotFoundException e1) {;
			throw e1;
		} catch (DataAccessException e2) {;
			throw e2;

	protected class CustomUsersByUsernameMapping extends MappingSqlQuery {

		protected CustomUsersByUsernameMapping(DataSource ds) {
			super(ds, getUsersByUsernameQuery());
			declareParameter(new SqlParameter(Types.VARCHAR));

		protected Object mapRow(ResultSet rs, int rownum) throws SQLException {
			String username = rs.getString(1);
			String password = rs.getString(2);
			String enabled_str = rs.getString(3);
			boolean enabled = false;
			if ("Y".equalsIgnoreCase(enabled_str)) {
				enabled = true;
			// get custom user attributes
			depId = rs.getLong(4);
			empName = rs.getString(5);
			empId = rs.getLong(6);

			User user = new User(username, password, enabled, true, true, true,
					new GrantedAuthority[0]);"mapRow user = " + user.getUsername());
			return user;

	protected class CustomAuthoritiesByUsernameMapping extends MappingSqlQuery {
		protected CustomAuthoritiesByUsernameMapping(DataSource ds) {
			super(ds, getAuthoritiesByUsernameQuery());
			declareParameter(new SqlParameter(12));

		protected Object mapRow(ResultSet rs, int rownum) throws SQLException {
			String roleName = "ROLE_" + rs.getString(1);
			GrantedAuthorityImpl authority = new GrantedAuthorityImpl(roleName);"mapRow authority = " + roleName);
			return authority;


This is indeed quite some code, and in fact we could have just a few lines (or just XML declaration) as we would be satisfied with the standard implementation, that is we would create a User object that just contains the attributes username, password and granted authoritieslist. However in the example above we create a custom user, that also holds attributes like: DepartmentId, EmployeeName, EmployeeId. The benefit of this is that at any place in the code of our application we can access the attributes and use this for our puposes. Please add class to package as follows:

import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.UserDetails;
import net.sf.acegisecurity.providers.dao.User;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class CustomUser extends User {

    private static final long serialVersionUID = 1L;

    protected final Log logger = LogFactory.getLog(getClass());

    private Long departmentId;

    private String employeeName;

    private Long employeeId;

    public Long getDepartmentId() {
        return departmentId;

    public void setDepartmentId(Long departmentId) {
        this.departmentId = departmentId;

    public Long getEmployeeId() {
        return employeeId;

    public void setEmployeeId(Long employeeId) {
        this.employeeId = employeeId;

    public String getEmployeeName() {
        return employeeName;

    public void setEmployeeName(String employeeName) {
        this.employeeName = employeeName;

    public CustomUser(String username, String password, boolean isEnabled,
            GrantedAuthority[] authorities, Long depId, String empName,
            Long empId) {
        super(username, password, isEnabled, true, true, true, authorities);

    public CustomUser(UserDetails u, Long depId, String empName, Long empId) {
        this(u.getUsername(), u.getPassword(), u.isEnabled(), u
                .getAuthorities(), depId, empName, empId);

5. Solutions

Solution 1



Solution 2

<prop key="/login.html">loginController</prop

Solution 3

Add the following element to webContext.xml:

<bean id="loginController" class="nl.amis.pallas.web.LoginController" />

Solution 4


21 thoughts on “Acegi Security for Dummies

  1. Hi Erik,
    I am a Java developer and the framework is Spring. This Examples helps me a lot.
    It will be very helpfull for me if you provide an another complete example which includes the complete acigi security.
    I actually don’t understand the flow of login. Please give me an examples.


    Sanjoy De

  2. I would like to thanks AMIS for publishing this article. It has been explained very nicely. Because of this only I was able to implement my Authentication thro JDBC for my Custom Tables as I can not use standard Acegi tables. Without this I would not have done my application’s authentication and authorization.
    Thanks and Regards
    Sachin Mali

  3. Hi Eric Could you plz help in integrating Jcaptcha in Spring, Hibernate, Acegi environament. The User Name and passwords are stored in the database(MySql). As I am new to these concepts, I am in desperate need. I would be obliged if you help me ata an earliest.

  4. I am using acegi 1.0.0 rc2 and seems that there is a problem, i cannot find method [ setUsersByUsernameMapping(); ]
    Can anyone help me with this. I was trying to override UsersByUsername Mapping() but i couldnt manage.

  5. Erik,

    Thank you for your reply.

    I finally figured out by customizing the CustomUser into the authentication. Since the authentication is in the SecureContext, I can either access the CustomUser at my login jsp and put it to the session or I can access it at my regular servlet.

    Here is how I access it:

    String customUserName =((CustomUser)



  6. Sounds like a valid business case and a good idea to switch to Spring gradually. See:
    See the answer of Ben Alex at
    If your other application is Struts, you could use a plug-in, see: Here’s another example of Acegi – Struts integration with plug-in:

  7. Erik,

    Now, that it works. The next step is I want to pass username, password, user roles, dept id… to HttpSession from AuthenticationJdbcDaoImpl so that my non-spring framework application can acces them.

    Do you know how to do that? The Acegi and Spring framework are new to me. We decide to switch to them because we think they are good and secure frameworks.

    I appreciate for your help.



    My plan is to intergrate a new spring framework appliaction to the current non-framework application and use Acegi Security login for both of applications. Eventually, we will migrate the non-spring framework application to spring framework.

  8. Sorry, I didn’t understand you Maven issue. Thank you very much for your reply; very kind.

  9. Since maven has some problem. I manually build the sample and it works.
    Thank you to Mr. Erik Kerkhoven for providing this sample.

  10. It could not fine the maven-war-plugin…

    [INFO] ————————————————————————-

    [INFO] The plugin ‘org.apache.maven.plugins:maven-war-plugin’ does not exist or
    no valid version could be found
    [INFO] ————————————————————————-

  11. Please help! I got a BUILD ERROR when I run >mvn install
    Here is my error:

    8K downloaded
    [INFO] ————————————————————————
    [INFO] ————————————————————————
    [INFO] Cannot execute mojo: resources. It requires a project with an existing po
    m.xml, but the build is not using one.
    [INFO] ————————————————————————
    [INFO] For more information, run Maven with the -e switch
    [INFO] ————————————————————————
    [INFO] Total time: 17 seconds
    [INFO] Finished at: Fri May 12 15:14:50 CDT 2006
    [INFO] Final Memory: 2M/5M
    [INFO] ————————————————————————

  12. Forbidden?! oeps!

    Reason for the building failure is that there are still three other jars in this respository (see pom.xml):




    These must be installed manually as well with mvn install:install-file 🙁

  13. Hi Erik.
    In regards to using I cannot access this. I get a 403 Forbidden error.
    I used the mvn install:install-file -Dfile=ojdbc14.jar -DartifactId=ojdbc14 -Dversion= -Dpackaging=jar -DgeneratePom=true after getting the driver from the Oracle site and that worked.

    When I issue the mvn eclipse:eclipse command, it still complains about not finding the driver in the remote repositories.


  14. OK. The pom.xml has been repaired. The Oracle Database 10g Release 2 ( JDBC Drivers, ojdbc14.jar is added to the repository. This can be done quite easily, namely:

    1. download driver jar from

    2. issue maven command:

    mvn install:install-file -Dfile=ojdbc14.jar -DartifactId=ojdbc14 -Dversion= -Dpackaging=jar -DgeneratePom=true

  15. Angelo — The ojdbc14.jar is not in the repository at the moment. I’ll fix that. In order to continue, I suggest that you delete the Oracle database driver dependencies from pom.xml alltogether, and just download the drivers from Oracle site yourself. Thanks for informing me!

  16. Hi. I am trying to set up the environment to run these samples and am not having much luck getting past the mvn install.
    I keep getting the following error:

    [INFO] ————————————————————————-

    [INFO] Error building POM (may not be this project’s POM).

    Project ID:

    Reason: Error getting POM for ‘’ from the repository: E
    rror transferring file

    from the specified remote repositories:
    AMIS (http://smnserver:8181/maven2),
    central (

    I have done a search for and have turned up nothing. I do know that this does not exist in the repository.

    Any suggestions would be greatly appreciated.


  17. In your security xml file:
    You can add these lines in the daoAuthenticationProvider if you want to use md5 encoding on your password, to make it a bit more secure. Then switch your cleartext password(s) with md5 one(s) you can create yourself in the memoryAuthenticationDao part.


    You’ll need the commons-codec jar file for the digest. And if you use the jdbc part of this I would guess you would store passwords in the md5 format in your database.


Comments are closed.

Next Post

Hiding the Web.show_document URL

Facebook0TwitterLinkedinLast week I delivered a Forms module which invoked the Oracle Reports server by submitting report requests displaying the report on the screen using the Web.Show_document procedure. One thing that I was always been surprised about was the fact that when the document is displayed the complete URL is displayed […]