Fix Not Signed In errors when multiple tabs are open

By default gwtjsonrpc is caching the XSRF token in a JavaScript global
variable, which means the token is per-browser tab.  The server however
requires that the XSRF token presented in the POST body match the cookie
that is also presented in the request headers.

If the session expires and the user signs in again using an open tab,
that new tab would get refreshed with the new XSRF token, but all of
the other tabs would not be refreshed.  Using an older tab would also
trigger the Not Signed In error, and a new sign-in attempt from an old
tab would again change the cookie, breaking all other tabs.

Instead of obtaining the XSRF token from the JavaScript global state,
always get it from the browser cookie.  This ensures we always start
a request with the current cookie value, even if another tab is what
reinitialized the session.

Bug: issue 286
Change-Id: Ic94ae6bb61325a7b01e12b43e844ceabc5c817b1
Signed-off-by: Shawn O. Pearce <sop@google.com>
diff --git a/src/main/java/com/google/gerrit/client/Gerrit.java b/src/main/java/com/google/gerrit/client/Gerrit.java
index c743a1e..3616dc8 100644
--- a/src/main/java/com/google/gerrit/client/Gerrit.java
+++ b/src/main/java/com/google/gerrit/client/Gerrit.java
@@ -30,6 +30,7 @@
 import com.google.gwt.event.logical.shared.ValueChangeEvent;
 import com.google.gwt.event.logical.shared.ValueChangeHandler;
 import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.Cookies;
 import com.google.gwt.user.client.History;
 import com.google.gwt.user.client.Window;
 import com.google.gwt.user.client.Window.Location;
@@ -46,7 +47,9 @@
 import com.google.gwtexpui.clippy.client.CopyableLabel;
 import com.google.gwtexpui.user.client.UserAgent;
 import com.google.gwtexpui.user.client.ViewSite;
+import com.google.gwtjsonrpc.client.JsonDefTarget;
 import com.google.gwtjsonrpc.client.JsonUtil;
+import com.google.gwtjsonrpc.client.XsrfManager;
 
 import java.util.ArrayList;
 
@@ -189,14 +192,22 @@
     final RpcStatus rpcStatus = new RpcStatus(menuArea);
     JsonUtil.addRpcStartHandler(rpcStatus);
     JsonUtil.addRpcCompleteHandler(rpcStatus);
+    JsonUtil.setDefaultXsrfManager(new XsrfManager() {
+      @Override
+      public String getToken(JsonDefTarget proxy) {
+        return Cookies.getCookie("GerritAccount");
+      }
+
+      @Override
+      public void setToken(JsonDefTarget proxy, String token) {
+        // Ignore the request, we always rely upon the cookie.
+      }
+    });
 
     final HostPageDataService hpd = GWT.create(HostPageDataService.class);
     hpd.load(new GerritCallback<HostPageData>() {
       public void onSuccess(final HostPageData result) {
         myConfig = result.config;
-        if (result.xsrfToken != null) {
-          JsonUtil.getDefaultXsrfManager().setToken(null, result.xsrfToken);
-        }
         if (result.userAccount != null) {
           myAccount = result.userAccount;
           applyUserPreferences();
diff --git a/src/main/java/com/google/gerrit/client/HostPageData.java b/src/main/java/com/google/gerrit/client/HostPageData.java
index 857ff88..14c6e76 100644
--- a/src/main/java/com/google/gerrit/client/HostPageData.java
+++ b/src/main/java/com/google/gerrit/client/HostPageData.java
@@ -20,6 +20,5 @@
 /** Data sent as part of the host page, to bootstrap the UI. */
 public class HostPageData {
   public Account userAccount;
-  public String xsrfToken;
   public GerritConfig config;
 }
diff --git a/src/main/java/com/google/gerrit/server/http/HostPageServlet.java b/src/main/java/com/google/gerrit/server/http/HostPageServlet.java
index e376715..524ba63 100644
--- a/src/main/java/com/google/gerrit/server/http/HostPageServlet.java
+++ b/src/main/java/com/google/gerrit/server/http/HostPageServlet.java
@@ -50,7 +50,6 @@
 @Singleton
 public class HostPageServlet extends HttpServlet {
   private final Provider<CurrentUser> currentUser;
-  private final Provider<WebSession> webSession;
   private final File sitePath;
   private final GerritConfig config;
   private final Provider<String> urlProvider;
@@ -58,14 +57,12 @@
   private final Document hostDoc;
 
   @Inject
-  HostPageServlet(final Provider<CurrentUser> cu,
-      final Provider<WebSession> ws, @SitePath final File path,
+  HostPageServlet(final Provider<CurrentUser> cu, @SitePath final File path,
       final GerritConfig gc,
       @CanonicalWebUrl @Nullable final Provider<String> up,
       @CanonicalWebUrl @Nullable final String configuredUrl,
       final ServletContext servletContext) throws IOException {
     currentUser = cu;
-    webSession = ws;
     urlProvider = up;
     sitePath = path;
     config = gc;
@@ -211,7 +208,6 @@
 
     final CurrentUser user = currentUser.get();
     if (user instanceof IdentifiedUser) {
-      pageData.xsrfToken = webSession.get().getToken();
       pageData.userAccount = ((IdentifiedUser) user).getAccount();
     }