Skip to content

Commit

Permalink
show more detail about email verification errors #8582
Browse files Browse the repository at this point in the history
  • Loading branch information
pdurbin committed Apr 11, 2022
1 parent 904a4e7 commit dc03e3d
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser;
import edu.harvard.iq.dataverse.util.BundleUtil;
import edu.harvard.iq.dataverse.util.JsfHelper;
import java.util.Arrays;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.faces.view.ViewScoped;
Expand Down Expand Up @@ -49,17 +50,27 @@ public class ConfirmEmailPage implements java.io.Serializable {
ConfirmEmailData confirmEmailData;

public String init() {
String failureDetails = "";
if (token != null) {
ConfirmEmailExecResponse confirmEmailExecResponse = confirmEmailService.processToken(token);
confirmEmailData = confirmEmailExecResponse.getConfirmEmailData();
if (confirmEmailData != null) {
user = confirmEmailData.getAuthenticatedUser();
session.setUser(user);
JsfHelper.addSuccessMessage(BundleUtil.getStringFromBundle("confirmEmail.details.success"));
return "/dataverse.xhtml?faces-redirect=true";
ConfirmEmailExecResponse confirmEmailExecResponse = null;
try {
confirmEmailExecResponse = confirmEmailService.processToken(token);
confirmEmailData = confirmEmailExecResponse.getConfirmEmailData();
if (confirmEmailData != null) {
user = confirmEmailData.getAuthenticatedUser();
session.setUser(user);
JsfHelper.addSuccessMessage(BundleUtil.getStringFromBundle("confirmEmail.details.success"));
return "/dataverse.xhtml?faces-redirect=true";
} else {
failureDetails = BundleUtil.getStringFromBundle("confirmEmail.details.failure.noConfirmEmailDataFromToken");
}
} catch (Exception ex) {
failureDetails = ex.getLocalizedMessage();
}
} else {
failureDetails = BundleUtil.getStringFromBundle("confirmEmail.details.failure.noToken");
}
JsfHelper.addErrorMessage(BundleUtil.getStringFromBundle("confirmEmail.details.failure"));
JsfHelper.addErrorMessage(BundleUtil.getStringFromBundle("confirmEmail.details.failure", Arrays.asList(failureDetails)));
/**
* @todo It would be nice to send a 404 response but if we enable this
* then the user sees the contents of 404.xhtml rather than the contents
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,55 +154,59 @@ private void sendLinkOnEmailChange(AuthenticatedUser aUser, String confirmationU
}

/**
* Process the email confirmation token, allowing the user to confirm the
* email address or report on a invalid token.
* Process the email confirmation token. If all looks good, set the
* timestamp and delete the token/confirmEmailData.
*
* @param tokenQueried
* @return ConfirmEmailExecResponse
* @throws Exception with details of the problem we can show the user.
*/
public ConfirmEmailExecResponse processToken(String tokenQueried) {
public ConfirmEmailExecResponse processToken(String tokenQueried) throws Exception {
deleteAllExpiredTokens();
ConfirmEmailExecResponse tokenUnusable = new ConfirmEmailExecResponse(tokenQueried, null);
ConfirmEmailData confirmEmailData = findSingleConfirmEmailDataByToken(tokenQueried);
if (confirmEmailData != null) {
if (confirmEmailData.isExpired()) {
// shouldn't reach here since tokens are being expired above
return tokenUnusable;
} else {
ConfirmEmailExecResponse goodTokenCanProceed = new ConfirmEmailExecResponse(tokenQueried, confirmEmailData);
if (confirmEmailData == null) {
logger.fine("Invalid token.");
return null;
}
long nowInMilliseconds = new Date().getTime();
Timestamp emailConfirmed = new Timestamp(nowInMilliseconds);
AuthenticatedUser authenticatedUser = confirmEmailData.getAuthenticatedUser();
if (authenticatedUser.isDeactivated()) {
logger.fine("User is deactivated.");
return null;
}
authenticatedUser.setEmailConfirmed(emailConfirmed);
em.remove(confirmEmailData);
return goodTokenCanProceed;
}
} else {
return tokenUnusable;
ConfirmEmailData confirmEmailData;
try {
confirmEmailData = findSingleConfirmEmailDataByToken(tokenQueried);
} catch (ConfirmEmailException ex) {
logger.info("processToken: could not find single ConfirmEmailData row using token " + tokenQueried);
throw new Exception(BundleUtil.getStringFromBundle("confirmEmail.details.failure.invalidToken"));
}
if (confirmEmailData == null) {
// shouldn't reach here because "invalid token" exception should have already been thrown.
logger.info("processToken: ConfirmEmailData is null using token " + tokenQueried);
throw new Exception(BundleUtil.getStringFromBundle("confirmEmail.details.failure.lookupFailed"));
}
if (confirmEmailData.isExpired()) {
// shouldn't reach here since tokens are being expired above
logger.info("processToken: Token is expired: " + tokenQueried);
throw new Exception(BundleUtil.getStringFromBundle("confirmEmail.details.failure.tokenExpired"));
}
// No need for null check because confirmEmailData always has a user (a foreign key).
AuthenticatedUser authenticatedUser = confirmEmailData.getAuthenticatedUser();
if (authenticatedUser.isDeactivated()) {
logger.info("processToken: User is deactivated. Token was " + tokenQueried);
throw new Exception(BundleUtil.getStringFromBundle("confirmEmail.details.failure.userDeactivated"));
}
ConfirmEmailExecResponse response = new ConfirmEmailExecResponse(tokenQueried, confirmEmailData);
long nowInMilliseconds = new Date().getTime();
Timestamp emailConfirmed = new Timestamp(nowInMilliseconds);
authenticatedUser.setEmailConfirmed(emailConfirmed);
em.remove(confirmEmailData);
return response;
}

/**
* @param token
* @return Null or a single row of email confirmation data.
*/
private ConfirmEmailData findSingleConfirmEmailDataByToken(String token) {
ConfirmEmailData confirmEmailData = null;
private ConfirmEmailData findSingleConfirmEmailDataByToken(String token) throws ConfirmEmailException {
TypedQuery<ConfirmEmailData> typedQuery = em.createNamedQuery("ConfirmEmailData.findByToken", ConfirmEmailData.class);
typedQuery.setParameter("token", token);
try {
confirmEmailData = typedQuery.getSingleResult();
return typedQuery.getSingleResult();
} catch (NoResultException | NonUniqueResultException ex) {
logger.fine("When looking up " + token + " caught " + ex);
logger.info("findSingleConfirmEmailDataByToken: When looking up " + token + " caught an exception:" + ex);
throw new ConfirmEmailException("");
}
return confirmEmailData;
}

public ConfirmEmailData findSingleConfirmEmailDataByUser(AuthenticatedUser user) {
Expand Down
8 changes: 7 additions & 1 deletion src/main/java/propertyFiles/Bundle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,13 @@ confirmEmail.pageTitle=Email Verification
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 "Send Verification Email" button.
confirmEmail.details.failure=We were unable to verify your email address: {0}. Please navigate to your Account Information page and click the "Send Verification Email" button.
confirmEmail.details.failure.invalidToken=Invalid token
confirmEmail.details.failure.lookupFailed=Lookup by token failed
confirmEmail.details.failure.tokenExpired=Token expired
confirmEmail.details.failure.userDeactivated=User deactivated
confirmEmail.details.failure.noToken=No token provided
confirmEmail.details.failure.noConfirmEmailDataFromToken=Problem processing token
confirmEmail.details.goToAccountPageButton=Go to Account Information
confirmEmail.notVerified=Not Verified
confirmEmail.verified=Verified
Expand Down

0 comments on commit dc03e3d

Please sign in to comment.