Overriding Tomcat Valve To Return Extended Login Failure Status
Join the DZone community and get the full member experience.
Join For FreeSee Shade Grown Code for more information.
ExtendedStatusSetter.java
package com.ofc.tomcat;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Interface flagging that the implementing Realm can set request
* headers providing additional information about an authentication
* failure.
*
* @author Nicholas Sushkin
*/
public interface ExtendedStatusSetter
{
/**
* The request attribute under which we forward an extended failure status message
* (as an object of type String) to a login error page.
*/
public static String LOGIN_FAILURE_MESSAGE_ATTR =
"com.ofc.tomcat.LOGIN_FAILURE_MESSAGE";
public void setExtendedStatus(String username, HttpServletRequest request, HttpServletResponse response);
}
ExtendedStatusFormAuthenticator.java
package com.ofc.tomcat;
import org.apache.catalina.authenticator.Constants;
import org.apache.catalina.authenticator.FormAuthenticator;
import org.apache.catalina.Realm;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.deploy.LoginConfig;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.servlet.RequestDispatcher;
/**
* Adds extended authentication failure status to tomcat FormAuthenticator.
*
* @author Nicholas Sushkin
*/
public class ExtendedStatusFormAuthenticator extends FormAuthenticator
{
/**
* Descriptive information about this implementation.
*/
protected static final String info =
"com.ofc.tomcat.ExtendedStatusFormAuthenticator/1.0";
private static Log log = LogFactory.getLog(ExtendedStatusFormAuthenticator.class);
// ------------------------------------------------------------- Properties
/**
* Return descriptive information about this Valve implementation.
*/
@Override
public String getInfo()
{
return info;
}
// ------------------------------------------------------------- Overridden behavior
/**
* Called to forward to the error page
*
* @param request Request we are processing
* @param response Response we are creating
* @param config Login configuration describing how authentication
* should be performed
*/
@Override
protected void forwardToErrorPage(Request request, Response response, LoginConfig config)
{
Realm realm = context.getRealm();
if (realm instanceof ExtendedStatusSetter)
{
log.debug("realm implements ExtendedStatusSetter, setting extended status for error page");
String username = request.getParameter(Constants.FORM_USERNAME);
((ExtendedStatusSetter) realm).setExtendedStatus(username, request.getRequest(), response.getResponse());
}
else
{
log.debug("realm does not implement ExtendedStatusSetter, NOT setting extended status for error page");
}
RequestDispatcher disp =
context.getServletContext().getRequestDispatcher
(config.getErrorPage());
try {
disp.forward(request.getRequest(), response.getResponse());
response.finishResponse();
} catch (Throwable t) {
log.warn("Unexpected error forwarding to error page", t);
}
}
}
Realm implementation will include the following
public class AccountLockoutDatasourceRealm extends DataSourceRealm implements ExtendedStatusSetter
{
// ...
public void setExtendedStatus(String username, HttpServletRequest request, HttpServletResponse response)
{
setMessage(request, "Account locked");
}
protected void setMessage(HttpServletRequest request, String message)
{
request.setAttribute(ExtendedStatusSetter.LOGIN_FAILURE_MESSAGE_ATTR, message);
}
}
Apache Tomcat
Opinions expressed by DZone contributors are their own.
Comments