comparison src/org/eclipse/jetty/server/handler/IPAccessHandler.java @ 802:3428c60d7cfc

replace jetty jars with source
author Franklin Schmidt <fschmidt@gmail.com>
date Wed, 07 Sep 2016 21:15:48 -0600
parents
children 8e9db0bbf4f9
comparison
equal deleted inserted replaced
801:6a21393191c1 802:3428c60d7cfc
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.handler;
20
21 import java.io.IOException;
22 import java.util.Collections;
23 import java.util.List;
24 import java.util.Map;
25
26 import javax.servlet.ServletException;
27 import javax.servlet.http.HttpServletRequest;
28 import javax.servlet.http.HttpServletResponse;
29
30 import org.eclipse.jetty.http.HttpStatus;
31 import org.eclipse.jetty.http.PathMap;
32 import org.eclipse.jetty.io.EndPoint;
33 import org.eclipse.jetty.server.AbstractHttpConnection;
34 import org.eclipse.jetty.server.Request;
35 import org.eclipse.jetty.util.IPAddressMap;
36 import org.eclipse.jetty.util.log.Log;
37 import org.eclipse.jetty.util.log.Logger;
38
39
40 /**
41 * IP Access Handler
42 * <p>
43 * Controls access to the wrapped handler by the real remote IP. Control is provided
44 * by white/black lists that include both internet addresses and URIs. This handler
45 * uses the real internet address of the connection, not one reported in the forwarded
46 * for headers, as this cannot be as easily forged.
47 * <p>
48 * Typically, the black/white lists will be used in one of three modes:
49 * <ul>
50 * <li>Blocking a few specific IPs/URLs by specifying several black list entries.
51 * <li>Allowing only some specific IPs/URLs by specifying several white lists entries.
52 * <li>Allowing a general range of IPs/URLs by specifying several general white list
53 * entries, that are then further refined by several specific black list exceptions
54 * </ul>
55 * <p>
56 * An empty white list is treated as match all. If there is at least one entry in
57 * the white list, then a request must match a white list entry. Black list entries
58 * are always applied, so that even if an entry matches the white list, a black list
59 * entry will override it.
60 * <p>
61 * Internet addresses may be specified as absolute address or as a combination of
62 * four octet wildcard specifications (a.b.c.d) that are defined as follows.
63 * </p>
64 * <pre>
65 * nnn - an absolute value (0-255)
66 * mmm-nnn - an inclusive range of absolute values,
67 * with following shorthand notations:
68 * nnn- => nnn-255
69 * -nnn => 0-nnn
70 * - => 0-255
71 * a,b,... - a list of wildcard specifications
72 * </pre>
73 * <p>
74 * Internet address specification is separated from the URI pattern using the "|" (pipe)
75 * character. URI patterns follow the servlet specification for simple * prefix and
76 * suffix wild cards (e.g. /, /foo, /foo/bar, /foo/bar/*, *.baz).
77 * <p>
78 * Earlier versions of the handler used internet address prefix wildcard specification
79 * to define a range of the internet addresses (e.g. 127., 10.10., 172.16.1.).
80 * They also used the first "/" character of the URI pattern to separate it from the
81 * internet address. Both of these features have been deprecated in the current version.
82 * <p>
83 * Examples of the entry specifications are:
84 * <ul>
85 * <li>10.10.1.2 - all requests from IP 10.10.1.2
86 * <li>10.10.1.2|/foo/bar - all requests from IP 10.10.1.2 to URI /foo/bar
87 * <li>10.10.1.2|/foo/* - all requests from IP 10.10.1.2 to URIs starting with /foo/
88 * <li>10.10.1.2|*.html - all requests from IP 10.10.1.2 to URIs ending with .html
89 * <li>10.10.0-255.0-255 - all requests from IPs within 10.10.0.0/16 subnet
90 * <li>10.10.0-.-255|/foo/bar - all requests from IPs within 10.10.0.0/16 subnet to URI /foo/bar
91 * <li>10.10.0-3,1,3,7,15|/foo/* - all requests from IPs addresses with last octet equal
92 * to 1,3,7,15 in subnet 10.10.0.0/22 to URIs starting with /foo/
93 * </ul>
94 * <p>
95 * Earlier versions of the handler used internet address prefix wildcard specification
96 * to define a range of the internet addresses (e.g. 127., 10.10., 172.16.1.).
97 * They also used the first "/" character of the URI pattern to separate it from the
98 * internet address. Both of these features have been deprecated in the current version.
99 */
100 public class IPAccessHandler extends HandlerWrapper
101 {
102 private static final Logger LOG = Log.getLogger(IPAccessHandler.class);
103
104 IPAddressMap<PathMap> _white = new IPAddressMap<PathMap>();
105 IPAddressMap<PathMap> _black = new IPAddressMap<PathMap>();
106
107 /* ------------------------------------------------------------ */
108 /**
109 * Creates new handler object
110 */
111 public IPAccessHandler()
112 {
113 super();
114 }
115
116 /* ------------------------------------------------------------ */
117 /**
118 * Creates new handler object and initializes white- and black-list
119 *
120 * @param white array of whitelist entries
121 * @param black array of blacklist entries
122 */
123 public IPAccessHandler(String[] white, String []black)
124 {
125 super();
126
127 if (white != null && white.length > 0)
128 setWhite(white);
129 if (black != null && black.length > 0)
130 setBlack(black);
131 }
132
133 /* ------------------------------------------------------------ */
134 /**
135 * Add a whitelist entry to an existing handler configuration
136 *
137 * @param entry new whitelist entry
138 */
139 public void addWhite(String entry)
140 {
141 add(entry, _white);
142 }
143
144 /* ------------------------------------------------------------ */
145 /**
146 * Add a blacklist entry to an existing handler configuration
147 *
148 * @param entry new blacklist entry
149 */
150 public void addBlack(String entry)
151 {
152 add(entry, _black);
153 }
154
155 /* ------------------------------------------------------------ */
156 /**
157 * Re-initialize the whitelist of existing handler object
158 *
159 * @param entries array of whitelist entries
160 */
161 public void setWhite(String[] entries)
162 {
163 set(entries, _white);
164 }
165
166 /* ------------------------------------------------------------ */
167 /**
168 * Re-initialize the blacklist of existing handler object
169 *
170 * @param entries array of blacklist entries
171 */
172 public void setBlack(String[] entries)
173 {
174 set(entries, _black);
175 }
176
177 /* ------------------------------------------------------------ */
178 /**
179 * Checks the incoming request against the whitelist and blacklist
180 *
181 * @see org.eclipse.jetty.server.handler.HandlerWrapper#handle(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
182 */
183 @Override
184 public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
185 {
186 // Get the real remote IP (not the one set by the forwarded headers (which may be forged))
187 AbstractHttpConnection connection = baseRequest.getConnection();
188 if (connection!=null)
189 {
190 EndPoint endp=connection.getEndPoint();
191 if (endp!=null)
192 {
193 String addr = endp.getRemoteAddr();
194 if (addr!=null && !isAddrUriAllowed(addr,baseRequest.getPathInfo()))
195 {
196 response.sendError(HttpStatus.FORBIDDEN_403);
197 baseRequest.setHandled(true);
198 return;
199 }
200 }
201 }
202
203 getHandler().handle(target,baseRequest, request, response);
204 }
205
206
207 /* ------------------------------------------------------------ */
208 /**
209 * Helper method to parse the new entry and add it to
210 * the specified address pattern map.
211 *
212 * @param entry new entry
213 * @param patternMap target address pattern map
214 */
215 protected void add(String entry, IPAddressMap<PathMap> patternMap)
216 {
217 if (entry != null && entry.length() > 0)
218 {
219 boolean deprecated = false;
220 int idx;
221 if (entry.indexOf('|') > 0 )
222 {
223 idx = entry.indexOf('|');
224 }
225 else
226 {
227 idx = entry.indexOf('/');
228 deprecated = (idx >= 0);
229 }
230
231 String addr = idx > 0 ? entry.substring(0,idx) : entry;
232 String path = idx > 0 ? entry.substring(idx) : "/*";
233
234 if (addr.endsWith("."))
235 deprecated = true;
236 if (path!=null && (path.startsWith("|") || path.startsWith("/*.")))
237 path=path.substring(1);
238
239 PathMap pathMap = patternMap.get(addr);
240 if (pathMap == null)
241 {
242 pathMap = new PathMap(true);
243 patternMap.put(addr,pathMap);
244 }
245 if (path != null && !"".equals(path))
246 pathMap.put(path,path);
247
248 if (deprecated)
249 LOG.debug(toString() +" - deprecated specification syntax: "+entry);
250 }
251 }
252
253 /* ------------------------------------------------------------ */
254 /**
255 * Helper method to process a list of new entries and replace
256 * the content of the specified address pattern map
257 *
258 * @param entries new entries
259 * @param patternMap target address pattern map
260 */
261 protected void set(String[] entries, IPAddressMap<PathMap> patternMap)
262 {
263 patternMap.clear();
264
265 if (entries != null && entries.length > 0)
266 {
267 for (String addrPath:entries)
268 {
269 add(addrPath, patternMap);
270 }
271 }
272 }
273
274 /* ------------------------------------------------------------ */
275 /**
276 * Check if specified request is allowed by current IPAccess rules.
277 *
278 * @param addr internet address
279 * @param path context path
280 * @return true if request is allowed
281 *
282 */
283 protected boolean isAddrUriAllowed(String addr, String path)
284 {
285 if (_white.size()>0)
286 {
287 boolean match = false;
288
289 Object whiteObj = _white.getLazyMatches(addr);
290 if (whiteObj != null)
291 {
292 List whiteList = (whiteObj instanceof List) ? (List)whiteObj : Collections.singletonList(whiteObj);
293
294 for (Object entry: whiteList)
295 {
296 PathMap pathMap = ((Map.Entry<String,PathMap>)entry).getValue();
297 if (match = (pathMap!=null && (pathMap.size()==0 || pathMap.match(path)!=null)))
298 break;
299 }
300 }
301
302 if (!match)
303 return false;
304 }
305
306 if (_black.size() > 0)
307 {
308 Object blackObj = _black.getLazyMatches(addr);
309 if (blackObj != null)
310 {
311 List blackList = (blackObj instanceof List) ? (List)blackObj : Collections.singletonList(blackObj);
312
313 for (Object entry: blackList)
314 {
315 PathMap pathMap = ((Map.Entry<String,PathMap>)entry).getValue();
316 if (pathMap!=null && (pathMap.size()==0 || pathMap.match(path)!=null))
317 return false;
318 }
319 }
320 }
321
322 return true;
323 }
324
325 /* ------------------------------------------------------------ */
326 /**
327 * Dump the white- and black-list configurations when started
328 *
329 * @see org.eclipse.jetty.server.handler.HandlerWrapper#doStart()
330 */
331 @Override
332 protected void doStart()
333 throws Exception
334 {
335 super.doStart();
336
337 if (LOG.isDebugEnabled())
338 {
339 System.err.println(dump());
340 }
341 }
342
343 /* ------------------------------------------------------------ */
344 /**
345 * Dump the handler configuration
346 */
347 public String dump()
348 {
349 StringBuilder buf = new StringBuilder();
350
351 buf.append(toString());
352 buf.append(" WHITELIST:\n");
353 dump(buf, _white);
354 buf.append(toString());
355 buf.append(" BLACKLIST:\n");
356 dump(buf, _black);
357
358 return buf.toString();
359 }
360
361 /* ------------------------------------------------------------ */
362 /**
363 * Dump a pattern map into a StringBuilder buffer
364 *
365 * @param buf buffer
366 * @param patternMap pattern map to dump
367 */
368 protected void dump(StringBuilder buf, IPAddressMap<PathMap> patternMap)
369 {
370 for (String addr: patternMap.keySet())
371 {
372 for (Object path: ((PathMap)patternMap.get(addr)).values())
373 {
374 buf.append("# ");
375 buf.append(addr);
376 buf.append("|");
377 buf.append(path);
378 buf.append("\n");
379 }
380 }
381 }
382 }