/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.infrastructure.security.service;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.WebAttributes;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.util.Assert;
public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {
protected final Log logger = LogFactory.getLog(getClass());
private String defaultFailureUrl;
private boolean forwardToDestination = false;
private boolean allowSessionCreation = true;
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
public CustomAuthenticationFailureHandler() {}
/**
* Performs the redirect or forward to the {@code defaultFailureUrl} if set,
* otherwise returns a 401 error code.
* <p>
* If redirecting or forwarding, {@code saveException} will be called to
* cache the exception for use in the target view.
*/
@Override
public void onAuthenticationFailure(final HttpServletRequest request, final HttpServletResponse response,
final AuthenticationException exception) throws IOException, ServletException {
if (this.defaultFailureUrl == null) {
this.logger.debug("No failure URL set, sending 401 Unauthorized error");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication Failed: " + exception.getMessage());
} else {
saveException(request, exception);
if (this.forwardToDestination) {
this.logger.debug("Forwarding to " + this.defaultFailureUrl);
request.getRequestDispatcher(this.defaultFailureUrl).forward(request, response);
} else {
this.logger.debug("Redirecting to " + this.defaultFailureUrl);
final String oauthToken = request.getParameter("oauth_token");
request.setAttribute("oauth_token", oauthToken);
final String url = this.defaultFailureUrl + "?oauth_token=" + oauthToken;
this.redirectStrategy.sendRedirect(request, response, url);
}
}
}
/**
* Caches the {@code AuthenticationException} for use in view rendering.
* <p>
* If {@code forwardToDestination} is set to true, request scope will be
* used, otherwise it will attempt to store the exception in the session. If
* there is no session and {@code allowSessionCreation} is {@code true} a
* session will be created. Otherwise the exception will not be stored.
*/
protected final void saveException(final HttpServletRequest request, final AuthenticationException exception) {
if (this.forwardToDestination) {
request.setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, exception);
} else {
final HttpSession session = request.getSession(false);
if (session != null || this.allowSessionCreation) {
request.getSession().setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, exception);
}
}
}
/**
* The URL which will be used as the failure destination.
*
* @param defaultFailureUrl
* the failure URL, for example "/loginFailed.jsp".
*/
public void setDefaultFailureUrl(final String defaultFailureUrl) {
Assert.isTrue(UrlUtils.isValidRedirectUrl(defaultFailureUrl), "'" + defaultFailureUrl + "' is not a valid redirect URL");
this.defaultFailureUrl = defaultFailureUrl;
}
protected boolean isUseForward() {
return this.forwardToDestination;
}
/**
* If set to <tt>true</tt>, performs a forward to the failure destination
* URL instead of a redirect. Defaults to <tt>false</tt>.
*/
public void setUseForward(final boolean forwardToDestination) {
this.forwardToDestination = forwardToDestination;
}
/**
* Allows overriding of the behaviour when redirecting to a target URL.
*/
public void setRedirectStrategy(final RedirectStrategy redirectStrategy) {
this.redirectStrategy = redirectStrategy;
}
protected RedirectStrategy getRedirectStrategy() {
return this.redirectStrategy;
}
protected boolean isAllowSessionCreation() {
return this.allowSessionCreation;
}
public void setAllowSessionCreation(final boolean allowSessionCreation) {
this.allowSessionCreation = allowSessionCreation;
}
}