You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2010/02/02 14:28:57 UTC
svn commit: r905627 - in /tomcat/trunk:
java/org/apache/catalina/valves/RemoteIpValve.java
java/org/apache/catalina/valves/mbeans-descriptors.xml
test/org/apache/catalina/valves/TestRemoteIpValve.java
webapps/docs/config/valve.xml
Author: markt
Date: Tue Feb 2 13:28:55 2010
New Revision: 905627
URL: http://svn.apache.org/viewvc?rev=905627&view=rev
Log:
Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=48653
RemoteIpValve : request.secure and request.scheme are not forced to "false" and "http" if X-Forwarded-Proto=http
Patch provided by Cyrille Le Clerc
Modified:
tomcat/trunk/java/org/apache/catalina/valves/RemoteIpValve.java
tomcat/trunk/java/org/apache/catalina/valves/mbeans-descriptors.xml
tomcat/trunk/test/org/apache/catalina/valves/TestRemoteIpValve.java
tomcat/trunk/webapps/docs/config/valve.xml
Modified: tomcat/trunk/java/org/apache/catalina/valves/RemoteIpValve.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/valves/RemoteIpValve.java?rev=905627&r1=905626&r2=905627&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/valves/RemoteIpValve.java (original)
+++ tomcat/trunk/java/org/apache/catalina/valves/RemoteIpValve.java Tue Feb 2 13:28:55 2010
@@ -26,6 +26,7 @@
import java.util.regex.PatternSyntaxException;
import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
import org.apache.tomcat.util.res.StringManager;
import org.apache.catalina.connector.Request;
@@ -126,6 +127,19 @@
* <td><code>https</code></td>
* </tr>
* <tr>
+ * <td>httpServerPort</td>
+ * <td>Value returned by {@link ServletRequest#getServerPort()} when the <code>protocolHeader</code> indicates <code>http</code> protocol</td>
+ * <td>N/A</td>
+ * <td>integer</td>
+ * <td>80</td>
+ * </tr>
+ * <tr>
+ * <td>httpsServerPort</td>
+ * <td>Value returned by {@link ServletRequest#getServerPort()} when the <code>protocolHeader</code> indicates <code>https</code> protocol</td>
+ * <td>N/A</td>
+ * <td>integer</td>
+ * <td>443</td>
+ * </tr>
* </table>
* </p>
* <p>
@@ -415,6 +429,11 @@
}
/**
+ * @see #setHttpServerPort(int)
+ */
+ private int httpServerPort = 80;
+
+ /**
* @see #setHttpsServerPort(int)
*/
private int httpsServerPort = 443;
@@ -456,6 +475,10 @@
return httpsServerPort;
}
+ public int getHttpServerPort() {
+ return httpServerPort;
+ }
+
/**
* Return descriptive information about this Valve implementation.
*/
@@ -507,7 +530,7 @@
public String getRemoteIpHeader() {
return remoteIpHeader;
}
-
+
/**
* @see #setTrustedProxies(String)
* @return comma delimited list of trusted proxies
@@ -580,12 +603,21 @@
if (protocolHeader != null) {
String protocolHeaderValue = request.getHeader(protocolHeader);
- if (protocolHeaderValue != null && protocolHeaderHttpsValue.equalsIgnoreCase(protocolHeaderValue)) {
+ if (protocolHeaderValue == null) {
+ // don't modify the secure,scheme and serverPort attributes
+ // of the request
+ } else if (protocolHeaderHttpsValue.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);
+ } else {
+ request.setSecure(false);
+ // use request.coyoteRequest.scheme instead of request.setScheme() because request.setScheme() is no-op in Tomcat 6.0
+ request.getCoyoteRequest().scheme().setString("http");
+
+ request.setServerPort(httpServerPort);
}
}
@@ -613,6 +645,18 @@
/**
* <p>
+ * Server Port value if the {@link #protocolHeader} is not <code>null</code> and does not indicate HTTP
+ * </p>
+ * <p>
+ * Default value : 80
+ * </p>
+ */
+ public void setHttpServerPort(int httpServerPort) {
+ this.httpServerPort = httpServerPort;
+ }
+
+ /**
+ * <p>
* Server Port value if the {@link #protocolHeader} indicates HTTPS
* </p>
* <p>
Modified: tomcat/trunk/java/org/apache/catalina/valves/mbeans-descriptors.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/valves/mbeans-descriptors.xml?rev=905627&r1=905626&r2=905627&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/valves/mbeans-descriptors.xml (original)
+++ tomcat/trunk/java/org/apache/catalina/valves/mbeans-descriptors.xml Tue Feb 2 13:28:55 2010
@@ -365,7 +365,17 @@
description="Comma delimited list of internal proxies"
type="java.lang.String"
writeable="false" />
-
+
+ <attribute name="httpServerPort"
+ description="Value returned by ServletRequest.getServerPort() when the protocolHeader indicates http protocol"
+ type="java.lang.String"
+ writeable="false" />
+
+ <attribute name="httpsServerPort"
+ description="Value returned by ServletRequest.getServerPort() when the protocolHeader indicates https protocol"
+ type="java.lang.String"
+ writeable="false" />
+
<attribute name="protocolHeader"
description="The protocol header (e.g. "X-Forwarded-Proto")"
type="java.lang.String"
@@ -381,7 +391,7 @@
type="java.lang.String"
writeable="false" />
- <attribute name="remoteIpHedaer"
+ <attribute name="remoteIpHeader"
description="The remote IP header name (e.g. "X-Forwarded-For")"
type="java.lang.String"
writeable="false" />
Modified: tomcat/trunk/test/org/apache/catalina/valves/TestRemoteIpValve.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/valves/TestRemoteIpValve.java?rev=905627&r1=905626&r2=905627&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/catalina/valves/TestRemoteIpValve.java (original)
+++ tomcat/trunk/test/org/apache/catalina/valves/TestRemoteIpValve.java Tue Feb 2 13:28:55 2010
@@ -38,6 +38,9 @@
static class RemoteAddrAndHostTrackerValve extends ValveBase {
private String remoteAddr;
private String remoteHost;
+ private String scheme;
+ private boolean secure;
+ private int serverPort;
public String getRemoteAddr() {
return remoteAddr;
@@ -47,10 +50,25 @@
return remoteHost;
}
+ public String getScheme() {
+ return scheme;
+ }
+
+ public int getServerPort() {
+ return serverPort;
+ }
+
+ public boolean isSecure() {
+ return secure;
+ }
+
@Override
public void invoke(Request request, Response response) throws IOException, ServletException {
this.remoteHost = request.getRemoteHost();
this.remoteAddr = request.getRemoteAddr();
+ this.scheme = request.getScheme();
+ this.secure = request.isSecure();
+ this.serverPort = request.getServerPort();
}
}
@@ -271,6 +289,262 @@
assertEquals("postInvoke remoteAddr", "remote-host-original-value", actualPostInvokeRemoteHost);
}
+ public void testInvokeXforwardedProtoSaysHttpsForIncomingHttpRequest() throws Exception {
+
+ // PREPARE
+ RemoteIpValve remoteIpValve = new RemoteIpValve();
+ remoteIpValve.setRemoteIpHeader("x-forwarded-for");
+ remoteIpValve.setProtocolHeader("x-forwarded-proto");
+ RemoteAddrAndHostTrackerValve remoteAddrAndHostTrackerValve = new RemoteAddrAndHostTrackerValve();
+ remoteIpValve.setNext(remoteAddrAndHostTrackerValve);
+
+ Request request = new Request();
+ request.setCoyoteRequest(new org.apache.coyote.Request());
+ // client ip
+ request.setRemoteAddr("192.168.0.10");
+ request.setRemoteHost("192.168.0.10");
+ request.getCoyoteRequest().getMimeHeaders().addValue("x-forwarded-for").setString("140.211.11.130");
+ // protocol
+ request.getCoyoteRequest().getMimeHeaders().addValue("x-forwarded-proto").setString("https");
+ request.setSecure(false);
+ request.setServerPort(8080);
+ request.getCoyoteRequest().scheme().setString("http");
+
+ // TEST
+ remoteIpValve.invoke(request, null);
+
+ // VERIFY
+ // client ip
+ String actualXForwardedFor = request.getHeader("x-forwarded-for");
+ assertNull("no intermediate non-trusted proxy, x-forwarded-for must be null", actualXForwardedFor);
+
+ String actualXForwardedBy = request.getHeader("x-forwarded-by");
+ assertNull("no intermediate trusted proxy", actualXForwardedBy);
+
+ String actualRemoteAddr = remoteAddrAndHostTrackerValve.getRemoteAddr();
+ assertEquals("remoteAddr", "140.211.11.130", actualRemoteAddr);
+
+ String actualRemoteHost = remoteAddrAndHostTrackerValve.getRemoteHost();
+ assertEquals("remoteHost", "140.211.11.130", actualRemoteHost);
+
+ String actualPostInvokeRemoteAddr = request.getRemoteAddr();
+ assertEquals("postInvoke remoteAddr", "192.168.0.10", actualPostInvokeRemoteAddr);
+
+ String actualPostInvokeRemoteHost = request.getRemoteHost();
+ assertEquals("postInvoke remoteAddr", "192.168.0.10", actualPostInvokeRemoteHost);
+
+ // protocol
+ String actualScheme = remoteAddrAndHostTrackerValve.getScheme();
+ assertEquals("x-forwarded-proto says https", "https", actualScheme);
+
+ int actualServerPort = remoteAddrAndHostTrackerValve.getServerPort();
+ assertEquals("x-forwarded-proto says https", 443, actualServerPort);
+
+ boolean actualSecure = remoteAddrAndHostTrackerValve.isSecure();
+ assertEquals("x-forwarded-proto says https", true, actualSecure);
+
+ boolean actualPostInvokeSecure = request.isSecure();
+ assertEquals("postInvoke secure", false, actualPostInvokeSecure);
+
+ int actualPostInvokeServerPort = request.getServerPort();
+ assertEquals("postInvoke serverPort", 8080, actualPostInvokeServerPort);
+
+ String actualPostInvokeScheme = request.getScheme();
+ assertEquals("postInvoke scheme", "http", actualPostInvokeScheme);
+ }
+
+ public void testInvokeXforwardedProtoIsNullForIncomingHttpRequest() throws Exception {
+
+ // PREPARE
+ RemoteIpValve remoteIpValve = new RemoteIpValve();
+ remoteIpValve.setRemoteIpHeader("x-forwarded-for");
+ remoteIpValve.setProtocolHeader("x-forwarded-proto");
+ RemoteAddrAndHostTrackerValve remoteAddrAndHostTrackerValve = new RemoteAddrAndHostTrackerValve();
+ remoteIpValve.setNext(remoteAddrAndHostTrackerValve);
+
+ Request request = new Request();
+ request.setCoyoteRequest(new org.apache.coyote.Request());
+ // client ip
+ request.setRemoteAddr("192.168.0.10");
+ request.setRemoteHost("192.168.0.10");
+ request.getCoyoteRequest().getMimeHeaders().addValue("x-forwarded-for").setString("140.211.11.130");
+ // protocol
+ // null "x-forwarded-proto"
+ request.setSecure(false);
+ request.setServerPort(8080);
+ request.getCoyoteRequest().scheme().setString("http");
+
+ // TEST
+ remoteIpValve.invoke(request, null);
+
+ // VERIFY
+ // client ip
+ String actualXForwardedFor = request.getHeader("x-forwarded-for");
+ assertNull("no intermediate non-trusted proxy, x-forwarded-for must be null", actualXForwardedFor);
+
+ String actualXForwardedBy = request.getHeader("x-forwarded-by");
+ assertNull("no intermediate trusted proxy", actualXForwardedBy);
+
+ String actualRemoteAddr = remoteAddrAndHostTrackerValve.getRemoteAddr();
+ assertEquals("remoteAddr", "140.211.11.130", actualRemoteAddr);
+
+ String actualRemoteHost = remoteAddrAndHostTrackerValve.getRemoteHost();
+ assertEquals("remoteHost", "140.211.11.130", actualRemoteHost);
+
+ String actualPostInvokeRemoteAddr = request.getRemoteAddr();
+ assertEquals("postInvoke remoteAddr", "192.168.0.10", actualPostInvokeRemoteAddr);
+
+ String actualPostInvokeRemoteHost = request.getRemoteHost();
+ assertEquals("postInvoke remoteAddr", "192.168.0.10", actualPostInvokeRemoteHost);
+
+ // protocol
+ String actualScheme = remoteAddrAndHostTrackerValve.getScheme();
+ assertEquals("x-forwarded-proto is null", "http", actualScheme);
+
+ int actualServerPort = remoteAddrAndHostTrackerValve.getServerPort();
+ assertEquals("x-forwarded-proto is null", 8080, actualServerPort);
+
+ boolean actualSecure = remoteAddrAndHostTrackerValve.isSecure();
+ assertEquals("x-forwarded-proto is null", false, actualSecure);
+
+ boolean actualPostInvokeSecure = request.isSecure();
+ assertEquals("postInvoke secure", false, actualPostInvokeSecure);
+
+ int actualPostInvokeServerPort = request.getServerPort();
+ assertEquals("postInvoke serverPort", 8080, actualPostInvokeServerPort);
+
+ String actualPostInvokeScheme = request.getScheme();
+ assertEquals("postInvoke scheme", "http", actualPostInvokeScheme);
+ }
+
+ public void testInvokeXforwardedProtoSaysHttpForIncomingHttpsRequest() throws Exception {
+
+ // PREPARE
+ RemoteIpValve remoteIpValve = new RemoteIpValve();
+ remoteIpValve.setRemoteIpHeader("x-forwarded-for");
+ remoteIpValve.setProtocolHeader("x-forwarded-proto");
+ RemoteAddrAndHostTrackerValve remoteAddrAndHostTrackerValve = new RemoteAddrAndHostTrackerValve();
+ remoteIpValve.setNext(remoteAddrAndHostTrackerValve);
+
+ Request request = new Request();
+ request.setCoyoteRequest(new org.apache.coyote.Request());
+ // client ip
+ request.setRemoteAddr("192.168.0.10");
+ request.setRemoteHost("192.168.0.10");
+ request.getCoyoteRequest().getMimeHeaders().addValue("x-forwarded-for").setString("140.211.11.130");
+ // protocol
+ request.getCoyoteRequest().getMimeHeaders().addValue("x-forwarded-proto").setString("http");
+ request.setSecure(true);
+ request.setServerPort(8443);
+ request.getCoyoteRequest().scheme().setString("https");
+
+ // TEST
+ remoteIpValve.invoke(request, null);
+
+ // VERIFY
+ // client ip
+ String actualXForwardedFor = request.getHeader("x-forwarded-for");
+ assertNull("no intermediate non-trusted proxy, x-forwarded-for must be null", actualXForwardedFor);
+
+ String actualXForwardedBy = request.getHeader("x-forwarded-by");
+ assertNull("no intermediate trusted proxy", actualXForwardedBy);
+
+ String actualRemoteAddr = remoteAddrAndHostTrackerValve.getRemoteAddr();
+ assertEquals("remoteAddr", "140.211.11.130", actualRemoteAddr);
+
+ String actualRemoteHost = remoteAddrAndHostTrackerValve.getRemoteHost();
+ assertEquals("remoteHost", "140.211.11.130", actualRemoteHost);
+
+ String actualPostInvokeRemoteAddr = request.getRemoteAddr();
+ assertEquals("postInvoke remoteAddr", "192.168.0.10", actualPostInvokeRemoteAddr);
+
+ String actualPostInvokeRemoteHost = request.getRemoteHost();
+ assertEquals("postInvoke remoteAddr", "192.168.0.10", actualPostInvokeRemoteHost);
+
+ // protocol
+ String actualScheme = remoteAddrAndHostTrackerValve.getScheme();
+ assertEquals("x-forwarded-proto says http", "http", actualScheme);
+
+ int actualServerPort = remoteAddrAndHostTrackerValve.getServerPort();
+ assertEquals("x-forwarded-proto says http", 80, actualServerPort);
+
+ boolean actualSecure = remoteAddrAndHostTrackerValve.isSecure();
+ assertEquals("x-forwarded-proto says http", false, actualSecure);
+
+ boolean actualPostInvokeSecure = request.isSecure();
+ assertEquals("postInvoke secure", true, actualPostInvokeSecure);
+
+ int actualPostInvokeServerPort = request.getServerPort();
+ assertEquals("postInvoke serverPort", 8443, actualPostInvokeServerPort);
+
+ String actualPostInvokeScheme = request.getScheme();
+ assertEquals("postInvoke scheme", "https", actualPostInvokeScheme);
+ }
+
+ public void testInvokeXforwardedProtoIsNullForIncomingHttpsRequest() throws Exception {
+
+ // PREPARE
+ RemoteIpValve remoteIpValve = new RemoteIpValve();
+ remoteIpValve.setRemoteIpHeader("x-forwarded-for");
+ remoteIpValve.setProtocolHeader("x-forwarded-proto");
+ RemoteAddrAndHostTrackerValve remoteAddrAndHostTrackerValve = new RemoteAddrAndHostTrackerValve();
+ remoteIpValve.setNext(remoteAddrAndHostTrackerValve);
+
+ Request request = new Request();
+ request.setCoyoteRequest(new org.apache.coyote.Request());
+ // client ip
+ request.setRemoteAddr("192.168.0.10");
+ request.setRemoteHost("192.168.0.10");
+ request.getCoyoteRequest().getMimeHeaders().addValue("x-forwarded-for").setString("140.211.11.130");
+ // protocol
+ // Don't declare "x-forwarded-proto"
+ request.setSecure(true);
+ request.setServerPort(8443);
+ request.getCoyoteRequest().scheme().setString("https");
+
+ // TEST
+ remoteIpValve.invoke(request, null);
+
+ // VERIFY
+ // client ip
+ String actualXForwardedFor = request.getHeader("x-forwarded-for");
+ assertNull("no intermediate non-trusted proxy, x-forwarded-for must be null", actualXForwardedFor);
+
+ String actualXForwardedBy = request.getHeader("x-forwarded-by");
+ assertNull("no intermediate trusted proxy", actualXForwardedBy);
+
+ String actualRemoteAddr = remoteAddrAndHostTrackerValve.getRemoteAddr();
+ assertEquals("remoteAddr", "140.211.11.130", actualRemoteAddr);
+
+ String actualRemoteHost = remoteAddrAndHostTrackerValve.getRemoteHost();
+ assertEquals("remoteHost", "140.211.11.130", actualRemoteHost);
+
+ String actualPostInvokeRemoteAddr = request.getRemoteAddr();
+ assertEquals("postInvoke remoteAddr", "192.168.0.10", actualPostInvokeRemoteAddr);
+
+ String actualPostInvokeRemoteHost = request.getRemoteHost();
+ assertEquals("postInvoke remoteAddr", "192.168.0.10", actualPostInvokeRemoteHost);
+
+ // protocol
+ String actualScheme = remoteAddrAndHostTrackerValve.getScheme();
+ assertEquals("x-forwarded-proto is null", "https", actualScheme);
+
+ int actualServerPort = remoteAddrAndHostTrackerValve.getServerPort();
+ assertEquals("x-forwarded-proto is null", 8443, actualServerPort);
+
+ boolean actualSecure = remoteAddrAndHostTrackerValve.isSecure();
+ assertEquals("x-forwarded-proto is null", true, actualSecure);
+
+ boolean actualPostInvokeSecure = request.isSecure();
+ assertEquals("postInvoke secure", true, actualPostInvokeSecure);
+
+ int actualPostInvokeServerPort = request.getServerPort();
+ assertEquals("postInvoke serverPort", 8443, actualPostInvokeServerPort);
+
+ String actualPostInvokeScheme = request.getScheme();
+ assertEquals("postInvoke scheme", "https", actualPostInvokeScheme);
+ }
+
public void testInvokeNotAllowedRemoteAddr() throws Exception {
// PREPARE
RemoteIpValve remoteIpValve = new RemoteIpValve();
Modified: tomcat/trunk/webapps/docs/config/valve.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/valve.xml?rev=905627&r1=905626&r2=905627&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/valve.xml (original)
+++ tomcat/trunk/webapps/docs/config/valve.xml Tue Feb 2 13:28:55 2010
@@ -622,9 +622,10 @@
via a request headers (e.g. "X-Forwarded-For").</p>
<p>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").</p>
-
+ (http/https), server port and <code>request.secure</code> with the scheme presented
+ by a proxy or a load balancer via a request header
+ (e.g. "X-Forwarded-Proto").</p>
+
<p>This Valve may be used at the <code>Engine</code>, <code>Host</code> or
<code>Context</code> level as required. Normally, this Valve would be used
at the <code>Engine</code> level.</p>
@@ -690,6 +691,20 @@
used.</p>
</attribute>
+ <attribute name="httpServerPort" required="false">
+ <p>Value returned by <code>ServletRequest.getServerPort()</code>
+ when the <strong>protocolHeader</strong> indicates <code>http</code>
+ protocol. If not specified, the default of <code>80</code> is
+ used.</p>
+ </attribute>
+
+ <attribute name="httpsServerPort" required="false">
+ <p>Value returned by <code>ServletRequest.getServerPort()</code>
+ when the <strong>protocolHeader</strong> indicates <code>https</code>
+ protocol. If not specified, the default of <code>443</code> is
+ used.</p>
+ </attribute>
+
</attributes>
</subsection>
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org