]> WPIA git - gigi.git/blob - lib/jetty/org/eclipse/jetty/server/ForwardedRequestCustomizer.java
Update notes about password security
[gigi.git] / lib / jetty / org / eclipse / jetty / server / ForwardedRequestCustomizer.java
1 //
2 //  ========================================================================
3 //  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4 //  ------------------------------------------------------------------------
5 //  All rights reserved. This program and the accompanying materials
6 //  are made available under the terms of the Eclipse Public License v1.0
7 //  and Apache License v2.0 which accompanies this distribution.
8 //
9 //      The Eclipse Public License is available at
10 //      http://www.eclipse.org/legal/epl-v10.html
11 //
12 //      The Apache License v2.0 is available at
13 //      http://www.opensource.org/licenses/apache2.0.php
14 //
15 //  You may elect to redistribute this code under either of these licenses.
16 //  ========================================================================
17 //
18
19 package org.eclipse.jetty.server;
20
21 import java.net.InetSocketAddress;
22
23 import javax.servlet.ServletRequest;
24
25 import org.eclipse.jetty.http.HttpFields;
26 import org.eclipse.jetty.http.HttpHeader;
27 import org.eclipse.jetty.http.HttpScheme;
28 import org.eclipse.jetty.server.HttpConfiguration.Customizer;
29
30
31 /* ------------------------------------------------------------ */
32 /** Customize Requests for Proxy Forwarding.
33  * <p>
34  * This customizer looks at at HTTP request for headers that indicate
35  * it has been forwarded by one or more proxies.  Specifically handled are:
36  * <ul>
37  * <li>X-Forwarded-Host</li>
38  * <li>X-Forwarded-Server</li>
39  * <li>X-Forwarded-For</li>
40  * <li>X-Forwarded-Proto</li>
41  * </ul>
42  * <p>If these headers are present, then the {@link Request} object is updated
43  * so that the proxy is not seen as the other end point of the connection on which
44  * the request came</p>
45  * <p>Headers can also be defined so that forwarded SSL Session IDs and Cipher
46  * suites may be customised</p> 
47  * @see <a href="http://en.wikipedia.org/wiki/X-Forwarded-For">Wikipedia: X-Forwarded-For</a>
48  */
49 public class ForwardedRequestCustomizer implements Customizer
50 {
51     private String _hostHeader;
52     private String _forwardedHostHeader = HttpHeader.X_FORWARDED_HOST.toString();
53     private String _forwardedServerHeader = HttpHeader.X_FORWARDED_SERVER.toString();
54     private String _forwardedForHeader = HttpHeader.X_FORWARDED_FOR.toString();
55     private String _forwardedProtoHeader = HttpHeader.X_FORWARDED_PROTO.toString();
56     private String _forwardedCipherSuiteHeader;
57     private String _forwardedSslSessionIdHeader;
58     
59
60     /* ------------------------------------------------------------ */
61     public String getHostHeader()
62     {
63         return _hostHeader;
64     }
65
66     /* ------------------------------------------------------------ */
67     /**
68      * Set a forced valued for the host header to control what is returned by {@link ServletRequest#getServerName()} and {@link ServletRequest#getServerPort()}.
69      *
70      * @param hostHeader
71      *            The value of the host header to force.
72      */
73     public void setHostHeader(String hostHeader)
74     {
75         _hostHeader = hostHeader;
76     }
77
78     /* ------------------------------------------------------------ */
79     /*
80      *
81      * @see #setForwarded(boolean)
82      */
83     public String getForwardedHostHeader()
84     {
85         return _forwardedHostHeader;
86     }
87
88     /* ------------------------------------------------------------ */
89     /**
90      * @param forwardedHostHeader
91      *            The header name for forwarded hosts (default x-forwarded-host)
92      */
93     public void setForwardedHostHeader(String forwardedHostHeader)
94     {
95         _forwardedHostHeader = forwardedHostHeader;
96     }
97
98     /* ------------------------------------------------------------ */
99     /**
100      * @return the header name for forwarded server.
101      */
102     public String getForwardedServerHeader()
103     {
104         return _forwardedServerHeader;
105     }
106
107     /* ------------------------------------------------------------ */
108     /**
109      * @param forwardedServerHeader
110      *            The header name for forwarded server (default x-forwarded-server)
111      */
112     public void setForwardedServerHeader(String forwardedServerHeader)
113     {
114         _forwardedServerHeader = forwardedServerHeader;
115     }
116
117     /* ------------------------------------------------------------ */
118     /**
119      * @return the forwarded for header
120      */
121     public String getForwardedForHeader()
122     {
123         return _forwardedForHeader;
124     }
125
126     /* ------------------------------------------------------------ */
127     /**
128      * @param forwardedRemoteAddressHeader
129      *            The header name for forwarded for (default x-forwarded-for)
130      */
131     public void setForwardedForHeader(String forwardedRemoteAddressHeader)
132     {
133         _forwardedForHeader = forwardedRemoteAddressHeader;
134     }
135
136     /* ------------------------------------------------------------ */
137     /**
138      * Get the forwardedProtoHeader.
139      *
140      * @return the forwardedProtoHeader (default X-Forwarded-For)
141      */
142     public String getForwardedProtoHeader()
143     {
144         return _forwardedProtoHeader;
145     }
146
147     /* ------------------------------------------------------------ */
148     /**
149      * Set the forwardedProtoHeader.
150      *
151      * @param forwardedProtoHeader
152      *            the forwardedProtoHeader to set (default X-Forwarded-For)
153      */
154     public void setForwardedProtoHeader(String forwardedProtoHeader)
155     {
156         _forwardedProtoHeader = forwardedProtoHeader;
157     }
158
159     /* ------------------------------------------------------------ */
160     /**
161      * @return The header name holding a forwarded cipher suite (default null)
162      */
163     public String getForwardedCipherSuiteHeader()
164     {
165         return _forwardedCipherSuiteHeader;
166     }
167
168     /* ------------------------------------------------------------ */
169     /**
170      * @param forwardedCipherSuite
171      *            The header name holding a forwarded cipher suite (default null)
172      */
173     public void setForwardedCipherSuiteHeader(String forwardedCipherSuite)
174     {
175         _forwardedCipherSuiteHeader = forwardedCipherSuite;
176     }
177
178     /* ------------------------------------------------------------ */
179     /**
180      * @return The header name holding a forwarded SSL Session ID (default null)
181      */
182     public String getForwardedSslSessionIdHeader()
183     {
184         return _forwardedSslSessionIdHeader;
185     }
186
187     /* ------------------------------------------------------------ */
188     /**
189      * @param forwardedSslSessionId
190      *            The header name holding a forwarded SSL Session ID (default null)
191      */
192     public void setForwardedSslSessionIdHeader(String forwardedSslSessionId)
193     {
194         _forwardedSslSessionIdHeader = forwardedSslSessionId;
195     }
196
197     /* ------------------------------------------------------------ */
198     @Override
199     public void customize(Connector connector, HttpConfiguration config, Request request)
200     {
201         HttpFields httpFields = request.getHttpFields();
202
203         // Do SSL first
204         if (getForwardedCipherSuiteHeader()!=null)
205         {
206             String cipher_suite=httpFields.getStringField(getForwardedCipherSuiteHeader());
207             if (cipher_suite!=null)
208                 request.setAttribute("javax.servlet.request.cipher_suite",cipher_suite);
209         }
210         if (getForwardedSslSessionIdHeader()!=null)
211         {
212             String ssl_session_id=httpFields.getStringField(getForwardedSslSessionIdHeader());
213             if(ssl_session_id!=null)
214             {
215                 request.setAttribute("javax.servlet.request.ssl_session_id", ssl_session_id);
216                 request.setScheme(HttpScheme.HTTPS.asString());
217             }
218         }
219
220         // Retrieving headers from the request
221         String forwardedHost = getLeftMostFieldValue(httpFields,getForwardedHostHeader());
222         String forwardedServer = getLeftMostFieldValue(httpFields,getForwardedServerHeader());
223         String forwardedFor = getLeftMostFieldValue(httpFields,getForwardedForHeader());
224         String forwardedProto = getLeftMostFieldValue(httpFields,getForwardedProtoHeader());
225
226         if (_hostHeader != null)
227         {
228             // Update host header
229             httpFields.put(HttpHeader.HOST.toString(),_hostHeader);
230             request.setServerName(null);
231             request.setServerPort(-1);
232             request.getServerName();
233         }
234         else if (forwardedHost != null)
235         {
236             // Update host header
237             httpFields.put(HttpHeader.HOST.toString(),forwardedHost);
238             request.setServerName(null);
239             request.setServerPort(-1);
240             request.getServerName();
241         }
242         else if (forwardedServer != null)
243         {
244             // Use provided server name
245             request.setServerName(forwardedServer);
246         }
247
248         if (forwardedFor != null)
249         {
250             request.setRemoteAddr(InetSocketAddress.createUnresolved(forwardedFor,request.getRemotePort()));
251         }
252
253         if (forwardedProto != null)
254         {
255             request.setScheme(forwardedProto);
256             if (forwardedProto.equals(config.getSecureScheme()))
257                 request.setSecure(true);
258         }
259     }
260
261     /* ------------------------------------------------------------ */
262     protected String getLeftMostFieldValue(HttpFields fields, String header)
263     {
264         if (header == null)
265             return null;
266
267         String headerValue = fields.getStringField(header);
268
269         if (headerValue == null)
270             return null;
271
272         int commaIndex = headerValue.indexOf(',');
273
274         if (commaIndex == -1)
275         {
276             // Single value
277             return headerValue;
278         }
279
280         // The left-most value is the farthest downstream client
281         return headerValue.substring(0,commaIndex);
282     }
283
284
285     /* ------------------------------------------------------------ */
286     @Override
287     public String toString()
288     {
289         return String.format("%s@%x",this.getClass().getSimpleName(),hashCode());
290     }
291 }