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/hgLogin/hgLogin.c src/hg/hgLogin/hgLogin.c index 153edb6..6f560ce 100644 --- src/hg/hgLogin/hgLogin.c +++ src/hg/hgLogin/hgLogin.c @@ -32,50 +32,30 @@ /* The excludeVars are not saved to the cart. */ char *excludeVars[] = { "submit", "Submit", "debug", "fixMembers", "update", "hgLogin_password", "hgLogin_password2", "hgLogin_newPassword1", "hgLogin_newPassword2", NULL }; struct cart *cart; /* This holds cgi and other variables between clicks. */ char *database; /* Name of genome database - hg15, mm3, or the like. */ struct hash *oldCart; /* Old cart hash. */ char *errMsg; /* Error message to show user when form data rejected */ char brwName[64]; char brwAddr[256]; char signature[256]; char returnAddr[256]; char *hgLoginUrl = NULL; /* ---- Global helper functions ---- */ -char *cookieNameForUserName() -/* Return the cookie name used for logged in user name like 'wikidb_mw1_UserName' */ -{ -if isEmpty(cfgOption(CFG_COOKIIENAME_USERNAME)) - return cloneString("NULL_cookieNameUserName"); -else - return cloneString(cfgOption(CFG_COOKIIENAME_USERNAME)); -} - -char *cookieNameForUserID() -/* Return the cookie name used for logged in user ID like 'wikidb_mw1_UserID' */ -{ -if isEmpty(cfgOption(CFG_COOKIIENAME_USERID)) - return cloneString("NULL_cookieNameUserID"); -else - return cloneString(cfgOption(CFG_COOKIIENAME_USERID)); -} - - - char *browserName() /* Return the browser name like 'UCSC Genome Browser' */ { if isEmpty(cfgOption(CFG_LOGIN_BROWSER_NAME)) return cloneString("NULL_browserName"); else return cloneString(cfgOption(CFG_LOGIN_BROWSER_NAME)); } char *browserAddr() /* Return the browser address like 'http://genome.ucsc.edu' */ { if isEmpty(cfgOption(CFG_LOGIN_BROWSER_ADDR)) return cloneString("NULL_browserAddr"); else @@ -316,31 +296,31 @@ do { if (*c == '.') { if (c == domain || *(c - 1) == '.') return 0; count++; } if (*c <= ' ' || *c >= 127) return 0; if (strchr(rfc822_specials, *c)) return 0; } while (*++c); return (count >= 1); } char *getReturnToURL() -/* get URL passed in with returnto URL */ +/* get URL from cart var returnto; if empty, make URL to hgSession on login host. */ { char *returnURL = cartUsualString(cart, "returnto", ""); char *hgLoginHost = wikiLinkHost(); char *cgiDir = cgiScriptDirUrl(); char returnTo[2048]; if (!returnURL || sameString(returnURL,"")) safef(returnTo, sizeof(returnTo), "http%s://%s%shgSession?hgS_doMainPage=1", cgiAppendSForHttps(), hgLoginHost, cgiDir); else safecpy(returnTo, sizeof(returnTo), returnURL); return cloneString(returnTo); } void returnToURL(int delay) @@ -1168,86 +1148,46 @@ boolean usingNewPassword(struct sqlConnection *conn, char *userName, char *password) /* The user is using requested new password */ { char query[256]; sqlSafef(query,sizeof(query), "SELECT passwordChangeRequired FROM gbMembers WHERE userName='%s'", userName); char *change = sqlQuickString(conn, query); sqlSafef(query,sizeof(query), "SELECT newPassword FROM gbMembers WHERE userName='%s'", userName); char *newPassword = sqlQuickString(conn, query); if (change && sameString(change, "Y") && checkPwd(password, newPassword)) return TRUE; else return FALSE; } -char *getCookieDomainName() -/* Return domain name to be used by the cookies or NULL. Allocd here. */ -/* Return central.domain if returnToURL is also in the same domain. */ -/* else return the domain in returnTo URL generated by remote hgSession.*/ -{ -char *centralDomain=cloneString(cfgOption(CFG_CENTRAL_DOMAIN)); -char *returnURL = getReturnToURL(); -char returnToDomain[256]; - -/* parse the URL */ -struct netParsedUrl rtpu; -netParseUrl(returnURL, &rtpu); -safecpy(returnToDomain, sizeof(returnToDomain), rtpu.host); -if (endsWith(returnToDomain,centralDomain)) - return centralDomain; -else - return cloneString(returnToDomain); -} - -char *getCookieDomainString() -/* Get a string that will look something like " domain=.ucsc.edu;" if getCookieDomainName - * returns something good, otherwise just " " */ -{ -char buf[256]; -char *domain = getCookieDomainName(); -if (domain != NULL && strchr(domain, '.') != NULL) - safef(buf, sizeof(buf), " domain=%s;", domain); -else - safef(buf, sizeof(buf), " "); -freeMem(domain); -return cloneString(buf); -} - -void displayLoginSuccess(char *userName, int userID) +void displayLoginSuccess(char *userName, uint idx) /* display login success msg, and set cookie */ { hPrintf("<h2>%s</h2>", brwName); hPrintf( "<p align=\"left\">" "</p>" "<span style='color:red;'></span>" "\n"); /* Set cookies */ -char *domainString=getCookieDomainString(); - -char *userNameCookie=cookieNameForUserName(); -char *userIDCookie=cookieNameForUserID(); hPrintf("<script language=\"JavaScript\">" - " document.write(\"Login successful, setting cookies now...\");" - "</script>\n" - "<script language=\"JavaScript\">" - "document.cookie = \"%s=%s;%s expires=Thu, 30-Dec-2037 23:59:59 GMT; path=/;\";" - "\n" - "document.cookie = \"%s=%d;%s expires=Thu, 30-Dec-2037 23:59:59 GMT; path=/;\";" - " </script>" - "\n", userNameCookie, userName, domainString, userIDCookie, userID, domainString); + " document.write(\"Login successful, setting cookies now...\");"); +struct slName *newCookies = loginLoginUser(userName, idx), *sl; +for (sl = newCookies; sl != NULL; sl = sl->next) + hPrintf(" document.cookie = '%s';", sl->name); +hPrintf(" </script>\n"); cartRemove(cart,"hgLogin_userName"); returnToURL(150); } void displayLogin(struct sqlConnection *conn) /* display and process login info */ { struct sqlResult *sr; char **row; char query[256]; char *userName = cartUsualString(cart, "hgLogin_userName", ""); if (sameString(userName,"")) { freez(&errMsg); errMsg = cloneString("User name cannot be blank."); @@ -1274,68 +1214,63 @@ return; } struct gbMembers *m = gbMembersLoad(row); sqlFreeResult(&sr); /* Check user name exist and account activated */ if (!sameString(m->accountActivated,"Y")) { freez(&errMsg); errMsg = cloneString("Account is not activated."); displayLoginPage(conn); return; } if (checkPwd(password,m->password)) { - unsigned int userID=m->idx; - hPrintf("<h2>Login successful for user %s with id %d.\n</h2>\n" - ,userName,userID); + hPrintf("<h2>Login successful for user %s.\n</h2>\n", userName); clearNewPasswordFields(conn, userName); - displayLoginSuccess(userName,userID); + displayLoginSuccess(m->userName, m->idx); return; } else if (usingNewPassword(conn, userName, password)) { cartSetString(cart, "hgLogin_changeRequired", "YES"); changePasswordPage(conn); } else { errMsg = cloneString(incorrectUsernameOrPassword); displayLoginPage(conn); return; } gbMembersFree(&m); } void displayLogoutSuccess() /* display logout success msg, and reset cookie */ { hPrintf("<h2>%s Sign Out</h2>", brwName); hPrintf( "<p align=\"left\">" "</p>" "<span style='color:red;'></span>" "\n"); -char *domainString=getCookieDomainString(); -char *userNameCookie=cookieNameForUserName(); -char *userIDCookie=cookieNameForUserID(); -hPrintf("<script language=\"JavaScript\">" - "document.cookie = \"%s=;%s expires=Thu, 1-Jan-1970 0:0:0 GMT; path=/;\";" - "\n" - "document.cookie = \"%s=;%s expires=Thu, 1-Jan-1970 0:0:0 GMT; path=/;\";" - "</script>\n", userNameCookie, domainString, userIDCookie, domainString); +hPrintf("<script language=\"JavaScript\">"); +struct slName *newCookies = loginLogoutUser(), *sl; +for (sl = newCookies; sl != NULL; sl = sl->next) + hPrintf(" document.cookie = '%s';", sl->name); +hPrintf("</script>\n"); /* return to "returnto" URL */ returnToURL(150); } void doMiddle(struct cart *theCart) /* Write the middle parts of the HTML page. * This routine sets up some globals and then * dispatches to the appropriate page-maker. */ { struct sqlConnection *conn = hConnectCentral(); cart = theCart; safecpy(brwName,sizeof(brwName), browserName()); safecpy(brwAddr,sizeof(brwAddr), browserAddr()); safecpy(signature,sizeof(signature), mailSignature()); safecpy(returnAddr,sizeof(returnAddr), mailReturnAddr());