From dbd7ccc07a34c02efd994636c5e892b4d7488659 Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Tue, 5 Apr 2022 12:04:31 -0400 Subject: [PATCH 1/5] rename button to "Send Verification Email", remove popup #8227 --- doc/release-notes/8227-verify-email.md | 1 + .../providers/builtin/DataverseUserPage.java | 5 ---- src/main/java/propertyFiles/Bundle.properties | 6 ++--- src/main/webapp/dataverseuser.xhtml | 26 ------------------- 4 files changed, 3 insertions(+), 35 deletions(-) create mode 100644 doc/release-notes/8227-verify-email.md diff --git a/doc/release-notes/8227-verify-email.md b/doc/release-notes/8227-verify-email.md new file mode 100644 index 00000000000..0f3faa5436a --- /dev/null +++ b/doc/release-notes/8227-verify-email.md @@ -0,0 +1 @@ +The "Verify Email" button has been changed to "Send Verification Email" and rather than sometimes showing a popup now always sends a fresh verification email (and invalidates previous verification emails). diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/DataverseUserPage.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/DataverseUserPage.java index 177c59c5873..1cba16968bf 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/DataverseUserPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/DataverseUserPage.java @@ -546,11 +546,6 @@ public boolean showVerifyEmailButton() { return !confirmEmailService.hasVerifiedEmail(currentUser); } - public boolean getHasActiveVerificationToken(){ - //for user page to determine how to handle Confirm Email click - return confirmEmailService.hasActiveVerificationToken(currentUser); - } - public boolean isEmailIsVerified() { return confirmEmailService.hasVerifiedEmail(currentUser); } diff --git a/src/main/java/propertyFiles/Bundle.properties b/src/main/java/propertyFiles/Bundle.properties index 9895cffe0e7..f8c2e5f97ec 100644 --- a/src/main/java/propertyFiles/Bundle.properties +++ b/src/main/java/propertyFiles/Bundle.properties @@ -183,8 +183,6 @@ contact.context.support.ending=\n\n---\n\nMessage sent from Support contact form account.info=Account Information account.edit=Edit Account account.apiToken=API Token -account.emailvalidation.header=Email Validation -account.emailvalidation.token.exists=A verification email has been sent to {0}. Please check your inbox. user.isShibUser=Account information cannot be edited when logged in through an institutional account. user.helpShibUserMigrateOffShibBeforeLink=Leaving your institution? Please contact user.helpShibUserMigrateOffShibAfterLink=for assistance. @@ -364,10 +362,10 @@ authenticationProvider.name.shib=Shibboleth #confirmemail.xhtml confirmEmail.pageTitle=Email Verification -confirmEmail.submitRequest=Verify Email +confirmEmail.submitRequest=Send Verification Email confirmEmail.submitRequest.success=A verification email has been sent to {0}. Note, the verify link will expire after {1}. confirmEmail.details.success=Email address verified! -confirmEmail.details.failure=We were unable to verify your email address. Please navigate to your Account Information page and click the "Verify Email" button. +confirmEmail.details.failure=We were unable to verify your email address. Please navigate to your Account Information page and click the "Send Verification Email" button. confirmEmail.details.goToAccountPageButton=Go to Account Information confirmEmail.notVerified=Not Verified confirmEmail.verified=Verified diff --git a/src/main/webapp/dataverseuser.xhtml b/src/main/webapp/dataverseuser.xhtml index cb922a0164d..7fe5c43054f 100644 --- a/src/main/webapp/dataverseuser.xhtml +++ b/src/main/webapp/dataverseuser.xhtml @@ -484,7 +484,6 @@ id="verifyEmailButton" action="#{DataverseUserPage.sendConfirmEmail()}" update="@([id$=verifyEmailButton]), :messagePanel" - onclick="if (!testHasEmailToken(#{DataverseUserPage.getHasActiveVerificationToken()})) return false;" > #{bundle['confirmEmail.submitRequest']} @@ -754,32 +753,7 @@ - - - - #{DataverseUserPage.currentUser.email} - - - -
- -
-
- From 25dc6813f2badcccf44f9bd23646d25db505c485 Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Thu, 7 Apr 2022 17:09:04 -0400 Subject: [PATCH 2/5] autoset emailconfirmed timestamp for Shib users, rm check for stale tokens #5663 For Shib users we now set the emailconfirmed timestamp on login. (The guides say we do this already but are wrong. It was only being set on account creation.) For Shib users, I also prevent "check for your welcome email to verify your address" from being shown in the in-app welcome/new account notification. I put in a check to make sure Shib users never get a "verify your email address" email notification. Finally, I removed the hasNoStaleVerificationTokens check from the hasVerifiedEmail method. We've never worried about if there are stale verification tokens in the database or not and this check was preventing "Verified" from being shown, even when the user has a timestamp (the timestamp being the way we know if an email is verified or not). --- doc/release-notes/5663-shib-confirm-email.md | 7 +++++++ .../source/admin/user-administration.rst | 2 +- .../AuthenticationServiceBean.java | 4 ++-- .../shib/ShibAuthenticationProvider.java | 4 ++++ .../authorization/users/AuthenticatedUser.java | 9 +++++++++ .../confirmemail/ConfirmEmailServiceBean.java | 17 ++++++++++++++--- src/main/java/propertyFiles/Bundle.properties | 3 ++- src/main/webapp/dataverseuser.xhtml | 2 ++ .../iq/dataverse/branding/BrandingUtilTest.java | 3 ++- 9 files changed, 43 insertions(+), 8 deletions(-) create mode 100644 doc/release-notes/5663-shib-confirm-email.md diff --git a/doc/release-notes/5663-shib-confirm-email.md b/doc/release-notes/5663-shib-confirm-email.md new file mode 100644 index 00000000000..b6ef4306d4b --- /dev/null +++ b/doc/release-notes/5663-shib-confirm-email.md @@ -0,0 +1,7 @@ +For Shib users we now set the emailconfirmed timestamp on login. (The guides say we do this already but are wrong. It was only being set on account creation.) + +For Shib users, I also prevent "check for your welcome email to verify your address" from being shown in the in-app welcome/new account notification. + +I put in a check to make sure Shib users never get a "verify your email address" email notification. + +Finally, I removed the hasNoStaleVerificationTokens check from the hasVerifiedEmail method. We've never worried about if there are stale verification tokens in the database or not and this check was preventing "Verified" from being shown, even when the user has a timestamp (the timestamp being the way we know if an email is verified or not). diff --git a/doc/sphinx-guides/source/admin/user-administration.rst b/doc/sphinx-guides/source/admin/user-administration.rst index 867f06bde8e..df9a9f61aaa 100644 --- a/doc/sphinx-guides/source/admin/user-administration.rst +++ b/doc/sphinx-guides/source/admin/user-administration.rst @@ -63,7 +63,7 @@ The app will send a standard welcome email with a URL the user can click, which, Should users' URL token expire, they will see a "Verify Email" button on the account information page to send another URL. -Sysadmins can determine which users have verified their email addresses by looking for the presence of the value ``emailLastConfirmed`` in the JSON output from listing users (see :ref:`admin` section of Native API in the API Guide). As mentioned in the :doc:`/user/account` section of the User Guide, the email addresses for Shibboleth users are re-confirmed on every login. +Sysadmins can determine which users have verified their email addresses by looking for the presence of the value ``emailLastConfirmed`` in the JSON output from listing users (see :ref:`admin` section of Native API in the API Guide). As mentioned in the :doc:`/user/account` section of the User Guide, the email addresses for Shibboleth users are re-confirmed on every login (so their welcome email does not contain a URL to click for this purpose). Deleting an API Token --------------------- diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationServiceBean.java index dd4b5430bd1..b242cd2936f 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationServiceBean.java @@ -636,9 +636,8 @@ public AuthenticatedUser createAuthenticatedUser(UserRecordIdentifier userRecord authenticatedUser.setAuthenticatedUserLookup(auusLookup); if (ShibAuthenticationProvider.PROVIDER_ID.equals(auusLookup.getAuthenticationProviderId())) { - Timestamp emailConfirmedNow = new Timestamp(new Date().getTime()); // Email addresses for Shib users are confirmed by the Identity Provider. - authenticatedUser.setEmailConfirmed(emailConfirmedNow); + authenticatedUser.updateEmailConfirmedToNow(); authenticatedUser = save(authenticatedUser); } else { /* @todo Rather than creating a token directly here it might be @@ -665,6 +664,7 @@ public boolean identifierExists( String idtf ) { public AuthenticatedUser updateAuthenticatedUser(AuthenticatedUser user, AuthenticatedUserDisplayInfo userDisplayInfo) { user.applyDisplayInfo(userDisplayInfo); + user.updateEmailConfirmedToNow(); actionLogSvc.log( new ActionLogRecord(ActionLogRecord.ActionType.Auth, "updateUser") .setInfo(user.getIdentifier())); return update(user); diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/shib/ShibAuthenticationProvider.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/shib/ShibAuthenticationProvider.java index f7c00a1635d..e7dccc34300 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/shib/ShibAuthenticationProvider.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/shib/ShibAuthenticationProvider.java @@ -33,4 +33,8 @@ public boolean isDisplayIdentifier() { return false; } + // We don't override "isEmailVerified" because we're using timestamps + // ("emailconfirmed" on the "authenticateduser" table) to know if + // Shib users have confirmed/verified their email or not. + } diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java b/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java index 9d76ce0e47c..2a7fc8194d3 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java @@ -10,11 +10,13 @@ import edu.harvard.iq.dataverse.authorization.providers.oauth2.OAuth2TokenData; import edu.harvard.iq.dataverse.userdata.UserUtil; import edu.harvard.iq.dataverse.authorization.providers.oauth2.impl.OrcidOAuth2AP; +import edu.harvard.iq.dataverse.authorization.providers.shib.ShibAuthenticationProvider; import edu.harvard.iq.dataverse.util.BundleUtil; import static edu.harvard.iq.dataverse.util.StringUtil.nonEmpty; import edu.harvard.iq.dataverse.util.json.NullSafeJsonBuilder; import java.io.Serializable; import java.sql.Timestamp; +import java.util.Date; import java.util.List; import java.util.Objects; import javax.json.Json; @@ -193,6 +195,13 @@ public void applyDisplayInfo( AuthenticatedUserDisplayInfo inf ) { } } + // For Shib users, set "email confirmed" timestamp on login. + public void updateEmailConfirmedToNow() { + if (ShibAuthenticationProvider.PROVIDER_ID.equals(this.getAuthenticatedUserLookup().getAuthenticationProviderId())) { + Timestamp emailConfirmedNow = new Timestamp(new Date().getTime()); + this.setEmailConfirmed(emailConfirmedNow); + } + } //For User List Admin dashboard @Transient diff --git a/src/main/java/edu/harvard/iq/dataverse/confirmemail/ConfirmEmailServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/confirmemail/ConfirmEmailServiceBean.java index e8748f1e158..5fdf40d3833 100644 --- a/src/main/java/edu/harvard/iq/dataverse/confirmemail/ConfirmEmailServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/confirmemail/ConfirmEmailServiceBean.java @@ -54,10 +54,16 @@ public class ConfirmEmailServiceBean { */ public boolean hasVerifiedEmail(AuthenticatedUser user) { boolean hasTimestamp = user.getEmailConfirmed() != null; - boolean hasNoStaleVerificationTokens = this.findSingleConfirmEmailDataByUser(user) == null; boolean isVerifiedByAuthProvider = authenticationService.lookupProvider(user).isEmailVerified(); - - return (hasTimestamp && hasNoStaleVerificationTokens) || isVerifiedByAuthProvider; + // Note: In practice, we are relying on hasTimestamp to know if an email + // has been confirmed/verified or not. We have switched the Shib code to automatically + // overwrite the "confirm email" timestamp on login. So hasTimeStamp will be enough. + // If we ever want to get away from using "confirmed email" timestamps for Shib users + // we can make use of the isVerifiedByAuthProvider boolean. Currently, + // isVerifiedByAuthProvider is set to false in the super class and nothing + // is overridden in the shib auth provider (or any auth provider) but we could override + // isVerifiedByAuthProvider in the Shib auth provider and have it return true. + return hasTimestamp || isVerifiedByAuthProvider; } /** @@ -128,6 +134,11 @@ private void sendLinkOnEmailChange(AuthenticatedUser aUser, String confirmationU userNotification.setType(UserNotification.Type.CONFIRMEMAIL); String subject = MailUtil.getSubjectTextBasedOnNotification(userNotification, null); logger.fine("sending email to " + toAddress + " with this subject: " + subject); + if (ShibAuthenticationProvider.PROVIDER_ID.equals(aUser.getAuthenticatedUserLookup().getAuthenticationProviderId())) { + // Shib users have "emailconfirmed" timestamp set on login. + logger.info("Returning early to prevent an email confirmation link from being sent to Shib user " + aUser.getUserIdentifier() + "."); + return; + } mailService.sendSystemEmail(toAddress, subject, messageBody); } catch (Exception ex) { /** diff --git a/src/main/java/propertyFiles/Bundle.properties b/src/main/java/propertyFiles/Bundle.properties index f8c2e5f97ec..8bcf6960b2d 100644 --- a/src/main/java/propertyFiles/Bundle.properties +++ b/src/main/java/propertyFiles/Bundle.properties @@ -198,7 +198,8 @@ wasReturnedByReviewer=, was returned by the curator of # TODO: Confirm that "toReview" can be deleted. toReview=Don't forget to publish it or send it back to the contributor! # Bundle file editors, please note that "notification.welcome" is used in a unit test. -notification.welcome=Welcome to {0}! Get started by adding or finding data. Have questions? Check out the {1}. Want to test out Dataverse features? Use our {2}. Also, check for your welcome email to verify your address. +notification.welcome=Welcome to {0}! Get started by adding or finding data. Have questions? Check out the {1}. Want to test out Dataverse features? Use our {2}. +notification.welcomeConfirmEmail=Also, check for your welcome email to verify your address. notification.demoSite=Demo Site notification.requestFileAccess=File access requested for dataset: {0} was made by {1} ({2}). notification.grantFileAccess=Access granted for files in dataset: {0}. diff --git a/src/main/webapp/dataverseuser.xhtml b/src/main/webapp/dataverseuser.xhtml index 7fe5c43054f..4a369c0d431 100644 --- a/src/main/webapp/dataverseuser.xhtml +++ b/src/main/webapp/dataverseuser.xhtml @@ -80,6 +80,8 @@ #{bundle['notification.demoSite']} + + diff --git a/src/test/java/edu/harvard/iq/dataverse/branding/BrandingUtilTest.java b/src/test/java/edu/harvard/iq/dataverse/branding/BrandingUtilTest.java index b3b80397eee..95deafc0cfe 100644 --- a/src/test/java/edu/harvard/iq/dataverse/branding/BrandingUtilTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/branding/BrandingUtilTest.java @@ -141,7 +141,8 @@ public void testWelcomeInAppNotification(TestInfo testInfo) { "LibraScholar", "User Guide", "Demo Site" - )); + )) + + " " + BundleUtil.getStringFromBundle("notification.welcomeConfirmEmail"); log.fine("message: " + message); assertEquals("Welcome to LibraScholar! Get started by adding or finding data. " + "Have questions? Check out the User Guide." From afc87b4466609ff03eb31da3aceb938401727c1c Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Fri, 8 Apr 2022 15:14:14 -0400 Subject: [PATCH 3/5] remove empty "Account Information" dropdown for Shib users #8223 --- src/main/webapp/dataverseuser.xhtml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/webapp/dataverseuser.xhtml b/src/main/webapp/dataverseuser.xhtml index 4a369c0d431..bbb7b7b0bc6 100644 --- a/src/main/webapp/dataverseuser.xhtml +++ b/src/main/webapp/dataverseuser.xhtml @@ -381,15 +381,12 @@ -
+