Acegi Security provides a comprehensive security solution for J2EE-based enterprise software applications, built using the Spring Framework. Acegi provides authentication service through the use of a web filter, an AuthenticationProvider and an AuthenticationEntryPoint. Authorization in Acegi can be done at different levels: authorizing web requests, authorizing which methods can be invoked, and authorizing access to individual domain object instances. In this example I will describe how to implement form-based authentication and URL level authorization using Acegi.
For this example, I use two secure JSPs, the secure/authenticatedusers.jsp file is available to all the authenticated users, and secure/admin/admin.jsp is only available to the users with ADMIN role. The login.jsp is used for login and denied.jsp is used to redirect unauthorized users. Follow these steps to run the example:
For this example, I use two secure JSPs, the secure/authenticatedusers.jsp file is available to all the authenticated users, and secure/admin/admin.jsp is only available to the users with ADMIN role. The login.jsp is used for login and denied.jsp is used to redirect unauthorized users. Follow these steps to run the example:
- Download Acegi and Spring.
- Start with a dynamic web project in eclipse.
- Copy the following Jar files into the WEB-INF/lib directory.
acegi-security-1.0.3.jar Main classes of the Acegi security system. commons-codec-1.3.jar Encoders and decoders such as Base64, Hex, Phonetic and URLs. ehcache-1.2.3.jar Used by the authentication provider. jstl.jar, standard.jar The JSTL tag library spring.jar Spring framework commons-logging.jar, cglib-nodep-2.1_3.jar Available in the spring download (spring with dependencies) - Create the Login page: The following is a listing for the login page.
<jsp:root version="1.2" xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:c="urn:jsptld:http://java.sun.com/jsp/jstl/core">
<jsp:directive.page contentType="text/html; charset=UTF-8" />
<jsp:directive.page
import="org.acegisecurity.ui.AbstractProcessingFilter, org.acegisecurity.ui.webapp.AuthenticationProcessingFilter, org.acegisecurity.AuthenticationException" />
<head>
<title>Login</title>
</head>
<body>
<form action="j_acegi_security_check" method="POST">
<table>
<tr>
<td>User:</td>
</td><input type='text' name='j_username' />
</td>
</tr>
<tr>
<td>Password:</td>
<td><input type='password' name='j_password' /></td>
</tr>
<tr>
<td><input type="checkbox" name="_acegi_security_remember_me" /></td>
<td>Remember me (14 days)</td>
</tr>
<tr><td colspan='2'><input name="submit" type="submit" /></td></tr>
<tr><td colspan='2'><input name="reset" type="reset" /></td></tr>
</table>
</form>
</body>
</jsp:root>login.jsp
Notes:- The login form uses j_acegi_security_check instead of j_security_check normally used for form-based authentication. Similarly for logout, we use j_acegi_logout action.
- In order to remember a user for a period of time, use the _acegi_security_remember_me attribute. This is configured in the applicatonContext.xml file(see below).
- Create the other JSP files: The listings for the JSP pages used for this example are shown below, along with their respective directories.
<html>
<body>
Everyone
<p><a href="secure/authenticatedusers.jsp">Authenticated users only</a>
<p><a href="secure/admin/admin.jsp">Admins only</a>
</body>
</html>index.jsp Access Denied.
denied.jsp <%@ page import="org.acegisecurity.context.SecurityContextHolder" %>
<h1>Welcome: <%= SecurityContextHolder.getContext().getAuthentication().getName() %></h1>
<p><a href="../">Home</a>
<p><a href="../j_acegi_logout">Logout</a>secure/authenticatedusers.jsp <%@ page import="org.acegisecurity.context.SecurityContextHolder" %>
<h1>Welcome: <%= SecurityContextHolder.getContext().getAuthentication().getName() %> is an Admin</h1>
<p><a href="../../">Home</a>
<p><a href="../../j_acegi_logout">Logout</a>
</body>
</html>secure/admin/admin.jsp - The users.properties file: This example uses an in memory user registry and the WEB-INF/users.properties file is used to store the usernames and passwords.
scott=tiger,ROLE_USER
harry=potter,ROLE_ADMIN
frodo=baggins,ROLE_USERWEB-INF/users.properties - Configure the Acegi filter in the Web deployment descriptor: The web.xml file is shown below
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>SpringSecurity</display-name>
<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>
<filter-mapping>
<filter-name>Acegi Filter Chain Proxy</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>web.xml - Configure Acegi in applicationContext.xml file: The following is a listing of the WEB-INF/applicationContext.xml file, followed be explanations of the different beans defined in there.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
<property name="filterInvocationDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
</value>
</property>
</bean>
<bean id="httpSessionContextIntegrationFilter" class="org.acegisecurity.context.HttpSessionContextIntegrationFilter"/>
<bean id="logoutFilter" class="org.acegisecurity.ui.logout.LogoutFilter">
<constructor-arg value="/index.jsp"/>
<constructor-arg>
<list>
<ref bean="rememberMeServices"/>
<bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler"/>
</list>
</constructor-arg>
</bean>
<bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationFailureUrl" value="/login.jsp?errorId=1"/>
<property name="defaultTargetUrl" value="/"/>
<property name="filterProcessesUrl" value="/j_acegi_security_check"/>
<property name="rememberMeServices" ref="rememberMeServices"/>
</bean>
<bean id="securityContextHolderAwareRequestFilter" class="org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter"/>
<bean id="rememberMeProcessingFilter" class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="rememberMeServices" ref="rememberMeServices"/>
</bean>
<bean id="anonymousProcessingFilter" class="org.acegisecurity.providers.anonymous.AnonymousProcessingFilter">
<property name="key" value="changeThis"/>
<property name="userAttribute" value="anonymousUser,ROLE_ANONYMOUS"/>
</bean>
<bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">
<property name="authenticationEntryPoint">
<bean class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<property name="loginFormUrl" value="/login.jsp"/>
<property name="forceHttps" value="false"/>
</bean>
</property>
<property name="accessDeniedHandler">
<bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl">
<property name="errorPage" value="/denied.jsp"/>
</bean>
</property>
</bean>
<bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager">
<bean class="org.acegisecurity.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions" value="false"/>
<property name="decisionVoters">
<list>
<bean class="org.acegisecurity.vote.RoleVoter"/>
<bean class="org.acegisecurity.vote.AuthenticatedVoter"/>
</list>
</property>
</bean>
</property>
<property name="objectDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/secure/admin/**=ROLE_ADMIN
/secure/**=IS_AUTHENTICATED_REMEMBERED
/**=IS_AUTHENTICATED_ANONYMOUSLY
</value>
</property>
</bean>
<bean id="rememberMeServices" class="org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices">
<property name="userDetailsService" ref="userDetailsService"/>
<property name="tokenValiditySeconds" value="1800"></property>
<property name="key" value="changeThis"/>
</bean>
<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref local="daoAuthenticationProvider"/>
<bean class="org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider">
<property name="key" value="changeThis"/>
</bean>
<bean class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">
<property name="key" value="changeThis"/>
</bean>
</list>
</property>
</bean>
<bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userDetailsService"/>
<property name="userCache">
<bean class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache">
<property name="cache">
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
</property>
<property name="cacheName" value="userCache"/>
</bean>
</property>
</bean>
</property>
</bean>
<bean id="userDetailsService" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
<property name="userProperties">
<bean class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="/WEB-INF/users.properties"/>
</bean>
</property>
</bean>
<bean id="loggerListener" class="org.acegisecurity.event.authentication.LoggerListener"/>
</beans>WEB-INF/applicationContext.xml - FilterChainProxy: Delegates Filter requests to a list of Spring-managed beans.
- HttpSessionContextIntegrationFilter: Populates the SecurityContextHolder with information obtained from the HttpSession.
- LogoutFilter: Logs a principal out.
- AuthenticationProcessingFilter: Processes an authentication form.
- SecurityContextHolderAwareRequestFilter: A Filter which populates the ServletRequest with a new request wrapper.
- RememberMeProcessingFilter: Detects if there is no Authentication object in the SecurityContext, and populates it with a remember-me authentication token if a RememberMeServices implementation so requests.
- AnonymousProcessingFilter: Detects if there is no Authentication object in the SecurityContextHolder, and populates it with one if needed.
- AnonymousProcessingFilter: Detects if there is no Authentication object in the SecurityContextHolder, and populates it with one if needed.
- ExceptionTranslationFilter: Handles any AccessDeniedException and AuthenticationException thrown within the filter chain.
- AuthenticationProcessingFilterEntryPoint: Used by the SecurityEnforcementFilter to commence authentication via the AuthenticationProcessingFilter. This object holds the location of the login form, relative to the web app context path, and is used to commence a redirect to that form.
- AccessDeniedHandlerImpl: Used by ExceptionTranslationFilter to handle an AccessDeniedException.
- FilterSecurityInterceptor: Performs security handling of HTTP resources via a filter implementation.
- TokenBasedRememberMeServices: Identifies previously remembered users by a Base-64 encoded cookie.
- DaoAuthenticationProvider: An AuthenticationProvider implementation that retrieves user details from an UserDetailsService.
- InMemoryDaoImpl: Retrieves user details from an in-memory list created by the bean context.

15 comments:
great article! was having a hard time getting a prototype to work, but with your instructions i was up and running in no time. thanks!
Very informative and detailed article. Was very helpful, thanks for sharing...
not a good article..number of errors..looks like acopy of article from Acegi itself...
Some suggestion:-
provide the war file
Good Thing :-
Only the steps thats it..
Great and comprehensive introductory article! Provides a very efficient path to implementing basic Acegi security w/o getting too much into the details of the framework itself, although explaining the necessary dependencies between the major concepts. Again - good work!
here i got an error when i tried to log in with scott whose pwd was supposed to be tiger. the error msg was "The requested resource (/AcgSpring/j_acegi_security_check) is not available."
can't figure out what's happening there. do you have any idea?
Thanks for the example!
I noticed a small typo in your 'login.jsp' HTML. you have an extra slash in your open TD tag.
"</td><input type='text' name='j_username' />"
should be
"<td><input type='text' name='j_username' />"
I could not make it work , I get this Error:
java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
maybe someone can help me...
thanks and great article...
tonelli,
you will have to include commons-logging.jar file in your classpath, it is available in the spring-with-dependencies download.
thanks, great article *thumbs up*
the same would be nice for basic authentication with spring security...
hey Abhi
Great article man!
But I am trying to use form-based authentication WITHOUT acegi security
After user enters its log name and password I get error:
The requested resource (/someapp/j_security_check) is not available.
What do you think coud cause this error ?
Thanks for your help
great. explained the most in the least. but after doing everything right, i.e. all libraries, code etc. in jboss4.2.2, i get this error: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named '' is defined
it's bugging me. any help or is it just a matter of using tomcat?
HI, I found the detailed configuration file and usage details.
Thanks
Arivuvel Ramu
But still i am facing one more issues.
First time i have logged in with "X" Name and visited "XYZ.jsp" page. then i logged out.
Second time i have logged in with "Y" Name and visited "YXSD.jsp" page, then i try to call "XYZ.jsp" from the browser, still the "X" person session is not experied.
My Question: if i press /j_acegi_logout and my session also needs to be invalidated.
Could u plz help me?
Can you check the web.xml to make sure the /j_acegi_logout is accessible and not mapped to other resource?
hi,
when i put this in my web.xml
{code}
code from context-param -end contenxt-param
and filter
name mapping and listener class
{code}
my application won't run in apache
response is
Application at context path /loyalty_final could not be started
plz tell me how to solve this error
Post a Comment