I made a login system with Spring Security. This is my spring-security.xml
...
Instead of the authentication-failure-url, you need to use authentication-failure-handler-ref and refer the failure handler bean which you need to create and map different urls (or different params to the same url) to different type of exceptions.
<form-login
login-page="/login"
default-target-url="/index"
always-use-default-target="true"
authentication-failure-handler-ref="customFailureHandler"
username-parameter="j_username"
password-parameter="j_password" />
<beans:bean id="customFailureHandler"
class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler">
<beans:property name="exceptionMappings">
<beans:props>
<beans:prop
key="org.springframework.security.authentication.BadCredentialsException">/url1</beans:prop>
<beans:prop
key="org.springframework.security.authentication.AuthenticationServiceException">/url2</beans:prop>
<beans:prop key="org.springframework.secuirty.authentication.DisabledException">/url3</beans:prop>
</beans:props>
</beans:property>
<beans:property name="defaultFailureUrl" value="/url4" />
</beans:bean>
There are bunch of other exceptions, mentioned in the docs. Please refer the doc
EDIT:
There is an exception for the same, SessionAuthenticationException is thrown typically because the same user has exceeded the number of sessions they are allowed to have concurrent. But this is at container level only and won't work if you have multiple containers.
<security:session-management session-authentication-strategy-ref="sas"/>
<bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl" />
<bean id="sas" class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy" >
<constructor-arg name="sessionRegistry" ref="sessionRegistry" />
<property name="maximumSessions" value="2" />
</bean>
I found this solution, it seems to work.
Extending SimpleUrlAuthenticationFailureHandler
you can send the user to different pages, and print the message you want.
My main goal wasn't to "override" SPRING_SECURITY_LAST_EXCEPTION.message
but was customizing the error message according to the various kind of errors Spring security gives me.
web.xml
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
security-config.xml (just some code)
session-management
<session-management invalid-session-url="/login" session-authentication-error-url="/login" >
<concurrency-control max-sessions="1" expired-url="/login" error-if-maximum-exceeded="true"/>
</session-management>
form-login where you call your own AuthenticationFailureHandler (customFailureHandler)
<form-login
login-page="/login"
default-target-url="/index"
always-use-default-target="true"
authentication-failure-handler-ref="customFailureHandler"
username-parameter="j_username"
password-parameter="j_password" />
the bean of your own AuthenticationFailureHandler
<beans:bean id="customFailureHandler" class="com.springgestioneerrori.controller.CustomAuthenticationFailureHandler"/>
and this is the class implementing SimpleUrlAuthenticationFailureHandler
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.session.SessionAuthenticationException;
public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
if(exception.getClass().isAssignableFrom(BadCredentialsException.class)) {
setDefaultFailureUrl("/url1");
}
else if (exception.getClass().isAssignableFrom(DisabledException.class)) {
setDefaultFailureUrl("/url2");
}
else if (exception.getClass().isAssignableFrom(SessionAuthenticationException.class)) {
setDefaultFailureUrl("/url3");
}
super.onAuthenticationFailure(request, response, exception);
}
}
Hope this can help someone.
This is an old question, but since the answer marked as correct actually contains a nasty subtle bug it should be noted that the correct solution would be to use built-in ExceptionMappingAuthenticationFailureHandler
instead of the CustomAuthenticationFailureHandler
suggested in the answer from @mdp.