Class XForwardedRequestWrapperFactory
- java.lang.Object
-
- org.apache.wicket.protocol.http.servlet.AbstractRequestWrapperFactory
-
- org.apache.wicket.protocol.http.servlet.XForwardedRequestWrapperFactory
-
public class XForwardedRequestWrapperFactory extends AbstractRequestWrapperFactory
Request wrapper factory to integrate "X-Forwarded-For" and "X-Forwarded-Proto" HTTP headers.Most of the design of this Servlet Filter is a port of mod_remoteip, this servlet filter replaces the apparent client remote IP address and hostname for the request with the IP address list presented by a proxy or a load balancer via a request headers (e.g. "X-Forwarded-For").
Another feature of this servlet filter 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 wrapper proceeds as follows:
If the incoming
request.getRemoteAddr()
matches the servlet filter's list of internal proxies :- Loop on the comma delimited list of IPs and hostnames passed by the preceding load balancer
or proxy in the given request's Http header named
$remoteIPHeader
(default valuex-forwarded-for
). Values are processed in right-to-left order. - For each ip/host of the list:
- if it matches the internal proxies list, the ip/host is swallowed
- if it matches the trusted proxies list, the ip/host is added to the created proxies header
- otherwise, the ip/host is declared to be the remote ip and looping is stopped.
- If the request http header named
$protocolHeader
(e.g.x-forwarded-for
) equals to the value ofprotocolHeaderHttpsValue
configuration parameter (defaulthttps
) thenrequest.isSecure = true
,request.scheme = https
andrequest.serverPort = 443
. Note that 443 can be overwritten with the$httpsServerPort
configuration parameter.
Configuration parameters:
Configuration parameters XForwardedFilter property Description Equivalent mod_remoteip directive Format Default Value remoteIPHeader Name of the Http Header read by this servlet filter that holds the list of traversed IP addresses starting from the requesting client RemoteIPHeader Compliant http header name x-forwarded-for allowedInternalProxies List of internal proxies ip adress. If they appear in the remoteIpHeader
value, they will be trusted and will not appear in theproxiesHeader
valueRemoteIPInternalProxy Comma delimited list of regular expressions (in the syntax supported by the Pattern
library)10\.\d{1,3}\.\d{1,3}\.\d{1,3}, 192\.168\.\d{1,3}\.\d{1,3}, 172\\.(?:1[6-9]|2\\d|3[0-1]).\\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, 172.16/12, 169.254/16 and 127/8 are allowedproxiesHeader Name of the http header created by this servlet filter to hold the list of proxies 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 remoteIpHeader
value, they will be trusted and will appear in theproxiesHeader
valueRemoteIPTrustedProxy Comma delimited list of regular expressions (in the syntax supported by the Pattern
library)protocolHeader Name of the http header read by this servlet filter that holds the flag that this request N/A Compliant http header name like X-Forwarded-Proto
,X-Forwarded-Ssl
orFront-End-Https
null
protocolHeaderHttpsValue Value of the protocolHeader
to indicate that it is an Https requestN/A String like https
orON
https
httpServerPort Value returned by ServletRequest.getServerPort()
when theprotocolHeader
indicateshttp
protocolN/A integer 80 httpsServerPort Value returned by ServletRequest.getServerPort()
when theprotocolHeader
indicateshttps
protocolN/A integer 443 Regular expression vs. IP address blocks:
mod_remoteip
allows to use address blocks (e.g.192.168/16
) to configureRemoteIPInternalProxy
andRemoteIPTrustedProxy
; as the JVM doesnt have a library similar to apr_ipsubnet_test.
Sample with internal proxies
XForwardedFilter configuration:
<filter> <filter-name>XForwardedFilter</filter-name> <filter-class>fr.xebia.servlet.filter.XForwardedFilter</filter-class> <init-param> <param-name>allowedInternalProxies</param-name><param-value>192\.168\.0\.10, 192\.168\.0\.11</param-value> </init-param> <init-param> <param-name>remoteIPHeader</param-name><param-value>x-forwarded-for</param-value> </init-param> <init-param> <param-name>remoteIPProxiesHeader</param-name><param-value>x-forwarded-by</param-value> </init-param> <init-param> <param-name>protocolHeader</param-name><param-value>x-forwarded-proto</param-value> </init-param> </filter> <filter-mapping> <filter-name>XForwardedFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> </filter-mapping>
Request values:
Request values property Value Before XForwardedFilter Value After XForwardedFilter 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
XForwardedFilter configuration:
<filter> <filter-name>XForwardedFilter</filter-name> <filter-class>fr.xebia.servlet.filter.XForwardedFilter</filter-class> <init-param> <param-name>allowedInternalProxies</param-name><param-value>192\.168\.0\.10, 192\.168\.0\.11</param-value> </init-param> <init-param> <param-name>remoteIPHeader</param-name><param-value>x-forwarded-for</param-value> </init-param> <init-param> <param-name>remoteIPProxiesHeader</param-name><param-value>x-forwarded-by</param-value> </init-param> <init-param> <param-name>trustedProxies</param-name><param-value>proxy1, proxy2</param-value> </init-param> </filter> <filter-mapping> <filter-name>XForwardedFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> </filter-mapping>
Request values:
Request values property Value Before XForwardedFilter Value After XForwardedFilter 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
andproxy2
are both trusted proxies that come inx-forwarded-for
header, they both are migrated inx-forwarded-by
header.x-forwarded-by
is null because all the proxies are trusted or internal.
Sample with internal and trusted proxies
XForwardedFilter configuration:
<filter> <filter-name>XForwardedFilter</filter-name> <filter-class>fr.xebia.servlet.filter.XForwardedFilter</filter-class> <init-param> <param-name>allowedInternalProxies</param-name><param-value>192\.168\.0\.10, 192\.168\.0\.11</param-value> </init-param> <init-param> <param-name>remoteIPHeader</param-name><param-value>x-forwarded-for</param-value> </init-param> <init-param> <param-name>remoteIPProxiesHeader</param-name><param-value>x-forwarded-by</param-value> </init-param> <init-param> <param-name>trustedProxies</param-name><param-value>proxy1, proxy2</param-value> </init-param> </filter> <filter-mapping> <filter-name>XForwardedFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> </filter-mapping>
Request values:
Request values property Value Before XForwardedFilter Value After XForwardedFilter 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
andproxy2
are both trusted proxies that come inx-forwarded-for
header, they both are migrated inx-forwarded-by
header. As192.168.0.10
is an internal proxy, it does not appear inx-forwarded-by
.x-forwarded-by
is null because all the proxies are trusted or internal.
Sample with an untrusted proxy
XForwardedFilter configuration:
<filter> <filter-name>XForwardedFilter</filter-name> <filter-class>fr.xebia.servlet.filter.XForwardedFilter</filter-class> <init-param> <param-name>allowedInternalProxies</param-name><param-value>192\.168\.0\.10, 192\.168\.0\.11</param-value> </init-param> <init-param> <param-name>remoteIPHeader</param-name><param-value>x-forwarded-for</param-value> </init-param> <init-param> <param-name>remoteIPProxiesHeader</param-name><param-value>x-forwarded-by</param-value> </init-param> <init-param> <param-name>trustedProxies</param-name><param-value>proxy1, proxy2</param-value> </init-param> </filter> <filter-mapping> <filter-name>XForwardedFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> </filter-mapping>
Request values:
Request values property Value Before XForwardedFilter Value After XForwardedFilter 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 proxyproxy1
.x-forwarded-by
holds140.211.11.130
becauseuntrusted-proxy
is not trusted and thus, we can not trust thatuntrusted-proxy
is the actual remote ip.request.remoteAddr
isuntrusted-proxy
that is an IP verified byproxy1
.- Author:
- Cyrille Le Clerc, Juergen Donnerstag
- Loop on the comma delimited list of IPs and hostnames passed by the preceding load balancer
or proxy in the given request's Http header named
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description static class
XForwardedRequestWrapperFactory.Config
Filter Config
-
Field Summary
Fields Modifier and Type Field Description protected static String
HTTP_SERVER_PORT_PARAMETER
protected static String
HTTPS_SERVER_PORT_PARAMETER
protected static String
INTERNAL_PROXIES_PARAMETER
protected static String
PROTOCOL_HEADER_PARAMETER
protected static String
PROTOCOL_HEADER_SSL_VALUE_PARAMETER
protected static String
PROXIES_HEADER_PARAMETER
protected static String
REMOTE_IP_HEADER_PARAMETER
protected static String
TRUSTED_PROXIES_PARAMETER
-
Constructor Summary
Constructors Constructor Description XForwardedRequestWrapperFactory()
Construct.
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description XForwardedRequestWrapperFactory.Config
getConfig()
void
init(javax.servlet.FilterConfig filterConfig)
boolean
needsWrapper(javax.servlet.http.HttpServletRequest request)
javax.servlet.http.HttpServletRequest
newRequestWrapper(javax.servlet.http.HttpServletRequest request)
void
setConfig(XForwardedRequestWrapperFactory.Config config)
The Wicket application might want to provide its own config-
Methods inherited from class org.apache.wicket.protocol.http.servlet.AbstractRequestWrapperFactory
commaDelimitedListToPatternArray, commaDelimitedListToStringArray, getWrapper, isEnabled, listToCommaDelimitedString, matchesOne, setEnabled
-
-
-
-
Field Detail
-
HTTP_SERVER_PORT_PARAMETER
protected static final String HTTP_SERVER_PORT_PARAMETER
- See Also:
- Constant Field Values
-
HTTPS_SERVER_PORT_PARAMETER
protected static final String HTTPS_SERVER_PORT_PARAMETER
- See Also:
- Constant Field Values
-
INTERNAL_PROXIES_PARAMETER
protected static final String INTERNAL_PROXIES_PARAMETER
- See Also:
- Constant Field Values
-
PROTOCOL_HEADER_PARAMETER
protected static final String PROTOCOL_HEADER_PARAMETER
- See Also:
- Constant Field Values
-
PROTOCOL_HEADER_SSL_VALUE_PARAMETER
protected static final String PROTOCOL_HEADER_SSL_VALUE_PARAMETER
- See Also:
- Constant Field Values
-
PROXIES_HEADER_PARAMETER
protected static final String PROXIES_HEADER_PARAMETER
- See Also:
- Constant Field Values
-
REMOTE_IP_HEADER_PARAMETER
protected static final String REMOTE_IP_HEADER_PARAMETER
- See Also:
- Constant Field Values
-
TRUSTED_PROXIES_PARAMETER
protected static final String TRUSTED_PROXIES_PARAMETER
- See Also:
- Constant Field Values
-
-
Constructor Detail
-
XForwardedRequestWrapperFactory
public XForwardedRequestWrapperFactory()
Construct.
-
-
Method Detail
-
getConfig
public final XForwardedRequestWrapperFactory.Config getConfig()
- Returns:
- XForwarded filter specific config
-
setConfig
public final void setConfig(XForwardedRequestWrapperFactory.Config config)
The Wicket application might want to provide its own config- Parameters:
config
-
-
needsWrapper
public boolean needsWrapper(javax.servlet.http.HttpServletRequest request)
- Specified by:
needsWrapper
in classAbstractRequestWrapperFactory
- Returns:
- True, if a wrapper is needed
-
newRequestWrapper
public javax.servlet.http.HttpServletRequest newRequestWrapper(javax.servlet.http.HttpServletRequest request)
- Specified by:
newRequestWrapper
in classAbstractRequestWrapperFactory
- Parameters:
request
-- Returns:
- Either the original request or the wrapper
-
init
public void init(javax.servlet.FilterConfig filterConfig)
- Parameters:
filterConfig
-
-
-