I'm using Spring Security 3 and I'm trying to implement a Brute force protection that works as follow. Rather than locking an account after a number of attempts, increase the time until another login attempt is allowed:
- 1st failed login: no delay
- 2nd failed login: 2 sec delay
- 3rd failed login: 4 sec delay
- 4th failed login: 8 sec delay
- 5th failed login: 16 sec delay
I have already set up the necessary to handle this in my AuthenticationProvider. Basically on failure I have a Map<Username, NextAvailableLoginTime> which I increase the counters on. On success I remove the entry and on login I check the times and so on.
@Override
public Authentication authenticate(Authentication authentication) {}
But my problem is that I would like to return a custom JSON when a user tried to login after he failed, something like this:
{"errorCode":999,"Message":"User cannot login before x seconds"}
where "x" is the value inside my Map. But I cannot figure how I can retrieve the username (to be able to fetch it in my Map) on login failure! The "AuthenticationSuccessHandler" doesn't allow me to retrieve the Authentication object any more (deprecated).
And for the moment I return a message by doing this, but it is an hardcoded message... I want a customisable one depending on the username.
void onAuthenticationFailure(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException exception)
throws IOException, ServletException {
String json = ....
PrintWriter out = response.getWriter();
response.setContentType("application/json");
out.print(json);
}
Could someone help me with this?
If the user can't be authenticated due to the time limit before next allowed login, just throw
AuthenticationExceptionfrom theAuthenticationProviderand put the message you want to return as the Exception message. You can assemble the message easily, because in the authentication provider you have access to both your Map and theAuthenticationobject.And in the failure handler just print out the exception message:
Hope this works