How to include SPRING_SECURITY_LAST_USERNAME in authentication failure url?

authentication, java, spring, spring-mvc, spring-security

Solution

It's deprecated:

/**
  * @deprecated If you want to retain the username, cache it in a customized {@code AuthenticationFailureHandler}
  */
@Deprecated
public static final String SPRING_SECURITY_LAST_USERNAME_KEY = "SPRING_SECURITY_LAST_USERNAME";

So you need to implement your own `AuthenticationFailureHandler`.

I implemented 1) strategy: (remember that username can contain some characters that are inappropriate inside URL!)

package some.package;

import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class UsernameInURLAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {

    private String urlPrefix;
    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
    private String formUsernameKey = UsernamePasswordAuthenticationFilter.SPRING_SECURITY_FORM_USERNAME_KEY;

    public UsernameInURLAuthenticationFailureHandler(String urlPrefix) {
        this.urlPrefix = urlPrefix;
    }

    //Failure logic:
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        //We inherited that method:
        saveException(request, exception);

        //Prepare URL:
        String username = request.getParameter(formUsernameKey);
        String redirectUrl = urlPrefix + username;

        //Redirect:
        redirectStrategy.sendRedirect(request, response, redirectUrl);
    }

    //Getters and setters:
    public String getUrlPrefix() {
        return urlPrefix;
    }

    public void setUrlPrefix(String urlPrefix) {
        this.urlPrefix = urlPrefix;
    }

    public String getFormUsernameKey() {
        return formUsernameKey;
    }

    public void setFormUsernameKey(String formUsernameKey) {
        this.formUsernameKey = formUsernameKey;
    }

    public RedirectStrategy getRedirectStrategy() {
        return redirectStrategy;
    }

    public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
        this.redirectStrategy = redirectStrategy;
    }
}

Bean:

<bean class="some.package.UsernameInURLAuthenticationFailureHandler">
        <!-- prefix: -->
        <constructor-arg value="/login/failure/"/>
</bean>

You can easily implement 2) strategy. Just save the username as one of the session attributes inside `onAuthenticationFailure` method instead of adding username to the URL.

You can easily set your own handler:

`<form-login>` Attributes

`authentication-failure-handler-ref`

Can be used as an alternative to authentication-failure-url, giving you full control over the navigation flow after an authentication failure. The value should be he name of an AuthenticationFailureHandler bean in the application context.

More in docs: CLICK

Problem

I've the following in my Spring Security XML: ``` <form-login login-page="/login" authentication-failure-url="/login/failure" /> ``` I want to get the username on authentication failure. I read over the net that it can be got from SPRING_SECURITY_LAST_USERNAME, but my question is: How can i access it either in: 1) the spring security XML e.g. something like authentication-failure-url="/login/failure/SPRING_SECURITY_LAST_USERNAME" 2) or the controller that's handling /login/failure mapping. Please help. I'm stuck! :(

Original source