Skip to content

Commit b875fbf

Browse files
committed
PD-5147 add auth challenge to password reset
1 parent dad5ffa commit b875fbf

3 files changed

Lines changed: 239 additions & 37 deletions

File tree

orcid-web/src/main/java/org/orcid/frontend/web/controllers/PasswordResetController.java

Lines changed: 49 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@
1919
import org.apache.commons.codec.binary.Base64;
2020
import org.jasypt.exceptions.EncryptionOperationNotPossibleException;
2121
import org.orcid.core.constants.OrcidOauth2Constants;
22-
import org.orcid.core.manager.EncryptionManager;
23-
import org.orcid.core.manager.ProfileEntityCacheManager;
24-
import org.orcid.core.manager.RegistrationManager;
22+
import org.orcid.core.manager.*;
2523
import org.orcid.core.manager.v3.ProfileEntityManager;
2624
import org.orcid.core.manager.v3.read_only.EmailManagerReadOnly;
2725
import org.orcid.core.togglz.Features;
@@ -32,7 +30,6 @@
3230
import org.orcid.frontend.spring.web.social.config.SocialSignInUtils;
3331
import org.orcid.frontend.web.forms.OneTimeResetPasswordForm;
3432
import org.orcid.frontend.web.util.CommonPasswords;
35-
import org.orcid.jaxb.model.v3.release.record.Email;
3633
import org.orcid.jaxb.model.v3.release.record.Emails;
3734
import org.orcid.persistence.jpa.entities.ProfileEntity;
3835
import org.orcid.pojo.EmailRequest;
@@ -71,6 +68,12 @@ public class PasswordResetController extends BaseController {
7168
@Resource
7269
private SocialAjaxAuthenticationSuccessHandler ajaxAuthenticationSuccessHandlerSocial;
7370

71+
@Resource
72+
private TwoFactorAuthenticationManager twoFactorAuthenticationManager;
73+
74+
@Resource
75+
private BackupCodeManager backupCodeManager;
76+
7477
@Resource
7578
private ShibbolethAjaxAuthenticationSuccessHandler ajaxAuthenticationSuccessHandlerShibboleth;
7679

@@ -203,14 +206,14 @@ public ModelAndView resetPasswordEmail(HttpServletRequest request, @PathVariable
203206
String orcid = emailManagerReadOnly.findOrcidIdByEmail(passwordResetToken.getEmail());
204207
emails = emailManager.getEmails(orcid);
205208
}
206-
passwordChecklistValidate(resetPasswordForm.getRetypedPassword(), resetPasswordForm.getPassword(), emails);
209+
passwordChecklistValidate(resetPasswordForm.getRetypedPassword(), resetPasswordForm.getNewPassword(), emails);
207210

208-
if (resetPasswordForm.getRetypedPassword() != null && !resetPasswordForm.getRetypedPassword().equals(resetPasswordForm.getPassword())) {
211+
if (resetPasswordForm.getRetypedPassword() != null && !resetPasswordForm.getRetypedPassword().equals(resetPasswordForm.getNewPassword())) {
209212
setError(resetPasswordForm, "FieldMatch.registrationForm");
210213
}
211214

212-
if (CommonPasswords.passwordIsCommon(resetPasswordForm.getPassword().getValue())) {
213-
setError(resetPasswordForm, "password.too_common", resetPasswordForm.getPassword());
215+
if (CommonPasswords.passwordIsCommon(resetPasswordForm.getNewPassword().getValue())) {
216+
setError(resetPasswordForm, "password.too_common", resetPasswordForm.getNewPassword());
214217
}
215218
return resetPasswordForm;
216219
}
@@ -219,7 +222,7 @@ public ModelAndView resetPasswordEmail(HttpServletRequest request, @PathVariable
219222
public @ResponseBody OneTimeResetPasswordForm getResetPassword() {
220223

221224
OneTimeResetPasswordForm oneTimeResetPasswordForm = new OneTimeResetPasswordForm();
222-
passwordChecklistValidate(oneTimeResetPasswordForm.getRetypedPassword(), oneTimeResetPasswordForm.getPassword());
225+
passwordChecklistValidate(oneTimeResetPasswordForm.getRetypedPassword(), oneTimeResetPasswordForm.getNewPassword());
223226
return oneTimeResetPasswordForm;
224227
}
225228

@@ -239,17 +242,17 @@ public ModelAndView resetPasswordEmail(HttpServletRequest request, @PathVariable
239242
return oneTimeResetPasswordForm;
240243
}
241244

242-
passwordConfirmValidate(oneTimeResetPasswordForm.getRetypedPassword(), oneTimeResetPasswordForm.getPassword());
245+
passwordConfirmValidate(oneTimeResetPasswordForm.getRetypedPassword(), oneTimeResetPasswordForm.getNewPassword());
243246

244247
String orcid = emailManagerReadOnly.findOrcidIdByEmail(passwordResetToken.getEmail());
245248
Emails emails = emailManager.getEmails(orcid);
246249

247-
passwordChecklistValidate(oneTimeResetPasswordForm.getRetypedPassword(), oneTimeResetPasswordForm.getPassword(), emails);
248-
if (!oneTimeResetPasswordForm.getPassword().getErrors().isEmpty() || !oneTimeResetPasswordForm.getRetypedPassword().getErrors().isEmpty()) {
250+
passwordChecklistValidate(oneTimeResetPasswordForm.getRetypedPassword(), oneTimeResetPasswordForm.getNewPassword(), emails);
251+
if (!oneTimeResetPasswordForm.getNewPassword().getErrors().isEmpty() || !oneTimeResetPasswordForm.getRetypedPassword().getErrors().isEmpty()) {
249252
return oneTimeResetPasswordForm;
250253
}
251254

252-
profileEntityManager.updatePassword(orcid, oneTimeResetPasswordForm.getPassword().getValue());
255+
profileEntityManager.updatePassword(orcid, oneTimeResetPasswordForm.getNewPassword().getValue());
253256
//reset the lock fields
254257
profileEntityManager.resetSigninLock(orcid);
255258
profileEntityCacheManager.remove(orcid);
@@ -280,7 +283,7 @@ public ModelAndView resetPasswordEmail(HttpServletRequest request, @PathVariable
280283
return oneTimeResetPasswordForm;
281284
}
282285

283-
passwordConfirmValidate(oneTimeResetPasswordForm.getRetypedPassword(), oneTimeResetPasswordForm.getPassword());
286+
passwordConfirmValidate(oneTimeResetPasswordForm.getRetypedPassword(), oneTimeResetPasswordForm.getNewPassword());
284287

285288
String orcid = null;
286289
//check first if valid orcid as the admin portal can send either and email or an orcid
@@ -299,13 +302,41 @@ public ModelAndView resetPasswordEmail(HttpServletRequest request, @PathVariable
299302
}
300303

301304
Emails emails = emailManager.getEmails(orcid);
302-
303-
passwordChecklistValidate(oneTimeResetPasswordForm.getRetypedPassword(), oneTimeResetPasswordForm.getPassword(), emails);
304-
if (!oneTimeResetPasswordForm.getPassword().getErrors().isEmpty() || !oneTimeResetPasswordForm.getRetypedPassword().getErrors().isEmpty()) {
305+
oneTimeResetPasswordForm.setOrcid(orcid);
306+
307+
passwordChecklistValidate(oneTimeResetPasswordForm.getRetypedPassword(), oneTimeResetPasswordForm.getNewPassword(), emails);
308+
if (!oneTimeResetPasswordForm.getNewPassword().getErrors().isEmpty() || !oneTimeResetPasswordForm.getRetypedPassword().getErrors().isEmpty()) {
305309
return oneTimeResetPasswordForm;
306310
}
307311

308-
profileEntityManager.updatePassword(orcid, oneTimeResetPasswordForm.getPassword().getValue());
312+
if (twoFactorAuthenticationManager.userUsing2FA(orcid)) {
313+
oneTimeResetPasswordForm.setTwoFactorEnabled(true);
314+
315+
if (oneTimeResetPasswordForm.getTwoFactorCode() == null && oneTimeResetPasswordForm.getTwoFactorRecoveryCode() == null) {
316+
oneTimeResetPasswordForm.setPassword(null);
317+
oneTimeResetPasswordForm.setRetypedPassword(null);
318+
return oneTimeResetPasswordForm;
319+
} else {
320+
if (oneTimeResetPasswordForm.getTwoFactorRecoveryCode() != null && !oneTimeResetPasswordForm.getTwoFactorRecoveryCode().isEmpty()) {
321+
if (!backupCodeManager.verify(orcid, oneTimeResetPasswordForm.getTwoFactorRecoveryCode())) {
322+
oneTimeResetPasswordForm.setInvalidTwoFactorRecoveryCode(true);
323+
return oneTimeResetPasswordForm;
324+
}
325+
}
326+
else if (oneTimeResetPasswordForm.getTwoFactorCode() != null && !oneTimeResetPasswordForm.getTwoFactorCode().isEmpty()) {
327+
if (!twoFactorAuthenticationManager.verificationCodeIsValid(oneTimeResetPasswordForm.getTwoFactorCode(), orcid)) {
328+
oneTimeResetPasswordForm.setInvalidTwoFactorCode(true);
329+
return oneTimeResetPasswordForm;
330+
}
331+
}
332+
else {
333+
oneTimeResetPasswordForm.setInvalidTwoFactorCode(true);
334+
return oneTimeResetPasswordForm;
335+
}
336+
}
337+
}
338+
339+
profileEntityManager.updatePassword(orcid, oneTimeResetPasswordForm.getNewPassword().getValue());
309340
//send the security notification email on change password
310341
if(Features.SEND_EMAIL_ON_RESET_PASSWORD.isActive()) {
311342
recordEmailSender.sendOrcidSecurityResetPasswordEmail(orcid);

orcid-web/src/main/java/org/orcid/frontend/web/forms/OneTimeResetPasswordForm.java

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22

33
import java.util.List;
44

5-
import org.orcid.pojo.ajaxForm.ErrorsInterface;
5+
import org.orcid.pojo.AuthChallenge;
66
import org.orcid.pojo.ajaxForm.Text;
77

8-
public class OneTimeResetPasswordForm implements ErrorsInterface {
8+
public class OneTimeResetPasswordForm extends AuthChallenge {
99

10-
private Text password;
10+
private String orcid;
11+
12+
private Text newPassword;
1113

1214
private Text retypedPassword;
1315

@@ -17,15 +19,23 @@ public class OneTimeResetPasswordForm implements ErrorsInterface {
1719

1820
private List<String> errors;
1921

20-
public Text getPassword() {
21-
if (password == null) {
22-
password = new Text();
22+
public Text getNewPassword() {
23+
if (newPassword == null) {
24+
newPassword = new Text();
2325
}
24-
return password;
26+
return newPassword;
27+
}
28+
29+
public void setNewPassword(Text newPassword) {
30+
this.newPassword = newPassword;
31+
}
32+
33+
public String getOrcid() {
34+
return orcid;
2535
}
2636

27-
public void setPassword(Text password) {
28-
this.password = password;
37+
public void setOrcid(String orcid) {
38+
this.orcid = orcid;
2939
}
3040

3141
public Text getRetypedPassword() {

0 commit comments

Comments
 (0)