1 package org.itracker.web.filters;
2
3 import java.io.IOException;
4 import java.util.HashSet;
5 import java.util.Iterator;
6 import java.util.Locale;
7 import java.util.Map;
8 import java.util.Set;
9 import java.util.StringTokenizer;
10 import java.util.regex.Pattern;
11
12 import javax.servlet.Filter;
13 import javax.servlet.FilterChain;
14 import javax.servlet.FilterConfig;
15 import javax.servlet.ServletException;
16 import javax.servlet.ServletRequest;
17 import javax.servlet.ServletResponse;
18 import javax.servlet.http.HttpServletRequest;
19 import javax.servlet.http.HttpServletResponse;
20 import javax.servlet.http.HttpSession;
21
22 import org.apache.log4j.Logger;
23 import org.apache.struts.Globals;
24 import org.apache.struts.action.ActionForward;
25 import org.apache.struts.action.ActionMessage;
26 import org.apache.struts.action.ActionMessages;
27 import org.itracker.core.resources.ITrackerResources;
28 import org.itracker.model.PermissionType;
29 import org.itracker.model.User;
30 import org.itracker.services.ConfigurationService;
31 import org.itracker.services.ITrackerServices;
32 import org.itracker.services.util.UserUtilities;
33 import org.itracker.web.util.Constants;
34 import org.itracker.web.util.LoginUtilities;
35 import org.itracker.web.util.RequestHelper;
36 import org.itracker.web.util.ServletContextUtils;
37 import org.itracker.web.util.SessionManager;
38
39
40
41
42
43
44
45
46
47
48
49 public class ExecuteAlwaysFilter implements Filter {
50
51
52
53
54 private static final Logger log = Logger
55 .getLogger(ExecuteAlwaysFilter.class);
56 private static final String DEFAULT_LOGIN_FORWARD = "/login.do";
57
58
59
60 private static final String SES_KEY_REDIRECT_ON_SUCCESS = ExecuteAlwaysFilter.class
61 .getName()
62 + "/REDIRECT_ON_SUCCESS";
63
64 private ITrackerServices iTrackerServices;
65
66
67
68 private Set<Pattern> unprotectedPaterns = null;
69
70 private String loginForwardPath;
71
72 public void destroy() {
73 this.unprotectedPaterns = null;
74 }
75
76 public void doFilter(ServletRequest servletRequest,
77 ServletResponse response, FilterChain chain) throws IOException,
78 ServletException {
79 if (null == this.unprotectedPaterns) {
80 RuntimeException re = new IllegalStateException(
81 "Filter has not been initialized yet.");
82 log.error("doFilter: failed, not initialized", re);
83 throw re;
84 }
85
86 if (!(servletRequest instanceof HttpServletRequest)) {
87 RuntimeException re = new IllegalArgumentException(
88 "Usupported servlet-request of type: "
89 + servletRequest.getClass().getName());
90 log.error("doFilter: failed, invalid request type", re);
91 throw re;
92 }
93
94 HttpServletRequest request = (HttpServletRequest) servletRequest;
95
96 String path = request.getRequestURI().substring(
97 request.getContextPath().length());
98 if (log.isDebugEnabled()) {
99 log.debug("doFilter: called with path " + path);
100 }
101
102
103 if (log.isDebugEnabled()) {
104 log
105 .debug("doFilter: setting the common request attributes, (coming from the former header.jsp)");
106 }
107 ConfigurationService configurationService = getITrackerServices()
108 .getConfigurationService();
109
110 boolean protect = isProtected(path, this.unprotectedPaterns);
111
112
113 if (protect && this.loginForwardPath.equals(path)) {
114 protect = false;
115 }
116
117 if (log.isDebugEnabled()) {
118 log.debug("doFilter: protecting '" + path + "': " + protect);
119 }
120
121
122
123 User currUser = LoginUtilities.getCurrentUser(request);
124
125 if (null == currUser && protect) {
126
127 if (LoginUtilities.checkAutoLogin(request, configurationService.getBooleanProperty(
128 "allow_save_login", true))) {
129
130 String login = String.valueOf(request.getAttribute(Constants.AUTH_LOGIN_KEY));
131 currUser = LoginUtilities.setupSession(login, request, (HttpServletResponse)response);
132
133 try {
134 SessionManager.createSession(login);
135 } catch (Exception e) {
136 handleError(e, request, response);
137 }
138
139 }
140 }
141
142 setupCommonReqAttributes(request, configurationService);
143
144 if (null != currUser) {
145 if (log.isDebugEnabled()) {
146 log.debug("doFilter: found user in session");
147 }
148 String currLogin = currUser.getLogin();
149
150 log.info("Login found...: " + currLogin);
151 if (SessionManager.getSessionNeedsReset(currLogin)) {
152
153 HttpSession session = request.getSession();
154 log.info("Resetting the Session stuff...");
155 session.removeAttribute(Constants.USER_KEY);
156 session.removeAttribute(Constants.PERMISSIONS_KEY);
157 currUser = null;
158 String newLogin = SessionManager.checkRenamedLogin(currLogin);
159 if (response instanceof HttpServletResponse) {
160 currUser = LoginUtilities.setupSession((newLogin == null ? currLogin
161 : newLogin), request, (HttpServletResponse)response);
162 }
163 SessionManager.removeRenamedLogin(currLogin);
164 if (currUser == null
165 || currUser.getStatus() != UserUtilities.STATUS_ACTIVE) {
166 ActionMessages errors = new ActionMessages();
167 errors.add(ActionMessages.GLOBAL_MESSAGE,
168 new ActionMessage(
169 "itracker.web.error.login.inactive"));
170 saveErrors(request, errors);
171
172
173 log.info("doFilter: forwarding to login");
174 forwardToLogin(path
175 + (request.getQueryString() != null ? "?"
176 + request.getQueryString() : ""), request,
177 (HttpServletResponse) response);
178 }
179 }
180
181 request.setAttribute("currLogin", currLogin);
182 } else if (!protect) {
183
184
185 request.setAttribute("currLogin", ITrackerResources
186 .getString("itracker.web.header.guest"));
187 } else {
188
189 log.info("doFilter: forwarding to login");
190 forwardToLogin(path
191 + (request.getQueryString() != null ? "?"
192 + request.getQueryString() : ""), request,
193 (HttpServletResponse) response);
194 return;
195 }
196 setupCommonReqAttributesEx(request);
197 try {
198 if (log.isDebugEnabled()) {
199 log.info("doFilter: executing chain..");
200 }
201 chain.doFilter(request, response);
202
203 if (log.isDebugEnabled()) {
204 log.info("doFilter: completed chain execution.");
205 }
206 } catch (RuntimeException e) {
207 log.error(
208 "doFilter: failed to execute chain with runtime exception: "
209 + e.getMessage(), e);
210 handleError(e, request, response);
211
212 } catch (IOException ioe) {
213 log.error("doFilter: failed to execute chain with i/o exception: "
214 + ioe.getMessage(), ioe);
215 handleError(ioe, request, response);
216
217 } catch (ServletException se) {
218 log.error(
219 "doFilter: failed to execute chain with servlet exception: "
220 + se.getMessage(), se);
221 handleError(se, request, response);
222
223 } catch (Error err) {
224 log.fatal("doFilter: caught fatal error executing filter chain",
225 err);
226 throw err;
227 }
228 }
229
230 private final void handleError(Throwable error, ServletRequest request, ServletResponse response) throws ServletException {
231
232 if (null == error) {
233 log.info("handleError: called with null throwable");
234 error = new RuntimeException(error);
235 }
236
237 log.info("handleError: called with " + error.getClass().getSimpleName(), error);
238
239 if (!(response instanceof HttpServletResponse) || !(request instanceof HttpServletRequest)) {
240 log.error("handleError: unknown request/response: " + request + ", " + response, error);
241 throw new ServletException(error.getMessage(), error);
242 }
243 HttpServletRequest httpRequest = (HttpServletRequest) request;
244 HttpServletResponse httpResponse = (HttpServletResponse) response;
245
246 ActionMessages errors = new ActionMessages();
247 errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("itracker.web.error.system.message",
248 new Object[]{error.getLocalizedMessage() == null ? error.getMessage() : error.getLocalizedMessage(),
249 error.getClass().getCanonicalName()}));
250
251 saveErrors((HttpServletRequest)request, errors);
252 try {
253
254 httpResponse.sendRedirect(httpRequest.getContextPath() + "/error.do");
255 } catch (IOException e) {
256 log.fatal("handleError: failed to redirect to error-page");
257 return;
258 }
259 }
260
261
262
263
264
265
266
267
268
269
270
271 protected void saveErrors(HttpServletRequest request, ActionMessages errors) {
272
273
274 if ((errors == null) || errors.isEmpty()) {
275 request.removeAttribute(Globals.ERROR_KEY);
276 request.getSession().removeAttribute(Globals.ERROR_KEY);
277 return;
278 }
279
280 if (log.isInfoEnabled()) {
281 log.info("saveErrors: saved errors: " + errors);
282 }
283
284 request.setAttribute(Globals.ERROR_KEY, errors);
285
286 request.getSession().setAttribute(Globals.ERROR_KEY, errors);
287 }
288
289
290 private static final void setupCommonReqAttributes(
291 HttpServletRequest request,
292 ConfigurationService configurationService) {
293 boolean allowForgotPassword = true;
294 boolean allowSelfRegister = false;
295 boolean allowSaveLogin = true;
296 String alternateLogo = null;
297
298 allowForgotPassword = configurationService.getBooleanProperty(
299 "allow_forgot_password", true);
300 allowSelfRegister = configurationService.getBooleanProperty(
301 "allow_self_register", false);
302 allowSaveLogin = configurationService.getBooleanProperty(
303 "allow_save_login", true);
304 alternateLogo = configurationService
305 .getProperty("alternate_logo", null);
306 Locale locale = LoginUtilities.getCurrentLocale(request);
307
308
309
310
311
312 String baseURL = configurationService.getSystemBaseURL();
313 if (null == baseURL) {
314 baseURL = request.getScheme() + "://" + request.getServerName()
315 + ":" + request.getServerPort() + request.getContextPath();
316 log.warn("setupCommonReqAttributes: not found system_base_url configuration, setting from request: " + baseURL);
317 }
318 request.setAttribute("allowForgotPassword", Boolean
319 .valueOf(allowForgotPassword));
320 request.setAttribute("allowSelfRegister", Boolean
321 .valueOf(allowSelfRegister));
322 request.setAttribute("allowSaveLogin", Boolean.valueOf(allowSaveLogin));
323 request.setAttribute("alternateLogo", alternateLogo);
324 request.setAttribute("baseURL", baseURL);
325
326 request.setAttribute("currLocale", locale);
327
328
329 request.setAttribute("pageTitleKey", "itracker.web.generic.itracker");
330 request.setAttribute("pageTitleArg", "");
331
332
333 request.setAttribute("locales", configurationService.getAvailableLanguages());
334
335
336 request.setAttribute(Constants.LOCALE_KEY, locale);
337
338
339 }
340
341 private static final void setupCommonReqAttributesEx(HttpServletRequest request) {
342 final Map<Integer, Set<PermissionType>> permissions = RequestHelper
343 .getUserPermissions(request.getSession());
344 request.setAttribute("hasPermissionUserAdmin", UserUtilities.hasPermission(permissions,
345 UserUtilities.PERMISSION_USER_ADMIN));
346 request.setAttribute("hasPermissionProductAdmin", UserUtilities.hasPermission(permissions,
347 UserUtilities.PERMISSION_PRODUCT_ADMIN));
348 request.setAttribute("contextPath", request.getContextPath());
349
350 request.setAttribute("currentDate", new java.util.Date());
351 }
352
353
354 private static final boolean isProtected(String path, Set<Pattern> patterns) {
355 if (null == path) {
356 path = "";
357 }
358
359 Iterator<Pattern> matchPattern = patterns.iterator();
360 Pattern pattern;
361
362 while (matchPattern.hasNext()) {
363 pattern = matchPattern.next();
364 if (log.isDebugEnabled()) {
365 log.debug("isProtected: processing path " + path
366 + " for pattern " + pattern.pattern());
367 }
368 if (pattern.matcher(path).matches()) {
369 if (log.isDebugEnabled()) {
370 log.debug("isProtected: matched path: " + path);
371 }
372 return false;
373 }
374 }
375
376 if (log.isDebugEnabled()) {
377 log.debug("isProtected: protecting " + path);
378 }
379 return true;
380 }
381
382
383
384
385
386
387 public void init(FilterConfig filterConfig) throws ServletException {
388 if (null != unprotectedPaterns) {
389 throw new IllegalStateException(
390 "Filter was already initialized before.");
391 }
392 String excludePaths = filterConfig
393 .getInitParameter("AuthExcludedPaths");
394
395 this.loginForwardPath = filterConfig.getInitParameter("LoginForward");
396 if (null == this.loginForwardPath) {
397 this.loginForwardPath = DEFAULT_LOGIN_FORWARD;
398 }
399 this.unprotectedPaterns = new HashSet<Pattern>();
400 if (null != excludePaths) {
401 StringTokenizer tk = new StringTokenizer(excludePaths, ",");
402 while (tk.hasMoreTokens()) {
403 this.unprotectedPaterns.add(Pattern.compile(tk.nextToken().trim()));
404 }
405 }
406 if (log.isInfoEnabled()) {
407 log.info("init: initialized with " + this.loginForwardPath
408 + ", excludes: " + this.unprotectedPaterns);
409 }
410 }
411
412 public ITrackerServices getITrackerServices() {
413 if (null == this.iTrackerServices) {
414
415 this.iTrackerServices = ServletContextUtils.getItrackerServices();
416 }
417 return iTrackerServices;
418 }
419
420
421
422
423
424
425
426
427
428
429 private void forwardToLogin(String path, HttpServletRequest request,
430 HttpServletResponse response) {
431 if (log.isDebugEnabled()) {
432 log.debug("forwardToLogin: called with " + path + " request: "
433 + request + " response: " + response);
434 }
435 String forwardPath = request.getContextPath() + this.loginForwardPath;
436 if (log.isDebugEnabled()) {
437 log
438 .debug("forwardToLogin: (formerly Checklogin tag) procedure... to "
439 + forwardPath);
440 }
441 HttpSession session = request.getSession();
442 try {
443
444 log.info("forwardToLogin: setting redirectURL "
445 + SES_KEY_REDIRECT_ON_SUCCESS + " = " + path);
446 session.setAttribute(SES_KEY_REDIRECT_ON_SUCCESS, path);
447 session.setAttribute("loginForwarded", true);
448 response.sendRedirect(forwardPath);
449 response.flushBuffer();
450
451 } catch (Exception e) {
452 log.error("forwardToLogin: IOException while checking login", e);
453 response.reset();
454 try {
455 session.setAttribute("loginForwarded", Boolean.TRUE);
456 response.sendRedirect(forwardPath);
457 } catch (IOException e1) {
458 log.error("forwardToLogin: failed to redirect to "
459 + forwardPath, e1);
460 }
461 }
462 }
463
464 public static void redirectToOnLoginSuccess(HttpServletRequest request,
465 HttpServletResponse response) throws IOException {
466 String path = (String) request.getSession().getAttribute(
467 SES_KEY_REDIRECT_ON_SUCCESS);
468 if (null == path) {
469 path = "/";
470 }
471 if (log.isDebugEnabled()) {
472 log.debug("redirectToOnLoginSuccess: sending redirect to " + path);
473 }
474 response.sendRedirect(path);
475 }
476
477 public static ActionForward forwardToOnLoginSuccess(
478 HttpServletRequest request, HttpServletResponse response)
479 throws IOException {
480 String path = (String) request.getSession().getAttribute(
481 SES_KEY_REDIRECT_ON_SUCCESS);
482 if (null == path) {
483 path ="/";
484 }
485 if (log.isDebugEnabled()) {
486 log.debug("redirectToOnLoginSuccess: sending redirect to " + path);
487 }
488 return new ActionForward(path, true);
489 }
490 }