83dd847b7449dd0fa83c22a4d60854f8d20d2847 max Fri Sep 18 08:51:14 2026 -0700 hgLogin: stop telling a CILogon user that CILogon shares no email address #Preview2 week - bugs introduced now will need a build patch to fix QA found three messages on the social sign-in pages claiming the provider does not give us an address. That was written when ORCID, which really releases none, was the only provider reaching those pages. CILogon does release the institution's address; we drop it because CILogon never marks it verified and login.oauth.cilogon.trustEmail is what says we may take it anyway. Once the address is dropped, nothing downstream could tell "released nothing" from "released something we would not take". oauthFetchIdentity now keeps the dropped address in a separate field that matching and sign-in never look at, and the three messages read it: the choose a username page, the confirmation page, and the one that turns down a typed address that already belongs to an account. The address box on the choose a username page starts from it as well, since retyping what we were just handed is the last thing a person wants to do. It still has to clear the duplicate check and be confirmed by mail, exactly as a typed address does. Three more things on the confirmation page, all from the same QA pass: The generic "a confirmation email has been sent" paragraph printed below the "use this address instead" form, so it read as if a mail had already gone to whatever was about to be typed in. It now goes above the form. Correcting the address redisplayed the same page with the new address swapped in and nothing to say the change had worked. It now says so. The rejection reason for an address that is already in use was set but never printed, so a refused change looked like nothing happening at all; that is printed now too. Reworded the unconfirmed-account explanation as QA suggested. refs #38339 diff --git src/hg/hgLogin/oauthLogin.c src/hg/hgLogin/oauthLogin.c index 2c7a625f20f..131c7e03245 100644 --- src/hg/hgLogin/oauthLogin.c +++ src/hg/hgLogin/oauthLogin.c @@ -516,38 +516,44 @@ else id = oidcFetch(p, code, redirectUri); } errCatchEnd(errCatch); if (errCatch->gotError) { fprintf(stderr, "hgLogin oauth: identity fetch for %s failed: %s\n", name, errCatch->message->string); id = NULL; } errCatchFree(&errCatch); /* An address the provider did not mark verified is only a string it is holding for the user, * and the user may well have typed it themselves. Unless hg.conf vouches for this provider, * forget it and let hgLogin treat the sign-in as one that came with no address at all: it then * asks for one and confirms it by mail, the same as ORCID, which releases none. Dropping it * rather than flagging it also keeps it out of the account matching in resolveIdentity, where - * an unverified address would otherwise be enough to reach somebody else's account. */ + * an unverified address would otherwise be enough to reach somebody else's account. + * Keep the address itself in emailUnverified, though. "Released nothing" and "released + * something we will not take" look identical downstream once email is NULL, and they are not + * the same thing to tell a user: telling a CILogon user that CILogon shares no address is + * simply untrue (#38339). */ if ((id != NULL) && isNotEmpty(id->email) && !id->emailVerified && !p->trustEmail) { fprintf(stderr, "hgLogin oauth: %s did not verify the address it released; asking the user " "for one instead (set login.oauth.%s.trustEmail=on to accept it)\n", name, name); - freez(&id->email); + id->emailUnverified = id->email; + id->email = NULL; } return id; } void oauthIdentityFree(struct oauthIdentity **pId) /* Free an oauthIdentity. */ { struct oauthIdentity *id = *pId; if (id != NULL) { freeMem(id->provider); freeMem(id->subject); freeMem(id->email); + freeMem(id->emailUnverified); freeMem(id->displayName); freez(pId); } }