From a039bb2ceac415ad3ac98ac0033ee38fc9be78e5 Mon Sep 17 00:00:00 2001 From: markt Date: Thu, 16 Jul 2009 19:34:49 +0000 Subject: [PATCH] More GSOC work from Xie Xiadong Initial implementation of RemoteHost and RemoteAddr filters. git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@794798 13f79535-47bb-0310-9956-ffa450edef68 --- java/org/apache/catalina/filters/Constants.java | 34 +++ java/org/apache/catalina/filters/FilterBase.java | 92 +++++++ .../catalina/filters/LocalStrings.properties | 18 ++ .../catalina/filters/LocalStrings_es.properties | 16 ++ .../catalina/filters/LocalStrings_fr.properties | 16 ++ .../apache/catalina/filters/RemoteAddrFilter.java | 79 ++++++ .../apache/catalina/filters/RemoteHostFilter.java | 79 ++++++ .../org/apache/catalina/filters/RequestFilter.java | 304 +++++++++++++++++++++ 8 files changed, 638 insertions(+) create mode 100644 java/org/apache/catalina/filters/Constants.java create mode 100644 java/org/apache/catalina/filters/FilterBase.java create mode 100644 java/org/apache/catalina/filters/LocalStrings.properties create mode 100644 java/org/apache/catalina/filters/LocalStrings_es.properties create mode 100644 java/org/apache/catalina/filters/LocalStrings_fr.properties create mode 100644 java/org/apache/catalina/filters/RemoteAddrFilter.java create mode 100644 java/org/apache/catalina/filters/RemoteHostFilter.java create mode 100644 java/org/apache/catalina/filters/RequestFilter.java diff --git a/java/org/apache/catalina/filters/Constants.java b/java/org/apache/catalina/filters/Constants.java new file mode 100644 index 000000000..76ed31c21 --- /dev/null +++ b/java/org/apache/catalina/filters/Constants.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.catalina.filters; + + +/** + * Manifest constants for this Java package. + * + * + * @author Craig R. McClanahan + * @version $Revision$ $Date$ + */ + +public final class Constants { + + public static final String Package = "org.apache.catalina.filters"; + +} diff --git a/java/org/apache/catalina/filters/FilterBase.java b/java/org/apache/catalina/filters/FilterBase.java new file mode 100644 index 000000000..6404d11e6 --- /dev/null +++ b/java/org/apache/catalina/filters/FilterBase.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.catalina.filters; + +import java.util.Enumeration; + +import javax.servlet.Filter; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.juli.logging.Log; +import org.apache.tomcat.util.IntrospectionUtils; +import org.apache.tomcat.util.res.StringManager; + +/** + * Base class for filters that provide some utility methods. + * + * @author xxd + * + */ +public abstract class FilterBase implements Filter { + + protected static final StringManager sm = + StringManager.getManager(Constants.Package); + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + Enumeration paramNames = filterConfig.getInitParameterNames(); + while (paramNames.hasMoreElements()) { + String paramName = paramNames.nextElement(); + if (!IntrospectionUtils.setProperty(this, paramName, + filterConfig.getInitParameter(paramName))) { + getLogger().warn(sm.getString("filterbase.noSuchProperty", + paramName, this.getClass().getName())); + } + } + } + + /** + * Whether the request object is an HttpServletRequest or not. + * + * @param request + * @return + */ + protected boolean isHttpServletRequest(ServletRequest request) { + return request instanceof HttpServletRequest; + } + + /** + * Whether the response object is an HttpServletResponse or not. + * + * @param response + * @return + */ + protected boolean isHttpServletResponse(ServletResponse response) { + return response instanceof HttpServletResponse; + } + + /** + * Whether the corresponding Servlet is an HttpServlet or not. + * + * @param request + * @param response + * @return + */ + protected boolean isHttpServlet(ServletRequest request, + ServletResponse response) { + return isHttpServletRequest(request) && isHttpServletResponse(response); + } + + protected abstract Log getLogger(); + +} diff --git a/java/org/apache/catalina/filters/LocalStrings.properties b/java/org/apache/catalina/filters/LocalStrings.properties new file mode 100644 index 000000000..4475c1730 --- /dev/null +++ b/java/org/apache/catalina/filters/LocalStrings.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. + +filterbase.noSuchProperty=The property "{0}" is not defined for filters of type "{1}" + +http.403=Access to the specified resource ({0}) has been forbidden. diff --git a/java/org/apache/catalina/filters/LocalStrings_es.properties b/java/org/apache/catalina/filters/LocalStrings_es.properties new file mode 100644 index 000000000..ffffd4890 --- /dev/null +++ b/java/org/apache/catalina/filters/LocalStrings_es.properties @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. + +http.403=El acceso al recurso especificado ({0}) ha sido prohibido. diff --git a/java/org/apache/catalina/filters/LocalStrings_fr.properties b/java/org/apache/catalina/filters/LocalStrings_fr.properties new file mode 100644 index 000000000..a2f474a9a --- /dev/null +++ b/java/org/apache/catalina/filters/LocalStrings_fr.properties @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. + +http.403=L''acc\u00e8s \u00e0 la ressource demand\u00e9e ({0}) a \u00e9t\u00e9 interdit. diff --git a/java/org/apache/catalina/filters/RemoteAddrFilter.java b/java/org/apache/catalina/filters/RemoteAddrFilter.java new file mode 100644 index 000000000..af47302d1 --- /dev/null +++ b/java/org/apache/catalina/filters/RemoteAddrFilter.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.catalina.filters; + + +import java.io.IOException; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; + + +/** + * Concrete implementation of RequestFilterFilter that filters + * based on the string representation of the remote client's IP address. + * + * @author Craig R. McClanahan + * + */ + +public final class RemoteAddrFilter + extends RequestFilter { + + // ----------------------------------------------------- Instance Variables + private static Log log = LogFactory.getLog(RemoteAddrFilter.class); + + + // ------------------------------------------------------------- Properties + + + + // --------------------------------------------------------- Public Methods + + + /** + * Extract the desired request property, and pass it (along with the + * specified request and response objects) to the protected + * process() 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 + */ + @Override + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) throws IOException, ServletException { + + process(request.getRemoteAddr(), request, response, chain); + + } + + protected Log getLogger() { + return log; + } + +} diff --git a/java/org/apache/catalina/filters/RemoteHostFilter.java b/java/org/apache/catalina/filters/RemoteHostFilter.java new file mode 100644 index 000000000..ec70ca66c --- /dev/null +++ b/java/org/apache/catalina/filters/RemoteHostFilter.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.catalina.filters; + + +import java.io.IOException; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; + + +/** + * Concrete implementation of RequestFilterFilter that filters + * based on the remote client's host name. + * + * @author Craig R. McClanahan + * + */ + +public final class RemoteHostFilter + extends RequestFilter { + + + // ----------------------------------------------------- Instance Variables + private static Log log = LogFactory.getLog(RemoteHostFilter.class); + + + // ------------------------------------------------------------- Properties + + + + // --------------------------------------------------------- Public Methods + + + /** + * Extract the desired request property, and pass it (along with the + * specified request and response objects) to the protected + * process() 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 + */ + @Override + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) throws IOException, ServletException { + + process(request.getRemoteHost(), request, response, chain); + + } + + protected Log getLogger() { + return log; + } +} diff --git a/java/org/apache/catalina/filters/RequestFilter.java b/java/org/apache/catalina/filters/RequestFilter.java new file mode 100644 index 000000000..5f605c97e --- /dev/null +++ b/java/org/apache/catalina/filters/RequestFilter.java @@ -0,0 +1,304 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.catalina.filters; + + +import java.io.IOException; +import java.util.ArrayList; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; + +import org.apache.tomcat.util.res.StringManager; + +/** + * Implementation of a Filter 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 Filter. + *

+ * This filter is configured by setting the allow and/or + * deny 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: + *

+ *

+ * This Filter may be attached to any Container, depending on the granularity + * of the filtering you wish to perform. + * + * @author Craig R. McClanahan + * + */ + +public abstract class RequestFilter + extends FilterBase { + + + // ----------------------------------------------------- Class Variables + + + /** + * The StringManager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + // ----------------------------------------------------- Instance Variables + + /** + * The comma-delimited set of allow expressions. + */ + protected String allow = null; + + + /** + * The set of allow regular expressions we will evaluate. + */ + protected Pattern allows[] = new Pattern[0]; + + + /** + * The set of deny regular expressions we will evaluate. + */ + protected Pattern denies[] = new Pattern[0]; + + + /** + * The comma-delimited set of deny expressions. + */ + protected String deny = null; + + /** + * mime type -- "text/plain" + */ + private static final String PLAIN_TEXT_MIME_TYPE = "text/plain"; + + + // ------------------------------------------------------------- Properties + + + /** + * Return a comma-delimited set of the allow expressions + * configured for this Filter, if any; otherwise, return null. + */ + public String getAllow() { + + return (this.allow); + + } + + + /** + * Set the comma-delimited set of the allow expressions + * configured for this Filter, if any. + * + * @param allow The new set of allow expressions + */ + public void setAllow(String allow) { + + this.allow = allow; + this.allows = precalculate(allow); + + } + + + /** + * Return a comma-delimited set of the deny expressions + * configured for this Filter, if any; otherwise, return null. + */ + public String getDeny() { + + return (this.deny); + + } + + + /** + * Set the comma-delimited set of the deny expressions + * configured for this Filter, if any. + * + * @param deny The new set of deny expressions + */ + public void setDeny(String deny) { + + + this.deny = deny; + this.denies = precalculate(deny); + + } + + + // --------------------------------------------------------- Public Methods + + + /* (non-Javadoc) + * @see javax.servlet.Filter#destroy() + */ + @Override + public void destroy() { + // NOOP + } + + /** + * Extract the desired request property, and pass it (along with the + * specified request and response objects) to the protected + * process() 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 + * @param chain The filter chain + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet error occurs + */ + @Override + public abstract void doFilter(ServletRequest request, + ServletResponse response, FilterChain chain) throws IOException, + ServletException; + + + // ------------------------------------------------------ Protected Methods + + + /** + * 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. + * + * @param list The comma-separated list of patterns + * + * @exception IllegalArgumentException if one of the patterns has + * invalid syntax + */ + protected Pattern[] precalculate(String list) { + + if (list == null) + return (new Pattern[0]); + list = list.trim(); + if (list.length() < 1) + return (new Pattern[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(Pattern.compile(pattern)); + } catch (PatternSyntaxException e) { + IllegalArgumentException iae = new IllegalArgumentException + (sm.getString("requestFilterFilter.syntax", pattern)); + iae.initCause(e); + throw iae; + } + list = list.substring(comma + 1); + } + + Pattern reArray[] = new Pattern[reList.size()]; + return reList.toArray(reArray); + + } + + + /** + * Perform the filtering that has been configured for this Filter, 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, ServletRequest request, + ServletResponse response, FilterChain chain) + throws IOException, ServletException { + + // Check the deny patterns, if any + for (int i = 0; i < this.denies.length; i++) { + if (this.denies[i].matcher(property).matches()) { + if (isHttpServletResponse(response)) { + ((HttpServletResponse) response) + .sendError(HttpServletResponse.SC_FORBIDDEN); + return; + } else { + sendErrorWhenNotHttp(response); + return; + } + } + } + + // Check the allow patterns, if any + for (int i = 0; i < this.allows.length; i++) { + if (this.allows[i].matcher(property).matches()) { + chain.doFilter(request, response); + return; + } + } + + // Allow if denies specified but not allows + if ((this.denies.length > 0) && (this.allows.length == 0)) { + chain.doFilter(request, response); + return; + } + + // Deny this request + if (isHttpServletResponse(response)) { + ((HttpServletResponse) response) + .sendError(HttpServletResponse.SC_FORBIDDEN); + } else { + sendErrorWhenNotHttp(response); + } + } + + + private void sendErrorWhenNotHttp(ServletResponse response) + throws IOException { + response.setContentType(PLAIN_TEXT_MIME_TYPE); + response.getWriter().write(sm.getString("http.403")); + response.getWriter().flush(); + } + + +} -- 2.11.0