From 9cf8cf3c0d60c7e92cf0239730183168e90a663b Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 17 Jun 2019 11:35:40 +0200 Subject: [PATCH] Issue #3782 X-Forwarded-Port can be remote or local Added option for X-Forwarded-Port to be remote or local with default being local. Signed-off-by: Greg Wilkins --- .../main/config/etc/jetty-http-forwarded.xml | 1 + .../main/config/modules/http-forwarded.mod | 1 + .../server/ForwardedRequestCustomizer.java | 93 ++++++++++++------- .../ForwardedRequestCustomizerTest.java | 25 +++++ 4 files changed, 89 insertions(+), 31 deletions(-) diff --git a/jetty-server/src/main/config/etc/jetty-http-forwarded.xml b/jetty-server/src/main/config/etc/jetty-http-forwarded.xml index 648d6c6a94f..8d0047cc54d 100644 --- a/jetty-server/src/main/config/etc/jetty-http-forwarded.xml +++ b/jetty-server/src/main/config/etc/jetty-http-forwarded.xml @@ -12,6 +12,7 @@ + diff --git a/jetty-server/src/main/config/modules/http-forwarded.mod b/jetty-server/src/main/config/modules/http-forwarded.mod index f67822065a4..7e6545a5902 100644 --- a/jetty-server/src/main/config/modules/http-forwarded.mod +++ b/jetty-server/src/main/config/modules/http-forwarded.mod @@ -24,6 +24,7 @@ etc/jetty-http-forwarded.xml # jetty.httpConfig.forwardedProtoHeader=X-Forwarded-Proto # jetty.httpConfig.forwardedForHeader=X-Forwarded-For # jetty.httpConfig.forwardedPortHeader=X-Forwarded-Port +# jetty.httpConfig.forwardedPortHeaderRemote=false # jetty.httpConfig.forwardedHttpsHeader=X-Proxied-Https # jetty.httpConfig.forwardedSslSessionIdHeader=Proxy-ssl-id # jetty.httpConfig.forwardedCipherSuiteHeader=Proxy-auth-cert diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java index e9320300153..171384bd672 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java @@ -73,6 +73,7 @@ public class ForwardedRequestCustomizer implements Customizer private String _forwardedProtoHeader = HttpHeader.X_FORWARDED_PROTO.toString(); private String _forwardedForHeader = HttpHeader.X_FORWARDED_FOR.toString(); private String _forwardedPortHeader = HttpHeader.X_FORWARDED_PORT.toString(); + private boolean _forwardedPortHeaderRemote = false; private String _forwardedHttpsHeader = "X-Proxied-Https"; private String _forwardedCipherSuiteHeader = "Proxy-auth-cert"; private String _forwardedSslSessionIdHeader = "Proxy-ssl-id"; @@ -251,6 +252,16 @@ public class ForwardedRequestCustomizer implements Customizer } } + public boolean isForwardedPortHeaderRemote() + { + return _forwardedPortHeaderRemote; + } + + public void setForwardedPortHeaderRemote(boolean forwardedPortHeaderRemote) + { + _forwardedPortHeaderRemote = forwardedPortHeaderRemote; + } + /** * Get the forwardedProtoHeader. * @@ -447,8 +458,6 @@ public class ForwardedRequestCustomizer implements Customizer size += 128; _handles = new ArrayTrie<>(size); - _handles.put(HttpHeader.HOST.toString(), lookup.findVirtual(Forwarded.class, "handleHttpHost", type)); - if (_forwardedCipherSuiteHeader != null && !_handles.put(_forwardedCipherSuiteHeader, lookup.findVirtual(Forwarded.class, "handleCipherSuite", type))) continue; if (_forwardedSslSessionIdHeader != null && !_handles.put(_forwardedSslSessionIdHeader, lookup.findVirtual(Forwarded.class, "handleSslSessionId", type))) @@ -484,14 +493,22 @@ public class ForwardedRequestCustomizer implements Customizer } } - private static class XHostPort extends HostPort + private static class PossiblyPartialHostPort extends HostPort { - XHostPort(String authority) + PossiblyPartialHostPort(String authority) { super(authority); } - XHostPort(String host, int port) + protected PossiblyPartialHostPort(String host, int port) + { + super(host, port); + } + } + + private static class PortSetHostPort extends PossiblyPartialHostPort + { + PortSetHostPort(String host, int port) { super(host, port); } @@ -514,7 +531,6 @@ public class ForwardedRequestCustomizer implements Customizer String _proto; HostPort _for; HostPort _host; - HostPort _httpHost; public Forwarded(Request request, HttpConfiguration config) { @@ -525,13 +541,6 @@ public class ForwardedRequestCustomizer implements Customizer _host = _forcedHost.getHostPort(); } - public void handleHttpHost(HttpField field) - { - _httpHost = new HostPort(field.getValue()); - if (_host != null && _host instanceof XHostPort && "unknown".equals(_host.getHost())) - _host = new XHostPort(_httpHost.getHost(), _host.getPort()); - } - public void handleCipherSuite(HttpField field) { _request.setAttribute("javax.servlet.request.cipher_suite", field.getValue()); @@ -554,16 +563,24 @@ public class ForwardedRequestCustomizer implements Customizer public void handleHost(HttpField field) { - if (_host==null) - _host = new XHostPort(getLeftMost(field.getValue())); - else if (_host instanceof XHostPort && "unknown".equals(_host.getHost())) - _host = new XHostPort(getLeftMost(field.getValue()), _host.getPort()); + if (!_forwardedPortHeaderRemote && !StringUtil.isEmpty(_forwardedPortHeader)) + { + if (_host == null) + _host = new PossiblyPartialHostPort(getLeftMost(field.getValue())); + else if (_for instanceof PortSetHostPort) + _host = new HostPort(HostPort.normalizeHost(getLeftMost(field.getValue())), _host.getPort()); + } + else if (_host==null) + { + _host = new HostPort(getLeftMost(field.getValue())); + } } public void handleServer(HttpField field) { - if (_proxyAsAuthority && _host==null) - _host = new XHostPort(getLeftMost(field.getValue())); + if (_proxyAsAuthority) + return; + handleHost(field); } public void handleProto(HttpField field) @@ -574,21 +591,35 @@ public class ForwardedRequestCustomizer implements Customizer public void handleFor(HttpField field) { - if (_for==null) - _for = new XHostPort(getLeftMost(field.getValue())); - else if (_for instanceof XHostPort && "unknown".equals(_for.getHost())) - _for = new XHostPort(HostPort.normalizeHost(getLeftMost(field.getValue())),_for.getPort()); + if (_forwardedPortHeaderRemote && !StringUtil.isEmpty(_forwardedPortHeader)) + { + if (_for == null) + _for = new PossiblyPartialHostPort(getLeftMost(field.getValue())); + else if (_for instanceof PortSetHostPort) + _for = new HostPort(HostPort.normalizeHost(getLeftMost(field.getValue())), _for.getPort()); + } + else if (_for == null) + { + _for = new HostPort(getLeftMost(field.getValue())); + } } public void handlePort(HttpField field) { - if (_host == null) + if (_forwardedPortHeaderRemote) { - String hostname = _httpHost != null ? _httpHost.getHost() : "unknown"; - _host = new XHostPort(hostname, field.getIntValue()); + if (_for == null) + _for = new PortSetHostPort(_request.getRemoteHost(), field.getIntValue()); + else if (_for instanceof PossiblyPartialHostPort && _for.getPort() <= 0) + _for = new HostPort(HostPort.normalizeHost(_for.getHost()), field.getIntValue()); + } + else + { + if (_host == null) + _host = new PortSetHostPort(_request.getServerName(), field.getIntValue()); + else if (_host instanceof PossiblyPartialHostPort && _host.getPort() <= 0) + _host = new HostPort(HostPort.normalizeHost(_host.getHost()), field.getIntValue()); } - else if (_host instanceof XHostPort && _host.getPort()<=0) - _host = new XHostPort(HostPort.normalizeHost(_host.getHost()), field.getIntValue()); } public void handleHttps(HttpField field) @@ -616,19 +647,19 @@ public class ForwardedRequestCustomizer implements Customizer break; if (value.startsWith("_") || "unknown".equals(value)) break; - if (_host == null || _host instanceof XHostPort) + if (_host == null || !(_host instanceof Rfc7239HostPort)) _host = new Rfc7239HostPort(value); break; case "for": if (value.startsWith("_") || "unknown".equals(value)) break; - if (_for == null || _for instanceof XHostPort) + if (_for == null || !(_for instanceof Rfc7239HostPort)) _for = new Rfc7239HostPort(value); break; case "host": if (value.startsWith("_") || "unknown".equals(value)) break; - if (_host == null || _host instanceof XHostPort) + if (_host == null || !(_host instanceof Rfc7239HostPort)) _host = new Rfc7239HostPort(value); break; case "proto": diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ForwardedRequestCustomizerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ForwardedRequestCustomizerTest.java index 8f5ef3b0f81..61181da2efc 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ForwardedRequestCustomizerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ForwardedRequestCustomizerTest.java @@ -560,6 +560,31 @@ public class ForwardedRequestCustomizerTest assertThat("requestURL", _requestURL.get(), is("http://myhost:4444/")); } + + + /** + * Resetting the server port via a forwarding header + */ + @Test + public void testRemote_Port_For() throws Exception + { + _customizer.setForwardedPortHeaderRemote(true); + HttpTester.Response response = HttpTester.parseResponse( + _connector.getResponse( + "GET / HTTP/1.1\n" + + "Host: myhost\n" + + "X-Forwarded-Port: 4444\n" + + "X-Forwarded-For: 192.168.1.200\n" + + "\n")); + assertThat("status", response.getStatus(), is(200)); + assertThat("scheme", _scheme.get(), is("http")); + assertThat("serverName", _serverName.get(), is("myhost")); + assertThat("serverPort", _serverPort.get(), is(80)); + assertThat("remoteAddr", _remoteAddr.get(), is("192.168.1.200")); + assertThat("remotePort", _remotePort.get(), is(4444)); + assertThat("requestURL", _requestURL.get(), is("http://myhost/")); + } + /** * Test setting the server Port before the "Host" header has been seen. */