1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 package net.sf.deadbolt;
52
53 import java.io.File;
54 import java.io.IOException;
55 import java.util.*;
56
57 import javax.servlet.*;
58 import javax.servlet.http.HttpServletRequest;
59 import javax.servlet.http.HttpServletResponse;
60
61 import net.sf.deadbolt.handlers.DeadboltHandler;
62 import net.sf.deadbolt.model.Room;
63 import net.sf.deadbolt.model.URLMapping;
64 import net.sf.deadbolt.tags.DisplayErrorsTag;
65
66 import org.apache.commons.lang.StringUtils;
67 import org.apache.log4j.Logger;
68 import org.jdom.Document;
69 import org.jdom.Element;
70 import org.jdom.JDOMException;
71 import org.jdom.input.SAXBuilder;
72
73
74 /***
75 * This class is the meat of the Deadbolt framework. This filter is executed on
76 * every request for an application, and it determines the authentication and
77 * authorization setup for the requested resource.
78 *
79 * @author Tim Solley <timsolley@yahoo.com>
80 */
81 public class DeadboltFilter implements Filter {
82
83 private static Logger logger = Logger.getLogger(DeadboltFilter.class.getName());
84
85
86 private static ServletContext context;
87
88
89
90
91
92 private static List urlMappings;
93
94
95
96
97
98 private static Map errorMessages;
99
100
101
102
103 private static Room globalRoom;
104
105 /***
106 * This method will return the <code>Map</code> of error messages, which
107 * are <code>String</code> objects. This is used by the
108 * {@link DeadboltHandler}to put messages in the request for later display
109 * by the {@link DisplayErrorsTag}custom tag on the JSP page.
110 *
111 * @return Returns the errorMessages.
112 */
113 public static Map getErrorMessages() {
114 return errorMessages;
115 }
116
117 /***
118 * This method is the starting point the the Deadbolt enabled application.
119 * It processes the configuration XML file and stores the configuration
120 * information in memory when the application starts up. That information
121 * will be later used by the <code>doFilter</code> method to secure the
122 * requested resource.
123 */
124 public void init(FilterConfig config) throws ServletException {
125 logger.debug("ENTERING: init");
126
127 context = config.getServletContext();
128
129
130
131
132
133
134
135
136
137
138 File configFile = new File(context.getRealPath(config
139 .getInitParameter("config-file")));
140
141
142
143
144
145
146 SAXBuilder builder = new SAXBuilder();
147 builder.setValidation(true);
148 builder.setFeature("http://apache.org/xml/features/validation/schema", true);
149 urlMappings = new ArrayList();
150
151 try {
152 Document document = builder.build(configFile);
153 Element deadboltConfigElement = document.getRootElement();
154
155
156 String globalErrorPage = deadboltConfigElement
157 .getChildText("global-error-page");
158
159
160
161
162
163
164
165
166 List handlerList = deadboltConfigElement.getChildren("handler");
167 Map handlers = new Hashtable();
168 for (Iterator it = handlerList.iterator(); it.hasNext();) {
169 Element handlerElement = (Element) it.next();
170 handlers.put(handlerElement.getChildText("handler-name"),
171 handlerElement.getChildText("handler-class"));
172 }
173
174
175
176
177
178
179 List globalHandlersList = deadboltConfigElement.getChildren("global-handler");
180 if(globalHandlersList.size() != 0) {
181 globalRoom = new Room();
182 TreeMap globalHandlerMap = new TreeMap();
183 Map globalInitParams = new Hashtable();
184 for(Iterator iterator = globalHandlersList.iterator(); iterator.hasNext();) {
185 Element handler = (Element) iterator.next();
186 String handlerClass = (String) handlers.get(handler.getChildText("handler-name"));
187 globalHandlerMap.put(handler.getChildText("execution-order"), handlerClass);
188 logger.debug("Global handler: " + handler.getChildText("execution-order") + " | " +
189 handlerClass);
190
191
192
193
194 List initParamsElements = handler.getChildren("init-param");
195 for (Iterator i = initParamsElements.iterator(); i.hasNext();) {
196 Element initParam = (Element) i.next();
197
198 globalInitParams.put(initParam.getChildText("param-name"),
199 initParam.getChildText("param-value"));
200 logger.debug("Param name: " + initParam.getChildText("param-name"));
201 logger.debug("Param value: " + initParam.getChildText("param-value"));
202 }
203 }
204 globalRoom.setInitParams(globalInitParams);
205 globalRoom.setHandler(globalHandlerMap);
206 }
207
208
209
210
211
212 List roomList = deadboltConfigElement.getChildren("room");
213 for (Iterator it = roomList.iterator(); it.hasNext();) {
214
215 Room room = new Room();
216 Map initParams = new Hashtable();
217 TreeMap handlerMap = new TreeMap();
218 Element roomElement = (Element) it.next();
219
220
221
222
223
224
225
226
227
228
229
230 List handlerListElement = roomElement.getChildren("handler");
231 for (Iterator iter = handlerListElement.iterator(); iter
232 .hasNext();) {
233 Element handler = (Element) iter.next();
234 String handlerClass = (String) handlers.get(handler
235 .getChildText("handler-name"));
236
237
238 handlerMap.put(handler.getChildText("execution-order"),
239 handlerClass);
240 logger.debug("Handler: "
241 + handler.getChildText("execution-order") + " | "
242 + handlerClass);
243 }
244
245 room.setHandler(handlerMap);
246
247
248
249
250
251
252
253 List initParamsElements = roomElement.getChildren("init-param");
254 for (Iterator i = initParamsElements.iterator(); i.hasNext();) {
255 Element initParam = (Element) i.next();
256
257 initParams.put(initParam.getChildText("param-name"),
258 initParam.getChildText("param-value"));
259 logger.debug("Param name: " + initParam.getChildText("param-name"));
260 logger.debug("Param value: " + initParam.getChildText("param-value"));
261 }
262
263 room.setInitParams(initParams);
264
265
266
267
268
269 String errorPage = roomElement.getChildText("error-page");
270 if (errorPage == null) {
271 room.setErrorPage(globalErrorPage);
272 } else {
273 room.setErrorPage(errorPage);
274 }
275
276
277
278
279
280 List urls = roomElement.getChildren("url-pattern");
281 for (Iterator i = urls.iterator(); i.hasNext();) {
282 URLMapping mapping = new URLMapping();
283 mapping.setRoom(room);
284
285 String pattern = ((Element) i.next()).getText();
286
287
288
289
290
291
292
293
294 pattern = StringUtils.replace(pattern, "*", ".++");
295 mapping.setUrlPattern(pattern);
296
297 urlMappings.add(mapping);
298 }
299 }
300
301
302
303
304
305
306
307
308 errorMessages = new Hashtable();
309 Element errorMessagesElement = deadboltConfigElement
310 .getChild("error-messages");
311 List errorMessageList = errorMessagesElement
312 .getChildren("error-message");
313 for (Iterator it = errorMessageList.iterator(); it.hasNext();) {
314 Element errorMessage = (Element) it.next();
315 errorMessages.put(errorMessage.getChildText("message-key"),
316 errorMessage.getChildText("message-content"));
317 }
318 } catch (IOException ioe) {
319 logger.warn("An IOException occurred during init: "
320 + ioe.getMessage());
321 } catch (JDOMException jde) {
322 logger.warn("A JDOM Exception occurred during init: " + jde.getMessage());
323 }
324 logger.debug("EXITING: init");
325 }
326
327 /***
328 * This method will be called on each request to the application, provided
329 * the user used <code>/*</code> as the url-pattern element in the web.xml
330 * file. This method will examine the request, compare it's URL to a list of
331 * URL patterns defined in the config file, and execute handlers based on
332 * any room found that matches the URL pattern. It will then let the user
333 * pass to the requested resource, or send the user to the specified error
334 * page if not allowed. If any handler sends back a false, the user will not
335 * be permitted to enter.
336 *
337 * It should be noted that if a resource exists, and it's URL pattern is not
338 * specified in the config file, and a blanket <code>/*</code> is not
339 * used, a client will be allowed to access the resource and will not be
340 * protected by Deadbolt.
341 */
342 public void doFilter(ServletRequest request, ServletResponse response,
343 FilterChain chain) throws IOException, ServletException {
344 logger.debug("ENTERING: doFilter");
345
346 HttpServletRequest httpRequest = (HttpServletRequest) request;
347 HttpServletResponse httpResponse = (HttpServletResponse) response;
348 Room room = null;
349
350
351 boolean forwardRequest = false;
352
353
354
355
356
357 if(globalRoom != null) {
358 try {
359 DeadboltHandler handler = null;
360 Collection handlers = globalRoom.getHandlers().values();
361 for(Iterator handlerIterator = handlers.iterator();
362 handlerIterator.hasNext();) {
363 String handlerClass = (String) handlerIterator.next();
364 logger.debug("Executing global handler: " + handlerClass);
365
366
367
368
369
370
371 handler = (DeadboltHandler) Class.forName(handlerClass)
372 .newInstance();
373
374
375 forwardRequest = handler.authenticate(httpRequest,
376 httpResponse, globalRoom);
377 logger.debug("Global handler returned: " + forwardRequest);
378 if (!forwardRequest)
379 break;
380 }
381 } catch (InstantiationException ie) {
382 logger.warn(ie);
383 throw new ServletException(ie);
384 } catch (IllegalAccessException iae) {
385 logger.warn(iae);
386 throw new ServletException(iae);
387 } catch (ClassNotFoundException cnfe) {
388 logger.warn(cnfe);
389 throw new ServletException(cnfe);
390 }
391 }
392
393
394 String currentPattern = httpRequest.getServletPath();
395
396 boolean matchFound = false;
397
398
399
400
401
402
403
404 for (Iterator it = urlMappings.iterator(); it.hasNext();) {
405 URLMapping mapping = (URLMapping) it.next();
406
407
408 if (currentPattern.matches(mapping.getUrlPattern())) {
409 matchFound = true;
410
411 room = mapping.getRoom();
412 break;
413 }
414 }
415
416
417 if(!matchFound) {
418 forwardRequest = true;
419 } else if(forwardRequest & room != null) {
420 try {
421 DeadboltHandler handler = null;
422
423 Collection handlers = room.getHandlers().values();
424
425
426
427
428
429 for (Iterator i = handlers.iterator(); i.hasNext();) {
430 String handlerClass = (String) i.next();
431 logger.debug("Executing handler: " + handlerClass);
432
433
434
435
436
437
438 handler = (DeadboltHandler) Class.forName(handlerClass)
439 .newInstance();
440
441
442 forwardRequest = handler.authenticate(httpRequest,
443 httpResponse, room);
444 logger.debug("Handler returned: " + forwardRequest);
445 if (!forwardRequest)
446 break;
447 }
448 } catch (InstantiationException ie) {
449 logger.warn(ie);
450 throw new ServletException(ie);
451 } catch (IllegalAccessException iae) {
452 logger.warn(iae);
453 throw new ServletException(iae);
454 } catch (ClassNotFoundException cnfe) {
455 logger.warn(cnfe);
456 throw new ServletException(cnfe);
457 }
458 }
459
460
461
462
463
464
465 if (forwardRequest) {
466 logger.debug("The request was approved. Continuing to resource.");
467 chain.doFilter(request, response);
468 } else {
469 logger.debug("The request was denied. Forwarding to error page.");
470 if (room.getErrorPage() != null) {
471 RequestDispatcher dispatcher = httpRequest
472 .getRequestDispatcher(room.getErrorPage());
473 dispatcher.forward(request, response);
474 }
475 }
476 logger.debug("EXITING: doFilter");
477 }
478
479 /***
480 * This is here for compliance with the <code>Filter</code> interface.
481 * Nothing is done in this method.
482 */
483 public void destroy() {
484 }
485 }