Spring Security CAS: show client error on login.jsp

298 Views Asked by At

I'm using Spring Security with CAS and have the following issue. When the authentication error is thrown from CAS Server (e.g. invalid username/password) it is shown well in form and is displayed correctly using tag:

<form:errors path="*" id="msg" cssClass="alert alert-danger" element="div"/>

But in cases when CAS Server returns success and the AuthenticationException is thrown on CAS Client none of the errors are displayed as basically CAS Client redirects back to http://localhost:8080/cas/login?service=http%3A%2F%2Flocalhost%3A8080%2Fj_spring_cas_security_check

So I can't really display what went wrong on the client side. Is it somehow possible to display an error from client on the same JSP in case it throws AuthenticationException?

1

There are 1 best solutions below

0
yyunikov On BEST ANSWER

Not sure if that's the super clean and right way to do it, but the way I've managed to do that is using cookies.

All I had to do is to extend SimpleUrlAuthenticationFailureHandler, get there last authentication exception using request.getSession().getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION) and write my custom error code cookie. The code is in Scala, but is pretty straightforward:

class CookieAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler{

  val clientErrorCookie = "clientError"

  override def onAuthenticationFailure(request: HttpServletRequest, response: HttpServletResponse, exception: AuthenticationException): Unit = {
    val authenticationException = SecurityUtility.getSessionAuthException(request).getOrElse(exception)

    ClientErrors.values
      .filter(clientError => clientError.exceptionClass.equals(authenticationException.getClass))
      .foreach(clientError => response.addCookie(new Cookie(clientErrorCookie, clientError.errorCode)))

    super.onAuthenticationFailure(request, response, authenticationException)
  }
}

Then, on the CAS server side I've displayed error on JSP in the following way:

<c:set var="clientErrorCookie" value="clientError"/>
<c:if test="${cookie.containsKey(clientErrorCookie)}">
                    <div class="alert alert-danger">
                        <spring:message code="error.client.authentication.${cookie.get(clientErrorCookie).value}"
                                        text="Client authentication error"/>
                    </div>
                </c:if>

And after the page is loaded and error is shown, I've just removed that cookie in JS:

function deleteCookie(name) {
            document.cookie = name + '=; Path=/; expires=Thu, 01 Jan 1970 00:00:01 GMT;';
        }

$(document).ready(function(){
          deleteCookie('${clientErrorCookie}');
        }