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/hgSession/hgSession.c src/hg/hgSession/hgSession.c index 350ea4d..2610a77 100644 --- src/hg/hgSession/hgSession.c +++ src/hg/hgSession/hgSession.c @@ -110,42 +110,30 @@ else { printf("Signing in enables you to save current settings into a " "named session, and then restore settings from the session later.\n" "If you wish, you can share named sessions with other users.\n"); printf("<P>The sign-in page is handled by our " "<A HREF=\"http://%s/\" TARGET=_BLANK>wiki system</A>:\n", wikiHost); printf("<A HREF=\"%s\"><B>click here to sign in.</B></A>\n", wikiLinkUserLoginUrl(cartSessionId(cart))); printf("The wiki also serves as a forum for users " "to share knowledge and ideas.\n"); } } -char *getLinkUserName() -/* Return the user name specified in cookies from the browser, or NULL - * if - * the user doesn't appear to be logged in. */ -{ -if (wikiLinkEnabled()) - { - return cloneString(wikiLinkUserName()); - } -return NULL; -} - void showCartLinks() /* Print out links to cartDump and cartReset. */ { char *session = cartSidUrlString(cart); char returnAddress[512]; safef(returnAddress, sizeof(returnAddress), "%s?%s", hgSessionName(), session); printf("<A HREF=\"../cgi-bin/cartReset?%s&destination=%s\">Click here to " "reset</A> the browser user interface settings to their defaults.\n", session, cgiEncodeFull(returnAddress)); } char *destAppScriptName() /* Return the complete path (/cgi-bin/... on our systems) of the destination @@ -590,79 +578,78 @@ "be bookmarked in your web browser and/or shared with " "others. If you right-click and copy the Browser link, " "it will be the same as the Email link. However, if you " "click the Browser link it will take you to the Genome " "Browser and become a uniquely identified URL once the " "session loads, so that resulting link is not advised " "for sharing.</LI>\n" "<li>Each previously saved named session also appears with " "a checkbox to add the session to our " "<a href=\"../cgi-bin/hgPublicSessions?%s\">Public Sessions</a> " "listing. Adding a session to this listing allows other " "browser users to view the description and a thumbnail " "image of your session, and to load the session if they " "are interested.</li>\n", cartSidUrlString(cart)); } -else if (wikiLinkEnabled()) +else if (loginSystemEnabled() || wikiLinkEnabled()) { printf("<LI>If you <A HREF=\"%s\">sign in</A>, you will be able " " to save named sessions which will be displayed with " " Browser and Email links.</LI>\n", wikiLinkUserLoginUrl(cartSessionId(cart))); } dyStringPrintf(dyUrl, "http%s://%s%s", cgiAppendSForHttps(), cgiServerNamePort(), cgiScriptName()); printf("<LI>If you have saved your settings to a local file, you can send " "email to others with the file as an attachment and direct them to " "<A HREF=\"%s\">%s</A> .</LI>\n", dyUrl->string, dyUrl->string); dyStringPrintf(dyUrl, "?hgS_doLoadUrl=submit&hgS_loadUrlName="); printf("<LI>If a saved settings file is available from a web server, " "you can send email to others with a link such as " "%s<B>U</B> where <B>U</B> is the URL of your " "settings file, e.g. http://www.mysite.edu/~me/mySession.txt . " "In this type of link, you can replace " "\"hgSession\" with \"hgTracks\" in order to proceed directly to " "the Genome Browser. For an example page using such links " "please see the <A HREF=\"../goldenPath/help/sessions.html\" " "TARGET=_BLANK>Session Gallery</A>.</LI>\n", dyUrl->string); printf("</UL>\n"); dyStringFree(&dyUrl); } -void doMainPage(char *message) +void doMainPage(char *userName, char *message) /* Login status/links and session controls. */ { puts("Content-Type:text/html\n"); -if (wikiLinkEnabled()) +if (loginSystemEnabled() || wikiLinkEnabled()) { - char *wikiUserName = wikiLinkUserName(); - if (wikiUserName) - welcomeUser(wikiUserName); + if (userName) + welcomeUser(userName); else offerLogin(); if (isNotEmpty(message)) { if (cartVarExists(cart, hgsDoSessionDetail)) webNewSection("Session Details"); else webNewSection("Updated Session"); puts(message); } - showSessionControls(wikiUserName, TRUE, TRUE); - showLinkingTemplates(wikiUserName); + showSessionControls(userName, TRUE, TRUE); + showLinkingTemplates(userName); } else { if (isNotEmpty(message)) { if (cartVarExists(cart, hgsDoSessionDetail)) webNewSection("Session Details"); else cartWebStart(cart, NULL, "Updated Session"); jsInit(); puts(message); showSessionControls(NULL, FALSE, TRUE); } else showSessionControls(NULL, FALSE, FALSE); @@ -725,39 +712,40 @@ } } if (tdb->visibility != tvHide) outIfNotPresent(cart, dy, tdb->track, tdb->visibility); } // Put a variable in the cart that says we put the default // visibilities in it. if (dy) dyStringPrintf(dy,"&%s=on", CART_HAS_DEFAULT_VISIBILITY); else printf("%s on", CART_HAS_DEFAULT_VISIBILITY); } #define INITIAL_USE_COUNT 0 -char *doNewSession() +char *doNewSession(char *userName) /* Save current settings in a new named session. * Return a message confirming what we did. */ { +if (userName == NULL) + return "Unable to save session -- please log in and try again."; struct dyString *dyMessage = dyStringNew(2048); char *sessionName = trimSpaces(cartString(cart, hgsNewSessionName)); char *encSessionName = cgiEncodeFull(sessionName); boolean shareSession = cartBoolean(cart, hgsNewSessionShare); -char *userName = getLinkUserName(); char *encUserName = cgiEncodeFull(userName); struct sqlConnection *conn = hConnectCentral(); if (sqlTableExists(conn, namedSessionTable)) { struct sqlResult *sr = NULL; struct dyString *dy = dyStringNew(16 * 1024); char **row; char *firstUse = "now()"; int useCount = INITIAL_USE_COUNT; char firstUseBuf[32]; /* If this session already existed, preserve its firstUse and useCount. */ sqlDyStringPrintf(dy, "SELECT firstUse, useCount FROM %s " "WHERE userName = '%s' AND sessionName = '%s';", @@ -901,36 +889,37 @@ "select m.idx, n.firstUse from gbMembers m join namedSessionDb n on m.userName = n.userName " "where m.userName = \"%s\" and n.sessionName = \"%s\"", encUserName, encSessionName); sr = sqlGetResult(conn, query); row = sqlNextRow(sr); if (row == NULL) errAbort("cannot remove session from gallery; user %s, session %s", encUserName, encSessionName); char *filePath = sessionThumbnailFilePath(row[0], encSessionName, row[1]); if (filePath != NULL) unlink(filePath); sqlFreeResult(&sr); } -char *doSessionDetail(char *sessionName) +char *doSessionDetail(char *userName, char *sessionName) /* Show details about a particular session. */ { +if (userName == NULL) + return "Sorry, please log in again."; struct dyString *dyMessage = dyStringNew(4096); char *encSessionName = cgiEncodeFull(sessionName); -char *userName = getLinkUserName(); char *encUserName = cgiEncodeFull(userName); struct sqlConnection *conn = hConnectCentral(); struct sqlResult *sr = NULL; char **row = NULL; char query[512]; webPushErrHandlersCartDb(cart, cartUsualString(cart, "db", NULL)); boolean gotSettings = (sqlFieldIndex(conn, namedSessionTable, "settings") >= 0); if (gotSettings) sqlSafef(query, sizeof(query), "SELECT shared, firstUse, settings from %s " "WHERE userName = '%s' AND sessionName = '%s'", namedSessionTable, encUserName, encSessionName); else sqlSafef(query, sizeof(query), "SELECT shared, firstUse from %s " "WHERE userName = '%s' AND sessionName = '%s'", @@ -1016,40 +1005,41 @@ "Description:<BR>\n" "<TEXTAREA NAME=\"%s\" ROWS=%d COLS=%d " "onChange=\"%s\" onKeypress=\"%s\">%s</TEXTAREA><BR>\n", hgsNewSessionDescription, 5, 80, highlightAccChanges, highlightAccChanges, description); } dyStringAppend(dyMessage, "</FORM>\n"); sqlFreeResult(&sr); } else errAbort("doSessionDetail: got no results from query:<BR>\n%s\n", query); return dyStringCannibalize(&dyMessage); } -char *doUpdateSessions() +char *doUpdateSessions(char *userName) /* Look for cart variables matching prefixes for sharing/unsharing, * loading or deleting a previously saved session. * Return a message confirming what we did, or NULL if no such variables * were in the cart. */ { +if (userName == NULL) + return NULL; struct dyString *dyMessage = dyStringNew(1024); struct hashEl *cartHelList = NULL, *hel = NULL; struct sqlConnection *conn = hConnectCentral(); -char *userName = getLinkUserName(); char *encUserName = cgiEncodeFull(userName); boolean didSomething = FALSE; char query[512]; cartHelList = cartFindPrefix(cart, hgsGalleryPrefix); if (cartHelList != NULL) { struct hash *galleryHash = hashNew(0); char **row; struct sqlResult *sr; sqlSafef(query, sizeof(query), "select sessionName,shared from %s where userName = '%s'", namedSessionTable, encUserName); sr = sqlGetResult(conn, query); while ((row = sqlNextRow(sr)) != NULL) @@ -1116,31 +1106,31 @@ htmlEncode(sessionName), (newShared == TRUE ? "shared" : "unshared")); if (newShared == FALSE && inGallery == TRUE) thumbnailRemove(encUserName, encSessionName, conn); didSomething = TRUE; } } hashFree(&sharedHash); } hel = cartFindPrefix(cart, hgsEditPrefix); if (hel != NULL) { char *encSessionName = hel->name + strlen(hgsEditPrefix); char *sessionName = cgiDecodeClone(encSessionName); - dyStringPrintf(dyMessage, "%s", doSessionDetail(sessionName)); + dyStringPrintf(dyMessage, "%s", doSessionDetail(userName, sessionName)); didSomething = TRUE; } hel = cartFindPrefix(cart, hgsLoadPrefix); if (hel != NULL) { char *encSessionName = hel->name + strlen(hgsLoadPrefix); char *sessionName = cgiDecodeClone(encSessionName); char wildStr[256]; safef(wildStr, sizeof(wildStr), "%s*", hgsLoadPrefix); dyStringPrintf(dyMessage, "Loaded settings from session <B>%s</B>. %s %s<BR>\n", htmlEncode(sessionName), getSessionLink(encUserName, encSessionName), getSessionEmailLink(encUserName, encSessionName)); @@ -1313,39 +1303,40 @@ } void renamePrefixedCartVar(char *prefix, char *oldName, char *newName) /* If cart has prefix+oldName, replace it with prefix+newName = submit. */ { char varName[256]; safef(varName, sizeof(varName), "%s%s", prefix, oldName); if (cartVarExists(cart, varName)) { cartRemove(cart, varName); safef(varName, sizeof(varName), "%s%s", prefix, newName); cartSetString(cart, varName, "submit"); } } -char *doSessionChange(char *oldSessionName) +char *doSessionChange(char *userName, char *oldSessionName) /* Process changes to session from session details page. */ { +if (userName == NULL) + return "Unable to make changes to session. Please log in again."; struct dyString *dyMessage = dyStringNew(1024); webPushErrHandlersCartDb(cart, cartUsualString(cart, "db", NULL)); char *sessionName = oldSessionName; char *encSessionName = cgiEncodeFull(sessionName); char *encOldSessionName = encSessionName; -char *userName = getLinkUserName(); char *encUserName = cgiEncodeFull(userName); struct sqlConnection *conn = hConnectCentral(); struct sqlResult *sr = NULL; char **row = NULL; char query[512]; int shared = 1; char *settings = NULL; boolean gotSettings = (sqlFieldIndex(conn, namedSessionTable, "settings") >= 0); if (gotSettings) sqlSafef(query, sizeof(query), "SELECT shared, settings from %s " "WHERE userName = '%s' AND sessionName = '%s'", namedSessionTable, encUserName, encSessionName); else sqlSafef(query, sizeof(query), "SELECT shared from %s " @@ -1462,83 +1453,85 @@ return dyStringCannibalize(&dyMessage); } void hgSession() /* hgSession - Interface with wiki login and do session saving/loading. * Here we set up cart and some global variables, dispatch the command, * and put away the cart when it is done. */ { struct hash *oldVars = hashNew(10); /* Sometimes we output HTML and sometimes plain text; let each outputter * take care of headers instead of using a fixed cart*Shell(). */ cart = cartAndCookieNoContent(hUserCookie(), excludeVars, oldVars); +char *userName = (loginSystemEnabled() || wikiLinkEnabled()) ? wikiLinkUserName() : NULL; + if (cartVarExists(cart, hgsDoMainPage) || cartVarExists(cart, hgsCancel)) - doMainPage(NULL); + doMainPage(userName, NULL); else if (cartVarExists(cart, hgsDoNewSession)) { - char *message = doNewSession(); - doMainPage(message); + char *message = doNewSession(userName); + doMainPage(userName, message); } else if (cartVarExists(cart, hgsDoOtherUser)) { char *message = doOtherUser(hgsDoOtherUser); - doMainPage(message); + doMainPage(userName, message); } else if (cartVarExists(cart, hgsDoSaveLocal)) { doSaveLocal(); } else if (cartVarExists(cart, hgsDoLoadLocal)) { char *message = doLoad(FALSE, hgsDoLoadLocal); - doMainPage(message); + doMainPage(userName, message); } else if (cartVarExists(cart, hgsDoLoadUrl)) { char *message = doLoad(TRUE, hgsDoLoadUrl); - doMainPage(message); + doMainPage(userName, message); } else if (cartVarExists(cart, hgsDoSessionDetail)) { - char *message = doSessionDetail(cartString(cart, hgsDoSessionDetail)); - doMainPage(message); + char *message = doSessionDetail(userName, cartString(cart, hgsDoSessionDetail)); + doMainPage(userName, message); } else if (cartVarExists(cart, hgsDoSessionChange)) { - char *message = doSessionChange(cartString(cart, hgsOldSessionName)); - doMainPage(message); + char *message = doSessionChange(userName, cartString(cart, hgsOldSessionName)); + doMainPage(userName, message); } else if (cartVarExists(cart, hgsOldSessionName)) { - char *message1 = doSessionChange(cartString(cart, hgsOldSessionName)); - char *message2 = doUpdateSessions(); + char *message1 = doSessionChange(userName, cartString(cart, hgsOldSessionName)); + char *message2 = doUpdateSessions(userName); char *message = message2; if (!startsWith("No changes to session", message1)) { size_t len = (sizeof message1[0]) * (strlen(message1) + strlen(message2) + 1); message = needMem(len); safef(message, len, "%s%s", message1, message2); } - doMainPage(message); + doMainPage(userName, message); } else { - char *message = doUpdateSessions(); - doMainPage(message); + char *message = doUpdateSessions(userName); + doMainPage(userName, message); } cleanHgSessionFromCart(cart); /* Save the cart state: */ cartCheckout(&cart); } int main(int argc, char *argv[]) /* Process command line. */ { long enteredMainTime = clock1000(); htmlPushEarlyHandlers(); cgiSpoof(&argc, argv); hgSession(); cgiExitTime("hgSession", enteredMainTime);