DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Nicholas has posted 1 posts at DZone. View Full User Profile

Overriding Tomcat Valve To Return Extended Login Failure Status

03.22.2007
| 8914 views |
  • submit to reddit
        See <a href="http://shadegrowncode.blogspot.com/2007/03/returning-login-failure-reason-in.html">Shade Grown Code</a> 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);
    }
}
    

Comments

Snippets Manager replied on Wed, 2008/10/08 - 5:03pm

How do you register this new valve? What I did is edit server.xml, find the element, and underneath it is a element, so just before the element as a direct child of I inserted But Tomcat throws an error when starting up. The error regards a parse exception of server.xml.