Issue #3630 Forwarded-Port

reformatted code
Avoid updating handles unless configuration is changed.

Signed-off-by: Greg Wilkins <gregw@webtide.com>
This commit is contained in:
Greg Wilkins 2019-05-08 14:00:58 +02:00
parent 05072b34dc
commit 9f3b0223ab
1 changed files with 117 additions and 99 deletions

View File

@ -43,7 +43,9 @@ import static java.lang.invoke.MethodType.methodType;
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** Customize Requests for Proxy Forwarding.
/**
* Customize Requests for Proxy Forwarding.
* <p> * <p>
* This customizer looks at at HTTP request for headers that indicate * This customizer looks at at HTTP request for headers that indicate
* it has been forwarded by one or more proxies. Specifically handled are * it has been forwarded by one or more proxies. Specifically handled are
@ -59,7 +61,8 @@ import static java.lang.invoke.MethodType.methodType;
* so that the proxy is not seen as the other end point of the connection on which * so that the proxy is not seen as the other end point of the connection on which
* the request came</p> * the request came</p>
* <p>Headers can also be defined so that forwarded SSL Session IDs and Cipher * <p>Headers can also be defined so that forwarded SSL Session IDs and Cipher
* suites may be customised</p> * suites may be customised</p>
*
* @see <a href="http://en.wikipedia.org/wiki/X-Forwarded-For">Wikipedia: X-Forwarded-For</a> * @see <a href="http://en.wikipedia.org/wiki/X-Forwarded-For">Wikipedia: X-Forwarded-For</a>
*/ */
public class ForwardedRequestCustomizer implements Customizer public class ForwardedRequestCustomizer implements Customizer
@ -76,9 +79,9 @@ public class ForwardedRequestCustomizer implements Customizer
private String _forwardedHttpsHeader = "X-Proxied-Https"; private String _forwardedHttpsHeader = "X-Proxied-Https";
private String _forwardedCipherSuiteHeader = "Proxy-auth-cert"; private String _forwardedCipherSuiteHeader = "Proxy-auth-cert";
private String _forwardedSslSessionIdHeader = "Proxy-ssl-id"; private String _forwardedSslSessionIdHeader = "Proxy-ssl-id";
private boolean _proxyAsAuthority=false; private boolean _proxyAsAuthority = false;
private boolean _sslIsSecure=true; private boolean _sslIsSecure = true;
private Trie <MethodHandle> _handles; private Trie<MethodHandle> _handles;
public ForwardedRequestCustomizer() public ForwardedRequestCustomizer()
{ {
@ -97,7 +100,7 @@ public class ForwardedRequestCustomizer implements Customizer
/** /**
* @param proxyAsAuthority if true, use the proxy address obtained via * @param proxyAsAuthority if true, use the proxy address obtained via
* {@code X-Forwarded-Server} or RFC7239 "by" as the request authority. * {@code X-Forwarded-Server} or RFC7239 "by" as the request authority.
*/ */
public void setProxyAsAuthority(boolean proxyAsAuthority) public void setProxyAsAuthority(boolean proxyAsAuthority)
{ {
@ -114,49 +117,47 @@ public class ForwardedRequestCustomizer implements Customizer
{ {
if (rfc7239only) if (rfc7239only)
{ {
if (_forwardedHeader==null) if (_forwardedHeader == null)
_forwardedHeader=HttpHeader.FORWARDED.toString(); _forwardedHeader = HttpHeader.FORWARDED.toString();
_forwardedHostHeader=null; _forwardedHostHeader = null;
_forwardedServerHeader=null; _forwardedServerHeader = null;
_forwardedForHeader=null; _forwardedForHeader = null;
_forwardedPortHeader=null; _forwardedPortHeader = null;
_forwardedProtoHeader=null; _forwardedProtoHeader = null;
_forwardedHttpsHeader=null; _forwardedHttpsHeader = null;
} }
else else
{ {
if (_forwardedHostHeader==null) if (_forwardedHostHeader == null)
_forwardedHostHeader = HttpHeader.X_FORWARDED_HOST.toString(); _forwardedHostHeader = HttpHeader.X_FORWARDED_HOST.toString();
if (_forwardedServerHeader==null) if (_forwardedServerHeader == null)
_forwardedServerHeader = HttpHeader.X_FORWARDED_SERVER.toString(); _forwardedServerHeader = HttpHeader.X_FORWARDED_SERVER.toString();
if (_forwardedForHeader==null) if (_forwardedForHeader == null)
_forwardedForHeader = HttpHeader.X_FORWARDED_FOR.toString(); _forwardedForHeader = HttpHeader.X_FORWARDED_FOR.toString();
if (_forwardedPortHeader==null) if (_forwardedPortHeader == null)
_forwardedPortHeader = HttpHeader.X_FORWARDED_PORT.toString(); _forwardedPortHeader = HttpHeader.X_FORWARDED_PORT.toString();
if (_forwardedProtoHeader==null) if (_forwardedProtoHeader == null)
_forwardedProtoHeader = HttpHeader.X_FORWARDED_PROTO.toString(); _forwardedProtoHeader = HttpHeader.X_FORWARDED_PROTO.toString();
if (_forwardedHttpsHeader==null) if (_forwardedHttpsHeader == null)
_forwardedHttpsHeader = "X-Proxied-Https"; _forwardedHttpsHeader = "X-Proxied-Https";
} }
updateHandles(); updateHandles();
} }
public String getForcedHost() public String getForcedHost()
{ {
return _forcedHost.getValue(); return _forcedHost.getValue();
} }
/** /**
* Set a forced valued for the host header to control what is returned by {@link ServletRequest#getServerName()} and {@link ServletRequest#getServerPort()}. * Set a forced valued for the host header to control what is returned by {@link ServletRequest#getServerName()} and {@link ServletRequest#getServerPort()}.
* *
* @param hostAndPort * @param hostAndPort The value of the host header to force.
* The value of the host header to force.
*/ */
public void setForcedHost(String hostAndPort) public void setForcedHost(String hostAndPort)
{ {
_forcedHost = new HostPortHttpField(hostAndPort); _forcedHost = new HostPortHttpField(hostAndPort);
updateHandles();
} }
/** /**
@ -168,13 +169,15 @@ public class ForwardedRequestCustomizer implements Customizer
} }
/** /**
* @param forwardedHeader * @param forwardedHeader The header name for RFC forwarded (default Forwarded)
* The header name for RFC forwarded (default Forwarded)
*/ */
public void setForwardedHeader(String forwardedHeader) public void setForwardedHeader(String forwardedHeader)
{ {
_forwardedHeader = forwardedHeader; if (_forwardedHeader == null || !_forwardedHeader.equals(forwardedHeader))
updateHandles(); {
_forwardedHeader = forwardedHeader;
updateHandles();
}
} }
public String getForwardedHostHeader() public String getForwardedHostHeader()
@ -183,13 +186,15 @@ public class ForwardedRequestCustomizer implements Customizer
} }
/** /**
* @param forwardedHostHeader * @param forwardedHostHeader The header name for forwarded hosts (default {@code X-Forwarded-Host})
* The header name for forwarded hosts (default {@code X-Forwarded-Host})
*/ */
public void setForwardedHostHeader(String forwardedHostHeader) public void setForwardedHostHeader(String forwardedHostHeader)
{ {
_forwardedHostHeader = forwardedHostHeader; if (_forwardedHostHeader == null || !_forwardedHostHeader.equalsIgnoreCase(forwardedHostHeader))
updateHandles(); {
_forwardedHostHeader = forwardedHostHeader;
updateHandles();
}
} }
/** /**
@ -201,13 +206,15 @@ public class ForwardedRequestCustomizer implements Customizer
} }
/** /**
* @param forwardedServerHeader * @param forwardedServerHeader The header name for forwarded server (default {@code X-Forwarded-Server})
* The header name for forwarded server (default {@code X-Forwarded-Server})
*/ */
public void setForwardedServerHeader(String forwardedServerHeader) public void setForwardedServerHeader(String forwardedServerHeader)
{ {
_forwardedServerHeader = forwardedServerHeader; if (_forwardedServerHeader == null || !_forwardedServerHeader.equalsIgnoreCase(forwardedServerHeader))
updateHandles(); {
_forwardedServerHeader = forwardedServerHeader;
updateHandles();
}
} }
/** /**
@ -219,13 +226,15 @@ public class ForwardedRequestCustomizer implements Customizer
} }
/** /**
* @param forwardedRemoteAddressHeader * @param forwardedRemoteAddressHeader The header name for forwarded for (default {@code X-Forwarded-For})
* The header name for forwarded for (default {@code X-Forwarded-For})
*/ */
public void setForwardedForHeader(String forwardedRemoteAddressHeader) public void setForwardedForHeader(String forwardedRemoteAddressHeader)
{ {
_forwardedForHeader = forwardedRemoteAddressHeader; if (_forwardedForHeader == null || !_forwardedForHeader.equalsIgnoreCase(forwardedRemoteAddressHeader))
updateHandles(); {
_forwardedForHeader = forwardedRemoteAddressHeader;
updateHandles();
}
} }
public String getForwardedPortHeader() public String getForwardedPortHeader()
@ -234,13 +243,15 @@ public class ForwardedRequestCustomizer implements Customizer
} }
/** /**
* @param forwardedPortHeader * @param forwardedPortHeader The header name for forwarded hosts (default {@code X-Forwarded-Port})
* The header name for forwarded hosts (default {@code X-Forwarded-Port})
*/ */
public void setForwardedPortHeader(String forwardedPortHeader) public void setForwardedPortHeader(String forwardedPortHeader)
{ {
_forwardedHostHeader = forwardedPortHeader; if (_forwardedHostHeader == null || !_forwardedHostHeader.equalsIgnoreCase(forwardedPortHeader))
updateHandles(); {
_forwardedHostHeader = forwardedPortHeader;
updateHandles();
}
} }
/** /**
@ -256,13 +267,15 @@ public class ForwardedRequestCustomizer implements Customizer
/** /**
* Set the forwardedProtoHeader. * Set the forwardedProtoHeader.
* *
* @param forwardedProtoHeader * @param forwardedProtoHeader the forwardedProtoHeader to set (default {@code X-Forwarded-Proto})
* the forwardedProtoHeader to set (default {@code X-Forwarded-Proto})
*/ */
public void setForwardedProtoHeader(String forwardedProtoHeader) public void setForwardedProtoHeader(String forwardedProtoHeader)
{ {
_forwardedProtoHeader = forwardedProtoHeader; if (_forwardedProtoHeader == null || !_forwardedProtoHeader.equalsIgnoreCase(forwardedProtoHeader))
updateHandles(); {
_forwardedProtoHeader = forwardedProtoHeader;
updateHandles();
}
} }
/** /**
@ -274,13 +287,15 @@ public class ForwardedRequestCustomizer implements Customizer
} }
/** /**
* @param forwardedCipherSuite * @param forwardedCipherSuiteHeader The header name holding a forwarded cipher suite (default {@code Proxy-auth-cert})
* The header name holding a forwarded cipher suite (default {@code Proxy-auth-cert})
*/ */
public void setForwardedCipherSuiteHeader(String forwardedCipherSuite) public void setForwardedCipherSuiteHeader(String forwardedCipherSuiteHeader)
{ {
_forwardedCipherSuiteHeader = forwardedCipherSuite; if (_forwardedCipherSuiteHeader == null || !_forwardedCipherSuiteHeader.equalsIgnoreCase(forwardedCipherSuiteHeader))
updateHandles(); {
_forwardedCipherSuiteHeader = forwardedCipherSuiteHeader;
updateHandles();
}
} }
/** /**
@ -292,13 +307,15 @@ public class ForwardedRequestCustomizer implements Customizer
} }
/** /**
* @param forwardedSslSessionId * @param forwardedSslSessionIdHeader The header name holding a forwarded SSL Session ID (default {@code Proxy-ssl-id})
* The header name holding a forwarded SSL Session ID (default {@code Proxy-ssl-id})
*/ */
public void setForwardedSslSessionIdHeader(String forwardedSslSessionId) public void setForwardedSslSessionIdHeader(String forwardedSslSessionIdHeader)
{ {
_forwardedSslSessionIdHeader = forwardedSslSessionId; if (_forwardedSslSessionIdHeader == null || !_forwardedSslSessionIdHeader.equalsIgnoreCase(forwardedSslSessionIdHeader))
updateHandles(); {
_forwardedSslSessionIdHeader = forwardedSslSessionIdHeader;
updateHandles();
}
} }
/** /**
@ -314,10 +331,13 @@ public class ForwardedRequestCustomizer implements Customizer
*/ */
public void setForwardedHttpsHeader(String forwardedHttpsHeader) public void setForwardedHttpsHeader(String forwardedHttpsHeader)
{ {
_forwardedHttpsHeader = forwardedHttpsHeader; if (_forwardedHttpsHeader == null || !_forwardedHttpsHeader.equalsIgnoreCase(forwardedHttpsHeader))
updateHandles(); {
_forwardedHttpsHeader = forwardedHttpsHeader;
updateHandles();
}
} }
/** /**
* @return true if the presence of a SSL session or certificate header is sufficient * @return true if the presence of a SSL session or certificate header is sufficient
* to indicate a secure request (default is true) * to indicate a secure request (default is true)
@ -329,7 +349,7 @@ public class ForwardedRequestCustomizer implements Customizer
/** /**
* @param sslIsSecure true if the presence of a SSL session or certificate header is sufficient * @param sslIsSecure true if the presence of a SSL session or certificate header is sufficient
* to indicate a secure request (default is true) * to indicate a secure request (default is true)
*/ */
public void setSslIsSecure(boolean sslIsSecure) public void setSslIsSecure(boolean sslIsSecure)
{ {
@ -362,13 +382,13 @@ public class ForwardedRequestCustomizer implements Customizer
{ {
// Update host header // Update host header
httpFields.put(_forcedHost); httpFields.put(_forcedHost);
request.setAuthority(_forcedHost.getHost(),_forcedHost.getPort()); request.setAuthority(_forcedHost.getHost(), _forcedHost.getPort());
} }
else if (forwarded._rfc7239!=null && forwarded._rfc7239._host!=null) else if (forwarded._rfc7239 != null && forwarded._rfc7239._host != null)
{ {
HostPortHttpField auth = forwarded._rfc7239._host; HostPortHttpField auth = forwarded._rfc7239._host;
httpFields.put(auth); httpFields.put(auth);
request.setAuthority(auth.getHost(),auth.getPort()); request.setAuthority(auth.getHost(), auth.getPort());
} }
else if (forwarded._forwardedHost != null) else if (forwarded._forwardedHost != null)
{ {
@ -378,26 +398,26 @@ public class ForwardedRequestCustomizer implements Customizer
} }
else if (_proxyAsAuthority) else if (_proxyAsAuthority)
{ {
if (forwarded._rfc7239!=null && forwarded._rfc7239._by!=null) if (forwarded._rfc7239 != null && forwarded._rfc7239._by != null)
{ {
HostPortHttpField auth = forwarded._rfc7239._by; HostPortHttpField auth = forwarded._rfc7239._by;
httpFields.put(auth); httpFields.put(auth);
request.setAuthority(auth.getHost(),auth.getPort()); request.setAuthority(auth.getHost(), auth.getPort());
} }
else if (forwarded._forwardedServer != null) else if (forwarded._forwardedServer != null)
{ {
request.setAuthority(forwarded._forwardedServer,request.getServerPort()); request.setAuthority(forwarded._forwardedServer, request.getServerPort());
} }
} }
// handle remote end identifier // handle remote end identifier
if (forwarded._rfc7239!=null && forwarded._rfc7239._for!=null) if (forwarded._rfc7239 != null && forwarded._rfc7239._for != null)
{ {
request.setRemoteAddr(InetSocketAddress.createUnresolved(forwarded._rfc7239._for.getHost(),forwarded._rfc7239._for.getPort())); request.setRemoteAddr(InetSocketAddress.createUnresolved(forwarded._rfc7239._for.getHost(), forwarded._rfc7239._for.getPort()));
} }
else if (forwarded._forwardedFor != null) else if (forwarded._forwardedFor != null)
{ {
int port = (forwarded._forwardedPort>0) int port = (forwarded._forwardedPort > 0)
? forwarded._forwardedPort ? forwarded._forwardedPort
: (forwarded._forwardedFor.getPort() > 0) : (forwarded._forwardedFor.getPort() > 0)
? forwarded._forwardedFor.getPort() ? forwarded._forwardedFor.getPort()
@ -406,7 +426,7 @@ public class ForwardedRequestCustomizer implements Customizer
} }
// handle protocol identifier // handle protocol identifier
if (forwarded._rfc7239!=null && forwarded._rfc7239._proto!=null) if (forwarded._rfc7239 != null && forwarded._rfc7239._proto != null)
{ {
request.setScheme(forwarded._rfc7239._proto); request.setScheme(forwarded._rfc7239._proto);
if (forwarded._rfc7239._proto.equals(config.getSecureScheme())) if (forwarded._rfc7239._proto.equals(config.getSecureScheme()))
@ -418,7 +438,7 @@ public class ForwardedRequestCustomizer implements Customizer
if (forwarded._forwardedProto.equals(config.getSecureScheme())) if (forwarded._forwardedProto.equals(config.getSecureScheme()))
request.setSecure(true); request.setSecure(true);
} }
else if (forwarded._forwardedHttps !=null && ("on".equalsIgnoreCase(forwarded._forwardedHttps)||"true".equalsIgnoreCase(forwarded._forwardedHttps))) else if (forwarded._forwardedHttps != null && ("on".equalsIgnoreCase(forwarded._forwardedHttps) || "true".equalsIgnoreCase(forwarded._forwardedHttps)))
{ {
request.setScheme(HttpScheme.HTTPS.asString()); request.setScheme(HttpScheme.HTTPS.asString());
if (HttpScheme.HTTPS.asString().equals(config.getSecureScheme())) if (HttpScheme.HTTPS.asString().equals(config.getSecureScheme()))
@ -441,7 +461,7 @@ public class ForwardedRequestCustomizer implements Customizer
} }
// The left-most value is the farthest downstream client // The left-most value is the farthest downstream client
return headerValue.substring(0,commaIndex).trim(); return headerValue.substring(0, commaIndex).trim();
} }
protected HostPort getRemoteAddr(String headerValue) protected HostPort getRemoteAddr(String headerValue)
@ -463,11 +483,11 @@ public class ForwardedRequestCustomizer implements Customizer
return null; return null;
} }
} }
@Override @Override
public String toString() public String toString()
{ {
return String.format("%s@%x",this.getClass().getSimpleName(),hashCode()); return String.format("%s@%x", this.getClass().getSimpleName(), hashCode());
} }
@Deprecated @Deprecated
@ -475,12 +495,11 @@ public class ForwardedRequestCustomizer implements Customizer
{ {
return _forcedHost.getValue(); return _forcedHost.getValue();
} }
/** /**
* Set a forced valued for the host header to control what is returned by {@link ServletRequest#getServerName()} and {@link ServletRequest#getServerPort()}. * Set a forced valued for the host header to control what is returned by {@link ServletRequest#getServerName()} and {@link ServletRequest#getServerPort()}.
* *
* @param hostHeader * @param hostHeader The value of the host header to force.
* The value of the host header to force.
*/ */
@Deprecated @Deprecated
public void setHostHeader(String hostHeader) public void setHostHeader(String hostHeader)
@ -494,7 +513,7 @@ public class ForwardedRequestCustomizer implements Customizer
HostPortHttpField _for; HostPortHttpField _for;
HostPortHttpField _host; HostPortHttpField _host;
String _proto; String _proto;
private RFC7239() private RFC7239()
{ {
super(false); super(false);
@ -503,27 +522,27 @@ public class ForwardedRequestCustomizer implements Customizer
@Override @Override
protected void parsedParam(StringBuffer buffer, int valueLength, int paramName, int paramValue) protected void parsedParam(StringBuffer buffer, int valueLength, int paramName, int paramValue)
{ {
if (valueLength==0 && paramValue>paramName) if (valueLength == 0 && paramValue > paramName)
{ {
String name=StringUtil.asciiToLowerCase(buffer.substring(paramName,paramValue-1)); String name = StringUtil.asciiToLowerCase(buffer.substring(paramName, paramValue - 1));
String value=buffer.substring(paramValue); String value = buffer.substring(paramValue);
switch(name) switch (name)
{ {
case "by": case "by":
if (_by==null && !value.startsWith("_") && !"unknown".equals(value)) if (_by == null && !value.startsWith("_") && !"unknown".equals(value))
_by=new HostPortHttpField(value); _by = new HostPortHttpField(value);
break; break;
case "for": case "for":
if (_for==null && !value.startsWith("_") && !"unknown".equals(value)) if (_for == null && !value.startsWith("_") && !"unknown".equals(value))
_for=new HostPortHttpField(value); _for = new HostPortHttpField(value);
break; break;
case "host": case "host":
if (_host==null) if (_host == null)
_host=new HostPortHttpField(value); _host = new HostPortHttpField(value);
break; break;
case "proto": case "proto":
if (_proto==null) if (_proto == null)
_proto=value; _proto = value;
break; break;
} }
} }
@ -536,7 +555,7 @@ public class ForwardedRequestCustomizer implements Customizer
MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodType type = methodType(Void.TYPE, HttpField.class); MethodType type = methodType(Void.TYPE, HttpField.class);
while(true) while (true)
{ {
try try
{ {
@ -563,7 +582,7 @@ public class ForwardedRequestCustomizer implements Customizer
continue; continue;
break; break;
} }
catch (NoSuchMethodException|IllegalAccessException e) catch (NoSuchMethodException | IllegalAccessException e)
{ {
throw new IllegalStateException(e); throw new IllegalStateException(e);
} }
@ -591,7 +610,7 @@ public class ForwardedRequestCustomizer implements Customizer
public void handleCipherSuite(HttpField field) public void handleCipherSuite(HttpField field)
{ {
_request.setAttribute("javax.servlet.request.cipher_suite",field.getValue()); _request.setAttribute("javax.servlet.request.cipher_suite", field.getValue());
if (isSslIsSecure()) if (isSslIsSecure())
{ {
_request.setSecure(true); _request.setSecure(true);
@ -633,6 +652,7 @@ public class ForwardedRequestCustomizer implements Customizer
{ {
_forwardedPort = field.getIntValue(); _forwardedPort = field.getIntValue();
} }
public void handleHttps(HttpField field) public void handleHttps(HttpField field)
{ {
_forwardedHttps = getLeftMost(field.getValue()); _forwardedHttps = getLeftMost(field.getValue());
@ -640,11 +660,9 @@ public class ForwardedRequestCustomizer implements Customizer
public void handleRFC7239(HttpField field) public void handleRFC7239(HttpField field)
{ {
if (_rfc7239 ==null) if (_rfc7239 == null)
_rfc7239 = new RFC7239(); _rfc7239 = new RFC7239();
_rfc7239.addValue(field.getValue()); _rfc7239.addValue(field.getValue());
} }
} }
} }