From a3eade38cbfa146093a6bf4fed4fbe240e74bf38 Mon Sep 17 00:00:00 2001 From: Matti Tahvonen Date: Tue, 3 Feb 2009 13:31:31 +0000 Subject: [PATCH] improvements to "last-desperate-onunload-request" and security key handling. fixes #2513 svn changeset:6711/svn branch:trunk --- .../gwt/client/ApplicationConnection.java | 19 +++-- .../gwt/server/ApplicationServlet.java | 80 ++++++++++--------- .../gwt/server/CommunicationManager.java | 57 ++++++------- 3 files changed, 86 insertions(+), 70 deletions(-) diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ApplicationConnection.java b/src/com/itmill/toolkit/terminal/gwt/client/ApplicationConnection.java index 2959aa74cd..04a2aa5237 100755 --- a/src/com/itmill/toolkit/terminal/gwt/client/ApplicationConnection.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/ApplicationConnection.java @@ -62,6 +62,8 @@ public class ApplicationConnection { public static final String UIDL_SECURITY_HEADER = "com.itmill.seckey"; + public static final String PARAM_UNLOADBURST = "onunloadburst"; + private static String uidl_security_key = "init"; private final HashMap resourcesMap = new HashMap(); @@ -402,7 +404,8 @@ public class ApplicationConnection { // Synchronized call, discarded response syncSendForce(((HTTPRequestImpl) GWT.create(HTTPRequestImpl.class)) - .createXmlHTTPRequest(), uri, requestData); + .createXmlHTTPRequest(), uri + "&" + PARAM_UNLOADBURST + + "=1", requestData); } } @@ -474,7 +477,9 @@ public class ApplicationConnection { } private void endRequest() { - checkForPendingVariableBursts(); + if (applicationRunning) { + checkForPendingVariableBursts(); + } activeRequests--; // deferring to avoid flickering DeferredCommand.addCommand(new Command() { @@ -767,10 +772,12 @@ public class ApplicationConnection { * windows - normally sendPendingVariableChanges() should be used. */ public void sendPendingVariableChangesSync() { - pendingVariableBursts.add(pendingVariables); - Vector nextBurst = pendingVariableBursts.firstElement(); - pendingVariableBursts.remove(0); - buildAndSendVariableBurst(nextBurst, true); + if (applicationRunning) { + pendingVariableBursts.add(pendingVariables); + Vector nextBurst = pendingVariableBursts.firstElement(); + pendingVariableBursts.remove(0); + buildAndSendVariableBurst(nextBurst, true); + } } // Redirect browser, null reloads current page diff --git a/src/com/itmill/toolkit/terminal/gwt/server/ApplicationServlet.java b/src/com/itmill/toolkit/terminal/gwt/server/ApplicationServlet.java index 5532fae62a..2321e50051 100644 --- a/src/com/itmill/toolkit/terminal/gwt/server/ApplicationServlet.java +++ b/src/com/itmill/toolkit/terminal/gwt/server/ApplicationServlet.java @@ -44,6 +44,7 @@ import com.itmill.toolkit.terminal.ParameterHandler; import com.itmill.toolkit.terminal.Terminal; import com.itmill.toolkit.terminal.ThemeResource; import com.itmill.toolkit.terminal.URIHandler; +import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection; import com.itmill.toolkit.ui.Window; /** @@ -129,7 +130,7 @@ public class ApplicationServlet extends HttpServlet { // TODO This is session specific not servlet wide data. No need to store // this here, move it to Session from where it can be queried when required - protected static HashMap applicationToAjaxAppMgrMap = new HashMap(); + protected static HashMap applicationToAjaxAppMgrMap = new HashMap(); private static final String RESOURCE_URI = "/RES/"; @@ -523,47 +524,51 @@ public class ApplicationServlet extends HttpServlet { } catch (final SessionExpired e) { // Session has expired, notify user try { - Application.SystemMessages ci = getSystemMessages(); - if (!UIDLrequest) { - // 'plain' http req - e.g. browser reload; - // just go ahead redirect the browser - response.sendRedirect(ci.getSessionExpiredURL()); - } else { - // send uidl redirect - criticalNotification(request, response, ci - .getSessionExpiredCaption(), ci - .getSessionExpiredMessage(), ci - .getSessionExpiredURL()); - // Invalidate session (weird to have session if we're saying - // that it's expired, and worse: portal integration will - // fail since the session is not created by the portal. - request.getSession().invalidate(); + if (!isOnUnloadRequest(request)) { + Application.SystemMessages ci = getSystemMessages(); + if (!UIDLrequest) { + // 'plain' http req - e.g. browser reload; + // just go ahead redirect the browser + response.sendRedirect(ci.getSessionExpiredURL()); + } else { + // send uidl redirect + criticalNotification(request, response, ci + .getSessionExpiredCaption(), ci + .getSessionExpiredMessage(), ci + .getSessionExpiredURL()); + // Invalidate session (weird to have session if we're + // saying + // that it's expired, and worse: portal integration will + // fail since the session is not created by the portal. + request.getSession().invalidate(); + } } } catch (SystemMessageException ee) { throw new ServletException(ee); } } catch (final GeneralSecurityException e) { - // TODO handle differently? - // Invalid security key, show session expired message for now. - try { - Application.SystemMessages ci = getSystemMessages(); - if (!UIDLrequest) { - // 'plain' http req - e.g. browser reload; - // just go ahead redirect the browser - response.sendRedirect(ci.getSessionExpiredURL()); - } else { - // send uidl redirect - criticalNotification(request, response, ci - .getSessionExpiredCaption(), ci - .getSessionExpiredMessage(), ci - .getSessionExpiredURL()); + if (!isOnUnloadRequest(request)) { + // TODO handle differently? + // Invalid security key, show session expired message for now. + try { + Application.SystemMessages ci = getSystemMessages(); + if (!UIDLrequest) { + // 'plain' http req - e.g. browser reload; + // just go ahead redirect the browser + response.sendRedirect(ci.getSessionExpiredURL()); + } else { + // send uidl redirect + criticalNotification(request, response, ci + .getSessionExpiredCaption(), ci + .getSessionExpiredMessage(), ci + .getSessionExpiredURL()); + } + request.getSession().invalidate(); + } catch (SystemMessageException ee) { + throw new ServletException(ee); } - request.getSession().invalidate(); - } catch (SystemMessageException ee) { - throw new ServletException(ee); } - } catch (final Throwable e) { // if this was an UIDL request, response UIDL back to client if (UIDLrequest) { @@ -589,6 +594,10 @@ public class ApplicationServlet extends HttpServlet { } } + private boolean isOnUnloadRequest(HttpServletRequest request) { + return request.getParameter(ApplicationConnection.PARAM_UNLOADBURST) != null; + } + /** Get system messages from the current application class */ private SystemMessages getSystemMessages() { try { @@ -1690,8 +1699,7 @@ public class ApplicationServlet extends HttpServlet { * @return CommunicationManager */ private CommunicationManager getApplicationManager(Application application) { - CommunicationManager mgr = (CommunicationManager) applicationToAjaxAppMgrMap - .get(application); + CommunicationManager mgr = applicationToAjaxAppMgrMap.get(application); if (mgr == null) { // Creates new manager diff --git a/src/com/itmill/toolkit/terminal/gwt/server/CommunicationManager.java b/src/com/itmill/toolkit/terminal/gwt/server/CommunicationManager.java index 448b2dcd62..ba09313413 100644 --- a/src/com/itmill/toolkit/terminal/gwt/server/CommunicationManager.java +++ b/src/com/itmill/toolkit/terminal/gwt/server/CommunicationManager.java @@ -621,35 +621,36 @@ public class CommunicationManager implements Paintable.RepaintRequestListener { // Manage bursts one by one final String[] bursts = changes.split(VAR_BURST_SEPARATOR); - // Security: double cookie submission pattern - boolean nocheck = "true".equals(application2 - .getProperty("disable-xsrf-protection")); - if (bursts.length == 1 && "init".equals(bursts[0])) { - // initial request, no variable changes: send key - String seckey = (String) request.getSession().getAttribute( - ApplicationConnection.UIDL_SECURITY_HEADER); - if (seckey == null) { - seckey = "" + (int) (Math.random() * 1000000); - } - /* - * Cookie c = new Cookie( - * ApplicationConnection.UIDL_SECURITY_COOKIE_NAME, uuid); - * response.addCookie(c); - */ - response.setHeader(ApplicationConnection.UIDL_SECURITY_HEADER, - seckey); - request.getSession().setAttribute( - ApplicationConnection.UIDL_SECURITY_HEADER, seckey); - return true; - } else if (!nocheck) { - // check the key - String sessId = (String) request.getSession().getAttribute( - ApplicationConnection.UIDL_SECURITY_HEADER); - if (sessId == null || !sessId.equals(bursts[0])) { - throw new InvalidUIDLSecurityKeyException( - "Security key mismatch"); + // Security: double cookie submission pattern unless disabled by + // property + if (!"true".equals(application2 + .getProperty("disable-xsrf-protection"))) { + if (bursts.length == 1 && "init".equals(bursts[0])) { + // initial request, no variable changes: send key + String seckey = (String) request.getSession().getAttribute( + ApplicationConnection.UIDL_SECURITY_HEADER); + if (seckey == null) { + seckey = "" + (int) (Math.random() * 1000000); + } + /* + * Cookie c = new Cookie( + * ApplicationConnection.UIDL_SECURITY_COOKIE_NAME, uuid); + * response.addCookie(c); + */ + response.setHeader( + ApplicationConnection.UIDL_SECURITY_HEADER, seckey); + request.getSession().setAttribute( + ApplicationConnection.UIDL_SECURITY_HEADER, seckey); + return true; + } else { + // check the key + String sessId = (String) request.getSession().getAttribute( + ApplicationConnection.UIDL_SECURITY_HEADER); + if (sessId == null || !sessId.equals(bursts[0])) { + throw new InvalidUIDLSecurityKeyException( + "Security key mismatch"); + } } - } for (int bi = 1; bi < bursts.length; bi++) { -- 2.39.5