org.apache.wicket.protocol.http.servlet
Class XForwardedRequestWrapperFactory

java.lang.Object
  extended by org.apache.wicket.protocol.http.servlet.AbstractRequestWrapperFactory
      extended by 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 :

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 the proxiesHeader value RemoteIPInternalProxy 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 allowed
proxiesHeader 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 the proxiesHeader value RemoteIPTrustedProxy 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 or 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
httpServerPort Value returned by ServletRequest.getServerPort() when the protocolHeader indicates http protocol N/A integer 80
httpsServerPort Value returned by ServletRequest.getServerPort() when the protocolHeader indicates https protocol N/A integer 443

Regular expression vs. IP address blocks: mod_remoteip allows to use address blocks (e.g. 192.168/16) to configure RemoteIPInternalProxy and RemoteIPTrustedProxy ; 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:

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
Note : 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:

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
Note : proxy1 and proxy2 are both trusted proxies that come in x-forwarded-for header, they both are migrated in x-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:

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
Note : proxy1 and proxy2 are both trusted proxies 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 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:

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
Note : 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.remoteAddr is untrusted-proxy that is an IP verified by proxy1.


Author:
Cyrille Le Clerc, Juergen Donnerstag

Nested Class Summary
static class XForwardedRequestWrapperFactory.Config
          Filter Config
 
Field Summary
protected static java.lang.String HTTP_SERVER_PORT_PARAMETER
           
protected static java.lang.String HTTPS_SERVER_PORT_PARAMETER
           
protected static java.lang.String INTERNAL_PROXIES_PARAMETER
           
protected static java.lang.String PROTOCOL_HEADER_PARAMETER
           
protected static java.lang.String PROTOCOL_HEADER_SSL_VALUE_PARAMETER
           
protected static java.lang.String PROXIES_HEADER_PARAMETER
           
protected static java.lang.String REMOTE_IP_HEADER_PARAMETER
           
protected static java.lang.String TRUSTED_PROXIES_PARAMETER
           
 
Constructor Summary
XForwardedRequestWrapperFactory()
          Construct.
 
Method Summary
 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
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

HTTP_SERVER_PORT_PARAMETER

protected static final java.lang.String HTTP_SERVER_PORT_PARAMETER
See Also:
Constant Field Values

HTTPS_SERVER_PORT_PARAMETER

protected static final java.lang.String HTTPS_SERVER_PORT_PARAMETER
See Also:
Constant Field Values

INTERNAL_PROXIES_PARAMETER

protected static final java.lang.String INTERNAL_PROXIES_PARAMETER
See Also:
Constant Field Values

PROTOCOL_HEADER_PARAMETER

protected static final java.lang.String PROTOCOL_HEADER_PARAMETER
See Also:
Constant Field Values

PROTOCOL_HEADER_SSL_VALUE_PARAMETER

protected static final java.lang.String PROTOCOL_HEADER_SSL_VALUE_PARAMETER
See Also:
Constant Field Values

PROXIES_HEADER_PARAMETER

protected static final java.lang.String PROXIES_HEADER_PARAMETER
See Also:
Constant Field Values

REMOTE_IP_HEADER_PARAMETER

protected static final java.lang.String REMOTE_IP_HEADER_PARAMETER
See Also:
Constant Field Values

TRUSTED_PROXIES_PARAMETER

protected static final java.lang.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)

Returns:
True, if a wrapper is needed

newRequestWrapper

public javax.servlet.http.HttpServletRequest newRequestWrapper(javax.servlet.http.HttpServletRequest request)
Specified by:
newRequestWrapper in class AbstractRequestWrapperFactory
Parameters:
request -
Returns:
Either the original request or the wrapper

init

public void init(javax.servlet.FilterConfig filterConfig)
Parameters:
filterConfig -


Copyright © 2006-2011 Apache Software Foundation. All Rights Reserved.