e5c786377cee95f737ff9d4bbada817e14f94aa4
angie
  Mon Dec 12 09:25:06 2016 -0800
Better cookies and validation for hgLogin: instead of sending gbMembers.idx as
the login cookie and then never checking the value of the incoming cookie, use
a salted hash.  The salt is a secret text value specified by login.cookieSalt
in hg.conf.private.  For remote login, both hosts' hg.conf.private files must
specify the same login.cookieSalt.  In order to avoid logging out all users,
for now the correct value of gbMembers.idx is accepted in place of the salted
hash for local logins.  For remote logins without login.cookieSalt, there is
still no way to check the incoming cookie.  For local logins without
login.cookieSalt, the correct gbMembers.idx is accepted.
refs #17327

diff --git src/hg/lib/cart.c src/hg/lib/cart.c
index fbf6a4f..42e5da3 100644
--- src/hg/lib/cart.c
+++ src/hg/lib/cart.c
@@ -469,30 +469,35 @@
 assert(hashNumEntries(hash) == 0);
 }
 
 #ifndef GBROWSE
 void cartLoadUserSession(struct sqlConnection *conn, char *sessionOwner,
 			 char *sessionName, struct cart *cart,
 			 struct hash *oldVars, char *actionVar)
 /* If permitted, load the contents of the given user's session, and then
  * reload the CGI settings (to support override of session settings).
  * If non-NULL, oldVars will contain values overloaded when reloading CGI.
  * If non-NULL, actionVar is a cartRemove wildcard string specifying the
  * CGI action variable that sent us here. */
 {
 struct sqlResult *sr = NULL;
 char **row = NULL;
+/* Validate login cookies if login is enabled -- must be called before wikiLinkUserName */
+if (loginSystemEnabled())
+    {
+    loginValidateCookies(cart);
+    }
 char *userName = wikiLinkUserName();
 char *encSessionName = cgiEncodeFull(sessionName);
 char *encSessionOwner = cgiEncodeFull(sessionOwner);
 char query[512];
 
 if (isEmpty(sessionOwner))
     errAbort("Please go back and enter a wiki user name for this session.");
 if (isEmpty(sessionName))
     errAbort("Please go back and enter a session name to load.");
 
 sqlSafef(query, sizeof(query), "SELECT shared, contents FROM %s "
       "WHERE userName = '%s' AND sessionName = '%s';",
       namedSessionTable, encSessionOwner, encSessionName);
 sr = sqlGetResult(conn, query);
 if ((row = sqlNextRow(sr)) != NULL)
@@ -1575,30 +1580,37 @@
 		cookieName, userIdKey, domain, cookieDate());
     else
 	printf("Set-Cookie: %s=%s; path=/; expires=%s\r\n",
 		cookieName, userIdKey, cookieDate());
     }
 if (geoMirrorEnabled())
     {
     // This occurs after the user has manually choosen to go back to the original site; we store redirect value into a cookie so we 
     // can use it in subsequent hgGateway requests before loading the user's cart
     char *redirect = cgiOptionalString("redirect");
     if (redirect)
         {
         printf("Set-Cookie: redirect=%s; path=/; domain=%s; expires=%s\r\n", redirect, cgiServerName(), cookieDate());
         }
     }
+/* Validate login cookies if login is enabled */
+if (loginSystemEnabled())
+    {
+    struct slName *newCookies = loginValidateCookies(cart), *sl;
+    for (sl = newCookies;  sl != NULL;  sl = sl->next)
+        printf("Set-Cookie: %s\r\n", sl->name);
+    }
 }
 
 struct cart *cartForSession(char *cookieName, char **exclude,
                             struct hash *oldVars)
 /* This gets the cart without writing any HTTP lines at all to stdout. */
 {
 char *hguid = getCookieId(cookieName);
 char *hgsid = getSessionId();
 struct cart *cart = cartNew(hguid, hgsid, exclude, oldVars);
 cartExclude(cart, sessionVar);
 if (sameOk(cfgOption("signalsHandler"), "on"))  /* most cgis call this routine */
     initSigHandlers(hDumpStackEnabled());
 char *httpProxy = cfgOption("httpProxy");  /* most cgis call this routine */
 if (httpProxy)
     setenv("http_proxy", httpProxy, TRUE);   /* net.c cannot see the cart, pass the value through env var */