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 :
+ *
$remoteIPHeader
(default value x-forwar=
ded-for
). Values are processed in right-to-left order.$protocolHeader
(e.g.=
x-forwarded-for
) equals to the value of
+ * protocolHeaderHttpsValue
configuration parameter (default =
https
) then request.isSecure =3D true
,
+ * request.scheme =3D https
and request.serverPort =3D =
443
. Note that 443 can be overwritten with the
+ * $httpsServerPort
configuration parameter.+ * Configuration parameters: + *
RemoteIpValve property | + *Description | + *Equivalent mod_remoteip directive | + *Format | + *Default Value | + *
---|---|---|---|---|
remoteIPHeader | + *Name of the Http Header read by this valve that holds the list of t= raversed IP addresses starting from the requesting client | + *RemoteIPHeader | + *Compliant http header name | + *x-forwarded-for | + *
internalProxies | + *List of internal proxies ip adress. If they appear in the rem=
oteIpHeader value, they will be trusted and will not appear
+ * in the proxiesHeader value |
+ * RemoteIPInternalProxy | + *Comma 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 |
+ *
proxiesHeader | + *Name of the http header created by this valve to hold the list of p=
roxies that have been processed in the incoming
+ * remoteIPHeader |
+ * RemoteIPProxiesHeader | + *Compliant http header name | + *x-forwarded-by | + *
trustedProxies | + *List of trusted proxies ip adress. If they appear in the remo=
teIpHeader value, they will be trusted and will appear
+ * in the proxiesHeader value |
+ * RemoteIPTrustedProxy | + *Comma delimited list of regular expressions (in the syntax supporte= d by the {@link java.util.regex.Pattern} library) | + *+ * |
protocolHeader | + *Name of the http header read by this valve that holds the flag that= this request | + *N/A | + *Compliant http header name like X-Forwarded-Proto , Front-End-Https |
+ * null |
+ *
protocolHeaderHttpsValue | + *Value of the protocolHeader to indicate that it is an =
Https request |
+ * N/A | + *String like https or ON |
+ * https |
+ *
+ *
+ * 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: + *
property | + *Value Before RemoteIpValve | + *Value After RemoteIpValve | + *
---|---|---|
request.remoteAddr | + *192.168.0.10 | + *140.211.11.130 | + *
request.header['x-forwarded-for'] | + *140.211.11.130, 192.168.0.10 | + *null | + *
request.header['x-forwarded-by'] | + *null | + *null | + *
request.header['x-forwarded-proto'] | + *https | + *https | + *
request.scheme | + *http | + *https | + *
request.secure | + *false | + *true | + *
request.serverPort | + *80 | + *443 | + *
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: + *
property | + *Value Before RemoteIpValve | + *Value After RemoteIpValve | + *
---|---|---|
request.remoteAddr | + *192.168.0.10 | + *140.211.11.130 | + *
request.header['x-forwarded-for'] | + *140.211.11.130, proxy1, proxy2 | + *null | + *
request.header['x-forwarded-by'] | + *null | + *proxy1, proxy2 | + *
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: + *
property | + *Value Before RemoteIpValve | + *Value After RemoteIpValve | + *
---|---|---|
request.remoteAddr | + *192.168.0.10 | + *140.211.11.130 | + *
request.header['x-forwarded-for'] | + *140.211.11.130, proxy1, proxy2, 192.168.0.10 | + *null | + *
request.header['x-forwarded-by'] | + *null | + *proxy1, proxy2 | + *
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: + *
property | + *Value Before RemoteIpValve | + *Value After RemoteIpValve | + *
---|---|---|
request.remoteAddr | + *192.168.0.10 | + *untrusted-proxy | + *
request.header['x-forwarded-for'] | + *140.211.11.130, untrusted-proxy, proxy1 | + *140.211.11.130 | + *
request.header['x-forwarded-by'] | + *null | + *proxy1 | + *
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);
+ Listnull
)
+ */
+ 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(Listtrue
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+ * 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
+ *
+ * Case insensitive value of the protocol header to indicate that the = incoming http request uses SSL. + *
+ *
+ * Default value : https
+ *
+ * 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
+ *
+ * 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
+ *
+ * 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 @@ = = +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.