From 21dc981b35a6068ca16a03ac0b379ef356989c50 Mon Sep 17 00:00:00 2001 From: dhaura Date: Fri, 31 May 2024 17:09:52 +0530 Subject: [PATCH 1/5] If recovery scenario is ASK_PASSWORD, update thread local properties specifying the flow is password set. --- .../password/NotificationPasswordRecoveryManager.java | 8 ++++++++ pom.xml | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/password/NotificationPasswordRecoveryManager.java b/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/password/NotificationPasswordRecoveryManager.java index 195414b47d..0b9ca49f9c 100644 --- a/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/password/NotificationPasswordRecoveryManager.java +++ b/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/password/NotificationPasswordRecoveryManager.java @@ -935,6 +935,14 @@ private HashMap getAccountStateClaims(UserRecoveryData userRecov userClaims.put(IdentityRecoveryConstants.ACCOUNT_LOCKED_CLAIM, Boolean.FALSE.toString()); } + // If the recovery scenario is ASK_PASSWORD, it indicates a password set flow. + // Hence, update the thread-local properties to specify that this is a password set flow. + if (RecoveryScenarios.ASK_PASSWORD.equals(recoveryScenario)) { + IdentityUtil.threadLocalProperties.get().put(AccountConstants.PASSWORD_SET_FLOW, true); + } else { + IdentityUtil.threadLocalProperties.get().put(AccountConstants.PASSWORD_SET_FLOW, false); + } + // If the scenario is initiated by the admin, set the account locked claim to FALSE. if (RecoveryScenarios.ADMIN_FORCED_PASSWORD_RESET_VIA_EMAIL_LINK.equals(recoveryScenario) || RecoveryScenarios.ADMIN_FORCED_PASSWORD_RESET_VIA_OTP.equals(recoveryScenario) diff --git a/pom.xml b/pom.xml index 91e7a26617..5f799d1d2e 100644 --- a/pom.xml +++ b/pom.xml @@ -700,7 +700,7 @@ - 1.9.4 + 1.9.5 [1.1.12, 2.0.0) From 0757aa6c7ced56ec6872f2f56b23d6cb25d11297 Mon Sep 17 00:00:00 2001 From: dhaura Date: Mon, 3 Jun 2024 16:10:50 +0530 Subject: [PATCH 2/5] Remove PasswordSetFlow from local thread properties. --- .../NotificationPasswordRecoveryManager.java | 90 ++++++++++--------- 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/password/NotificationPasswordRecoveryManager.java b/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/password/NotificationPasswordRecoveryManager.java index 0b9ca49f9c..ad5bbfc252 100644 --- a/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/password/NotificationPasswordRecoveryManager.java +++ b/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/password/NotificationPasswordRecoveryManager.java @@ -627,53 +627,57 @@ public User updateUserPassword(String code, String password, Property[] properti String domainQualifiedName = IdentityUtil.addDomainToName(userRecoveryData.getUser().getUserName(), userRecoveryData.getUser().getUserStoreDomain()); - // Update the password. - updateNewPassword(userRecoveryData.getUser(), password, domainQualifiedName, userRecoveryData, - notificationsInternallyManaged); - if (recoveryFlowId != null) { - userRecoveryDataStore.invalidateWithRecoveryFlowId(recoveryFlowId); - } else { - userRecoveryDataStore.invalidate(userRecoveryData.getUser()); - } - if (notificationsInternallyManaged && - !NotificationChannels.EXTERNAL_CHANNEL.getChannelType().equals(notificationChannel)) { - String emailTemplate = null; - if (isAskPasswordFlow(userRecoveryData) && - isAskPasswordEmailTemplateTypeExists(userRecoveryData.getUser().getTenantDomain())) { - if (isNotificationSendOnAccountActivation) { - emailTemplate = IdentityRecoveryConstants.ACCOUNT_ACTIVATION_SUCCESS; - } - } else if (isNotificationSendWhenSuccess) { - emailTemplate = IdentityRecoveryConstants.NOTIFICATION_TYPE_PASSWORD_RESET_SUCCESS; + try { + // Update the password. + updateNewPassword(userRecoveryData.getUser(), password, domainQualifiedName, userRecoveryData, + notificationsInternallyManaged); + if (recoveryFlowId != null) { + userRecoveryDataStore.invalidateWithRecoveryFlowId(recoveryFlowId); + } else { + userRecoveryDataStore.invalidate(userRecoveryData.getUser()); } - try { - String eventName = Utils.resolveEventName(notificationChannel); - if (StringUtils.isNotBlank(emailTemplate)) { - triggerNotification(userRecoveryData.getUser(), notificationChannel, emailTemplate, - StringUtils.EMPTY, eventName, properties, userRecoveryData); + if (notificationsInternallyManaged && + !NotificationChannels.EXTERNAL_CHANNEL.getChannelType().equals(notificationChannel)) { + String emailTemplate = null; + if (isAskPasswordFlow(userRecoveryData) && + isAskPasswordEmailTemplateTypeExists(userRecoveryData.getUser().getTenantDomain())) { + if (isNotificationSendOnAccountActivation) { + emailTemplate = IdentityRecoveryConstants.ACCOUNT_ACTIVATION_SUCCESS; + } + } else if (isNotificationSendWhenSuccess) { + emailTemplate = IdentityRecoveryConstants.NOTIFICATION_TYPE_PASSWORD_RESET_SUCCESS; + } + try { + String eventName = Utils.resolveEventName(notificationChannel); + if (StringUtils.isNotBlank(emailTemplate)) { + triggerNotification(userRecoveryData.getUser(), notificationChannel, emailTemplate, + StringUtils.EMPTY, eventName, properties, userRecoveryData); + } + } catch (IdentityRecoveryException e) { + String errorMsg = String.format("Error while sending password reset success notification to user : %s", + userRecoveryData.getUser().getUserName()); + log.error(errorMsg); + String recoveryScenario = userRecoveryData.getRecoveryScenario().name(); + String recoveryStep = userRecoveryData.getRecoveryStep().name(); + auditPasswordReset(userRecoveryData.getUser(), AuditConstants.ACTION_PASSWORD_RESET, errorMsg, + FrameworkConstants.AUDIT_SUCCESS, recoveryScenario, recoveryStep); } - } catch (IdentityRecoveryException e) { - String errorMsg = String.format("Error while sending password reset success notification to user : %s", - userRecoveryData.getUser().getUserName()); - log.error(errorMsg); - String recoveryScenario = userRecoveryData.getRecoveryScenario().name(); - String recoveryStep = userRecoveryData.getRecoveryStep().name(); - auditPasswordReset(userRecoveryData.getUser(), AuditConstants.ACTION_PASSWORD_RESET, errorMsg, - FrameworkConstants.AUDIT_SUCCESS, recoveryScenario, recoveryStep); } - } - publishEvent(userRecoveryData.getUser(), null, code, password, properties, - IdentityEventConstants.Event.POST_ADD_NEW_PASSWORD, userRecoveryData); - if (log.isDebugEnabled()) { - String msg = "Password is updated for user: " + domainQualifiedName; - log.debug(msg); - } - String recoveryScenario = userRecoveryData.getRecoveryScenario().name(); - String recoveryStep = userRecoveryData.getRecoveryStep().name(); - auditPasswordReset(userRecoveryData.getUser(), AuditConstants.ACTION_PASSWORD_RESET, null, - FrameworkConstants.AUDIT_SUCCESS, recoveryScenario, recoveryStep); + publishEvent(userRecoveryData.getUser(), null, code, password, properties, + IdentityEventConstants.Event.POST_ADD_NEW_PASSWORD, userRecoveryData); + if (log.isDebugEnabled()) { + String msg = "Password is updated for user: " + domainQualifiedName; + log.debug(msg); + } + String recoveryScenario = userRecoveryData.getRecoveryScenario().name(); + String recoveryStep = userRecoveryData.getRecoveryStep().name(); + auditPasswordReset(userRecoveryData.getUser(), AuditConstants.ACTION_PASSWORD_RESET, null, + FrameworkConstants.AUDIT_SUCCESS, recoveryScenario, recoveryStep); - return userRecoveryData.getUser(); + return userRecoveryData.getUser(); + } finally { + IdentityUtil.threadLocalProperties.get().remove(AccountConstants.PASSWORD_SET_FLOW); + } } /** From de1c7a9263dc2bead527d5763871e5a35fa0f2ff Mon Sep 17 00:00:00 2001 From: dhaura Date: Mon, 3 Jun 2024 17:35:17 +0530 Subject: [PATCH 3/5] Improve code formatting. --- .../password/NotificationPasswordRecoveryManager.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/password/NotificationPasswordRecoveryManager.java b/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/password/NotificationPasswordRecoveryManager.java index ad5bbfc252..660f5f7724 100644 --- a/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/password/NotificationPasswordRecoveryManager.java +++ b/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/password/NotificationPasswordRecoveryManager.java @@ -589,7 +589,6 @@ public void updatePassword(String code, String confirmationCode, String password public User updateUserPassword(String code, String password, Property[] properties) throws IdentityRecoveryException, IdentityEventException { - UserRecoveryDataStore userRecoveryDataStore = JDBCRecoveryDataStore.getInstance(); UserRecoveryData userRecoveryData; try { @@ -654,8 +653,9 @@ public User updateUserPassword(String code, String password, Property[] properti StringUtils.EMPTY, eventName, properties, userRecoveryData); } } catch (IdentityRecoveryException e) { - String errorMsg = String.format("Error while sending password reset success notification to user : %s", - userRecoveryData.getUser().getUserName()); + String errorMsg = + String.format("Error while sending password reset success notification to user : %s", + userRecoveryData.getUser().getUserName()); log.error(errorMsg); String recoveryScenario = userRecoveryData.getRecoveryScenario().name(); String recoveryStep = userRecoveryData.getRecoveryStep().name(); @@ -675,7 +675,7 @@ public User updateUserPassword(String code, String password, Property[] properti FrameworkConstants.AUDIT_SUCCESS, recoveryScenario, recoveryStep); return userRecoveryData.getUser(); - } finally { + } finally { IdentityUtil.threadLocalProperties.get().remove(AccountConstants.PASSWORD_SET_FLOW); } } From 66219cef153745cb33c5ac8a082db4facaf2ac3d Mon Sep 17 00:00:00 2001 From: dhaura Date: Mon, 3 Jun 2024 18:02:01 +0530 Subject: [PATCH 4/5] Make clearance of PASSWORD_SET_FLOW thread local property more fine-grained. --- .../NotificationPasswordRecoveryManager.java | 93 +++++++++---------- 1 file changed, 45 insertions(+), 48 deletions(-) diff --git a/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/password/NotificationPasswordRecoveryManager.java b/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/password/NotificationPasswordRecoveryManager.java index 660f5f7724..f88cba9525 100644 --- a/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/password/NotificationPasswordRecoveryManager.java +++ b/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/password/NotificationPasswordRecoveryManager.java @@ -626,58 +626,53 @@ public User updateUserPassword(String code, String password, Property[] properti String domainQualifiedName = IdentityUtil.addDomainToName(userRecoveryData.getUser().getUserName(), userRecoveryData.getUser().getUserStoreDomain()); - try { - // Update the password. - updateNewPassword(userRecoveryData.getUser(), password, domainQualifiedName, userRecoveryData, - notificationsInternallyManaged); - if (recoveryFlowId != null) { - userRecoveryDataStore.invalidateWithRecoveryFlowId(recoveryFlowId); - } else { - userRecoveryDataStore.invalidate(userRecoveryData.getUser()); - } - if (notificationsInternallyManaged && - !NotificationChannels.EXTERNAL_CHANNEL.getChannelType().equals(notificationChannel)) { - String emailTemplate = null; - if (isAskPasswordFlow(userRecoveryData) && - isAskPasswordEmailTemplateTypeExists(userRecoveryData.getUser().getTenantDomain())) { - if (isNotificationSendOnAccountActivation) { - emailTemplate = IdentityRecoveryConstants.ACCOUNT_ACTIVATION_SUCCESS; - } - } else if (isNotificationSendWhenSuccess) { - emailTemplate = IdentityRecoveryConstants.NOTIFICATION_TYPE_PASSWORD_RESET_SUCCESS; - } - try { - String eventName = Utils.resolveEventName(notificationChannel); - if (StringUtils.isNotBlank(emailTemplate)) { - triggerNotification(userRecoveryData.getUser(), notificationChannel, emailTemplate, - StringUtils.EMPTY, eventName, properties, userRecoveryData); - } - } catch (IdentityRecoveryException e) { - String errorMsg = - String.format("Error while sending password reset success notification to user : %s", - userRecoveryData.getUser().getUserName()); - log.error(errorMsg); - String recoveryScenario = userRecoveryData.getRecoveryScenario().name(); - String recoveryStep = userRecoveryData.getRecoveryStep().name(); - auditPasswordReset(userRecoveryData.getUser(), AuditConstants.ACTION_PASSWORD_RESET, errorMsg, - FrameworkConstants.AUDIT_SUCCESS, recoveryScenario, recoveryStep); + // Update the password. + updateNewPassword(userRecoveryData.getUser(), password, domainQualifiedName, userRecoveryData, + notificationsInternallyManaged); + if (recoveryFlowId != null) { + userRecoveryDataStore.invalidateWithRecoveryFlowId(recoveryFlowId); + } else { + userRecoveryDataStore.invalidate(userRecoveryData.getUser()); + } + if (notificationsInternallyManaged && + !NotificationChannels.EXTERNAL_CHANNEL.getChannelType().equals(notificationChannel)) { + String emailTemplate = null; + if (isAskPasswordFlow(userRecoveryData) && + isAskPasswordEmailTemplateTypeExists(userRecoveryData.getUser().getTenantDomain())) { + if (isNotificationSendOnAccountActivation) { + emailTemplate = IdentityRecoveryConstants.ACCOUNT_ACTIVATION_SUCCESS; } + } else if (isNotificationSendWhenSuccess) { + emailTemplate = IdentityRecoveryConstants.NOTIFICATION_TYPE_PASSWORD_RESET_SUCCESS; } - publishEvent(userRecoveryData.getUser(), null, code, password, properties, - IdentityEventConstants.Event.POST_ADD_NEW_PASSWORD, userRecoveryData); - if (log.isDebugEnabled()) { - String msg = "Password is updated for user: " + domainQualifiedName; - log.debug(msg); + try { + String eventName = Utils.resolveEventName(notificationChannel); + if (StringUtils.isNotBlank(emailTemplate)) { + triggerNotification(userRecoveryData.getUser(), notificationChannel, emailTemplate, + StringUtils.EMPTY, eventName, properties, userRecoveryData); + } + } catch (IdentityRecoveryException e) { + String errorMsg = String.format("Error while sending password reset success notification to user : %s", + userRecoveryData.getUser().getUserName()); + log.error(errorMsg); + String recoveryScenario = userRecoveryData.getRecoveryScenario().name(); + String recoveryStep = userRecoveryData.getRecoveryStep().name(); + auditPasswordReset(userRecoveryData.getUser(), AuditConstants.ACTION_PASSWORD_RESET, errorMsg, + FrameworkConstants.AUDIT_SUCCESS, recoveryScenario, recoveryStep); } - String recoveryScenario = userRecoveryData.getRecoveryScenario().name(); - String recoveryStep = userRecoveryData.getRecoveryStep().name(); - auditPasswordReset(userRecoveryData.getUser(), AuditConstants.ACTION_PASSWORD_RESET, null, - FrameworkConstants.AUDIT_SUCCESS, recoveryScenario, recoveryStep); - - return userRecoveryData.getUser(); - } finally { - IdentityUtil.threadLocalProperties.get().remove(AccountConstants.PASSWORD_SET_FLOW); } + publishEvent(userRecoveryData.getUser(), null, code, password, properties, + IdentityEventConstants.Event.POST_ADD_NEW_PASSWORD, userRecoveryData); + if (log.isDebugEnabled()) { + String msg = "Password is updated for user: " + domainQualifiedName; + log.debug(msg); + } + String recoveryScenario = userRecoveryData.getRecoveryScenario().name(); + String recoveryStep = userRecoveryData.getRecoveryStep().name(); + auditPasswordReset(userRecoveryData.getUser(), AuditConstants.ACTION_PASSWORD_RESET, null, + FrameworkConstants.AUDIT_SUCCESS, recoveryScenario, recoveryStep); + + return userRecoveryData.getUser(); } /** @@ -888,6 +883,8 @@ private void updateNewPassword(User user, String password, String domainQualifie + "for the user: " + domainQualifiedName, e); } throw Utils.handleServerException(IdentityRecoveryConstants.ErrorMessages.ERROR_CODE_UNEXPECTED, null, e); + } finally { + IdentityUtil.threadLocalProperties.get().remove(AccountConstants.PASSWORD_SET_FLOW); } } From 4d87d00b6c135f127995dd8f02c35ae756692387 Mon Sep 17 00:00:00 2001 From: dhaura Date: Tue, 4 Jun 2024 16:49:41 +0530 Subject: [PATCH 5/5] Clear ADMIN_INITIATED thread local property. --- .../recovery/password/NotificationPasswordRecoveryManager.java | 1 + 1 file changed, 1 insertion(+) diff --git a/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/password/NotificationPasswordRecoveryManager.java b/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/password/NotificationPasswordRecoveryManager.java index f88cba9525..9afc423a52 100644 --- a/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/password/NotificationPasswordRecoveryManager.java +++ b/components/org.wso2.carbon.identity.recovery/src/main/java/org/wso2/carbon/identity/recovery/password/NotificationPasswordRecoveryManager.java @@ -884,6 +884,7 @@ private void updateNewPassword(User user, String password, String domainQualifie } throw Utils.handleServerException(IdentityRecoveryConstants.ErrorMessages.ERROR_CODE_UNEXPECTED, null, e); } finally { + IdentityUtil.threadLocalProperties.get().remove(AccountConstants.ADMIN_INITIATED); IdentityUtil.threadLocalProperties.get().remove(AccountConstants.PASSWORD_SET_FLOW); } }