From 7168d257658a54ae92cbe28e6e932c20c3cb436b Mon Sep 17 00:00:00 2001 From: Camelia Dumitru <62257307+Camelia-Orcid@users.noreply.github.com> Date: Wed, 19 Feb 2025 15:17:23 +0000 Subject: [PATCH 1/4] the end point takes an orcid or email as parameter (#7226) * the end point takes an orcid or email as parameter * Fixed failing test --- .../orcid/pojo/AdminResetPasswordLink.java | 10 +-- .../web/controllers/AdminController.java | 72 +++++++++++-------- .../controllers/PasswordResetController.java | 17 ++++- .../web/controllers/AdminControllerTest.java | 10 ++- properties/development.properties | 1 + 5 files changed, 72 insertions(+), 38 deletions(-) diff --git a/orcid-core/src/main/java/org/orcid/pojo/AdminResetPasswordLink.java b/orcid-core/src/main/java/org/orcid/pojo/AdminResetPasswordLink.java index 3dfeec8f61..58a16101b2 100644 --- a/orcid-core/src/main/java/org/orcid/pojo/AdminResetPasswordLink.java +++ b/orcid-core/src/main/java/org/orcid/pojo/AdminResetPasswordLink.java @@ -5,7 +5,7 @@ public class AdminResetPasswordLink { private String resetLink; - private String email; + private String orcidOrEmail; private String error; @@ -21,12 +21,12 @@ public void setResetLink(String resetLink) { this.resetLink = resetLink; } - public String getEmail() { - return email; + public String getOrcidOrEmail() { + return orcidOrEmail; } - public void setEmail(String email) { - this.email = email; + public void setOrcidOrEmail(String orcidOrEmail) { + this.orcidOrEmail = orcidOrEmail; } public String getError() { diff --git a/orcid-web/src/main/java/org/orcid/frontend/web/controllers/AdminController.java b/orcid-web/src/main/java/org/orcid/frontend/web/controllers/AdminController.java index 7aaae08774..2153d883af 100644 --- a/orcid-web/src/main/java/org/orcid/frontend/web/controllers/AdminController.java +++ b/orcid-web/src/main/java/org/orcid/frontend/web/controllers/AdminController.java @@ -88,23 +88,22 @@ public class AdminController extends BaseController { @Resource(name = "clientDetailsManagerV3") private ClientDetailsManager clientDetailsManager; - + @Resource private VerifyEmailUtils verifyEmailUtils; - + @Resource private EncryptionManager encryptionManager; @Resource(name = "spamManager") SpamManager spamManager; - - @Resource + + @Resource private RecordEmailSender recordEmailSender; - + @Resource private TwoFactorAuthenticationManager twoFactorAuthenticationManager; - - + @Value("${org.orcid.admin.registry.url:https://orcid.org}") private String registryUrl; @@ -120,7 +119,7 @@ public class AdminController extends BaseController { private static final String OUT_NOT_AVAILABLE = "N/A"; private static final String OUT_NOT_AVAILABLE_ID = "N/A "; private static final String OUT_NEW_LINE = "\n"; - + private static final int RESET_PASSWORD_LINK_DURATION = 24; private void isAdmin(HttpServletRequest serverRequest, HttpServletResponse response) throws IllegalAccessException { @@ -347,7 +346,8 @@ else if (PojoUtil.isEmpty(email) || !validateEmailAddress(email)) } if (profileDetails.getErrors() == null || profileDetails.getErrors().size() == 0) { - // Return a list of email addresses that should be notified by this change + // Return a list of email addresses that should be notified by this + // change List emailsToNotify = profileEntityManager.reactivate(orcid, email, null); // Notify any new email address if (!emailsToNotify.isEmpty()) { @@ -644,7 +644,7 @@ public Map findIdByEmailHelper(String csvEmails) { } return form; } - + /** * Reset password validate * @@ -656,18 +656,34 @@ public Map findIdByEmailHelper(String csvEmails) { @RequestBody AdminResetPasswordLink form) throws IllegalAccessException, UnsupportedEncodingException { isAdmin(serverRequest, response); form.setError(null); - String email = URLDecoder.decode(form.getEmail(), "UTF-8").trim(); - LOGGER.debug("The email to reset password link to is: " + email); - if (OrcidStringUtils.isEmailValid(email) && emailManager.emailExists(email)) { - Pair resetLinkData = verifyEmailUtils.createResetLinkForAdmin(email, registryUrl); + String orcidOrEmail = URLDecoder.decode(form.getOrcidOrEmail(), "UTF-8").trim(); + boolean isOrcid = OrcidStringUtils.isValidOrcid(orcidOrEmail); + String orcid = null; + // If it is not an orcid, check the value from the emails table + if (!isOrcid) { + if (OrcidStringUtils.isEmailValid(orcidOrEmail) && emailManager.emailExists(orcidOrEmail)) { + orcid = emailManager.findOrcidIdByEmail(orcidOrEmail); + } else { + form.setError(getMessage("admin.errors.unable_to_fetch_info")); + return form; + } + } else { + orcid = orcidOrEmail; + } + + if (!PojoUtil.isEmpty(orcid) || profileEntityManager.orcidExists(orcid)) { + Pair resetLinkData = verifyEmailUtils.createResetLinkForAdmin(orcid, registryUrl); LOGGER.debug("Reset link to be sent to the client: " + resetLinkData.getKey()); - + form.setResetLink(resetLinkData.getKey()); form.setIssueDate(resetLinkData.getValue()); - form.setDurationInHours(RESET_PASSWORD_LINK_DURATION); + form.setDurationInHours(RESET_PASSWORD_LINK_DURATION); + } else { - form.setError(getMessage("admin.errors.unexisting_email")); + form.setError(getMessage("admin.errors.unexisting_orcid")); + return form; } + return form; } @@ -862,10 +878,11 @@ private String getOrcidFromParam(String orcidOrEmail) { } else if (lockAccounts.getDescription() == null || lockAccounts.getDescription().isEmpty()) { descriptionMissing.add(nextToken); } else { - boolean wasLocked = profileEntityManager.lockProfile(orcidId, lockAccounts.getLockReason(), lockAccounts.getDescription(), getCurrentUserOrcid()); + boolean wasLocked = profileEntityManager.lockProfile(orcidId, lockAccounts.getLockReason(), lockAccounts.getDescription(), + getCurrentUserOrcid()); if (wasLocked) { recordEmailSender.sendOrcidLockedEmail(orcidId); - } + } successIds.add(nextToken); } } @@ -1053,7 +1070,7 @@ private String getOrcidFromParam(String orcidOrEmail) { } else { email = emailOrOrcid; } - recordEmailSender.sendClaimReminderEmail(orcidId,0,email); + recordEmailSender.sendClaimReminderEmail(orcidId, 0, email); successIds.add(emailOrOrcid); } } @@ -1094,7 +1111,7 @@ private String getOrcidFromParam(String orcidOrEmail) { if (entity.getUsing2FA()) { twoFactorAuthenticationManager.adminDisable2FA(orcidId, getCurrentUserOrcid()); - recordEmailSender.send2FADisabledEmail(orcidId); + recordEmailSender.send2FADisabledEmail(orcidId); disabledIds.add(emailOrOrcid); } else { without2FAs.add(emailOrOrcid); @@ -1118,8 +1135,6 @@ private String getOrcidFromParam(String orcidOrEmail) { data.setAlreadyMember(false); data.setClientDeactivated(false); - - isAdmin(serverRequest, response); if (PojoUtil.isEmpty(data.getClientId()) || !clientDetailsManager.exists(data.getClientId())) { data.setClientNotFound(true); @@ -1144,14 +1159,14 @@ private String getOrcidFromParam(String orcidOrEmail) { ProfileEntity group = profileEntityCacheManager.retrieve(data.getGroupId()); if (group == null || !OrcidType.GROUP.name().equals(group.getOrcidType())) { data.setGroupIdNotFound(true); - } else { + } else { if (!group.isEnabled() || group.getRecordLocked() || group.getDeactivationDate() != null) { data.setGroupIdDeactivated(true); - } else { + } else { ClientType clientType = MemberType.PREMIUM.name().equals(group.getGroupType()) ? ClientType.PREMIUM_UPDATER : ClientType.UPDATER; data.setTargetClientType(clientType.name()); } - + } } catch (IllegalArgumentException e) { @@ -1160,13 +1175,12 @@ private String getOrcidFromParam(String orcidOrEmail) { } } - return data; } @RequestMapping(value = "/convert-client.json", method = RequestMethod.POST) public @ResponseBody ConvertClient convertClient(HttpServletRequest serverRequest, HttpServletResponse response, @RequestBody ConvertClient data) - throws IllegalAccessException { + throws IllegalAccessException { isAdmin(serverRequest, response); data = validateClientConversion(serverRequest, response, data); if (data.isClientNotFound() || data.isAlreadyMember() || data.isGroupIdNotFound()) { @@ -1196,7 +1210,7 @@ private String getOrcidFromParam(String orcidOrEmail) { data.setSuccess(false); return data; } - + try { clientDetailsManager.moveClientGroupId(data.getClientId(), data.getGroupId()); data.setSuccess(true); diff --git a/orcid-web/src/main/java/org/orcid/frontend/web/controllers/PasswordResetController.java b/orcid-web/src/main/java/org/orcid/frontend/web/controllers/PasswordResetController.java index 48ed267395..9de289a781 100644 --- a/orcid-web/src/main/java/org/orcid/frontend/web/controllers/PasswordResetController.java +++ b/orcid-web/src/main/java/org/orcid/frontend/web/controllers/PasswordResetController.java @@ -283,7 +283,22 @@ public ModelAndView resetPasswordEmail(HttpServletRequest request, @PathVariable passwordConfirmValidate(oneTimeResetPasswordForm.getRetypedPassword(), oneTimeResetPasswordForm.getPassword()); - String orcid = emailManagerReadOnly.findOrcidIdByEmail(passwordResetToken.getEmail()); + String orcid = null; + //check first if valid orcid as the admin portal can send either and email or an orcid + if(OrcidStringUtils.isValidOrcid(passwordResetToken.getEmail()) ){ + if(profileEntityManager.orcidExists(passwordResetToken.getEmail())) { + orcid = passwordResetToken.getEmail(); + } + else { + String message = "invalidPasswordResetToken"; + oneTimeResetPasswordForm.getErrors().add(message); + return oneTimeResetPasswordForm; + } + } + else { + orcid = emailManagerReadOnly.findOrcidIdByEmail(passwordResetToken.getEmail()); + } + Emails emails = emailManager.getEmails(orcid); passwordChecklistValidate(oneTimeResetPasswordForm.getRetypedPassword(), oneTimeResetPasswordForm.getPassword(), emails); diff --git a/orcid-web/src/test/java/org/orcid/frontend/web/controllers/AdminControllerTest.java b/orcid-web/src/test/java/org/orcid/frontend/web/controllers/AdminControllerTest.java index 34f17016fe..ab32d6dcc8 100644 --- a/orcid-web/src/test/java/org/orcid/frontend/web/controllers/AdminControllerTest.java +++ b/orcid-web/src/test/java/org/orcid/frontend/web/controllers/AdminControllerTest.java @@ -1429,6 +1429,7 @@ public void resetPasswordLink() throws Exception { AdminController adminController = new AdminController(); EmailManager emailManager = Mockito.mock(EmailManager.class); LocaleManager localeManager = Mockito.mock(LocaleManager.class); + ProfileEntityManager profileEntityManager = Mockito.mock(ProfileEntityManager.class); ReflectionTestUtils.setField(adminController, "verifyEmailUtils", verifyEmailUtils); @@ -1436,6 +1437,7 @@ public void resetPasswordLink() throws Exception { ReflectionTestUtils.setField(adminController, "emailManager", emailManager); ReflectionTestUtils.setField(adminController, "localeManager", localeManager); ReflectionTestUtils.setField(adminController, "orcidSecurityManager", orcidSecurityManager); + ReflectionTestUtils.setField(adminController, "profileEntityManager", profileEntityManager); Mockito.when(orcidSecurityManager.isAdmin()).thenReturn(true); @@ -1445,18 +1447,20 @@ public void resetPasswordLink() throws Exception { Mockito.when(localeManager.resolveMessage(Mockito.anyString(), Mockito.any())).thenReturn("That email address is not on our records"); Mockito.when(verifyEmailUtils.createResetLinkForAdmin(Mockito.anyString(), Mockito.any())).thenReturn(new Pair("xyz", new Date())); - + Mockito.when(localeManager.resolveMessage(Mockito.anyString(), Mockito.any())).thenReturn("That email address is not on our records"); + Mockito.when(profileEntityManager.orcidExists(Mockito.anyString())).thenReturn(true); AdminResetPasswordLink adminResetPasswordLink = new AdminResetPasswordLink(); - adminResetPasswordLink.setEmail("not-found-email1@test.com"); + adminResetPasswordLink.setOrcidOrEmail("not-found-email1@test.com"); adminResetPasswordLink = adminController.resetPasswordLink(mockRequest, mockResponse, adminResetPasswordLink); assertEquals("That email address is not on our records", adminResetPasswordLink.getError()); adminResetPasswordLink = new AdminResetPasswordLink(); - adminResetPasswordLink.setEmail("existent_email@test.com"); + Mockito.when(emailManager.findOrcidIdByEmail(Mockito.anyString())).thenReturn("0000-0002-0551-5914"); + adminResetPasswordLink.setOrcidOrEmail("existent_email@test.com"); XMLGregorianCalendar date = DateUtils.convertToXMLGregorianCalendarNoTimeZoneNoMillis(new Date()); Mockito.when(encryptionManager.decryptForExternalUse(Mockito.anyString())).thenReturn("email=existent_email@test.com&issueDate="+ date.toXMLFormat()+ "&h=24"); adminResetPasswordLink = adminController.resetPasswordLink(mockRequest, mockResponse, adminResetPasswordLink); diff --git a/properties/development.properties b/properties/development.properties index 4978837784..6367dfed8c 100644 --- a/properties/development.properties +++ b/properties/development.properties @@ -291,3 +291,4 @@ org.orcid.core.utils.cache.papi.redis.enabled=true org.orcid.core.csrf.domain=dev.orcid.org org.orcid.scheduler.web.processOrgsForIndexing=0 48 12 * * * +org.orcid.admin.registry.url:https://dev.orcid.org From f8241e8101197921b498aab84ffe9cea66850023 Mon Sep 17 00:00:00 2001 From: github actions Date: Wed, 19 Feb 2025 15:29:13 +0000 Subject: [PATCH 2/4] v2.71.21 changelog update --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f2de124ef..f336c70594 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## v2.71.21 - 2025-02-19 + +[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.71.20...v2.71.21) + ## v2.71.20 - 2025-02-15 [Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.71.19...v2.71.20) From c438a86743a52e1920cd22d8c421470808b10606 Mon Sep 17 00:00:00 2001 From: Camelia Dumitru <62257307+Camelia-Orcid@users.noreply.github.com> Date: Thu, 20 Feb 2025 13:24:19 +0000 Subject: [PATCH 3/4] Fixed providing the ling for a valid orcid format but not associated with a record (#7227) --- .../org/orcid/frontend/web/controllers/AdminController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orcid-web/src/main/java/org/orcid/frontend/web/controllers/AdminController.java b/orcid-web/src/main/java/org/orcid/frontend/web/controllers/AdminController.java index 2153d883af..54ff5b312b 100644 --- a/orcid-web/src/main/java/org/orcid/frontend/web/controllers/AdminController.java +++ b/orcid-web/src/main/java/org/orcid/frontend/web/controllers/AdminController.java @@ -671,7 +671,7 @@ public Map findIdByEmailHelper(String csvEmails) { orcid = orcidOrEmail; } - if (!PojoUtil.isEmpty(orcid) || profileEntityManager.orcidExists(orcid)) { + if (!PojoUtil.isEmpty(orcid) && profileEntityManager.orcidExists(orcid)) { Pair resetLinkData = verifyEmailUtils.createResetLinkForAdmin(orcid, registryUrl); LOGGER.debug("Reset link to be sent to the client: " + resetLinkData.getKey()); From 1f2ce2466c627ff74fcf73e6ca6d8454b010d09d Mon Sep 17 00:00:00 2001 From: github actions Date: Thu, 20 Feb 2025 13:36:06 +0000 Subject: [PATCH 4/4] v2.71.22 changelog update --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f336c70594..5a7eab4a3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## v2.71.22 - 2025-02-20 + +[Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.71.21...v2.71.22) + ## v2.71.21 - 2025-02-19 [Full Changelog](https://github.com/ORCID/ORCID-Source/compare/v2.71.20...v2.71.21)