You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by cr...@locus.apache.org on 2000/06/11 05:04:41 UTC

cvs commit: jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/valves RemoteAddrValve.java RemoteHostValve.java RequestFilterValve.java LocalStrings.properties

craigmcc    00/06/10 20:04:41

  Modified:    proposals/catalina/src/share/org/apache/tomcat/valves
                        LocalStrings.properties
  Added:       proposals/catalina/src/share/org/apache/tomcat/valves
                        RemoteAddrValve.java RemoteHostValve.java
                        RequestFilterValve.java
  Log:
  Add a convenience base class and two implementations of a request filter
  valve that checks an appropriate request property (in the cases at hand,
  either the remote IP address or the remote host name) against a series of
  "allow" and "deny" regular expressions configured for each valve.  These
  filters can be added at any Container level (such as Engine, Host, or
  Context) depending on the granularity of the filtering you wish to
  perform.
  
  Filters are configured by setting the "allow" and/or "deny" properties
  to a comma-delimited set of regular expressions, using the syntax of the
  jakarta-regexp regular expression library.
  
  The general filtering logic for all subclasses of RequestFilterValve
  works like this:
  * Check the appropriate request property against the set of "deny"
    patterns.  If any of these patterns match, reject the request with
    an HTTP "Forbidden" response.
  * Check the appropriate request property against the set of "allow"
    patterns.  If any of these patterns match, pass this request and
    response on to the next Valve in the pipeline.
  * If one or more deny patterns was specified but no allow patterns,
    pass this request and response on to the next Valve in the pipeline
    (because none of the deny patterns rejected it).
  * Reject this request with an HTTP "Forbidden" response.
  
  Filters on other request properties can be easily created by subclassing
  RequestFilterValve, using the two initial implementations as examples.
  
  Revision  Changes    Path
  1.3       +2 -0      jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/valves/LocalStrings.properties
  
  Index: LocalStrings.properties
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/valves/LocalStrings.properties,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- LocalStrings.properties	2000/05/05 18:25:18	1.2
  +++ LocalStrings.properties	2000/06/11 03:04:41	1.3
  @@ -2,4 +2,6 @@
   accessLogValve.notStarted=Access Logger has not yet been started
   interceptorValve.alreadyStarted=Interceptor Valve has already been started
   interceptorValve.notStarted=Interceptor Valve has not yet been started
  +requestFilterValve.next=No 'next' valve has been configured
  +requestFilterValve.syntax=Syntax error in request filter pattern {0}
   valveBase.noNext=Configuration error: No 'next' valve configured
  
  
  
  1.1                  jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/valves/RemoteAddrValve.java
  
  Index: RemoteAddrValve.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/valves/RemoteAddrValve.java,v 1.1 2000/06/11 03:04:41 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2000/06/11 03:04:41 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  
  
  package org.apache.tomcat.valves;
  
  
  import java.io.IOException;
  import javax.servlet.ServletException;
  import org.apache.tomcat.Request;
  import org.apache.tomcat.Response;
  
  
  /**
   * Concrete implementation of <code>RequestFilterValve</code> that filters
   * based on the string representation of the remote client's IP address.
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2000/06/11 03:04:41 $
   */
  
  public final class RemoteAddrValve
      extends RequestFilterValve {
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The descriptive information related to this implementation.
       */
      private static final String info =
  	"org.apache.tomcat.valves.RemoteAddrValve/1.0";
  
  
      // ------------------------------------------------------------- Properties
  
  
      /**
       * Return descriptive information about this Valve implementation.
       */
      public String getInfo() {
  
  	return (info);
  
      }
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Extract the desired request property, and pass it (along with the
       * specified request and response objects) to the protected
       * <code>process()</code> method to perform the actual filtering.
       * This method must be implemented by a concrete subclass.
       *
       * @param request The servlet request to be processed
       * @param response The servlet response to be created
       *
       * @exception IOException if an input/output error occurs
       * @exception ServletException if a servlet error occurs
       */
      public void invoke(Request request, Response response)
  	throws IOException, ServletException {
  
  	process(request.getRequest().getRemoteAddr(),
  		request, response);
  
      }
  
  
  }
  
  
  
  1.1                  jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/valves/RemoteHostValve.java
  
  Index: RemoteHostValve.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/valves/RemoteHostValve.java,v 1.1 2000/06/11 03:04:41 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2000/06/11 03:04:41 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  
  
  package org.apache.tomcat.valves;
  
  
  import java.io.IOException;
  import javax.servlet.ServletException;
  import org.apache.tomcat.Request;
  import org.apache.tomcat.Response;
  
  
  /**
   * Concrete implementation of <code>RequestFilterValve</code> that filters
   * based on the string representation of the remote client's IP address.
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2000/06/11 03:04:41 $
   */
  
  public final class RemoteHostValve
      extends RequestFilterValve {
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The descriptive information related to this implementation.
       */
      private static final String info =
  	"org.apache.tomcat.valves.RemoteAddrValve/1.0";
  
  
      // ------------------------------------------------------------- Properties
  
  
      /**
       * Return descriptive information about this Valve implementation.
       */
      public String getInfo() {
  
  	return (info);
  
      }
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Extract the desired request property, and pass it (along with the
       * specified request and response objects) to the protected
       * <code>process()</code> method to perform the actual filtering.
       * This method must be implemented by a concrete subclass.
       *
       * @param request The servlet request to be processed
       * @param response The servlet response to be created
       *
       * @exception IOException if an input/output error occurs
       * @exception ServletException if a servlet error occurs
       */
      public void invoke(Request request, Response response)
  	throws IOException, ServletException {
  
  	process(request.getRequest().getRemoteHost(),
  		request, response);
  
      }
  
  
  }
  
  
  
  1.1                  jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/valves/RequestFilterValve.java
  
  Index: RequestFilterValve.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/valves/RequestFilterValve.java,v 1.1 2000/06/11 03:04:41 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2000/06/11 03:04:41 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  
  
  package org.apache.tomcat.valves;
  
  
  import java.io.IOException;
  import java.util.Enumeration;
  import java.util.Vector;
  import javax.servlet.ServletException;
  import javax.servlet.ServletRequest;
  import javax.servlet.ServletResponse;
  import javax.servlet.http.HttpServletResponse;
  import org.apache.regexp.RE;
  import org.apache.regexp.RESyntaxException;
  import org.apache.tomcat.Container;
  import org.apache.tomcat.Request;
  import org.apache.tomcat.Response;
  import org.apache.tomcat.Valve;
  import org.apache.tomcat.util.StringManager;
  
  
  /**
   * Implementation of a Valve that performs filtering based on comparing the
   * appropriate request property (selected based on which subclass you choose
   * to configure into your Container's pipeline) against a set of regular
   * expressions configured for this Valve.
   * <p>
   * This valve is configured by setting the <code>allow</code> and/or
   * <code>deny</code> properties to a comma-delimited list of regular
   * expressions (in the syntax supported by the jakarta-regexp library) to
   * which the appropriate request property will be compared.  Evaluation
   * proceeds as follows:
   * <ul>
   * <li>The subclass extracts the request property to be filtered, and
   *     calls the common <code>process()</code> method.
   * <li>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 rejected with a "Forbidden" HTTP response.</li>
   * <li>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 Valve in the
   *     current pipeline.</li>
   * <li>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).
   * <li>The request will be rejected with a "Forbidden" HTTP response.</li>
   * </ul>
   * <p>
   * This Valve may be attached to any Container, depending on the granularity
   * of the filtering you wish to perform.
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2000/06/11 03:04:41 $
   */
  
  public abstract class RequestFilterValve
      extends ValveBase {
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The comma-delimited set of <code>allow</code> expressions.
       */
      protected String allow = null;
  
  
      /**
       * The set of <code>allow</code> regular expressions we will evaluate.
       */
      protected RE allows[] = new RE[0];
  
  
      /**
       * The set of <code>deny</code> regular expressions we will evaluate.
       */
      protected RE denies[] = new RE[0];
  
  
      /**
       * The comma-delimited set of <code>deny</code> expressions.
       */
      protected String deny = null;
  
  
      /**
       * The descriptive information related to this implementation.
       */
      private static final String info =
  	"org.apache.tomcat.valves.RequestFilterValve/1.0";
  
  
      /**
       * The StringManager for this package.
       */
      protected StringManager sm =
  	StringManager.getManager(Constants.Package);
  
  
      // ------------------------------------------------------------- Properties
  
  
      /**
       * Return a comma-delimited set of the <code>allow</code> expressions
       * configured for this Valve, if any; otherwise, return <code>null</code>.
       */
      public String getAllow() {
  
  	return (this.allow);
  
      }
  
  
      /**
       * Set the comma-delimited set of the <code>allow</code> expressions
       * configured for this Valve, if any.
       *
       * @param allow The new set of allow expressions
       */
      public void setAllow(String allow) {
  
  	this.allow = allow;
  	allows = precalculate(allow);
  
      }
  
  
      /**
       * Return a comma-delimited set of the <code>deny</code> expressions
       * configured for this Valve, if any; otherwise, return <code>null</code>.
       */
      public String getDeny() {
  
  	return (this.deny);
  
      }
  
  
      /**
       * Set the comma-delimited set of the <code>deny</code> expressions
       * configured for this Valve, if any.
       *
       * @param deny The new set of deny expressions
       */
      public void setDeny(String deny) {
  
  	this.deny = deny;
  	denies = precalculate(deny);
  
      }
  
  
      /**
       * Return descriptive information about this Valve implementation.
       */
      public String getInfo() {
  
  	return (info);
  
      }
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Extract the desired request property, and pass it (along with the
       * specified request and response objects) to the protected
       * <code>process()</code> method to perform the actual filtering.
       * This method must be implemented by a concrete subclass.
       *
       * @param request The servlet request to be processed
       * @param response The servlet response to be created
       *
       * @exception IOException if an input/output error occurs
       * @exception ServletException if a servlet error occurs
       */
      public abstract void invoke(Request request, Response response)
  	throws IOException, ServletException;
  
  
      // ------------------------------------------------------ Protected Methods
  
  
      /**
       * Return an array of regular expression objects initialized from the
       * specified argument, which must be <code>null</code> or a comma-delimited
       * list of regular expression patterns.
       *
       * @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 += ",";
  
  	Vector reVector = new Vector();
  	while (list.length() > 0) {
  	    int comma = list.indexOf(",");
  	    if (comma < 0)
  		break;
  	    String pattern = list.substring(0, comma).trim();
  	    try {
  		reVector.addElement(new RE(pattern));
  	    } catch (RESyntaxException e) {
  		throw new IllegalArgumentException
  		    (sm.getString("requestFilterValve.syntax", pattern));
  	    }
  	    list = list.substring(comma + 1);
  	}
  
  	RE reArray[] = new RE[reVector.size()];
  	for (int i = 0; i < reArray.length; i++)
  	    reArray[i] = (RE) reVector.elementAt(i);
  	return (reArray);
  
      }
  
  
      /**
       * Perform the filtering that has been configured for this Valve, matching
       * against the specified request property.
       *
       * @param property The request property on which to filter
       * @param request The servlet request to be processed
       * @param response The servlet response to be processed
       *
       * @exception IOException if an input/output error occurs
       * @exception ServletException if a servlet error occurs
       */
      protected void process(String property,
  			   Request request, Response response)
  	throws IOException, ServletException {
  
  	// Validate our current state
  	Valve next = getNext();
  	if (next == null)
  	    throw new IllegalStateException
  		(sm.getString("requestFilterValve.next"));
  
  	// Check the deny patterns, if any
  	for (int i = 0; i < denies.length; i++) {
  	    if (denies[i].match(property)) {
  		ServletResponse sres = response.getResponse();
  		if (sres instanceof HttpServletResponse) {
  		    HttpServletResponse hres = (HttpServletResponse) sres;
  		    hres.sendError(HttpServletResponse.SC_FORBIDDEN);
  		    return;
  		}
  	    }
  	}
  
  	// Check the allow patterns, if any
  	for (int i = 0; i < allows.length; i++) {
  	    if (allows[i].match(property)) {
  		next.invoke(request, response);
  		return;
  	    }
  	}
  
  	// Allow if denies specified but not allows
  	if ((denies.length > 0) && (allows.length == 0)) {
  	    next.invoke(request, response);
  	    return;
  	}
  
  
  	// Deny this request
  	ServletResponse sres = response.getResponse();
  	if (sres instanceof HttpServletResponse) {
  	    HttpServletResponse hres = (HttpServletResponse) sres;
  	    hres.sendError(HttpServletResponse.SC_FORBIDDEN);
  	    return;
  	}
  
      }
  
  
  }