• Home
  • RSS Feed
  • Log in


How to implement your own Security provider with the Acegi framework.
Posted by Okke Harsta in the early morning: March 4th, 2007

In a previous blog I described the minimal basic configuration of the Acegi framework. In this blog I’ll show you how easy it is to implement your own security provider. There can be many reasons why you would want to implement such a customized security provider. In my case I had to secure an application using user information that was being maintained by an external php-based application. The user information could only be retrieved using a web service. In this blog I will demonstrate several ways to implement your own security provider.

The starting point is -again- the simple web application from the previous blog. The part of the acegi-security.xml that is relevant is shown below.


	<!--
		The authenticationManager is the hook for all authenticationProviders we want
		to configure.
	-->
	 <bean id="authenticationManager"
        class="org.acegisecurity.providers.ProviderManager">
        <property name="providers">
            <list>
                <ref local="authenticationProvider" />
            </list>
        </property>
    </bean>

	<!--
		The Acegi DaoAuthenticationProvider
	-->
    <bean id="authenticationProvider"
		class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
        <property name="userDetailsService" ref="userDetailsServiceImpl"/>
	</bean>

    <!--
        The Acegi InMemoryDaoImpl
    -->
    <bean id="userDetailsServiceImpl"
        class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
        <property name="userProperties">
            <props>
                <prop key="admin">secret,ROLE_ADMIN</prop>
            </props>
        </property>
    </bean>

We will replace this fragment with the following code:


	 <bean id="authenticationManager"
        class="com.xebia.acegi.CustomAuthenticationManager"/>

What does our CustomAuthenticationManager has to do? Well actually the interface AuthenticationProvider that needs to be implemented is quite straightforward:


public Authentication authenticate(Authentication authentication)
        throws AuthenticationException;

Lets begin with the most simple implementation possible:


	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		authentication.setAuthenticated(true);
		return authentication;
	}

When we start jetty (see previous blog) we can tweak Maven to give us a remote debugging hook by setting the MAVEN_OPTS variable:


$ echo $MAVEN_OPTS
-XX:MaxPermSize=512m -Xmx1024m -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=4000,server=y,suspend=n

The first two arguments allocate more memory to the Maven process and the last arguments provide us a way to remotely debug the application. Using eclipse we can configure a remote debug application:

Eclipse Remote Debugging

The implementation of the Authentication interface used by Acegi is an instance of UsernamePasswordAuthenticationToken as we can see when debugging the application.

Eclipse Debug Info

The UsernamePasswordAuthenticationToken is constructed in the AuthenticationProcessingFilter -as configured in acegi-secutiry.xml-, but we could also subclass this filter to use more exotic implementations like the X509AuthenticationToken.

When checking out the result at http://localhost:8080/blog-acegi/site/admin.html it appears the implementation we have provided is to simple:


HTTP ERROR: 500

Cannot set this token to trusted - use constructor containing GrantedAuthority[]s instead

RequestURI=/blog-acegi/j_acegi_security_check
Caused by:

java.lang.IllegalArgumentException: Cannot set this token to trusted - use constructor containing GrantedAuthority[]s instead
	at org.acegisecurity.providers.UsernamePasswordAuthenticationToken.setAuthenticated(UsernamePasswordAuthenticationToken.java:85)
	at com.xebia.acegi.CustomAuthenticationManager.authenticate(CustomAuthenticationManager.java:25)
	at org.acegisecurity.ui.webapp.AuthenticationProcessingFilter.attemptAuthentication(AuthenticationProcessingFilter.java:71)
	at org.acegisecurity.ui.AbstractProcessingFilter.doFilter(AbstractProcessingFilter.java:199)
	at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:274)
	at org.acegisecurity.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:107)
	at org.acegisecurity.intercept.web.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:72)
	at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:274)
	at org.acegisecurity.ui.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:110)
	at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:274)
	at org.acegisecurity.util.FilterChainProxy.doFilter(FilterChainProxy.java:148)
	at org.acegisecurity.util.FilterToBeanProxy.doFilter(FilterToBeanProxy.java:98)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1065)

Acegi insists we create our instance of the Authentication interface. So let’s change our custom authentication manager using the following code:


return new UsernamePasswordAuthenticationToken(
				authentication.getPrincipal(),
				authentication.getCredentials(),
				new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_ADMIN") });

Of course a more serious implementation would do some lookup of the User and apply business logic to authenticate the user.

Acegi provides also an abstract AbstractUserDetailsAuthenticationProvider class that can be subclassed in able to benefit from the existing functionality from the Acegi framework. We change the relevant xml part in the acegi-security.xml with this fragment:


	<!--
		The authenticationManager is the hook for all authenticationProviders we want
		to configure.
	-->
	 <bean id="authenticationManager"
        class="org.acegisecurity.providers.ProviderManager">
        <property name="providers">
            <list>
                <ref local="authenticationProvider" />
            </list>
        </property>
    </bean>

	<!--
		Our own custom authenticationProvider.
	-->
    <bean id="authenticationProvider"
		class="com.xebia.acegi.CustomUserDetailsAuthenticationProvider">
	</bean>

The abstract methods that need to be implemented are simple:


protected abstract void additionalAuthenticationChecks(UserDetails userDetails,
			UsernamePasswordAuthenticationToken authentication)
			throws AuthenticationException ;

protected UserDetails retrieveUser(String username,
			UsernamePasswordAuthenticationToken authentication)
			throws AuthenticationException ;

And a -again very simple- implementation could be:


protected UserDetails retrieveUser(String username,
			UsernamePasswordAuthenticationToken authentication)
			throws AuthenticationException {
		Assert.hasText(username);
		Assert.notNull(authentication.getCredentials());
		if (username.equals("admin")
				&& authentication.getCredentials().equals("secret")) {
			return new User("admin", "secret", true, true, true, true,
					getAuthorities());
		}
		throw new BadCredentialsException("invalid username/password");
	}
	/*
	 * return GrantedAuthorities
	 */
	private GrantedAuthority[] getAuthorities() {
		return new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_ADMIN") };
	}

The hook that Acegi offers when subclassing the AbstractUserDetailsAuthenticationProvider allows you to call a web service to get the relevant information, query a legacy database or do whatever it takes to populate the User object. Note that because the authentication providers/managers are normal Spring beans you can inject them with configured data sources or any other -more exotic- beans.

A more complex use case could require the following security constraints to be implemented:

  • An user account will be locked if the number of consecutive faulty login attempts exceeds 3.
  • The password of an user account must be stored encrypted.
  • An user account can be disabled/enabled for a certain period.
  • An user account expiries after a certain period of inactivity.
  • A password expiries after a certain period.

The actual implementation (not provided ;-) , but you can use this as a starting point ) of such a security policy is quite simple using the Acegi framework and the many hooks Acegi provides. When you consider implementing your own authentication provider do have a good look at the stuff that Acegi provides. There is good chance you can use/re-use existing functionality. There is a lot more to tell about the Acegi Framework like securing your services, securing specific part of your pages, accessing the user data stored in the session, integration with LDAP and using Acegi for standalone desktop applications but not now……

Share

Filed under Security | 2 Comments »



2 Responses to “How to implement your own Security provider with the Acegi framework.”



    Idrees Says:
    Posted at: March 7, 2007 at 8:00 pm

    I have gone through the hints you provided, Actually my situation is where I have to call a web service for authentication, so there will be a java class which will call the webservice and i want that class to act as a authentication provider.

    So please help help help

    Thank you

    Reply


    Idrees Says:
    Posted at: March 8, 2007 at 1:08 am

    I have figued it out. My listner was giving some weired problem

    Now its working excelent.
    Thank you very much for providing this blog and helping my understanding.

    Really Appreciated

    God Bless you

    Reply


Leave a Reply

Click here to cancel reply.


Xebia Sites

  • Xebia Corporate
  • Xebia France
  • Xebia India
  • XebiCon 2012

Categories

  • Java (312)
  • Agile (192)
  • General (141)
  • Scrum (70)
  • Testing (65)
  • Architecture (65)
  • Performance (47)
  • Middleware (59)
    • Deployment (40)
  • Xebia Labs (41)
  • SOA (31)
  • Project Management (31)
  • Podcast (31)
  • Tools (28)
  • Uncategorized (24)
  • lean architecture (20)
  • Quality Assurance (19)
  • Articles (15)
  • Requirements Management (14)
  • Virtualization (21)

Tag Cloud

    lean architectuur TDD product owner SOA Eclipse Lean Xebia Concurrency Control Flex Agile Scala Javascript Groovy Architecture agile architectuur Frameworks Java Grails ACT Ajax Maven Oracle XML Spring JPA Hibernate lean architecture Scrum Moving to India JPA implementation patterns

Archives

  • May 2012
  • April 2012
  • March 2012
  • February 2012
  • January 2012
  • December 2011
  • November 2011
  • October 2011
  • September 2011
  • August 2011
  • July 2011
  • June 2011
Avatars by Sterling Adventures