From jbossweb-commits at lists.jboss.org Tue Jan 26 09:34:33 2010 Content-Type: multipart/mixed; boundary="===============6969824599729815362==" MIME-Version: 1.0 From: jbossweb-commits at lists.jboss.org To: jbossweb-commits at lists.jboss.org Subject: [jbossweb-commits] JBossWeb SVN: r1370 - in trunk: webapps/docs and 1 other directories. Date: Tue, 26 Jan 2010 09:34:32 -0500 Message-ID: <201001261434.o0QEYWt6005657@svn01.web.mwc.hst.phx2.redhat.com> --===============6969824599729815362== Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Author: remy.maucherat(a)jboss.com Date: 2010-01-26 09:34:32 -0500 (Tue, 26 Jan 2010) New Revision: 1370 Added: trunk/java/org/apache/catalina/valves/RemoteIpValve.java Modified: trunk/java/org/apache/catalina/valves/LocalStrings.properties trunk/java/org/apache/catalina/valves/ValveBase.java trunk/java/org/apache/catalina/valves/mbeans-descriptors.xml trunk/webapps/docs/changelog.xml trunk/webapps/docs/config/valve.xml Log: - Port mod_remoteip clone. Modified: trunk/java/org/apache/catalina/valves/LocalStrings.properties =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/java/org/apache/catalina/valves/LocalStrings.properties 2010-01-2= 6 13:04:28 UTC (rev 1369) +++ trunk/java/org/apache/catalina/valves/LocalStrings.properties 2010-01-2= 6 14:34:32 UTC (rev 1370) @@ -26,6 +26,9 @@ errorReportValve.note=3Dnote errorReportValve.rootCauseInLogs=3DThe full stack trace of the root cause = is available in the {0} logs. = +# Remote IP valve +remoteIpValve.syntax=3DInvalid regular expressions [{0}] provided. + # HTTP status reports http.100=3DThe client may continue ({0}). http.101=3DThe server is switching protocols according to the "Upgrade" he= ader ({0}). Added: trunk/java/org/apache/catalina/valves/RemoteIpValve.java =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/java/org/apache/catalina/valves/RemoteIpValve.java = (rev 0) +++ trunk/java/org/apache/catalina/valves/RemoteIpValve.java 2010-01-26 14:= 34:32 UTC (rev 1370) @@ -0,0 +1,708 @@ +/* + * 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.valves; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import javax.servlet.ServletException; + +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.tomcat.util.res.StringManager; + +/** + *

+ * Tomcat port of mod_remoteip, this valve replaces the apparent + * client remote IP address and hostname for the request with the IP addre= ss list presented by a proxy or a load balancer via a request + * headers (e.g. "X-Forwarded-For"). + *

+ *

+ * Another feature of this valve is to replace the apparent scheme (http/h= ttps) and server port with the scheme presented by a proxy or a + * load balancer via a request header (e.g. "X-Forwarded-Proto"). + *

+ *

+ * This valve proceeds as follows: + *

+ *

+ * If the incoming request.getRemoteAddr() matches the valve'= s list of internal proxies : + *

+ *

+ *

+ * Configuration parameters: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
RemoteIpValve propertyDescriptionEquivalent mod_remoteip directiveFormatDefault Value
remoteIPHeaderName of the Http Header read by this valve that holds the list of t= raversed IP addresses starting from the requesting clientRemoteIPHeaderCompliant http header namex-forwarded-for
internalProxiesList of internal proxies ip adress. If they appear in the rem= oteIpHeader value, they will be trusted and will not appear + * in the proxiesHeader valueRemoteIPInternalProxyComma delimited list of regular expressions (in the syntax supporte= d by the {@link java.util.regex.Pattern} library)10\.\d{1,3}\.\d{1,3}\.\d{1,3}, 192\.168\.\d{1,3}\.\d{1,3}, 169\.254= \.\d{1,3}\.\d{1,3}, 127\.\d{1,3}\.\d{1,3}\.\d{1,3}
+ * By default, 10/8, 192.168/16, 169.254/16 and 127/8 are allowed ; 172.16= /12 has not been enabled by default because it is complex to + * describe with regular expressions
proxiesHeaderName of the http header created by this valve to hold the list of p= roxies that have been processed in the incoming + * remoteIPHeaderRemoteIPProxiesHeaderCompliant http header namex-forwarded-by
trustedProxiesList of trusted proxies ip adress. If they appear in the remo= teIpHeader value, they will be trusted and will appear + * in the proxiesHeader valueRemoteIPTrustedProxyComma delimited list of regular expressions (in the syntax supporte= d by the {@link java.util.regex.Pattern} library) 
protocolHeaderName of the http header read by this valve that holds the flag that= this request N/ACompliant http header name like X-Forwarded-Proto, X-Forwarded-Ssl or Front-End-Httpsnull
protocolHeaderHttpsValueValue of the protocolHeader to indicate that it is an = Https requestN/AString like https or ONhttps
+ *

+ *

+ *

+ * This Valve may be attached to any Container, depending on the granulari= ty of the filtering you wish to perform. + *

+ *

+ * Regular expression vs. IP address blocks: mod_re= moteip allows to use address blocks (e.g. + * 192.168/16) to configure RemoteIPInternalProxy and RemoteIPTrustedProxy ; as Tomcat doesn't have a + * library similar to apr_ipsubnet_test, + * RemoteIpValve uses regular expression to configure i= nternalProxies and trustedProxies in the same + * fashion as {@link RequestFilterValve} does. + *

+ *
+ *

+ * Sample with internal proxies + *

+ *

+ * RemoteIpValve configuration: + *

+ *
+ * <Valve =

+ *   className=3D"org.apache.catalina.connector.RemoteIpValve"
+ *   internalProxies=3D"192\.168\.0\.10, 192\.168\.0\.11"
+ *   remoteIPHeader=3D"x-forwarded-for"
+ *   remoteIPProxiesHeader=3D"x-forwarded-by"
+ *   protocolHeader=3D"x-forwarded-proto"
+ *   />
+ *

+ * Request values: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
propertyValue Before RemoteIpValveValue After RemoteIpValve
request.remoteAddr192.168.0.10140.211.11.130
request.header['x-forwarded-for']140.211.11.130, 192.168.0.10null
request.header['x-forwarded-by']nullnull
request.header['x-forwarded-proto']httpshttps
request.schemehttphttps
request.securefalsetrue
request.serverPort80443
+ * Note : x-forwarded-by header is null because only internal= proxies as been traversed by the request. + * x-forwarded-by is null because all the proxies are trusted= or internal. + *

+ *
+ *

+ * Sample with trusted proxies + *

+ *

+ * RemoteIpValve configuration: + *

+ *
+ * <Valve =

+ *   className=3D"org.apache.catalina.connector.RemoteIpValve"
+ *   internalProxies=3D"192\.168\.0\.10, 192\.168\.0\.11"
+ *   remoteIPHeader=3D"x-forwarded-for"
+ *   remoteIPProxiesHeader=3D"x-forwarded-by"
+ *   trustedProxies=3D"proxy1, proxy2"
+ *   />
+ *

+ * Request values: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
propertyValue Before RemoteIpValveValue After RemoteIpValve
request.remoteAddr192.168.0.10140.211.11.130
request.header['x-forwarded-for']140.211.11.130, proxy1, proxy2null
request.header['x-forwarded-by']nullproxy1, proxy2
+ * Note : proxy1 and proxy2 are both trusted pro= xies that come in x-forwarded-for header, they both + * are migrated in x-forwarded-by header. x-forwarded-b= y is null because all the proxies are trusted or internal. + *

+ *
+ *

+ * Sample with internal and trusted proxies + *

+ *

+ * RemoteIpValve configuration: + *

+ *
+ * <Valve =

+ *   className=3D"org.apache.catalina.connector.RemoteIpValve"
+ *   internalProxies=3D"192\.168\.0\.10, 192\.168\.0\.11"
+ *   remoteIPHeader=3D"x-forwarded-for"
+ *   remoteIPProxiesHeader=3D"x-forwarded-by"
+ *   trustedProxies=3D"proxy1, proxy2"
+ *   />
+ *

+ * Request values: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
propertyValue Before RemoteIpValveValue After RemoteIpValve
request.remoteAddr192.168.0.10140.211.11.130
request.header['x-forwarded-for']140.211.11.130, proxy1, proxy2, 192.168.0.10null
request.header['x-forwarded-by']nullproxy1, proxy2
+ * Note : proxy1 and proxy2 are both trusted pro= xies that come in x-forwarded-for header, they both + * are migrated in x-forwarded-by header. As 192.168.0.= 10 is an internal proxy, it does not appear in + * x-forwarded-by. x-forwarded-by is null becaus= e all the proxies are trusted or internal. + *

+ *
+ *

+ * Sample with an untrusted proxy + *

+ *

+ * RemoteIpValve configuration: + *

+ *
+ * <Valve =

+ *   className=3D"org.apache.catalina.connector.RemoteIpValve"
+ *   internalProxies=3D"192\.168\.0\.10, 192\.168\.0\.11"
+ *   remoteIPHeader=3D"x-forwarded-for"
+ *   remoteIPProxiesHeader=3D"x-forwarded-by"
+ *   trustedProxies=3D"proxy1, proxy2"
+ *   />
+ *

+ * Request values: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
propertyValue Before RemoteIpValveValue After RemoteIpValve
request.remoteAddr192.168.0.10untrusted-proxy
request.header['x-forwarded-for']140.211.11.130, untrusted-proxy, proxy1140.211.11.130
request.header['x-forwarded-by']nullproxy1
+ * Note : x-forwarded-by holds the trusted proxy proxy1= . x-forwarded-by holds + * 140.211.11.130 because untrusted-proxy is not= trusted and thus, we can not trust that + * untrusted-proxy is the actual remote ip. request.rem= oteAddr is untrusted-proxy that is an IP + * verified by proxy1. + *

+ */ +public class RemoteIpValve extends ValveBase { + = + /** + * {@link Pattern} for a comma delimited string that support whitespac= e characters + */ + private static final Pattern commaSeparatedValuesPattern =3D Pattern.c= ompile("\\s*,\\s*"); + = + /** + * The descriptive information related to this implementation. + */ + private static final String info =3D "org.apache.catalina.connector.Re= moteIpValve/1.0"; + = + /** + * Logger + */ + private static org.jboss.logging.Logger log =3D + org.jboss.logging.Logger.getLogger(RemoteIpValve.class); + = + /** + * The StringManager for this package. + */ + protected static StringManager sm =3D StringManager.getManager(Constan= ts.Package); + = + /** + * Convert a given comma delimited list of regular expressions into an= array of compiled {@link Pattern} + * = + * @return array of patterns (not null) + */ + protected static Pattern[] commaDelimitedListToPatternArray(String com= maDelimitedPatterns) { + String[] patterns =3D commaDelimitedListToStringArray(commaDelimit= edPatterns); + List patternsList =3D new ArrayList(); + for (String pattern : patterns) { + try { + patternsList.add(Pattern.compile(pattern)); + } catch (PatternSyntaxException e) { + throw new IllegalArgumentException(sm.getString("remoteIpV= alve.syntax", pattern), e); + } + } + return patternsList.toArray(new Pattern[0]); + } + = + /** + * Convert a given comma delimited list of regular expressions into an= array of String + * = + * @return array of patterns (non null) + */ + protected static String[] commaDelimitedListToStringArray(String comma= DelimitedStrings) { + return (commaDelimitedStrings =3D=3D null || commaDelimitedStrings= .length() =3D=3D 0) ? new String[0] : commaSeparatedValuesPattern + .split(commaDelimitedStrings); + } + = + /** + * Convert an array of strings in a comma delimited string + */ + protected static String listToCommaDelimitedString(List string= List) { + if (stringList =3D=3D null) { + return ""; + } + StringBuilder result =3D new StringBuilder(); + for (Iterator it =3D stringList.iterator(); it.hasNext();)= { + Object element =3D it.next(); + if (element !=3D null) { + result.append(element); + if (it.hasNext()) { + result.append(", "); + } + } + } + return result.toString(); + } + = + /** + * Return true if the given str matches at l= east one of the given patterns. + */ + protected static boolean matchesOne(String str, Pattern... patterns) { + for (Pattern pattern : patterns) { + if (pattern.matcher(str).matches()) { + return true; + } + } + return false; + } + = + /** + * @see #setHttpsServerPort(int) + */ + private int httpsServerPort =3D 443; + = + /** + * @see #setInternalProxies(String) + */ + private Pattern[] internalProxies =3D new Pattern[] { + Pattern.compile("10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"), Pattern.co= mpile("192\\.168\\.\\d{1,3}\\.\\d{1,3}"), + Pattern.compile("169\\.254\\.\\d{1,3}\\.\\d{1,3}"), Pattern.compil= e("127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}") + }; + = + /** + * @see #setProtocolHeader(String) + */ + private String protocolHeader =3D null; + = + /** + * @see #setProtocolHeaderHttpsValue(String) + */ + private String protocolHeaderHttpsValue =3D "https"; + = + /** + * @see #setProxiesHeader(String) + */ + private String proxiesHeader =3D "X-Forwarded-By"; + = + /** + * @see #setRemoteIpHeader(String) + */ + private String remoteIpHeader =3D "X-Forwarded-For"; + = + /** + * @see RemoteIpValve#setTrustedProxies(String) + */ + private Pattern[] trustedProxies =3D new Pattern[0]; + = + public int getHttpsServerPort() { + return httpsServerPort; + } + = + /** + * Return descriptive information about this Valve implementation. + */ + @Override + public String getInfo() { + return info; + } + = + /** + * @see #setInternalProxies(String) + * @return comma delimited list of internal proxies + */ + public String getInternalProxies() { + List internalProxiesAsStringList =3D new ArrayList= (); + for (Pattern internalProxyPattern : internalProxies) { + internalProxiesAsStringList.add(String.valueOf(internalProxyPa= ttern)); + } + return listToCommaDelimitedString(internalProxiesAsStringList); + } + = + /** + * @see #setProtocolHeader(String) + * @return the protocol header (e.g. "X-Forwarded-Proto") + */ + public String getProtocolHeader() { + return protocolHeader; + } + = + /** + * @see RemoteIpValve#setProtocolHeaderHttpsValue(String) + * @return the value of the protocol header for incoming https request= (e.g. "https") + */ + public String getProtocolHeaderHttpsValue() { + return protocolHeaderHttpsValue; + } + = + /** + * @see #setProxiesHeader(String) + * @return the proxies header name (e.g. "X-Forwarded-By") + */ + public String getProxiesHeader() { + return proxiesHeader; + } + = + /** + * @see #setRemoteIpHeader(String) + * @return the remote IP header name (e.g. "X-Forwarded-For") + */ + public String getRemoteIpHeader() { + return remoteIpHeader; + } + = + /** + * @see #setTrustedProxies(String) + * @return comma delimited list of trusted proxies + */ + public String getTrustedProxies() { + List trustedProxiesAsStringList =3D new ArrayList(= ); + for (Pattern trustedProxy : trustedProxies) { + trustedProxiesAsStringList.add(String.valueOf(trustedProxy)); + } + return listToCommaDelimitedString(trustedProxiesAsStringList); + } + = + /** + * {@inheritDoc} + */ + @Override + public void invoke(Request request, Response response) throws IOExcept= ion, ServletException { + final String originalRemoteAddr =3D request.getRemoteAddr(); + final String originalRemoteHost =3D request.getRemoteHost(); + final String originalScheme =3D request.getScheme(); + final boolean originalSecure =3D request.isSecure(); + final int originalServerPort =3D request.getServerPort(); + = + if (matchesOne(originalRemoteAddr, internalProxies)) { + String remoteIp =3D null; + // In java 6, proxiesHeaderValue should be declared as a java.= util.Deque + LinkedList proxiesHeaderValue =3D new LinkedList(); + = + String[] remoteIPHeaderValue =3D commaDelimitedListToStringArr= ay(request.getHeader(remoteIpHeader)); + int idx; + // loop on remoteIPHeaderValue to find the first trusted remot= e ip and to build the proxies chain + for (idx =3D remoteIPHeaderValue.length - 1; idx >=3D 0; idx--= ) { + String currentRemoteIp =3D remoteIPHeaderValue[idx]; + remoteIp =3D currentRemoteIp; + if (matchesOne(currentRemoteIp, internalProxies)) { + // do nothing, internalProxies IPs are not appended to= the + } else if (matchesOne(currentRemoteIp, trustedProxies)) { + proxiesHeaderValue.addFirst(currentRemoteIp); + } else { + idx--; // decrement idx because break statement doesn'= t do it + break; + } + } + // continue to loop on remoteIPHeaderValue to build the new va= lue of the remoteIPHeader + LinkedList newRemoteIpHeaderValue =3D new LinkedList(); + for (; idx >=3D 0; idx--) { + String currentRemoteIp =3D remoteIPHeaderValue[idx]; + newRemoteIpHeaderValue.addFirst(currentRemoteIp); + } + if (remoteIp !=3D null) { + = + request.setRemoteAddr(remoteIp); + request.setRemoteHost(remoteIp); + = + // use request.coyoteRequest.mimeHeaders.setValue(str).set= String(str) because request.addHeader(str, str) is no-op in Tomcat + // 6.0 + if (proxiesHeaderValue.size() =3D=3D 0) { + request.getCoyoteRequest().getMimeHeaders().removeHead= er(proxiesHeader); + } else { + String commaDelimitedListOfProxies =3D listToCommaDeli= mitedString(proxiesHeaderValue); + request.getCoyoteRequest().getMimeHeaders().setValue(p= roxiesHeader).setString(commaDelimitedListOfProxies); + } + if (newRemoteIpHeaderValue.size() =3D=3D 0) { + request.getCoyoteRequest().getMimeHeaders().removeHead= er(remoteIpHeader); + } else { + String commaDelimitedRemoteIpHeaderValue =3D listToCom= maDelimitedString(newRemoteIpHeaderValue); + request.getCoyoteRequest().getMimeHeaders().setValue(r= emoteIpHeader).setString(commaDelimitedRemoteIpHeaderValue); + } + } + = + if (protocolHeader !=3D null) { + String protocolHeaderValue =3D request.getHeader(protocolH= eader); + if (protocolHeaderValue !=3D null && protocolHeaderHttpsVa= lue.equalsIgnoreCase(protocolHeaderValue)) { + request.setSecure(true); + // use request.coyoteRequest.scheme instead of request= .setScheme() because request.setScheme() is no-op in Tomcat 6.0 + request.getCoyoteRequest().scheme().setString("https"); + = + request.setServerPort(httpsServerPort); + } + } + = + if (log.isDebugEnabled()) { + log.debug("Incoming request " + request.getRequestURI() + = " with originalRemoteAddr '" + originalRemoteAddr + + "', originalRemoteHost=3D'" + originalRemoteHo= st + "', originalSecure=3D'" + originalSecure + "', originalScheme=3D'" + + originalScheme + "' will be seen as newRemoteA= ddr=3D'" + request.getRemoteAddr() + "', newRemoteHost=3D'" + + request.getRemoteHost() + "', newScheme=3D'" += request.getScheme() + "', newSecure=3D'" + request.isSecure() + "'"); + } + } + try { + getNext().invoke(request, response); + } finally { + request.setRemoteAddr(originalRemoteAddr); + request.setRemoteHost(originalRemoteHost); + = + request.setSecure(originalSecure); + = + // use request.coyoteRequest.scheme instead of request.setSche= me() because request.setScheme() is no-op in Tomcat 6.0 + request.getCoyoteRequest().scheme().setString(originalScheme); + = + request.setServerPort(originalServerPort); + } + } + = + /** + *

+ * Server Port value if the {@link #protocolHeader} indicates HTTPS + *

+ *

+ * Default value : 443 + *

+ */ + public void setHttpsServerPort(int httpsServerPort) { + this.httpsServerPort =3D httpsServerPort; + } + = + /** + *

+ * Comma delimited list of internal proxies. Can be expressed with reg= ular expressions. + *

+ *

+ * Default value : 10\.\d{1,3}\.\d{1,3}\.\d{1,3}, 192\.168\.\d{1,3}\.\= d{1,3}, 127\.\d{1,3}\.\d{1,3}\.\d{1,3} + *

+ */ + public void setInternalProxies(String commaDelimitedInternalProxies) { + this.internalProxies =3D commaDelimitedListToPatternArray(commaDel= imitedInternalProxies); + } + = + /** + *

+ * Header that holds the incoming protocol, usally named X-Forwa= rded-Proto. If null, request.scheme and + * request.secure will not be modified. + *

+ *

+ * Default value : null + *

+ */ + public void setProtocolHeader(String protocolHeader) { + this.protocolHeader =3D protocolHeader; + } + = + /** + *

+ * Case insensitive value of the protocol header to indicate that the = incoming http request uses SSL. + *

+ *

+ * Default value : https + *

+ */ + public void setProtocolHeaderHttpsValue(String protocolHeaderHttpsValu= e) { + this.protocolHeaderHttpsValue =3D protocolHeaderHttpsValue; + } + = + /** + *

+ * The proxiesHeader directive specifies a header into which mod_remot= eip will collect a list of all of the intermediate client IP + * addresses trusted to resolve the actual remote IP. Note that interm= ediate RemoteIPTrustedProxy addresses are recorded in this header, + * while any intermediate RemoteIPInternalProxy addresses are discarde= d. + *

+ *

+ * Name of the http header that holds the list of trusted proxies that= has been traversed by the http request. + *

+ *

+ * The value of this header can be comma delimited. + *

+ *

+ * Default value : X-Forwarded-By + *

+ */ + public void setProxiesHeader(String proxiesHeader) { + this.proxiesHeader =3D proxiesHeader; + } + = + /** + *

+ * Name of the http header from which the remote ip is extracted. + *

+ *

+ * The value of this header can be comma delimited. + *

+ *

+ * Default value : X-Forwarded-For + *

+ * = + * @param remoteIPHeader + */ + public void setRemoteIpHeader(String remoteIpHeader) { + this.remoteIpHeader =3D remoteIpHeader; + } + = + /** + *

+ * Comma delimited list of proxies that are trusted when they appear i= n the {@link #remoteIPHeader} header. Can be expressed as a + * regular expression. + *

+ *

+ * Default value : empty list, no external proxy is trusted. + *

+ */ + public void setTrustedProxies(String commaDelimitedTrustedProxies) { + this.trustedProxies =3D commaDelimitedListToPatternArray(commaDeli= mitedTrustedProxies); + } +} Modified: trunk/java/org/apache/catalina/valves/ValveBase.java =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/java/org/apache/catalina/valves/ValveBase.java 2010-01-26 13:04:2= 8 UTC (rev 1369) +++ trunk/java/org/apache/catalina/valves/ValveBase.java 2010-01-26 14:34:3= 2 UTC (rev 1370) @@ -56,8 +56,8 @@ = public abstract class ValveBase implements Contained, Valve, MBeanRegistration { - private static Logger log =3D Logger.getLogger(ValveBase.class); = + //------------------------------------------------------ Instance Vari= ables = = @@ -303,7 +303,6 @@ parentName=3D",servlet=3D" + container.getName() + ",path=3D" + path + ",host=3D" + host.getName(); } - log.debug("valve parent=3D" + parentName + " " + parent); = String className=3Dthis.getClass().getName(); int period =3D className.lastIndexOf('.'); @@ -318,7 +317,6 @@ } if( valves[i]!=3Dnull && valves[i].getClass() =3D=3D this.getClass() ) { - log.debug("Duplicate " + valves[i] + " " + this + " " + co= ntainer); seq++; } } @@ -327,10 +325,7 @@ ext=3D",seq=3D" + seq; } = - ObjectName objectName =3D = - new ObjectName( domain + ":type=3DValve,name=3D" + className += ext + parentName); - log.debug("valve objectname =3D "+objectName); - return objectName; + return new ObjectName( domain + ":type=3DValve,name=3D" + classNam= e + ext + parentName); } = // -------------------- JMX data -------------------- Modified: trunk/java/org/apache/catalina/valves/mbeans-descriptors.xml =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/java/org/apache/catalina/valves/mbeans-descriptors.xml 2010-01-26= 13:04:28 UTC (rev 1369) +++ trunk/java/org/apache/catalina/valves/mbeans-descriptors.xml 2010-01-26= 14:34:32 UTC (rev 1370) @@ -339,4 +339,42 @@ = = + + = + + = + + = + + = + + = + + = + + = + + Modified: trunk/webapps/docs/changelog.xml =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/webapps/docs/changelog.xml 2010-01-26 13:04:28 UTC (rev 1369) +++ trunk/webapps/docs/changelog.xml 2010-01-26 14:34:32 UTC (rev 1370) @@ -25,6 +25,9 @@ 157: NPE on host with HTTP/1.0, submitted by Markus G= rieder. (remm) + + Remote IP valve. (markt) + Modified: trunk/webapps/docs/config/valve.xml =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/webapps/docs/config/valve.xml 2010-01-26 13:04:28 UTC (rev 1369) +++ trunk/webapps/docs/config/valve.xml 2010-01-26 14:34:32 UTC (rev 1370) @@ -434,6 +434,92 @@ = = +
+ + + = +

Tomcat port of + m= od_remoteip, + this valve replaces the apparent client remote IP address and hostname= for + the request with the IP address list presented by a proxy or a load ba= lancer + via a request headers (e.g. "X-Forwarded-For").

+ +

Another feature of this valve is to replace the apparent scheme + (http/https) and server port with the scheme presented by a proxy or a= load + balancer via a request header (e.g. "X-Forwarded-Proto").

+ = +

This Valve may be used at the Engine, Host or + Context level as required. Normally, this Valve would be = used + at the Engine level.

+ = +

If used in conjunction with Remote Address/Host valves then this va= lve + should be defined first to ensure that the correct client IP address is + presented to the Remote Address/Host valves.

+ +
+ + + +

The Remote IP Valve supports the + following configuration attributes:

+ + + + +

Java class name of the implementation to use. This MUST be set= to + org.apache.catalina.valves.RemoteIpValve.

+
+ + +

Name of the HTTP Header read by this valve that holds the list = of + traversed IP addresses starting from the requesting client. If not + specified, the default of x-forwarded-for is used.

+
+ + +

List of internal proxies' IP addresses as comma separated regul= ar + expressions. If they appear in the remoteIpHeader + value, they will be trusted and will not appear in the + proxiesHeader value. If not specified the default= value + of 10\.\d{1,3}\.\d{1,3}\.\d{1,3}, 192\.168\.\d{1,3}\.\d{1,3}, + 169\.254\.\d{1,3}\.\d{1,3}, 127\.\d{1,3}\.\d{1,3}\.\d{1,3} = will + be used.

+
+ + +

Name of the HTTP header created by this valve to hold the list = of + proxies that have been processed in the incoming + remoteIpHeader. If not specified, the default of + x-forwarded-by is used.

+
+ + +

List of trusted proxies' IP addresses as comma separated regular + expressions. If they appear in the remoteIpHeader + value, they will be trusted and will appear in the + proxiesHeader value. If not specified, no proxies= will + be trusted.

+
+ + +

Name of the HTTP Header read by this valve that holds the proto= col + used by the client to connect to the proxy. If not specified, the + default of null is used.

+
+ + +

Value of the protocolHeader to indicate that i= t is + an HTTPS request. If not specified, the default of https is + used.

+
+ +
+ +
+ +
+ + = = --===============6969824599729815362==--