Servlets Java

/*
 * Copyright 2004 Matthew Moodie.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.apress.admin.filters;
import java.io.IOException;
import java.util.ArrayList;
import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import javax.servlet.FilterChain;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.ServletException;
import org.apache.regexp.RE;
import org.apache.regexp.RESyntaxException;
import javax.servlet.http.HttpServletRequest;
/**
 * Implementation of a filter that performs filtering based on comparing the
 * appropriate request property against a set of regular
 * expressions configured for this filter.
 * 


 * This filter is configured by setting the allow and/or
 * deny filter initialization parameters to a comma-delimited 
 * list of regular expressions (in the syntax supported by the jakarta-regexp 
 * library) in web.xml to which the appropriate request property 
 * will be compared.  Evaluation proceeds as follows:
 * 


     * 
  • The filter extracts the request property to be filtered.
     * 
  • If there are any deny expressions configured, the property will
     *     be compared to each such expression.  If a match is found, this
     *     request will be forwarded to a blocked page (configured with the
     *     blockPage filter initialization parameter in 
     *     web.xml).

  •  * 
  • If there are any allow expressions configured, the property will
     *     be compared to each such expression.  If a match is found, this
     *     request will be allowed to pass through to the next filter in the
     *     current pipeline.

  •  * 
  • If one or more deny expressions was specified but no allow expressions,
     *     allow this request to pass through (because none of the deny
     *     expressions matched it).
     * 
  • The request will be forwarded to a blocked page (configured with the
     *     blockPage filter initialization parameter in 
     *     web.xml).

  •  * 

 * 


 * This filter is based on, and is a modification of, the request 
 * interception mechanism provided by Tomcat's remote request 
 * filter valves. Instead of returning a forbidden HTTP response,
 * it forwards the request to a custom blocked page.
 * 
 * In particular, it uses code from org.apache.catalina.valves.RequestFilterValve
 * to process a list of allowed and denied IP addresses and remote hosts, as well
 * as code to check the user's details against this list. The difference in this
 * filter is that it doesn't have implementing classes to differentiate between
 * IP addresses and remote hosts. It simply checks them all at once.
 *
 * @author Matthew Moodie
 * @version $Revision: 1.0 $ $Date: 2004/08/04 23:07:00 $
 */
public class RequestFilter implements Filter {
    // ----------------------------------------------------- Instance Variables
    /**
     * The comma-delimited set of allow expressions.
     */
    protected String allowedList = null;
    /**
     * The set of allow regular expressions we will evaluate.
     */
    protected RE allows[] = new RE[0];
    /**
     * The set of deny regular expressions we will evaluate.
     */
    protected RE denies[] = new RE[0];
    /**
     * The comma-delimited set of deny expressions.
     */
    protected String deniedList = null;
    /* The configuration associated with this filter */
    private FilterConfig config =  null;
    /* The page informing users that their request has been blocked */
    private String blockPage = "";
    /* The remote host and IP address of the client */
    private String host = null;
    private String ip = null; 
    /**
     * Initializes the filter at server startup.
     * Initialization consists of setting the list of allowed
     * and disallowed remote hosts and IP addresses.
     * @param _config The configuration associated with this filter
     *
     * @exception ServletException if there was a problem initializing this filter
     */
    public void init(FilterConfig _config)
      throws ServletException {
        this.config = _config;
        /* Get the initialization parameters as a string */
        allowedList = _config.getInitParameter("allow");
        deniedList = _config.getInitParameter("deny");
  blockPage = _config.getInitParameter("blockPage");
        /* Turn the lists into regular expression lists */
        allows = precalculate(allowedList);
        denies = precalculate(deniedList);
    }
    /**
     * Processes a request and blocks it as appropriate.
     * This method takes the list of allowed and disallowed
     * remote hosts and IP addresses and checks if the client's
     * details match them.
     *
     * Some of the code in this method comes from org.apache.catalina.valves.RequestFilterValve.
     *
     * @param _req The request
     * @param _res The response
     * @param _chain The filter chain that this filter belongs to
     *
     * @exception IOException if there is a problem with the filter
     *  chain or the forward
     * @exception ServletException if there is a problem with the filter
     *  chain or the forward
     */
    public void doFilter(ServletRequest _req, ServletResponse _res,
        FilterChain _chain) throws IOException, ServletException {
        /* Get the type */
        if (_req instanceof HttpServletRequest) {
            host = _req.getRemoteHost();
            ip = _req.getRemoteAddr();
        }
        // Check the deny patterns, if any
        for (int i = 0; i < denies.length; i++) {
            if (denies[i].match(host) || denies[i].match(ip)) {
                if (_req instanceof HttpServletRequest) {
              config.getServletContext().getRequestDispatcher(blockPage).forward(_req, _res);
              return;
                }
            }
        }
        if(!(_res.isCommitted())){
            // Check the allow patterns, if any
            for (int i = 0; i < allows.length; i++) {
                if (allows[i].match(host) || allows[i].match(ip)) {
        _chain.doFilter(_req, _res);
        return;
                }
            }
        }
        if(!(_res.isCommitted())){
            // Allow if denies specified but not allows
            if ((denies.length > 0) && (allows.length == 0)) {
                _chain.doFilter(_req, _res);
                return;
            }
        }
       if(!(_res.isCommitted())){
           // Deny this request
           if (_req instanceof HttpServletRequest) {
        config.getServletContext().getRequestDispatcher(blockPage).forward(_req, _res);
           } 
       }
    }
  
    /**
     * Return an array of regular expression objects initialized from the
     * specified argument, which must be null or a comma-delimited
     * list of regular expression patterns.
     *
     * This method comes from org.apache.catalina.valves.RequestFilterValve.
     *
     * @param list The comma-separated list of patterns
     *
     * @exception IllegalArgumentException if one of the patterns has
     *  invalid syntax
     */
    protected RE[] precalculate(String list) {
        if (list == null)
            return (new RE[0]);
        list = list.trim();
        if (list.length() < 1)
            return (new RE[0]);
        list += ",";
        ArrayList reList = new ArrayList();
        while (list.length() > 0) {
            int comma = list.indexOf(',');
            if (comma < 0)
                break;
            String pattern = list.substring(0, comma).trim();
            try {
                reList.add(new RE(pattern));
            } catch (RESyntaxException e) {
                IllegalArgumentException iae = new IllegalArgumentException("Illegal pattern: " +  pattern);
                throw iae;
            }
            list = list.substring(comma + 1);
        }
        RE reArray[] = new RE[reList.size()];
        return ((RE[]) reList.toArray(reArray));
    }
    /**
     * Called when the filter is taken out of service at server shutdown.
     *
     */
    public void destroy() {
        config = null;
    }
}