Abner Ballardo

I’ve been using Acegi Security in several projects with good results. It’s powerful and flexible! Sadly, sometimes, developers have problems when they want to customize it. The code is the best documentation, so, I recommend them to read the code and javadocs. Well, this time I’ll show you how to customize the authentication. I assume a good knowledge of Spring Framework and basic knowledge of Acegi Security.

<bean id="authenticationProcessingFilter"
      class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
  <property name="authenticationManager"    ref="authenticationManager"/>
  <property name="authenticationFailureUrl" value="/login.htm?login_error=1"/>
  <property name="defaultTargetUrl"         value="/foobar.htm"/>
  <property name="filterProcessesUrl"       value="/j_acegi_security_check"/>
</bean>

You usually define a bean like authenticationProcessingFilter and add it to a chain in the FilterChainProxy bean. With this configuration, you attempt to authenticate when a request to /j_acegi_security_check has been made, delegating the authentication to the authenticationManager bean. If everything is OK, the user is redirected to /foobar.htm otherwise to /login.htm?login_error=1

Most of the time, you will be happy with this configuration but what happens if you need to do some additional validations before authentication. You have to extend AuthenticationProcessingFilter

package net.modlost.framework.security;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.acegisecurity.AuthenticationException;
import org.acegisecurity.ui.webapp.AuthenticationProcessingFilter;

/**
 * @author Abner Ballardo Urco
 *
 */
public class CustomAuthenticationProcessingFilter extends
                AuthenticationProcessingFilter {

        @Override
        protected void onPreAuthentication(HttpServletRequest request,
                        HttpServletResponse response) throws AuthenticationException,
                        IOException {

                if (! validAuthenticationRequest(request,response)) {
                        throw new FooBarAuthenticationException();
                }

        }

        private boolean validAuthenticationRequest(HttpServletRequest request,
                        HttpServletResponse response) {
                return false;
        }

}

Acegi provides a handily method: onPreAuthentication, you just need to override it, do your additional validations and throw an exception when the validation failed. This exception could extend AuthenticationException or IOException.

package net.modlost.framework.security;

import org.acegisecurity.AuthenticationException;

/**
 * @author Abner Ballardo Urco
 *
 */
public class FooBarAuthenticationException extends AuthenticationException {

        public FooBarAuthenticationException() {
                super("FooBar Authentication Exception");
        }

}

If onPreAuthentication doesn’t throw an exception, the normal authentication process continues. This isn’t the end of the story, what happens if you need to show different views according to the exception?. This step is a peace of cake!

<bean id="authenticationProcessingFilter"
      class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
  <property name="authenticationManager"    ref="authenticationManager"/>
  <property name="authenticationFailureUrl" value="/login.htm?login_error=1"/>
  <property name="defaultTargetUrl"         value="/foobar.htm"/>
  <property name="filterProcessesUrl"       value="/j_acegi_security_check"/>
  <property name="exceptionMappings">
  <props>
    <prop key="net.modlost.framework.security.FooBarAuthenticationException">/foobarError.jsp</prop>
  </props>
  </property>
</bean>

Defining the property exceptionMappings in authenticationProcessingFilter you can add all the exceptions (from Acegi and yours) and the urls to redirect to. If the exception is not found in exceptionMappings the default authenticationFailureUrl will be used.