diff --git a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/internal/impl/UserSessionManagementServiceImpl.java b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/internal/impl/UserSessionManagementServiceImpl.java index 2969470a97c6..1dd9fee0259d 100644 --- a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/internal/impl/UserSessionManagementServiceImpl.java +++ b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/internal/impl/UserSessionManagementServiceImpl.java @@ -39,6 +39,7 @@ import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkUtils; import org.wso2.carbon.identity.application.authentication.framework.util.SessionMgtConstants; import org.wso2.carbon.identity.application.common.model.User; +import org.wso2.carbon.identity.core.util.IdentityUtil; import org.wso2.carbon.user.api.UserStoreException; import org.wso2.carbon.user.core.service.RealmService; import org.wso2.carbon.user.api.UserStoreManager; @@ -48,6 +49,11 @@ import java.util.ArrayList; import java.util.List; +import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants. + CURRENT_SESSION_IDENTIFIER; +import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.Config. + PRESERVE_LOGGED_IN_SESSION_AT_PASSWORD_UPDATE; + /** * This a service class used to manage user sessions. */ @@ -176,8 +182,27 @@ public boolean terminateSessionsByUserId(String userId) throws SessionManagement null); } List sessionIdList = getSessionIdListByUserId(userId); + + boolean isSessionPreservingAtPasswordUpdateEnabled = + Boolean.parseBoolean(IdentityUtil.getProperty(PRESERVE_LOGGED_IN_SESSION_AT_PASSWORD_UPDATE)); + String currentSessionId = ""; + boolean isSessionTerminationSkipped = false; + if (isSessionPreservingAtPasswordUpdateEnabled) { + if (IdentityUtil.threadLocalProperties.get().get(CURRENT_SESSION_IDENTIFIER) != null) { + currentSessionId = (String) IdentityUtil.threadLocalProperties.get().get(CURRENT_SESSION_IDENTIFIER); + } + // Remove current sessionId from the list so that its termination is bypassed. + if (sessionIdList.remove(currentSessionId)) { + isSessionTerminationSkipped = true; + } + } + if (log.isDebugEnabled()) { - log.debug("Terminating all the active sessions of user: " + userId + "."); + if (isSessionTerminationSkipped) { + log.debug("Terminating the active sessions of user: " + userId + "except the current session."); + } else { + log.debug("Terminating all the active sessions of user: " + userId + "."); + } } terminateSessionsOfUser(sessionIdList); if (!sessionIdList.isEmpty()) { diff --git a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/FrameworkConstants.java b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/FrameworkConstants.java index 627a5545632a..569b60db0ba5 100644 --- a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/FrameworkConstants.java +++ b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/FrameworkConstants.java @@ -133,6 +133,9 @@ public abstract class FrameworkConstants { public static final String FEDERATED_IDP_ROLE_CLAIM_VALUE_SEPARATOR = "FederatedIDPRoleClaimValueAttributeSeparator"; + // Current session thread local identifier. + public static final String CURRENT_SESSION_IDENTIFIER = "currentSessionIdentifier"; + private FrameworkConstants() { } @@ -231,6 +234,13 @@ public static class Config { */ public static final String PUBLISH_ACTIVE_SESSION_COUNT = "Analytics.PublishActiveSessionCount"; + /** + * Configuration to enable preserving user from being logged out at password update by skipping current + * session and token from being terminated. + */ + public static final String PRESERVE_LOGGED_IN_SESSION_AT_PASSWORD_UPDATE = + "PasswordUpdate.PreserveLoggedInSession"; + private Config() { } diff --git a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/identity.xml.j2 b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/identity.xml.j2 index 42a027bfa55a..6d4b755db029 100644 --- a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/identity.xml.j2 +++ b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/identity.xml.j2 @@ -2370,4 +2370,9 @@ {% endfor %} {% endif %} + + + + {{identity_mgt.password_update.preserve_logged_in_session}} + diff --git a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/org.wso2.carbon.identity.core.server.feature.default.json b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/org.wso2.carbon.identity.core.server.feature.default.json index ff1183bee3f5..4f553be210d9 100644 --- a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/org.wso2.carbon.identity.core.server.feature.default.json +++ b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/org.wso2.carbon.identity.core.server.feature.default.json @@ -297,6 +297,8 @@ "identity_mgt.password_reset_by_admin.enable_emailed_otp_based_reset": false, "identity_mgt.password_reset_by_admin.enable_offline_otp_based_reset": false, + "identity_mgt.password_update.preserve_logged_in_session": false, + "identity_mgt.username_recovery.email.enable_username_recovery": false, "identity_mgt.username_recovery.email.enable_recaptcha": false, diff --git a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/org.wso2.carbon.identity.core.server.feature.key-mappings.json b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/org.wso2.carbon.identity.core.server.feature.key-mappings.json index 194fe9f0b2bf..abdf8f976b2e 100644 --- a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/org.wso2.carbon.identity.core.server.feature.key-mappings.json +++ b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/org.wso2.carbon.identity.core.server.feature.key-mappings.json @@ -3,5 +3,6 @@ "scim.authentication_handler.oauth.properties.priority": "scim.authentication_handler.oauth.properties.Priority", "scim.authentication_handler.oauth.properties.authorization_server": "scim.authentication_handler.oauth.properties.AuthorizationServer", "scim.authentication_handler.oauth.properties.username": "scim.authentication_handler.oauth.properties.UserName", - "scim.authentication_handler.oauth.properties.password": "scim.authentication_handler.oauth.properties.Password" + "scim.authentication_handler.oauth.properties.password": "scim.authentication_handler.oauth.properties.Password", + "password_update.preserve_logged_in_session": "identity_mgt.password_update.preserve_logged_in_session" }