Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to customize SPRING_SECURITY_LAST_EXCEPTION.message according to the error I get

I made a login system with Spring Security. This is my spring-security.xml

... 
<session-management invalid-session-url="/login">
       <concurrency-control max-sessions="1" expired-url="/login" error-if-maximum-exceeded="true"/>
</session-management>

<form-login 
        login-page="/login"                         
        default-target-url="/index" 
        always-use-default-target="true"
        authentication-failure-url="/login?error=true"          
        username-parameter="j_username"         
        password-parameter="j_password" />

<logout
        logout-success-url="/login"          
        delete-cookies="JSESSIONID" 
        invalidate-session="true" />     
    ...

Since i have this line authentication-failure-url="/login?error=true" I know that if error is 'true' there's an error: it might be "bad credentials" or "Maximum sessions number exceeded".But I'd like to know which error really occorred?

Is there a way, inside a java class (@controller), to know what kind of error Spring is giving me, in order to customize those error messages?

like image 536
MDP Avatar asked Dec 20 '22 10:12

MDP


2 Answers

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.

like image 132
MDP Avatar answered Dec 29 '22 00:12

MDP


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>
like image 22
Janendra Avatar answered Dec 29 '22 01:12

Janendra