From 221c30dd8b0276263bb1c07e852aa32e994cfa78 Mon Sep 17 00:00:00 2001 From: ThaminduDilshan Date: Wed, 10 Apr 2024 11:40:30 +0000 Subject: [PATCH 1/9] Adding initial commit of pw migration utils - backup --- .../user/UpdateUserPasswordFunction.java | 30 +++++++++++++ .../user/UpdateUserPasswordFunctionImpl.java | 45 +++++++++++++++++++ .../pom.xml | 5 +++ ...esolveMultiAttributeLoginUserFunction.java | 30 +++++++++++++ ...veMultiAttributeLoginUserFunctionImpl.java | 34 ++++++++++++++ .../UtilsFunctionServiceComponent.java | 9 ++++ pom.xml | 5 +++ 7 files changed, 158 insertions(+) create mode 100644 components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunction.java create mode 100644 components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImpl.java create mode 100644 components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginUserFunction.java create mode 100644 components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginUserFunctionImpl.java diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunction.java b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunction.java new file mode 100644 index 00000000..f0f1b58f --- /dev/null +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunction.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.conditional.auth.functions.user; + +import org.wso2.carbon.identity.application.authentication.framework.exception.FrameworkException; + +/** + * Function to update user password. + */ +@FunctionalInterface +public interface UpdateUserPasswordFunction { + + void updateUserPassword(String username, String newPassword, String tenantDomain) throws FrameworkException; +} diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImpl.java b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImpl.java new file mode 100644 index 00000000..145eec13 --- /dev/null +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImpl.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.conditional.auth.functions.user; + +import org.apache.commons.lang.StringUtils; +import org.wso2.carbon.identity.application.authentication.framework.exception.FrameworkException; + +/** + * Function to update user password. + */ +public class UpdateUserPasswordFunctionImpl implements UpdateUserPasswordFunction { + + @Override + public void updateUserPassword(String username, String newPassword, String tenantDomain) + throws FrameworkException { + + if (StringUtils.isBlank(username)) { + throw new FrameworkException("Username cannot be empty."); + } + if (StringUtils.isBlank(newPassword)) { + throw new FrameworkException("The password cannot be empty."); + } + if (StringUtils.isBlank(tenantDomain)) { + throw new FrameworkException("Tenant domain cannot be empty."); + } + + // Update user password + } +} diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/pom.xml b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/pom.xml index 5fddbd63..90827909 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/pom.xml +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/pom.xml @@ -40,6 +40,10 @@ org.wso2.carbon.identity.framework org.wso2.carbon.identity.application.authentication.framework + + org.wso2.carbon.identity.framework + org.wso2.carbon.identity.multi.attribute.login.mgt + @@ -69,6 +73,7 @@ org.osgi.service.component; version="${org.osgi.service.imp.pkg.version.range}", org.wso2.carbon.identity.application.authentication.framework; version="${carbon.identity.package.import.version.range}", org.wso2.carbon.identity.application.authentication.framework.util; version="${carbon.identity.package.import.version.range}", + org.wso2.carbon.identity.multi.attribute.login.mgt; version="${carbon.identity.package.import.version.range}", diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginUserFunction.java b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginUserFunction.java new file mode 100644 index 00000000..2190e544 --- /dev/null +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginUserFunction.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.conditional.auth.functions.utils; + +import org.wso2.carbon.identity.multi.attribute.login.mgt.ResolvedUserResult; + +/** + * Function to resolve user from multi attribute login identifier. + */ +@FunctionalInterface +public interface ResolveMultiAttributeLoginUserFunction { + + ResolvedUserResult resolveMultiAttributeLoginUser(String loginIdentifier, String tenantDomain); +} diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginUserFunctionImpl.java b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginUserFunctionImpl.java new file mode 100644 index 00000000..afcf249d --- /dev/null +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginUserFunctionImpl.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.conditional.auth.functions.utils; + +import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkUtils; +import org.wso2.carbon.identity.multi.attribute.login.mgt.ResolvedUserResult; + +/** + * Function to resolve user from multi attribute login identifier. + */ +public class ResolveMultiAttributeLoginUserFunctionImpl implements ResolveMultiAttributeLoginUserFunction { + + @Override + public ResolvedUserResult resolveMultiAttributeLoginUser(String loginIdentifier, String tenantDomain) { + + return FrameworkUtils.processMultiAttributeLoginIdentification(loginIdentifier, tenantDomain); + } +} diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/internal/UtilsFunctionServiceComponent.java b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/internal/UtilsFunctionServiceComponent.java index 15e3e8cb..8f4d307a 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/internal/UtilsFunctionServiceComponent.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/internal/UtilsFunctionServiceComponent.java @@ -28,6 +28,8 @@ import org.wso2.carbon.identity.application.authentication.framework.JsFunctionRegistry; import org.wso2.carbon.identity.conditional.auth.functions.utils.FilterAuthenticatorsFunction; import org.wso2.carbon.identity.conditional.auth.functions.utils.FilterAuthenticatorsFunctionImpl; +import org.wso2.carbon.identity.conditional.auth.functions.utils.ResolveMultiAttributeLoginUserFunction; +import org.wso2.carbon.identity.conditional.auth.functions.utils.ResolveMultiAttributeLoginUserFunctionImpl; /** * OSGi declarative services component which handles registration and de-registration of utils related @@ -46,6 +48,11 @@ protected void activate(ComponentContext ctxt) { JsFunctionRegistry jsFunctionRegistry = UtilsFunctionServiceHolder.getInstance().getJsFunctionRegistry(); jsFunctionRegistry.register(JsFunctionRegistry.Subsystem.SEQUENCE_HANDLER, "filterAuthenticators", filterAuthenticatorsFunctionImpl); + + ResolveMultiAttributeLoginUserFunction resolveMultiAttributeLoginUserFunctionImpl = + new ResolveMultiAttributeLoginUserFunctionImpl(); + jsFunctionRegistry.register(JsFunctionRegistry.Subsystem.SEQUENCE_HANDLER, "resolveMultiAttributeLoginUser", + resolveMultiAttributeLoginUserFunctionImpl); } @Deactivate @@ -54,6 +61,8 @@ protected void deactivate(ComponentContext ctxt) { JsFunctionRegistry jsFunctionRegistry = UtilsFunctionServiceHolder.getInstance().getJsFunctionRegistry(); if (jsFunctionRegistry != null) { jsFunctionRegistry.deRegister(JsFunctionRegistry.Subsystem.SEQUENCE_HANDLER, "filterAuthenticators"); + jsFunctionRegistry.deRegister(JsFunctionRegistry.Subsystem.SEQUENCE_HANDLER, + "resolveMultiAttributeLoginUser"); } } diff --git a/pom.xml b/pom.xml index 1ae4d143..e1279d0e 100644 --- a/pom.xml +++ b/pom.xml @@ -164,6 +164,11 @@ org.wso2.carbon.identity.secret.mgt.core ${carbon.identity.framework.version} + + org.wso2.carbon.identity.framework + org.wso2.carbon.identity.multi.attribute.login.mgt + ${carbon.identity.framework.version} + org.json.wso2 json From 67da293632315db521481ddefa3f267ba333fb78 Mon Sep 17 00:00:00 2001 From: ThaminduDilshan Date: Wed, 17 Apr 2024 13:07:01 +0530 Subject: [PATCH 2/9] Implement password update functionality --- .../user/UpdateUserPasswordFunction.java | 3 +- .../user/UpdateUserPasswordFunctionImpl.java | 36 ++++++++++++++----- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunction.java b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunction.java index f0f1b58f..957a95c1 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunction.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunction.java @@ -18,6 +18,7 @@ package org.wso2.carbon.identity.conditional.auth.functions.user; +import org.wso2.carbon.identity.application.authentication.framework.config.model.graph.js.JsAuthenticatedUser; import org.wso2.carbon.identity.application.authentication.framework.exception.FrameworkException; /** @@ -26,5 +27,5 @@ @FunctionalInterface public interface UpdateUserPasswordFunction { - void updateUserPassword(String username, String newPassword, String tenantDomain) throws FrameworkException; + void updateUserPassword(JsAuthenticatedUser user, String newPassword) throws FrameworkException; } diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImpl.java b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImpl.java index 145eec13..415da8cd 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImpl.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImpl.java @@ -19,7 +19,11 @@ package org.wso2.carbon.identity.conditional.auth.functions.user; import org.apache.commons.lang.StringUtils; +import org.wso2.carbon.identity.application.authentication.framework.config.model.graph.js.JsAuthenticatedUser; import org.wso2.carbon.identity.application.authentication.framework.exception.FrameworkException; +import org.wso2.carbon.user.core.UserRealm; +import org.wso2.carbon.user.core.UserStoreException; +import org.wso2.carbon.user.core.UserStoreManager; /** * Function to update user password. @@ -27,19 +31,35 @@ public class UpdateUserPasswordFunctionImpl implements UpdateUserPasswordFunction { @Override - public void updateUserPassword(String username, String newPassword, String tenantDomain) - throws FrameworkException { + public void updateUserPassword(JsAuthenticatedUser user, String newPassword) throws FrameworkException { - if (StringUtils.isBlank(username)) { - throw new FrameworkException("Username cannot be empty."); + if (user == null) { + throw new FrameworkException("User is not defined."); } if (StringUtils.isBlank(newPassword)) { throw new FrameworkException("The password cannot be empty."); } - if (StringUtils.isBlank(tenantDomain)) { - throw new FrameworkException("Tenant domain cannot be empty."); - } - // Update user password + try { + if (user.getWrapped() != null) { + String tenantDomain = user.getWrapped().getTenantDomain(); + String userStoreDomain = user.getWrapped().getUserStoreDomain(); + String username = user.getWrapped().getUserName(); + UserRealm userRealm = Utils.getUserRealm(tenantDomain); + + if (userRealm != null) { + UserStoreManager userStoreManager = Utils.getUserStoreManager( + tenantDomain, userRealm, userStoreDomain); + userStoreManager.updateCredentialByAdmin(username, newPassword); + } else { + throw new FrameworkException(String.format("Unable to find user realm for the user: %s " + + "in tenant: %s", username, tenantDomain)); + } + } else { + throw new FrameworkException("Unable to get wrapped content for the user."); + } + } catch (UserStoreException e) { + throw new FrameworkException("Error while updating the user password.", e); + } } } From 794e02a512cf4b51c47b761d424cd530174a8e00 Mon Sep 17 00:00:00 2001 From: ThaminduDilshan Date: Thu, 18 Apr 2024 10:08:11 +0530 Subject: [PATCH 3/9] Add password migration claim update functionality --- .../user/UpdateUserPasswordFunction.java | 2 +- .../user/UpdateUserPasswordFunctionImpl.java | 44 ++++++++++++++++++- .../UserFunctionsServiceComponent.java | 7 +++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunction.java b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunction.java index 957a95c1..8c34588b 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunction.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunction.java @@ -27,5 +27,5 @@ @FunctionalInterface public interface UpdateUserPasswordFunction { - void updateUserPassword(JsAuthenticatedUser user, String newPassword) throws FrameworkException; + void updateUserPassword(JsAuthenticatedUser user, Object... parameters) throws FrameworkException; } diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImpl.java b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImpl.java index 415da8cd..6221600a 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImpl.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImpl.java @@ -19,6 +19,8 @@ package org.wso2.carbon.identity.conditional.auth.functions.user; import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.wso2.carbon.identity.application.authentication.framework.config.model.graph.js.JsAuthenticatedUser; import org.wso2.carbon.identity.application.authentication.framework.exception.FrameworkException; import org.wso2.carbon.user.core.UserRealm; @@ -30,12 +32,30 @@ */ public class UpdateUserPasswordFunctionImpl implements UpdateUserPasswordFunction { + private static final Log LOG = LogFactory.getLog(UpdateUserPasswordFunctionImpl.class); + @Override - public void updateUserPassword(JsAuthenticatedUser user, String newPassword) throws FrameworkException { + public void updateUserPassword(JsAuthenticatedUser user, Object... parameters) throws FrameworkException { if (user == null) { throw new FrameworkException("User is not defined."); } + if (parameters == null || parameters.length == 0) { + throw new FrameworkException("Password parameters are not defined."); + } + + String newPassword = null; + String passwordMigrationStatusClaim = null; + + if (parameters.length == 2) { + LOG.debug("Both password and password migration status claim parameters are provided."); + newPassword = (String) parameters[0]; + passwordMigrationStatusClaim = (String) parameters[1]; + } else { + LOG.debug("Only the new password is provided."); + newPassword = (String) parameters[0]; + } + if (StringUtils.isBlank(newPassword)) { throw new FrameworkException("The password cannot be empty."); } @@ -50,7 +70,29 @@ public void updateUserPassword(JsAuthenticatedUser user, String newPassword) thr if (userRealm != null) { UserStoreManager userStoreManager = Utils.getUserStoreManager( tenantDomain, userRealm, userStoreDomain); + + // Check for password migration status only if the claim is present. + if (StringUtils.isNotBlank(passwordMigrationStatusClaim)) { + String passwordMigrationStatus = userStoreManager.getUserClaimValue( + username, passwordMigrationStatusClaim, null); + LOG.debug("Password migration status for the user: " + username + " in tenant: " + + tenantDomain + " is: " + passwordMigrationStatus); + + if (Boolean.parseBoolean(passwordMigrationStatus)) { + throw new FrameworkException("Password migration has already been completed for the " + + "user: " + username + " in tenant: " + tenantDomain); + } + } + + // Update the user password. userStoreManager.updateCredentialByAdmin(username, newPassword); + + // Update the password migration status claim. + if (StringUtils.isNotBlank(passwordMigrationStatusClaim)) { + LOG.debug("Updating the password migration status for the user: " + username + + " in tenant: " + tenantDomain + " to true."); + userStoreManager.setUserClaimValue(username, passwordMigrationStatusClaim, "true", null); + } } else { throw new FrameworkException(String.format("Unable to find user realm for the user: %s " + "in tenant: %s", username, tenantDomain)); diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/internal/UserFunctionsServiceComponent.java b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/internal/UserFunctionsServiceComponent.java index 7ad30c96..1021069f 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/internal/UserFunctionsServiceComponent.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/internal/UserFunctionsServiceComponent.java @@ -59,6 +59,8 @@ import org.wso2.carbon.identity.conditional.auth.functions.user.TerminateUserSessionImpl; import org.wso2.carbon.identity.conditional.auth.functions.user.SetAccountAssociationToLocalUserImpl; import org.wso2.carbon.identity.conditional.auth.functions.user.SetAccountAssociationToLocalUser; +import org.wso2.carbon.identity.conditional.auth.functions.user.UpdateUserPasswordFunction; +import org.wso2.carbon.identity.conditional.auth.functions.user.UpdateUserPasswordFunctionImpl; import org.wso2.carbon.identity.role.v2.mgt.core.RoleManagementService; import org.wso2.carbon.idp.mgt.IdpManager; import org.wso2.carbon.user.core.service.RealmService; @@ -91,6 +93,8 @@ protected void activate(ComponentContext ctxt) { SetAccountAssociationToLocalUser setAccountAssociationToLocalUserImpl = new SetAccountAssociationToLocalUserImpl(); GetAuthenticatedApplicationsFunction getAuthenticatedApplicationsFunctionImp = new GetAuthenticatedAppsFuncImp(); MicrosoftEmailVerificationFunction microsoftEmailVerificationFunction = new MicrosoftEmailVerificationFunctionImpl(); + UpdateUserPasswordFunction updateUserPasswordFunction = new UpdateUserPasswordFunctionImpl(); + JsFunctionRegistry jsFunctionRegistry = UserFunctionsServiceHolder.getInstance().getJsFunctionRegistry(); jsFunctionRegistry.register(JsFunctionRegistry.Subsystem.SEQUENCE_HANDLER, "hasRole", hasRoleFunctionImpl); jsFunctionRegistry.register(JsFunctionRegistry.Subsystem.SEQUENCE_HANDLER, "hasAnyOfTheRoles", @@ -125,6 +129,8 @@ protected void activate(ComponentContext ctxt) { getAuthenticatedApplicationsFunctionImp); jsFunctionRegistry.register(JsFunctionRegistry.Subsystem.SEQUENCE_HANDLER, "checkMicrosoftEmailVerification", microsoftEmailVerificationFunction); + jsFunctionRegistry.register(JsFunctionRegistry.Subsystem.SEQUENCE_HANDLER, "updateUserPassword", + updateUserPasswordFunction); } catch (Throwable e) { LOG.error("Error occurred during conditional authentication user functions bundle activation. ", e); } @@ -149,6 +155,7 @@ protected void deactivate(ComponentContext ctxt) { jsFunctionRegistry.deRegister(JsFunctionRegistry.Subsystem.SEQUENCE_HANDLER, "doAssociationWithLocalUser"); jsFunctionRegistry.deRegister(JsFunctionRegistry.Subsystem.SEQUENCE_HANDLER, "isAnyOfTheRolesAssignedToUser"); jsFunctionRegistry.deRegister(JsFunctionRegistry.Subsystem.SEQUENCE_HANDLER, "checkMicrosoftEmailVerification"); + jsFunctionRegistry.deRegister(JsFunctionRegistry.Subsystem.SEQUENCE_HANDLER, "updateUserPassword"); } } From dd5da37e95e011552ded549fe293b3dc0f94c130 Mon Sep 17 00:00:00 2001 From: ThaminduDilshan Date: Fri, 19 Apr 2024 08:26:43 +0530 Subject: [PATCH 4/9] Fix minor issues with the functions --- .../pom.xml | 5 +++++ ...olveMultiAttributeLoginIdentifierFunction.java} | 8 +++----- ...MultiAttributeLoginIdentifierFunctionImpl.java} | 13 ++++++++++--- .../internal/UtilsFunctionServiceComponent.java | 14 +++++++------- 4 files changed, 25 insertions(+), 15 deletions(-) rename components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/{ResolveMultiAttributeLoginUserFunction.java => ResolveMultiAttributeLoginIdentifierFunction.java} (71%) rename components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/{ResolveMultiAttributeLoginUserFunctionImpl.java => ResolveMultiAttributeLoginIdentifierFunctionImpl.java} (60%) diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/pom.xml b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/pom.xml index 90827909..3b86fe0e 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/pom.xml +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/pom.xml @@ -44,6 +44,10 @@ org.wso2.carbon.identity.framework org.wso2.carbon.identity.multi.attribute.login.mgt + + org.wso2.carbon + org.wso2.carbon.user.core + @@ -74,6 +78,7 @@ org.wso2.carbon.identity.application.authentication.framework; version="${carbon.identity.package.import.version.range}", org.wso2.carbon.identity.application.authentication.framework.util; version="${carbon.identity.package.import.version.range}", org.wso2.carbon.identity.multi.attribute.login.mgt; version="${carbon.identity.package.import.version.range}", + org.wso2.carbon.user.core.common; version="${carbon.kernel.package.import.version.range}", diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginUserFunction.java b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginIdentifierFunction.java similarity index 71% rename from components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginUserFunction.java rename to components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginIdentifierFunction.java index 2190e544..e8b30f55 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginUserFunction.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginIdentifierFunction.java @@ -18,13 +18,11 @@ package org.wso2.carbon.identity.conditional.auth.functions.utils; -import org.wso2.carbon.identity.multi.attribute.login.mgt.ResolvedUserResult; - /** - * Function to resolve user from multi attribute login identifier. + * Function to resolve username from the multi attribute login identifier. */ @FunctionalInterface -public interface ResolveMultiAttributeLoginUserFunction { +public interface ResolveMultiAttributeLoginIdentifierFunction { - ResolvedUserResult resolveMultiAttributeLoginUser(String loginIdentifier, String tenantDomain); + String resolveMultiAttributeLoginIdentifier(String loginIdentifier, String tenantDomain); } diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginUserFunctionImpl.java b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginIdentifierFunctionImpl.java similarity index 60% rename from components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginUserFunctionImpl.java rename to components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginIdentifierFunctionImpl.java index afcf249d..776053e2 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginUserFunctionImpl.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginIdentifierFunctionImpl.java @@ -24,11 +24,18 @@ /** * Function to resolve user from multi attribute login identifier. */ -public class ResolveMultiAttributeLoginUserFunctionImpl implements ResolveMultiAttributeLoginUserFunction { +public class ResolveMultiAttributeLoginIdentifierFunctionImpl implements ResolveMultiAttributeLoginIdentifierFunction { @Override - public ResolvedUserResult resolveMultiAttributeLoginUser(String loginIdentifier, String tenantDomain) { + public String resolveMultiAttributeLoginIdentifier(String loginIdentifier, String tenantDomain) { - return FrameworkUtils.processMultiAttributeLoginIdentification(loginIdentifier, tenantDomain); + ResolvedUserResult resolvedUserResult = FrameworkUtils.processMultiAttributeLoginIdentification( + loginIdentifier, tenantDomain); + + if (resolvedUserResult != null && + ResolvedUserResult.UserResolvedStatus.SUCCESS.equals(resolvedUserResult.getResolvedStatus())) { + return resolvedUserResult.getUser().getPreferredUsername(); + } + return null; } } diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/internal/UtilsFunctionServiceComponent.java b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/internal/UtilsFunctionServiceComponent.java index 8f4d307a..6db29c47 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/internal/UtilsFunctionServiceComponent.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/internal/UtilsFunctionServiceComponent.java @@ -28,8 +28,8 @@ import org.wso2.carbon.identity.application.authentication.framework.JsFunctionRegistry; import org.wso2.carbon.identity.conditional.auth.functions.utils.FilterAuthenticatorsFunction; import org.wso2.carbon.identity.conditional.auth.functions.utils.FilterAuthenticatorsFunctionImpl; -import org.wso2.carbon.identity.conditional.auth.functions.utils.ResolveMultiAttributeLoginUserFunction; -import org.wso2.carbon.identity.conditional.auth.functions.utils.ResolveMultiAttributeLoginUserFunctionImpl; +import org.wso2.carbon.identity.conditional.auth.functions.utils.ResolveMultiAttributeLoginIdentifierFunction; +import org.wso2.carbon.identity.conditional.auth.functions.utils.ResolveMultiAttributeLoginIdentifierFunctionImpl; /** * OSGi declarative services component which handles registration and de-registration of utils related @@ -49,10 +49,10 @@ protected void activate(ComponentContext ctxt) { jsFunctionRegistry.register(JsFunctionRegistry.Subsystem.SEQUENCE_HANDLER, "filterAuthenticators", filterAuthenticatorsFunctionImpl); - ResolveMultiAttributeLoginUserFunction resolveMultiAttributeLoginUserFunctionImpl = - new ResolveMultiAttributeLoginUserFunctionImpl(); - jsFunctionRegistry.register(JsFunctionRegistry.Subsystem.SEQUENCE_HANDLER, "resolveMultiAttributeLoginUser", - resolveMultiAttributeLoginUserFunctionImpl); + ResolveMultiAttributeLoginIdentifierFunction resolveMultiAttributeLoginIdentifierFunctionImpl = + new ResolveMultiAttributeLoginIdentifierFunctionImpl(); + jsFunctionRegistry.register(JsFunctionRegistry.Subsystem.SEQUENCE_HANDLER, + "resolveMultiAttributeLoginIdentifier", resolveMultiAttributeLoginIdentifierFunctionImpl); } @Deactivate @@ -62,7 +62,7 @@ protected void deactivate(ComponentContext ctxt) { if (jsFunctionRegistry != null) { jsFunctionRegistry.deRegister(JsFunctionRegistry.Subsystem.SEQUENCE_HANDLER, "filterAuthenticators"); jsFunctionRegistry.deRegister(JsFunctionRegistry.Subsystem.SEQUENCE_HANDLER, - "resolveMultiAttributeLoginUser"); + "resolveMultiAttributeLoginIdentifier"); } } From 9d7b604962bf61fde17433b1f80530c053f4d991 Mon Sep 17 00:00:00 2001 From: ThaminduDilshan Date: Mon, 22 Apr 2024 15:56:27 +0530 Subject: [PATCH 5/9] Add diagnostic logs and remove exceptions --- .../functions/common/utils/Constants.java | 2 + .../pom.xml | 17 ++ .../user/UpdateUserPasswordFunction.java | 9 +- .../user/UpdateUserPasswordFunctionImpl.java | 183 ++++++++++++++++-- ...MultiAttributeLoginIdentifierFunction.java | 7 + 5 files changed, 202 insertions(+), 16 deletions(-) diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.common/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/common/utils/Constants.java b/components/org.wso2.carbon.identity.conditional.auth.functions.common/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/common/utils/Constants.java index 1a5fb7c9..e32340d0 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.common/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/common/utils/Constants.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.common/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/common/utils/Constants.java @@ -63,6 +63,8 @@ public static class ActionIDs { public static final String RECEIVE_TOKEN = "receive-token"; public static final String RECEIVE_API_RESPONSE = "receive-api-response"; + public static final String VALIDATE_INPUT_PARAMS = "validate-input-parameters"; + public static final String UPDATE_USER_PASSWORD = "update-user-password"; } /** diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.user/pom.xml b/components/org.wso2.carbon.identity.conditional.auth.functions.user/pom.xml index 0816ac96..a8f62962 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.user/pom.xml +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.user/pom.xml @@ -85,6 +85,16 @@ org.wso2.carbon.identity.conditional.auth.functions.test.utils test + + org.wso2.carbon.identity.conditional.auth.functions + org.wso2.carbon.identity.conditional.auth.functions.common + + + org.slf4j + slf4j-jdk14 + + + com.h2database.wso2 h2-database-engine @@ -116,6 +126,10 @@ org.wso2.carbon.identity.organization.management.core org.wso2.carbon.identity.organization.management.service + + org.wso2.carbon.identity.framework + org.wso2.carbon.identity.central.log.mgt + @@ -197,6 +211,9 @@ org.wso2.carbon.identity.application.common.*; version="${carbon.identity.package.import.version.range}", com.nimbusds.jose.*; version="${nimbusds.osgi.version.range}", net.minidev.json; version="${net.minidev.json.imp.pkg.version.range}", + org.wso2.carbon.identity.central.log.mgt.utils; version="${carbon.identity.package.import.version.range}", + org.wso2.carbon.identity.conditional.auth.functions.common.utils, + org.wso2.carbon.utils;version="${carbon.kernel.package.import.version.range}", diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunction.java b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunction.java index 8c34588b..7a9540bb 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunction.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunction.java @@ -27,5 +27,12 @@ @FunctionalInterface public interface UpdateUserPasswordFunction { - void updateUserPassword(JsAuthenticatedUser user, Object... parameters) throws FrameworkException; + /** + * Update user password. + * + * @param user Authenticated user. + * @param parameters Parameters. It is mandatory to provide the new password as the first parameter. + * Then an optional local claim can be provided to hold the password update status. + */ + void updateUserPassword(JsAuthenticatedUser user, Object... parameters); } diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImpl.java b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImpl.java index 6221600a..f2e59757 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImpl.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImpl.java @@ -23,9 +23,12 @@ import org.apache.commons.logging.LogFactory; import org.wso2.carbon.identity.application.authentication.framework.config.model.graph.js.JsAuthenticatedUser; import org.wso2.carbon.identity.application.authentication.framework.exception.FrameworkException; +import org.wso2.carbon.identity.central.log.mgt.utils.LoggerUtils; +import org.wso2.carbon.identity.conditional.auth.functions.common.utils.Constants; import org.wso2.carbon.user.core.UserRealm; import org.wso2.carbon.user.core.UserStoreException; import org.wso2.carbon.user.core.UserStoreManager; +import org.wso2.carbon.utils.DiagnosticLog; /** * Function to update user password. @@ -35,13 +38,37 @@ public class UpdateUserPasswordFunctionImpl implements UpdateUserPasswordFunctio private static final Log LOG = LogFactory.getLog(UpdateUserPasswordFunctionImpl.class); @Override - public void updateUserPassword(JsAuthenticatedUser user, Object... parameters) throws FrameworkException { + public void updateUserPassword(JsAuthenticatedUser user, Object... parameters) { if (user == null) { - throw new FrameworkException("User is not defined."); + LOG.debug("User is not defined."); + if (LoggerUtils.isDiagnosticLogsEnabled()) { + DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = new DiagnosticLog.DiagnosticLogBuilder( + Constants.LogConstants.ADAPTIVE_AUTH_SERVICE, + Constants.LogConstants.ActionIDs.VALIDATE_INPUT_PARAMS + ); + diagnosticLogBuilder.resultMessage("User is not defined.") + .logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION) + .resultStatus(DiagnosticLog.ResultStatus.FAILED); + LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); + } + + return; } if (parameters == null || parameters.length == 0) { - throw new FrameworkException("Password parameters are not defined."); + LOG.debug("Password parameters are not defined."); + if (LoggerUtils.isDiagnosticLogsEnabled()) { + DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = new DiagnosticLog.DiagnosticLogBuilder( + Constants.LogConstants.ADAPTIVE_AUTH_SERVICE, + Constants.LogConstants.ActionIDs.VALIDATE_INPUT_PARAMS + ); + diagnosticLogBuilder.resultMessage("Password parameters are not defined.") + .logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION) + .resultStatus(DiagnosticLog.ResultStatus.FAILED); + LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); + } + + return; } String newPassword = null; @@ -57,7 +84,19 @@ public void updateUserPassword(JsAuthenticatedUser user, Object... parameters) t } if (StringUtils.isBlank(newPassword)) { - throw new FrameworkException("The password cannot be empty."); + LOG.debug("The provided password is empty."); + if (LoggerUtils.isDiagnosticLogsEnabled()) { + DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = new DiagnosticLog.DiagnosticLogBuilder( + Constants.LogConstants.ADAPTIVE_AUTH_SERVICE, + Constants.LogConstants.ActionIDs.VALIDATE_INPUT_PARAMS + ); + diagnosticLogBuilder.resultMessage("The provided password is empty.") + .logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION) + .resultStatus(DiagnosticLog.ResultStatus.FAILED); + LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); + } + + return; } try { @@ -65,43 +104,157 @@ public void updateUserPassword(JsAuthenticatedUser user, Object... parameters) t String tenantDomain = user.getWrapped().getTenantDomain(); String userStoreDomain = user.getWrapped().getUserStoreDomain(); String username = user.getWrapped().getUserName(); + String loggableUserId = user.getWrapped().getLoggableMaskedUserId(); UserRealm userRealm = Utils.getUserRealm(tenantDomain); if (userRealm != null) { UserStoreManager userStoreManager = Utils.getUserStoreManager( tenantDomain, userRealm, userStoreDomain); + if (userStoreManager == null) { + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("Unable to find user store manager for the " + + "user store domain: %s in tenant: %s", userStoreDomain, tenantDomain)); + } + if (LoggerUtils.isDiagnosticLogsEnabled()) { + DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = + new DiagnosticLog.DiagnosticLogBuilder( + Constants.LogConstants.ADAPTIVE_AUTH_SERVICE, + Constants.LogConstants.ActionIDs.UPDATE_USER_PASSWORD + ); + diagnosticLogBuilder.resultMessage("Unable to find user store manager for the " + + "user store domain.") + .inputParam("tenantDomain", tenantDomain) + .inputParam("userStoreDomain", userStoreDomain) + .logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION) + .resultStatus(DiagnosticLog.ResultStatus.FAILED); + LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); + } + + return; + } + // Check for password migration status only if the claim is present. if (StringUtils.isNotBlank(passwordMigrationStatusClaim)) { String passwordMigrationStatus = userStoreManager.getUserClaimValue( username, passwordMigrationStatusClaim, null); - LOG.debug("Password migration status for the user: " + username + " in tenant: " - + tenantDomain + " is: " + passwordMigrationStatus); + + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("Password migration status for the user: %s in tenant: %s is: %s", + username, tenantDomain, passwordMigrationStatus)); + } if (Boolean.parseBoolean(passwordMigrationStatus)) { - throw new FrameworkException("Password migration has already been completed for the " + - "user: " + username + " in tenant: " + tenantDomain); + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("Password migration has already been completed for the " + + "user: %s in tenant: %s", username, tenantDomain)); + } + if (LoggerUtils.isDiagnosticLogsEnabled()) { + DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = + new DiagnosticLog.DiagnosticLogBuilder( + Constants.LogConstants.ADAPTIVE_AUTH_SERVICE, + Constants.LogConstants.ActionIDs.UPDATE_USER_PASSWORD + ); + diagnosticLogBuilder.resultMessage("Password migration has already been completed " + + "for the user.").inputParam("user", loggableUserId) + .logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION) + .resultStatus(DiagnosticLog.ResultStatus.FAILED); + LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); + } + + return; } } // Update the user password. userStoreManager.updateCredentialByAdmin(username, newPassword); + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("User password updated successfully for the user: %s " + + "in tenant: %s.", username, tenantDomain)); + } + if (LoggerUtils.isDiagnosticLogsEnabled()) { + DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = + new DiagnosticLog.DiagnosticLogBuilder( + Constants.LogConstants.ADAPTIVE_AUTH_SERVICE, + Constants.LogConstants.ActionIDs.UPDATE_USER_PASSWORD + ); + diagnosticLogBuilder.resultMessage("User password updated successfully.") + .inputParam("user", loggableUserId) + .logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION) + .resultStatus(DiagnosticLog.ResultStatus.SUCCESS); + LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); + } + // Update the password migration status claim. if (StringUtils.isNotBlank(passwordMigrationStatusClaim)) { - LOG.debug("Updating the password migration status for the user: " + username - + " in tenant: " + tenantDomain + " to true."); + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("Updating the password migration status claim: %s " + + "for the user: %s in tenant: %s to true.", + passwordMigrationStatusClaim, username, tenantDomain)); + } userStoreManager.setUserClaimValue(username, passwordMigrationStatusClaim, "true", null); + + LOG.debug("Password migration status claim updated successfully for the user: " + username + + " in tenant: " + tenantDomain + "."); + if (LoggerUtils.isDiagnosticLogsEnabled()) { + DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = + new DiagnosticLog.DiagnosticLogBuilder( + Constants.LogConstants.ADAPTIVE_AUTH_SERVICE, + Constants.LogConstants.ActionIDs.UPDATE_USER_PASSWORD + ); + diagnosticLogBuilder.resultMessage("Password migration status claim updated successfully.") + .inputParam("user", loggableUserId) + .logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION) + .resultStatus(DiagnosticLog.ResultStatus.SUCCESS); + LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); + } } } else { - throw new FrameworkException(String.format("Unable to find user realm for the user: %s " + - "in tenant: %s", username, tenantDomain)); + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("Unable to find user realm for the user: %s " + + "in tenant: %s", username, tenantDomain)); + } + if (LoggerUtils.isDiagnosticLogsEnabled()) { + DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = + new DiagnosticLog.DiagnosticLogBuilder( + Constants.LogConstants.ADAPTIVE_AUTH_SERVICE, + Constants.LogConstants.ActionIDs.UPDATE_USER_PASSWORD + ); + diagnosticLogBuilder.resultMessage("Unable to find user realm for the user.") + .inputParam("user", loggableUserId) + .inputParam("tenantDomain", tenantDomain) + .inputParam("userStoreDomain", userStoreDomain) + .logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION) + .resultStatus(DiagnosticLog.ResultStatus.FAILED); + LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); + } } } else { - throw new FrameworkException("Unable to get wrapped content for the user."); + LOG.debug("Unable to get wrapped content for the user."); + if (LoggerUtils.isDiagnosticLogsEnabled()) { + DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = new DiagnosticLog.DiagnosticLogBuilder( + Constants.LogConstants.ADAPTIVE_AUTH_SERVICE, + Constants.LogConstants.ActionIDs.UPDATE_USER_PASSWORD + ); + diagnosticLogBuilder.resultMessage("Unable to get wrapped content for the user.") + .logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION) + .resultStatus(DiagnosticLog.ResultStatus.FAILED); + LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); + } + } + } catch (UserStoreException | FrameworkException e) { + LOG.error("Error occurred while updating the user password.", e); + if (LoggerUtils.isDiagnosticLogsEnabled()) { + DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = new DiagnosticLog.DiagnosticLogBuilder( + Constants.LogConstants.ADAPTIVE_AUTH_SERVICE, + Constants.LogConstants.ActionIDs.UPDATE_USER_PASSWORD + ); + diagnosticLogBuilder.resultMessage("Error occurred while updating the user password.") + .logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION) + .resultStatus(DiagnosticLog.ResultStatus.FAILED); + LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); } - } catch (UserStoreException e) { - throw new FrameworkException("Error while updating the user password.", e); } } } diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginIdentifierFunction.java b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginIdentifierFunction.java index e8b30f55..15d1d78b 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginIdentifierFunction.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginIdentifierFunction.java @@ -24,5 +24,12 @@ @FunctionalInterface public interface ResolveMultiAttributeLoginIdentifierFunction { + /** + * Resolves username from the provided login identifier when multi attribute login is enabled. + * + * @param loginIdentifier The user provided login identifier. + * @param tenantDomain The tenant domain. + * @return The resolved username. + */ String resolveMultiAttributeLoginIdentifier(String loginIdentifier, String tenantDomain); } From d850e405d3c9c736692cbb45384a9092056a0295 Mon Sep 17 00:00:00 2001 From: ThaminduDilshan Date: Wed, 24 Apr 2024 19:09:07 +0530 Subject: [PATCH 6/9] Add unit tests --- .../pom.xml | 10 + .../user/UpdateUserPasswordFunction.java | 1 - .../user/UpdateUserPasswordFunctionImpl.java | 23 - .../UpdateUserPasswordFunctionImplTest.java | 239 ++++++ .../pom.xml | 30 + ...ributeLoginIdentifierFunctionImplTest.java | 95 +++ .../test/resources/repository/conf/carbon.xml | 686 ++++++++++++++++++ 7 files changed, 1060 insertions(+), 24 deletions(-) create mode 100644 components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImplTest.java create mode 100644 components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginIdentifierFunctionImplTest.java create mode 100644 components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/test/resources/repository/conf/carbon.xml diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.user/pom.xml b/components/org.wso2.carbon.identity.conditional.auth.functions.user/pom.xml index a8f62962..a4e741f3 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.user/pom.xml +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.user/pom.xml @@ -130,6 +130,16 @@ org.wso2.carbon.identity.framework org.wso2.carbon.identity.central.log.mgt + + org.wso2.carbon.identity.governance + org.wso2.carbon.identity.governance + test + + + org.wso2.carbon.identity.framework + org.wso2.carbon.identity.event + test + diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunction.java b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunction.java index 7a9540bb..cc06217f 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunction.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunction.java @@ -19,7 +19,6 @@ package org.wso2.carbon.identity.conditional.auth.functions.user; import org.wso2.carbon.identity.application.authentication.framework.config.model.graph.js.JsAuthenticatedUser; -import org.wso2.carbon.identity.application.authentication.framework.exception.FrameworkException; /** * Function to update user password. diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImpl.java b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImpl.java index f2e59757..2877ad41 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImpl.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImpl.java @@ -111,29 +111,6 @@ public void updateUserPassword(JsAuthenticatedUser user, Object... parameters) { UserStoreManager userStoreManager = Utils.getUserStoreManager( tenantDomain, userRealm, userStoreDomain); - if (userStoreManager == null) { - if (LOG.isDebugEnabled()) { - LOG.debug(String.format("Unable to find user store manager for the " + - "user store domain: %s in tenant: %s", userStoreDomain, tenantDomain)); - } - if (LoggerUtils.isDiagnosticLogsEnabled()) { - DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = - new DiagnosticLog.DiagnosticLogBuilder( - Constants.LogConstants.ADAPTIVE_AUTH_SERVICE, - Constants.LogConstants.ActionIDs.UPDATE_USER_PASSWORD - ); - diagnosticLogBuilder.resultMessage("Unable to find user store manager for the " + - "user store domain.") - .inputParam("tenantDomain", tenantDomain) - .inputParam("userStoreDomain", userStoreDomain) - .logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION) - .resultStatus(DiagnosticLog.ResultStatus.FAILED); - LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); - } - - return; - } - // Check for password migration status only if the claim is present. if (StringUtils.isNotBlank(passwordMigrationStatusClaim)) { String passwordMigrationStatus = userStoreManager.getUserClaimValue( diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImplTest.java b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImplTest.java new file mode 100644 index 00000000..a94f3587 --- /dev/null +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImplTest.java @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.conditional.auth.functions.user; + +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import org.wso2.carbon.base.ServerConfiguration; +import org.wso2.carbon.identity.application.authentication.framework.config.model.graph.js.JsAuthenticatedUser; +import org.wso2.carbon.identity.application.authentication.framework.config.model.graph.js.openjdk.nashorn.JsOpenJdkNashornAuthenticatedUser; +import org.wso2.carbon.identity.application.authentication.framework.internal.FrameworkServiceDataHolder; +import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; +import org.wso2.carbon.identity.central.log.mgt.internal.CentralLogMgtServiceComponentHolder; +import org.wso2.carbon.identity.common.testng.WithCarbonHome; +import org.wso2.carbon.identity.common.testng.WithRealmService; +import org.wso2.carbon.identity.conditional.auth.functions.common.utils.Constants; +import org.wso2.carbon.identity.conditional.auth.functions.user.internal.UserFunctionsServiceHolder; +import org.wso2.carbon.identity.event.IdentityEventException; +import org.wso2.carbon.identity.event.event.Event; +import org.wso2.carbon.identity.event.services.IdentityEventService; +import org.wso2.carbon.user.core.UserStoreException; +import org.wso2.carbon.user.core.UserRealm; +import org.wso2.carbon.user.core.UserStoreManager; +import org.wso2.carbon.user.core.service.RealmService; +import org.wso2.carbon.utils.DiagnosticLog; + +import java.lang.reflect.Field; +import java.util.List; + +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.MockitoAnnotations.initMocks; +import static org.powermock.api.mockito.PowerMockito.when; + +@WithCarbonHome +@WithRealmService(injectToSingletons = {FrameworkServiceDataHolder.class}) +public class UpdateUserPasswordFunctionImplTest { + + private UpdateUserPasswordFunctionImpl testFunction; + private JsAuthenticatedUser jsAuthenticatedUser; + + @Mock + RealmService realmServiceMock; + @Mock + UserRealm userRealmMock; + + UserStoreManager userStoreManagerMock; + IdentityEventService identityEventServiceMock; + + private final String USERNAME = "testUser"; + private final String PASSWORD = "password"; + private final String PASSWORD_UPDATE_STATUS_CLAIM = "http://wso2.org/claims/password_migration_status"; + + @BeforeClass + public void setUp() throws NoSuchFieldException, IllegalAccessException { + + testFunction = new UpdateUserPasswordFunctionImpl(); + initMocks(this); + + AuthenticatedUser authenticatedUser = new AuthenticatedUser(); + authenticatedUser.setUserName(USERNAME); + authenticatedUser.setTenantDomain("carbon.super"); + authenticatedUser.setUserStoreDomain("PRIMARY"); + authenticatedUser.setUserId("123456"); + jsAuthenticatedUser = new JsOpenJdkNashornAuthenticatedUser(authenticatedUser); + + // Diagnostic log related mocks. + Field serverConfiguration = ServerConfiguration.class.getDeclaredField("instance"); + serverConfiguration.setAccessible(true); + ServerConfiguration serverConfigurationInstance = (ServerConfiguration) serverConfiguration.get(null); + serverConfigurationInstance.setConfigurationProperty("DiagnosticLogMode", "full"); + } + + @AfterClass + public void tearDown() throws NoSuchFieldException, IllegalAccessException { + + // Reset diagnostic log mode. + Field serverConfiguration = ServerConfiguration.class.getDeclaredField("instance"); + serverConfiguration.setAccessible(true); + ServerConfiguration serverConfigurationInstance = (ServerConfiguration) serverConfiguration.get(null); + serverConfigurationInstance.setConfigurationProperty("DiagnosticLogMode", ""); + } + + @BeforeMethod + public void setUpMethod() throws org.wso2.carbon.user.api.UserStoreException, NoSuchFieldException, + IllegalAccessException { + + Field userFunctionsServiceHolder = UserFunctionsServiceHolder.class.getDeclaredField("instance"); + userFunctionsServiceHolder.setAccessible(true); + UserFunctionsServiceHolder instance = (UserFunctionsServiceHolder) userFunctionsServiceHolder.get(null); + instance.setRealmService(realmServiceMock); + + userStoreManagerMock = mock(UserStoreManager.class); + when(realmServiceMock.getTenantUserRealm(anyInt())).thenReturn(userRealmMock); + when(userRealmMock.getUserStoreManager()).thenReturn(userStoreManagerMock); + when(userStoreManagerMock.getSecondaryUserStoreManager(anyString())).thenReturn(userStoreManagerMock); + + // Diagnostic log related mocks. + identityEventServiceMock = mock(IdentityEventService.class); + Field logMgtServiceHolder = CentralLogMgtServiceComponentHolder.class.getDeclaredField( + "centralLogMgtServiceComponentHolder"); + logMgtServiceHolder.setAccessible(true); + CentralLogMgtServiceComponentHolder logMgtInstance = + (CentralLogMgtServiceComponentHolder) logMgtServiceHolder.get(null); + logMgtInstance.setIdentityEventService(identityEventServiceMock); + } + + @DataProvider(name = "updateUserPasswordWithEmptyInputDataProvider") + public Object[][] updateUserPasswordWithEmptyInputDataProvider() { + + return new Object[][]{ + {null, "newPassword", null, "User is not defined."}, + {jsAuthenticatedUser, null, null, "Password parameters are not defined."}, + {jsAuthenticatedUser, "", null, "The provided password is empty."}, + {jsAuthenticatedUser, "", "testClaim", "The provided password is empty."} + }; + } + + @Test(dataProvider = "updateUserPasswordWithEmptyInputDataProvider") + public void testUpdateUserPasswordWithEmptyInput(JsAuthenticatedUser user, String password, + String claimURI, String logMessage) + throws UserStoreException, IdentityEventException { + + if (password == null && claimURI == null) { + testFunction.updateUserPassword(user); + } else { + testFunction.updateUserPassword(user, password, claimURI); + } + + // Assert that user store manager methods are never invoked. + verify(userStoreManagerMock, times(0)).updateCredentialByAdmin(anyString(), anyString()); + + // Assert for the correct diagnostic logs. + ArgumentCaptor logEventCaptor = ArgumentCaptor.forClass(Event.class); + verify(identityEventServiceMock).handleEvent(logEventCaptor.capture()); + assertDiagnosticLog(logEventCaptor.getValue(), Constants.LogConstants.ActionIDs.VALIDATE_INPUT_PARAMS, + DiagnosticLog.ResultStatus.FAILED, logMessage); + } + + @DataProvider(name = "updateUserPasswordDataProvider") + public Object[][] updateUserPasswordDataProvider() { + + return new Object[][]{ + {null, null}, + {PASSWORD_UPDATE_STATUS_CLAIM, null}, + {PASSWORD_UPDATE_STATUS_CLAIM, "false"}, + {PASSWORD_UPDATE_STATUS_CLAIM, "true"} + }; + } + + @Test(dataProvider = "updateUserPasswordDataProvider") + public void testUpdateUserPassword(String claim, String claimValue) + throws UserStoreException, IdentityEventException { + + if (claim != null) { + when(userStoreManagerMock.getUserClaimValue(USERNAME, PASSWORD_UPDATE_STATUS_CLAIM, null)) + .thenReturn(claimValue); + testFunction.updateUserPassword(jsAuthenticatedUser, PASSWORD, PASSWORD_UPDATE_STATUS_CLAIM); + + if ("true".equals(claimValue)) { + // Assert that user store manager methods are never invoked when the password is already updated. + verify(userStoreManagerMock, times(0)).updateCredentialByAdmin(USERNAME, PASSWORD); + + // Assert for the correct diagnostic logs. + ArgumentCaptor logEventCaptor = ArgumentCaptor.forClass(Event.class); + verify(identityEventServiceMock).handleEvent(logEventCaptor.capture()); + assertDiagnosticLog(logEventCaptor.getValue(), + Constants.LogConstants.ActionIDs.UPDATE_USER_PASSWORD, DiagnosticLog.ResultStatus.FAILED, + "Password migration has already been completed for the user."); + } else { + // Assert that user store manager methods are invoked when the password is not updated. + verify(userStoreManagerMock, times(1)).updateCredentialByAdmin(USERNAME, PASSWORD); + verify(userStoreManagerMock, times(1)) + .getUserClaimValue(USERNAME, PASSWORD_UPDATE_STATUS_CLAIM, null); + verify(userStoreManagerMock, times(1)) + .setUserClaimValue(USERNAME, PASSWORD_UPDATE_STATUS_CLAIM, "true", null); + + // Assert for the correct diagnostic logs. + ArgumentCaptor logEventCaptor = ArgumentCaptor.forClass(Event.class); + verify(identityEventServiceMock, times(2)).handleEvent(logEventCaptor.capture()); + List eventList = logEventCaptor.getAllValues(); + + assertDiagnosticLog(eventList.get(0), Constants.LogConstants.ActionIDs.UPDATE_USER_PASSWORD, + DiagnosticLog.ResultStatus.SUCCESS, "User password updated successfully."); + + assertDiagnosticLog(eventList.get(1), + Constants.LogConstants.ActionIDs.UPDATE_USER_PASSWORD, DiagnosticLog.ResultStatus.SUCCESS, + "Password migration status claim updated successfully."); + } + } else { + testFunction.updateUserPassword(jsAuthenticatedUser, PASSWORD); + + // Assert that only the updateCredentialByAdmin method is invoked. + verify(userStoreManagerMock, times(1)).updateCredentialByAdmin(USERNAME, PASSWORD); + verify(userStoreManagerMock, times(0)) + .setUserClaimValue(USERNAME, PASSWORD_UPDATE_STATUS_CLAIM, "true", null); + + // Assert for the correct diagnostic logs. + ArgumentCaptor logEventCaptor = ArgumentCaptor.forClass(Event.class); + verify(identityEventServiceMock).handleEvent(logEventCaptor.capture()); + assertDiagnosticLog(logEventCaptor.getValue(), Constants.LogConstants.ActionIDs.UPDATE_USER_PASSWORD, + DiagnosticLog.ResultStatus.SUCCESS, "User password updated successfully."); + } + } + + private void assertDiagnosticLog(Event capturedEvent, String expectedActionID, + DiagnosticLog.ResultStatus expectedResultStatus, String expectedMessage) { + + DiagnosticLog diagnosticLog = (DiagnosticLog) capturedEvent.getEventProperties().get("diagnosticLog"); + Assert.assertEquals(diagnosticLog.getComponentId(), Constants.LogConstants.ADAPTIVE_AUTH_SERVICE); + Assert.assertEquals(diagnosticLog.getActionId(), expectedActionID); + Assert.assertEquals(diagnosticLog.getResultStatus(), expectedResultStatus.name()); + Assert.assertEquals(diagnosticLog.getResultMessage(), expectedMessage); + } +} diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/pom.xml b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/pom.xml index 3a7964fb..5e758887 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/pom.xml +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/pom.xml @@ -48,6 +48,36 @@ org.wso2.carbon org.wso2.carbon.user.core + + + + org.wso2.carbon.identity.framework + org.wso2.carbon.identity.testutil + + + org.testng + testng + + + org.mockito + mockito-core + + + + org.wso2.carbon + org.wso2.carbon.utils + test + + + com.h2database.wso2 + h2-database-engine + test + + + org.wso2.carbon.identity.organization.management.core + org.wso2.carbon.identity.organization.management.service + test + diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginIdentifierFunctionImplTest.java b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginIdentifierFunctionImplTest.java new file mode 100644 index 00000000..18264546 --- /dev/null +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginIdentifierFunctionImplTest.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.conditional.auth.functions.utils; + +import org.mockito.Mock; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import org.wso2.carbon.identity.application.authentication.framework.internal.FrameworkServiceDataHolder; +import org.wso2.carbon.identity.common.testng.WithCarbonHome; +import org.wso2.carbon.identity.common.testng.WithRealmService; +import org.wso2.carbon.identity.multi.attribute.login.mgt.MultiAttributeLoginService; +import org.wso2.carbon.identity.multi.attribute.login.mgt.ResolvedUserResult; +import org.wso2.carbon.user.core.common.User; + +import java.lang.reflect.Field; + +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +@WithCarbonHome +@WithRealmService(injectToSingletons = {FrameworkServiceDataHolder.class}) +public class ResolveMultiAttributeLoginIdentifierFunctionImplTest { + + private ResolveMultiAttributeLoginIdentifierFunctionImpl testFunction; + + @Mock + private MultiAttributeLoginService multiAttributeLoginServiceMock; + + @BeforeClass + public void setUp() throws NoSuchFieldException, IllegalAccessException { + + testFunction = new ResolveMultiAttributeLoginIdentifierFunctionImpl(); + initMocks(this); + + Field frameworkServiceDataHolder = FrameworkServiceDataHolder.class.getDeclaredField("instance"); + frameworkServiceDataHolder.setAccessible(true); + FrameworkServiceDataHolder instance = (FrameworkServiceDataHolder) frameworkServiceDataHolder.get(null); + instance.setMultiAttributeLoginService(multiAttributeLoginServiceMock); + } + + @DataProvider(name = "loginIdentifierProvider") + public Object[][] loginIdentifierProvider() { + + return new Object[][]{ + {false, "username", "username"}, + {true, "username", "username"}, + {true, "test@wso2.com", "username"} + }; + } + + @Test (dataProvider = "loginIdentifierProvider") + public void testResolveMultiAttributeLoginIdentifier(boolean multiAttributeLoginEnabled, + String loginIdentifier, String username) { + + ResolvedUserResult userResult = new ResolvedUserResult(ResolvedUserResult.UserResolvedStatus.SUCCESS); + + if (multiAttributeLoginEnabled) { + User user = new User("123456", username, username); + userResult.setUser(user); + } else { + userResult.setResolvedStatus(ResolvedUserResult.UserResolvedStatus.FAIL); + } + + when(multiAttributeLoginServiceMock.isEnabled(anyString())).thenReturn(multiAttributeLoginEnabled); + when(multiAttributeLoginServiceMock.resolveUser(loginIdentifier, "carbon.super")).thenReturn(userResult); + + String result = testFunction.resolveMultiAttributeLoginIdentifier(loginIdentifier, "carbon.super"); + + if (multiAttributeLoginEnabled) { + Assert.assertNotNull(result); + Assert.assertEquals(result, username); + } else { + Assert.assertNull(result); + } + } +} diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/test/resources/repository/conf/carbon.xml b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/test/resources/repository/conf/carbon.xml new file mode 100644 index 00000000..7ae4bca3 --- /dev/null +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/test/resources/repository/conf/carbon.xml @@ -0,0 +1,686 @@ + + + + + + + + WSO2 Identity Server + + + IS + + + 5.3.0 + + + localhost + + + localhost + + + local:/${carbon.context}/services/ + + + + + + + IdentityServer + + + + + + + org.wso2.carbon + + + / + + + + + + + + + 15 + + + + + + + + + 0 + + + + + 9999 + + 11111 + + + + + + 10389 + + 8000 + + + + + + 10500 + + + + + + + + + org.wso2.carbon.tomcat.jndi.CarbonJavaURLContextFactory + + + + + + + + + java + + + + + + + + + + false + + + false + + + 600 + + + + false + + + + + + + + 30 + + + + + + + + + 15 + + + + + + ${carbon.home}/repository/deployment/server/ + + + 15 + + + ${carbon.home}/repository/conf/axis2/axis2.xml + + + 30000 + + + ${carbon.home}/repository/deployment/client/ + + ${carbon.home}/repository/conf/axis2/axis2_client.xml + + true + + + + + + + + + + admin + Default Administrator Role + + + user + Default User Role + + + + + + + + + + + + ${carbon.home}/repository/resources/security/wso2carbon.jks + + JKS + + wso2carbon + + wso2carbon + + wso2carbon + + + + + + ${carbon.home}/repository/resources/security/client-truststore.jks + + JKS + + wso2carbon + + + + + + + + + + + + + + + + + + + UserManager + + + false + + org.wso2.carbon.identity.provider.AttributeCallbackHandler + + + org.wso2.carbon.identity.sts.store.DBTokenStore + + + true + allow + + + + + + + claim_mgt_menu + identity_mgt_emailtemplate_menu + identity_security_questions_menu + + + + ${carbon.home}/tmp/work + + + + + + true + + + 10 + + + 30 + + + + + + 100 + + + + keystore + certificate + * + + org.wso2.carbon.ui.transports.fileupload.AnyFileUploadExecutor + + + + + jarZip + + org.wso2.carbon.ui.transports.fileupload.JarZipUploadExecutor + + + + dbs + + org.wso2.carbon.ui.transports.fileupload.DBSFileUploadExecutor + + + + tools + + org.wso2.carbon.ui.transports.fileupload.ToolsFileUploadExecutor + + + + toolsAny + + org.wso2.carbon.ui.transports.fileupload.ToolsAnyFileUploadExecutor + + + + + + + + + + info + org.wso2.carbon.core.transports.util.InfoProcessor + + + wsdl + org.wso2.carbon.core.transports.util.Wsdl11Processor + + + wsdl2 + org.wso2.carbon.core.transports.util.Wsdl20Processor + + + xsd + org.wso2.carbon.core.transports.util.XsdProcessor + + + + + + false + false + true + svn + http://svnrepo.example.com/repos/ + username + password + true + + + + + + + + + + + + + + + ${require.carbon.servlet} + + + + + true + + + + + + + default repository + http://product-dist.wso2.com/p2/carbon/releases/wilkes/ + + + + + + + + true + + + + + + true + + From 85358a3d0bcd0c57b1fd4c0de80fb0d128191d34 Mon Sep 17 00:00:00 2001 From: ThaminduDilshan Date: Thu, 9 May 2024 10:52:13 +0530 Subject: [PATCH 7/9] Replace powermock references --- .../auth/functions/user/UpdateUserPasswordFunctionImplTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImplTest.java b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImplTest.java index a94f3587..640761ca 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImplTest.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImplTest.java @@ -53,8 +53,8 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; -import static org.powermock.api.mockito.PowerMockito.when; @WithCarbonHome @WithRealmService(injectToSingletons = {FrameworkServiceDataHolder.class}) From 7726c4d727c869d129fde4c3fd9f21a8e6b5e280 Mon Sep 17 00:00:00 2001 From: ThaminduDilshan Date: Thu, 9 May 2024 17:51:36 +0530 Subject: [PATCH 8/9] Add maven surefire plugin to user and utils components --- .../pom.xml | 17 +++++++++++ .../src/test/resources/testng.xml | 30 +++++++++++++++++++ .../pom.xml | 17 +++++++++++ .../test/resources/repository/conf/carbon.xml | 2 +- .../src/test/resources/testng.xml | 27 +++++++++++++++++ 5 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/resources/testng.xml create mode 100644 components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/test/resources/testng.xml diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.user/pom.xml b/components/org.wso2.carbon.identity.conditional.auth.functions.user/pom.xml index a4e741f3..32951128 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.user/pom.xml +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.user/pom.xml @@ -228,6 +228,23 @@ + + org.apache.maven.plugins + maven-surefire-plugin + ${maven.surefire.plugin.version} + + + --add-opens=java.base/java.lang=ALL-UNNAMED + --add-opens=java.base/java.util=ALL-UNNAMED + --add-opens java.xml/jdk.xml.internal=ALL-UNNAMED + --add-opens=java.base/java.io=ALL-UNNAMED + --add-opens=java.base/sun.nio.fs=ALL-UNNAMED + + + src/test/resources/testng.xml + + + org.jacoco jacoco-maven-plugin diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/resources/testng.xml b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/resources/testng.xml new file mode 100644 index 00000000..0138bf73 --- /dev/null +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/resources/testng.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/pom.xml b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/pom.xml index 5e758887..c1834b68 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/pom.xml +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/pom.xml @@ -113,6 +113,23 @@ + + org.apache.maven.plugins + maven-surefire-plugin + ${maven.surefire.plugin.version} + + + --add-opens=java.base/java.lang=ALL-UNNAMED + --add-opens=java.base/java.util=ALL-UNNAMED + --add-opens java.xml/jdk.xml.internal=ALL-UNNAMED + --add-opens=java.base/java.io=ALL-UNNAMED + --add-opens=java.base/sun.nio.fs=ALL-UNNAMED + + + src/test/resources/testng.xml + + + org.jacoco jacoco-maven-plugin diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/test/resources/repository/conf/carbon.xml b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/test/resources/repository/conf/carbon.xml index 7ae4bca3..04e39a8f 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/test/resources/repository/conf/carbon.xml +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/test/resources/repository/conf/carbon.xml @@ -2,7 +2,7 @@ + + + + + + + + + + From f952fc5a0ac1376d672cf67d0cb952c0b7f7b4e1 Mon Sep 17 00:00:00 2001 From: ThaminduDilshan Date: Fri, 10 May 2024 16:26:29 +0530 Subject: [PATCH 9/9] Remove password status claim and add event callbacks handlers --- .../user/UpdateUserPasswordFunction.java | 2 +- .../user/UpdateUserPasswordFunctionImpl.java | 159 +++++-------- .../UpdateUserPasswordFunctionImplTest.java | 222 +++++++++--------- .../src/test/resources/dbscripts/h2.sql | 11 + .../user/update-password-async-sp.xml | 76 ++++++ .../functions/user/update-password-sp.xml | 68 ++++++ .../pom.xml | 5 + ...ributeLoginIdentifierFunctionImplTest.java | 70 +++++- .../src/test/resources/dbscripts/h2.sql | 50 ++++ .../resolve-multi-attribute-login-sp.xml | 74 ++++++ 10 files changed, 505 insertions(+), 232 deletions(-) create mode 100644 components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/user/update-password-async-sp.xml create mode 100644 components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/user/update-password-sp.xml create mode 100644 components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/test/resources/dbscripts/h2.sql create mode 100644 components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/utils/resolve-multi-attribute-login-sp.xml diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunction.java b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunction.java index cc06217f..d289bd85 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunction.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunction.java @@ -31,7 +31,7 @@ public interface UpdateUserPasswordFunction { * * @param user Authenticated user. * @param parameters Parameters. It is mandatory to provide the new password as the first parameter. - * Then an optional local claim can be provided to hold the password update status. + * Then an optional map of event handlers can be provided. */ void updateUserPassword(JsAuthenticatedUser user, Object... parameters); } diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImpl.java b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImpl.java index 2877ad41..250857ca 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImpl.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImpl.java @@ -21,6 +21,8 @@ import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.identity.application.authentication.framework.AsyncProcess; +import org.wso2.carbon.identity.application.authentication.framework.config.model.graph.JsGraphBuilder; import org.wso2.carbon.identity.application.authentication.framework.config.model.graph.js.JsAuthenticatedUser; import org.wso2.carbon.identity.application.authentication.framework.exception.FrameworkException; import org.wso2.carbon.identity.central.log.mgt.utils.LoggerUtils; @@ -30,6 +32,9 @@ import org.wso2.carbon.user.core.UserStoreManager; import org.wso2.carbon.utils.DiagnosticLog; +import java.util.Collections; +import java.util.Map; + /** * Function to update user password. */ @@ -41,63 +46,55 @@ public class UpdateUserPasswordFunctionImpl implements UpdateUserPasswordFunctio public void updateUserPassword(JsAuthenticatedUser user, Object... parameters) { if (user == null) { - LOG.debug("User is not defined."); - if (LoggerUtils.isDiagnosticLogsEnabled()) { - DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = new DiagnosticLog.DiagnosticLogBuilder( - Constants.LogConstants.ADAPTIVE_AUTH_SERVICE, - Constants.LogConstants.ActionIDs.VALIDATE_INPUT_PARAMS - ); - diagnosticLogBuilder.resultMessage("User is not defined.") - .logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION) - .resultStatus(DiagnosticLog.ResultStatus.FAILED); - LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); - } - - return; + throw new IllegalArgumentException("User is not defined."); } if (parameters == null || parameters.length == 0) { - LOG.debug("Password parameters are not defined."); - if (LoggerUtils.isDiagnosticLogsEnabled()) { - DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = new DiagnosticLog.DiagnosticLogBuilder( - Constants.LogConstants.ADAPTIVE_AUTH_SERVICE, - Constants.LogConstants.ActionIDs.VALIDATE_INPUT_PARAMS - ); - diagnosticLogBuilder.resultMessage("Password parameters are not defined.") - .logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION) - .resultStatus(DiagnosticLog.ResultStatus.FAILED); - LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); - } - - return; + throw new IllegalArgumentException("Password is not defined."); } String newPassword = null; - String passwordMigrationStatusClaim = null; + Map eventHandlers = null; if (parameters.length == 2) { - LOG.debug("Both password and password migration status claim parameters are provided."); + LOG.debug("Both password and event handlers are provided."); newPassword = (String) parameters[0]; - passwordMigrationStatusClaim = (String) parameters[1]; + + if (parameters[1] instanceof Map) { + eventHandlers = (Map) parameters[1]; + } else { + throw new IllegalArgumentException("Invalid argument type. Expected eventHandlers " + + "(Map)."); + } } else { - LOG.debug("Only the new password is provided."); + LOG.debug("Only the password is provided."); newPassword = (String) parameters[0]; } if (StringUtils.isBlank(newPassword)) { - LOG.debug("The provided password is empty."); - if (LoggerUtils.isDiagnosticLogsEnabled()) { - DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = new DiagnosticLog.DiagnosticLogBuilder( - Constants.LogConstants.ADAPTIVE_AUTH_SERVICE, - Constants.LogConstants.ActionIDs.VALIDATE_INPUT_PARAMS - ); - diagnosticLogBuilder.resultMessage("The provided password is empty.") - .logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION) - .resultStatus(DiagnosticLog.ResultStatus.FAILED); - LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); - } + throw new IllegalArgumentException("The provided password is empty."); + } - return; + if (eventHandlers != null) { + String finalNewPassword = newPassword; + AsyncProcess asyncProcess = new AsyncProcess((context, asyncReturn) -> { + try { + doUpdatePassword(user, finalNewPassword); + asyncReturn.accept(context, Collections.emptyMap(), Constants.OUTCOME_SUCCESS); + } catch (FrameworkException e) { + asyncReturn.accept(context, Collections.emptyMap(), Constants.OUTCOME_FAIL); + } + }); + JsGraphBuilder.addLongWaitProcess(asyncProcess, eventHandlers); + } else { + try { + doUpdatePassword(user, newPassword); + } catch (FrameworkException e) { + // Ignore FrameworkException as the function is not expected to throw any. + } } + } + + private void doUpdatePassword(JsAuthenticatedUser user, String newPassword) throws FrameworkException { try { if (user.getWrapped() != null) { @@ -111,38 +108,6 @@ public void updateUserPassword(JsAuthenticatedUser user, Object... parameters) { UserStoreManager userStoreManager = Utils.getUserStoreManager( tenantDomain, userRealm, userStoreDomain); - // Check for password migration status only if the claim is present. - if (StringUtils.isNotBlank(passwordMigrationStatusClaim)) { - String passwordMigrationStatus = userStoreManager.getUserClaimValue( - username, passwordMigrationStatusClaim, null); - - if (LOG.isDebugEnabled()) { - LOG.debug(String.format("Password migration status for the user: %s in tenant: %s is: %s", - username, tenantDomain, passwordMigrationStatus)); - } - - if (Boolean.parseBoolean(passwordMigrationStatus)) { - if (LOG.isDebugEnabled()) { - LOG.debug(String.format("Password migration has already been completed for the " + - "user: %s in tenant: %s", username, tenantDomain)); - } - if (LoggerUtils.isDiagnosticLogsEnabled()) { - DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = - new DiagnosticLog.DiagnosticLogBuilder( - Constants.LogConstants.ADAPTIVE_AUTH_SERVICE, - Constants.LogConstants.ActionIDs.UPDATE_USER_PASSWORD - ); - diagnosticLogBuilder.resultMessage("Password migration has already been completed " + - "for the user.").inputParam("user", loggableUserId) - .logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION) - .resultStatus(DiagnosticLog.ResultStatus.FAILED); - LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); - } - - return; - } - } - // Update the user password. userStoreManager.updateCredentialByAdmin(username, newPassword); @@ -162,43 +127,19 @@ public void updateUserPassword(JsAuthenticatedUser user, Object... parameters) { .resultStatus(DiagnosticLog.ResultStatus.SUCCESS); LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); } - - // Update the password migration status claim. - if (StringUtils.isNotBlank(passwordMigrationStatusClaim)) { - if (LOG.isDebugEnabled()) { - LOG.debug(String.format("Updating the password migration status claim: %s " + - "for the user: %s in tenant: %s to true.", - passwordMigrationStatusClaim, username, tenantDomain)); - } - userStoreManager.setUserClaimValue(username, passwordMigrationStatusClaim, "true", null); - - LOG.debug("Password migration status claim updated successfully for the user: " + username - + " in tenant: " + tenantDomain + "."); - if (LoggerUtils.isDiagnosticLogsEnabled()) { - DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = - new DiagnosticLog.DiagnosticLogBuilder( - Constants.LogConstants.ADAPTIVE_AUTH_SERVICE, - Constants.LogConstants.ActionIDs.UPDATE_USER_PASSWORD - ); - diagnosticLogBuilder.resultMessage("Password migration status claim updated successfully.") - .inputParam("user", loggableUserId) - .logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION) - .resultStatus(DiagnosticLog.ResultStatus.SUCCESS); - LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); - } - } } else { if (LOG.isDebugEnabled()) { LOG.debug(String.format("Unable to find user realm for the user: %s " + "in tenant: %s", username, tenantDomain)); } + String message = "Unable to find user realm for the user."; if (LoggerUtils.isDiagnosticLogsEnabled()) { DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = new DiagnosticLog.DiagnosticLogBuilder( Constants.LogConstants.ADAPTIVE_AUTH_SERVICE, Constants.LogConstants.ActionIDs.UPDATE_USER_PASSWORD ); - diagnosticLogBuilder.resultMessage("Unable to find user realm for the user.") + diagnosticLogBuilder.resultMessage(message) .inputParam("user", loggableUserId) .inputParam("tenantDomain", tenantDomain) .inputParam("userStoreDomain", userStoreDomain) @@ -206,32 +147,42 @@ public void updateUserPassword(JsAuthenticatedUser user, Object... parameters) { .resultStatus(DiagnosticLog.ResultStatus.FAILED); LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); } + + throw new FrameworkException(message); } } else { - LOG.debug("Unable to get wrapped content for the user."); + String message = "Unable to get wrapped content for the user."; + + LOG.debug(message); if (LoggerUtils.isDiagnosticLogsEnabled()) { DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = new DiagnosticLog.DiagnosticLogBuilder( Constants.LogConstants.ADAPTIVE_AUTH_SERVICE, Constants.LogConstants.ActionIDs.UPDATE_USER_PASSWORD ); - diagnosticLogBuilder.resultMessage("Unable to get wrapped content for the user.") + diagnosticLogBuilder.resultMessage(message) .logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION) .resultStatus(DiagnosticLog.ResultStatus.FAILED); LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); } + + throw new FrameworkException(message); } } catch (UserStoreException | FrameworkException e) { - LOG.error("Error occurred while updating the user password.", e); + String message = "Error occurred while updating the user password."; + + LOG.error(message, e); if (LoggerUtils.isDiagnosticLogsEnabled()) { DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = new DiagnosticLog.DiagnosticLogBuilder( Constants.LogConstants.ADAPTIVE_AUTH_SERVICE, Constants.LogConstants.ActionIDs.UPDATE_USER_PASSWORD ); - diagnosticLogBuilder.resultMessage("Error occurred while updating the user password.") + diagnosticLogBuilder.resultMessage(message) .logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION) .resultStatus(DiagnosticLog.ResultStatus.FAILED); LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); } + + throw new FrameworkException(message, e); } } } diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImplTest.java b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImplTest.java index 640761ca..84ab0c71 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImplTest.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/user/UpdateUserPasswordFunctionImplTest.java @@ -18,36 +18,47 @@ package org.wso2.carbon.identity.conditional.auth.functions.user; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import org.wso2.carbon.CarbonConstants; import org.wso2.carbon.base.ServerConfiguration; +import org.wso2.carbon.identity.application.authentication.framework.config.model.SequenceConfig; import org.wso2.carbon.identity.application.authentication.framework.config.model.graph.js.JsAuthenticatedUser; import org.wso2.carbon.identity.application.authentication.framework.config.model.graph.js.openjdk.nashorn.JsOpenJdkNashornAuthenticatedUser; +import org.wso2.carbon.identity.application.authentication.framework.context.AuthenticationContext; +import org.wso2.carbon.identity.application.authentication.framework.dao.impl.CacheBackedLongWaitStatusDAO; +import org.wso2.carbon.identity.application.authentication.framework.dao.impl.LongWaitStatusDAOImpl; import org.wso2.carbon.identity.application.authentication.framework.internal.FrameworkServiceDataHolder; import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; +import org.wso2.carbon.identity.application.authentication.framework.store.LongWaitStatusStoreService; +import org.wso2.carbon.identity.application.common.model.ServiceProvider; import org.wso2.carbon.identity.central.log.mgt.internal.CentralLogMgtServiceComponentHolder; import org.wso2.carbon.identity.common.testng.WithCarbonHome; +import org.wso2.carbon.identity.common.testng.WithH2Database; import org.wso2.carbon.identity.common.testng.WithRealmService; -import org.wso2.carbon.identity.conditional.auth.functions.common.utils.Constants; +import org.wso2.carbon.identity.conditional.auth.functions.common.internal.FunctionsDataHolder; +import org.wso2.carbon.identity.conditional.auth.functions.test.utils.sequence.JsSequenceHandlerAbstractTest; +import org.wso2.carbon.identity.conditional.auth.functions.test.utils.sequence.JsTestException; import org.wso2.carbon.identity.conditional.auth.functions.user.internal.UserFunctionsServiceHolder; -import org.wso2.carbon.identity.event.IdentityEventException; -import org.wso2.carbon.identity.event.event.Event; +import org.wso2.carbon.identity.core.util.IdentityTenantUtil; import org.wso2.carbon.identity.event.services.IdentityEventService; import org.wso2.carbon.user.core.UserStoreException; import org.wso2.carbon.user.core.UserRealm; import org.wso2.carbon.user.core.UserStoreManager; import org.wso2.carbon.user.core.service.RealmService; -import org.wso2.carbon.utils.DiagnosticLog; import java.lang.reflect.Field; +import java.util.Collections; import java.util.List; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.mock; @@ -57,38 +68,47 @@ import static org.mockito.MockitoAnnotations.initMocks; @WithCarbonHome -@WithRealmService(injectToSingletons = {FrameworkServiceDataHolder.class}) -public class UpdateUserPasswordFunctionImplTest { - - private UpdateUserPasswordFunctionImpl testFunction; - private JsAuthenticatedUser jsAuthenticatedUser; +@WithRealmService(injectToSingletons = {UserFunctionsServiceHolder.class, IdentityTenantUtil.class, + FrameworkServiceDataHolder.class}) +@WithH2Database(files = "dbscripts/h2.sql") +public class UpdateUserPasswordFunctionImplTest extends JsSequenceHandlerAbstractTest { - @Mock RealmService realmServiceMock; - @Mock UserRealm userRealmMock; - + FunctionsDataHolder functionsDataHolderMock; UserStoreManager userStoreManagerMock; IdentityEventService identityEventServiceMock; - private final String USERNAME = "testUser"; - private final String PASSWORD = "password"; - private final String PASSWORD_UPDATE_STATUS_CLAIM = "http://wso2.org/claims/password_migration_status"; + private UpdateUserPasswordFunctionImpl testFunction; @BeforeClass - public void setUp() throws NoSuchFieldException, IllegalAccessException { + public void setUp() throws Exception { + + super.setUp(); + CarbonConstants.ENABLE_LEGACY_AUTHZ_RUNTIME = true; + sequenceHandlerRunner.registerJsFunction("updateUserPassword", new UpdateUserPasswordFunctionImpl()); - testFunction = new UpdateUserPasswordFunctionImpl(); initMocks(this); + testFunction = new UpdateUserPasswordFunctionImpl(); - AuthenticatedUser authenticatedUser = new AuthenticatedUser(); - authenticatedUser.setUserName(USERNAME); - authenticatedUser.setTenantDomain("carbon.super"); - authenticatedUser.setUserStoreDomain("PRIMARY"); - authenticatedUser.setUserId("123456"); - jsAuthenticatedUser = new JsOpenJdkNashornAuthenticatedUser(authenticatedUser); + functionsDataHolderMock = mock(FunctionsDataHolder.class); + Field functionsDataHolderInstance = FunctionsDataHolder.class.getDeclaredField("instance"); + functionsDataHolderInstance.setAccessible(true); + functionsDataHolderInstance.set(null, functionsDataHolderMock); + + Field frameworkServiceDataHolderInstance = FrameworkServiceDataHolder.class.getDeclaredField("instance"); + frameworkServiceDataHolderInstance.setAccessible(true); + FrameworkServiceDataHolder availableInstance = + (FrameworkServiceDataHolder) frameworkServiceDataHolderInstance.get(null); - // Diagnostic log related mocks. + LongWaitStatusDAOImpl daoImpl = new LongWaitStatusDAOImpl(); + CacheBackedLongWaitStatusDAO cacheBackedDao = new CacheBackedLongWaitStatusDAO(daoImpl); + int connectionTimeout = 10000; + LongWaitStatusStoreService longWaitStatusStoreService = + new LongWaitStatusStoreService(cacheBackedDao, connectionTimeout); + availableInstance.setLongWaitStatusStoreService(longWaitStatusStoreService); + + // Set and initialize diagnostic log mode. Field serverConfiguration = ServerConfiguration.class.getDeclaredField("instance"); serverConfiguration.setAccessible(true); ServerConfiguration serverConfigurationInstance = (ServerConfiguration) serverConfiguration.get(null); @@ -106,20 +126,23 @@ public void tearDown() throws NoSuchFieldException, IllegalAccessException { } @BeforeMethod - public void setUpMethod() throws org.wso2.carbon.user.api.UserStoreException, NoSuchFieldException, - IllegalAccessException { + public void setUpMethod() throws NoSuchFieldException, IllegalAccessException, + org.wso2.carbon.user.api.UserStoreException { + // Mock realm service and user store manager. + realmServiceMock = mock(RealmService.class); + userRealmMock = mock(UserRealm.class); + userStoreManagerMock = mock(UserStoreManager.class); Field userFunctionsServiceHolder = UserFunctionsServiceHolder.class.getDeclaredField("instance"); userFunctionsServiceHolder.setAccessible(true); UserFunctionsServiceHolder instance = (UserFunctionsServiceHolder) userFunctionsServiceHolder.get(null); instance.setRealmService(realmServiceMock); - userStoreManagerMock = mock(UserStoreManager.class); when(realmServiceMock.getTenantUserRealm(anyInt())).thenReturn(userRealmMock); when(userRealmMock.getUserStoreManager()).thenReturn(userStoreManagerMock); when(userStoreManagerMock.getSecondaryUserStoreManager(anyString())).thenReturn(userStoreManagerMock); - // Diagnostic log related mocks. + // Mock identity event service for diagnostic log publishing. identityEventServiceMock = mock(IdentityEventService.class); Field logMgtServiceHolder = CentralLogMgtServiceComponentHolder.class.getDeclaredField( "centralLogMgtServiceComponentHolder"); @@ -129,111 +152,82 @@ public void setUpMethod() throws org.wso2.carbon.user.api.UserStoreException, No logMgtInstance.setIdentityEventService(identityEventServiceMock); } + private AuthenticationContext getAuthenticationContextForSP(String spFileName) throws JsTestException { + + sequenceHandlerRunner.addSubjectAuthenticator("BasicMockAuthenticator", "test_user", Collections.emptyMap()); + ServiceProvider sp = sequenceHandlerRunner.loadServiceProviderFromResource(spFileName, this); + AuthenticationContext context = sequenceHandlerRunner.createAuthenticationContext(sp); + SequenceConfig sequenceConfig = sequenceHandlerRunner.getSequenceConfig(context, sp); + context.setSequenceConfig(sequenceConfig); + context.initializeAnalyticsData(); + + return context; + } + @DataProvider(name = "updateUserPasswordWithEmptyInputDataProvider") public Object[][] updateUserPasswordWithEmptyInputDataProvider() { + AuthenticatedUser authenticatedUser = new AuthenticatedUser(); + authenticatedUser.setUserName("test_user"); + authenticatedUser.setTenantDomain("carbon.super"); + authenticatedUser.setUserStoreDomain("PRIMARY"); + authenticatedUser.setUserId("123456"); + JsAuthenticatedUser jsAuthenticatedUser = new JsOpenJdkNashornAuthenticatedUser(authenticatedUser); + return new Object[][]{ {null, "newPassword", null, "User is not defined."}, - {jsAuthenticatedUser, null, null, "Password parameters are not defined."}, + {jsAuthenticatedUser, null, null, "Password is not defined."}, {jsAuthenticatedUser, "", null, "The provided password is empty."}, - {jsAuthenticatedUser, "", "testClaim", "The provided password is empty."} + {jsAuthenticatedUser, "newPassword", Collections.EMPTY_LIST, "Invalid argument type. " + + "Expected eventHandlers (Map)."} }; } @Test(dataProvider = "updateUserPasswordWithEmptyInputDataProvider") public void testUpdateUserPasswordWithEmptyInput(JsAuthenticatedUser user, String password, - String claimURI, String logMessage) - throws UserStoreException, IdentityEventException { - - if (password == null && claimURI == null) { - testFunction.updateUserPassword(user); - } else { - testFunction.updateUserPassword(user, password, claimURI); + List eventHandlers, String errorMessage) + throws UserStoreException { + + try { + if (password == null) { + testFunction.updateUserPassword(user); + } else if (eventHandlers != null) { + testFunction.updateUserPassword(user, password, eventHandlers); + } else { + testFunction.updateUserPassword(user, password); + } + } catch (IllegalArgumentException e) { + // Assert for the correct exception. + Assert.assertEquals(e.getMessage(), errorMessage); } // Assert that user store manager methods are never invoked. verify(userStoreManagerMock, times(0)).updateCredentialByAdmin(anyString(), anyString()); - - // Assert for the correct diagnostic logs. - ArgumentCaptor logEventCaptor = ArgumentCaptor.forClass(Event.class); - verify(identityEventServiceMock).handleEvent(logEventCaptor.capture()); - assertDiagnosticLog(logEventCaptor.getValue(), Constants.LogConstants.ActionIDs.VALIDATE_INPUT_PARAMS, - DiagnosticLog.ResultStatus.FAILED, logMessage); } - @DataProvider(name = "updateUserPasswordDataProvider") - public Object[][] updateUserPasswordDataProvider() { + @Test + public void testUpdateUserPassword() throws UserStoreException, JsTestException { - return new Object[][]{ - {null, null}, - {PASSWORD_UPDATE_STATUS_CLAIM, null}, - {PASSWORD_UPDATE_STATUS_CLAIM, "false"}, - {PASSWORD_UPDATE_STATUS_CLAIM, "true"} - }; - } + AuthenticationContext context = getAuthenticationContextForSP("update-password-sp.xml"); + HttpServletRequest req = sequenceHandlerRunner.createHttpServletRequest(); + HttpServletResponse resp = sequenceHandlerRunner.createHttpServletResponse(); - @Test(dataProvider = "updateUserPasswordDataProvider") - public void testUpdateUserPassword(String claim, String claimValue) - throws UserStoreException, IdentityEventException { - - if (claim != null) { - when(userStoreManagerMock.getUserClaimValue(USERNAME, PASSWORD_UPDATE_STATUS_CLAIM, null)) - .thenReturn(claimValue); - testFunction.updateUserPassword(jsAuthenticatedUser, PASSWORD, PASSWORD_UPDATE_STATUS_CLAIM); - - if ("true".equals(claimValue)) { - // Assert that user store manager methods are never invoked when the password is already updated. - verify(userStoreManagerMock, times(0)).updateCredentialByAdmin(USERNAME, PASSWORD); - - // Assert for the correct diagnostic logs. - ArgumentCaptor logEventCaptor = ArgumentCaptor.forClass(Event.class); - verify(identityEventServiceMock).handleEvent(logEventCaptor.capture()); - assertDiagnosticLog(logEventCaptor.getValue(), - Constants.LogConstants.ActionIDs.UPDATE_USER_PASSWORD, DiagnosticLog.ResultStatus.FAILED, - "Password migration has already been completed for the user."); - } else { - // Assert that user store manager methods are invoked when the password is not updated. - verify(userStoreManagerMock, times(1)).updateCredentialByAdmin(USERNAME, PASSWORD); - verify(userStoreManagerMock, times(1)) - .getUserClaimValue(USERNAME, PASSWORD_UPDATE_STATUS_CLAIM, null); - verify(userStoreManagerMock, times(1)) - .setUserClaimValue(USERNAME, PASSWORD_UPDATE_STATUS_CLAIM, "true", null); - - // Assert for the correct diagnostic logs. - ArgumentCaptor logEventCaptor = ArgumentCaptor.forClass(Event.class); - verify(identityEventServiceMock, times(2)).handleEvent(logEventCaptor.capture()); - List eventList = logEventCaptor.getAllValues(); - - assertDiagnosticLog(eventList.get(0), Constants.LogConstants.ActionIDs.UPDATE_USER_PASSWORD, - DiagnosticLog.ResultStatus.SUCCESS, "User password updated successfully."); - - assertDiagnosticLog(eventList.get(1), - Constants.LogConstants.ActionIDs.UPDATE_USER_PASSWORD, DiagnosticLog.ResultStatus.SUCCESS, - "Password migration status claim updated successfully."); - } - } else { - testFunction.updateUserPassword(jsAuthenticatedUser, PASSWORD); - - // Assert that only the updateCredentialByAdmin method is invoked. - verify(userStoreManagerMock, times(1)).updateCredentialByAdmin(USERNAME, PASSWORD); - verify(userStoreManagerMock, times(0)) - .setUserClaimValue(USERNAME, PASSWORD_UPDATE_STATUS_CLAIM, "true", null); - - // Assert for the correct diagnostic logs. - ArgumentCaptor logEventCaptor = ArgumentCaptor.forClass(Event.class); - verify(identityEventServiceMock).handleEvent(logEventCaptor.capture()); - assertDiagnosticLog(logEventCaptor.getValue(), Constants.LogConstants.ActionIDs.UPDATE_USER_PASSWORD, - DiagnosticLog.ResultStatus.SUCCESS, "User password updated successfully."); - } + sequenceHandlerRunner.handle(req, resp, context, "test_domain"); + + // Assert that updateCredentialByAdmin method is invoked. + verify(userStoreManagerMock, times(1)).updateCredentialByAdmin(anyString(), any()); } - private void assertDiagnosticLog(Event capturedEvent, String expectedActionID, - DiagnosticLog.ResultStatus expectedResultStatus, String expectedMessage) { + @Test + public void testUpdateUserPasswordWithCallbacks() throws UserStoreException, JsTestException { + + AuthenticationContext context = getAuthenticationContextForSP("update-password-async-sp.xml"); + HttpServletRequest req = sequenceHandlerRunner.createHttpServletRequest(); + HttpServletResponse resp = sequenceHandlerRunner.createHttpServletResponse(); + + sequenceHandlerRunner.handle(req, resp, context, "test_domain"); - DiagnosticLog diagnosticLog = (DiagnosticLog) capturedEvent.getEventProperties().get("diagnosticLog"); - Assert.assertEquals(diagnosticLog.getComponentId(), Constants.LogConstants.ADAPTIVE_AUTH_SERVICE); - Assert.assertEquals(diagnosticLog.getActionId(), expectedActionID); - Assert.assertEquals(diagnosticLog.getResultStatus(), expectedResultStatus.name()); - Assert.assertEquals(diagnosticLog.getResultMessage(), expectedMessage); + // Assert that updateCredentialByAdmin method is invoked. + verify(userStoreManagerMock, times(1)).updateCredentialByAdmin(anyString(), any()); } } diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/resources/dbscripts/h2.sql b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/resources/dbscripts/h2.sql index f26d41fc..300b50a0 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/resources/dbscripts/h2.sql +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/resources/dbscripts/h2.sql @@ -48,3 +48,14 @@ CREATE TABLE IF NOT EXISTS IDN_CLAIM_MAPPING ( FOREIGN KEY (MAPPED_LOCAL_CLAIM_ID) REFERENCES IDN_CLAIM(ID) ON DELETE CASCADE, CONSTRAINT EXT_TO_LOC_MAPPING_CONSTRN UNIQUE (EXT_CLAIM_ID, TENANT_ID), ); + +CREATE TABLE IF NOT EXISTS IDN_AUTH_WAIT_STATUS ( + ID INTEGER AUTO_INCREMENT NOT NULL, + TENANT_ID INTEGER NOT NULL, + LONG_WAIT_KEY VARCHAR(255) NOT NULL, + WAIT_STATUS CHAR(1) NOT NULL DEFAULT '1', + TIME_CREATED TIMESTAMP DEFAULT 0, + EXPIRE_TIME TIMESTAMP DEFAULT 0, + PRIMARY KEY (ID), + CONSTRAINT IDN_AUTH_WAIT_STATUS_KEY UNIQUE (LONG_WAIT_KEY) +); diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/user/update-password-async-sp.xml b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/user/update-password-async-sp.xml new file mode 100644 index 00000000..120e448e --- /dev/null +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/user/update-password-async-sp.xml @@ -0,0 +1,76 @@ + + + 1 + default + Default Service Provider + + + + default + + + + + + + + + 1 + + + BasicMockAuthenticator + basicauth + true + + + true + true + + + + flow + + + + + + true + + + diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/user/update-password-sp.xml b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/user/update-password-sp.xml new file mode 100644 index 00000000..d3888f0f --- /dev/null +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.user/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/user/update-password-sp.xml @@ -0,0 +1,68 @@ + + + 1 + default + Default Service Provider + + + + default + + + + + + + + + 1 + + + BasicMockAuthenticator + basicauth + true + + + true + true + + + + flow + + + + + + true + + + diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/pom.xml b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/pom.xml index c1834b68..befd675a 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/pom.xml +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/pom.xml @@ -54,6 +54,11 @@ org.wso2.carbon.identity.framework org.wso2.carbon.identity.testutil + + org.wso2.carbon.identity.conditional.auth.functions + org.wso2.carbon.identity.conditional.auth.functions.test.utils + test + org.testng testng diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginIdentifierFunctionImplTest.java b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginIdentifierFunctionImplTest.java index 18264546..50c4d398 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginIdentifierFunctionImplTest.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/utils/ResolveMultiAttributeLoginIdentifierFunctionImplTest.java @@ -23,32 +23,49 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import org.wso2.carbon.CarbonConstants; +import org.wso2.carbon.identity.application.authentication.framework.config.model.SequenceConfig; +import org.wso2.carbon.identity.application.authentication.framework.context.AuthenticationContext; import org.wso2.carbon.identity.application.authentication.framework.internal.FrameworkServiceDataHolder; +import org.wso2.carbon.identity.application.common.model.LocalAndOutboundAuthenticationConfig; +import org.wso2.carbon.identity.application.common.model.ServiceProvider; +import org.wso2.carbon.identity.application.common.model.script.AuthenticationScriptConfig; import org.wso2.carbon.identity.common.testng.WithCarbonHome; +import org.wso2.carbon.identity.common.testng.WithH2Database; import org.wso2.carbon.identity.common.testng.WithRealmService; +import org.wso2.carbon.identity.conditional.auth.functions.test.utils.sequence.JsSequenceHandlerAbstractTest; +import org.wso2.carbon.identity.conditional.auth.functions.test.utils.sequence.JsTestException; +import org.wso2.carbon.identity.core.util.IdentityTenantUtil; import org.wso2.carbon.identity.multi.attribute.login.mgt.MultiAttributeLoginService; import org.wso2.carbon.identity.multi.attribute.login.mgt.ResolvedUserResult; import org.wso2.carbon.user.core.common.User; import java.lang.reflect.Field; +import java.util.Collections; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; @WithCarbonHome -@WithRealmService(injectToSingletons = {FrameworkServiceDataHolder.class}) -public class ResolveMultiAttributeLoginIdentifierFunctionImplTest { - - private ResolveMultiAttributeLoginIdentifierFunctionImpl testFunction; +@WithRealmService(injectToSingletons = {IdentityTenantUtil.class, FrameworkServiceDataHolder.class}) +@WithH2Database(files = "dbscripts/h2.sql") +public class ResolveMultiAttributeLoginIdentifierFunctionImplTest extends JsSequenceHandlerAbstractTest { @Mock private MultiAttributeLoginService multiAttributeLoginServiceMock; @BeforeClass - public void setUp() throws NoSuchFieldException, IllegalAccessException { + public void setUp() throws Exception { + + super.setUp(); + CarbonConstants.ENABLE_LEGACY_AUTHZ_RUNTIME = true; + sequenceHandlerRunner.registerJsFunction("resolveMultiAttributeLoginIdentifier", + new ResolveMultiAttributeLoginIdentifierFunctionImpl()); - testFunction = new ResolveMultiAttributeLoginIdentifierFunctionImpl(); initMocks(this); Field frameworkServiceDataHolder = FrameworkServiceDataHolder.class.getDeclaredField("instance"); @@ -69,10 +86,10 @@ public Object[][] loginIdentifierProvider() { @Test (dataProvider = "loginIdentifierProvider") public void testResolveMultiAttributeLoginIdentifier(boolean multiAttributeLoginEnabled, - String loginIdentifier, String username) { + String loginIdentifier, String username) + throws JsTestException { ResolvedUserResult userResult = new ResolvedUserResult(ResolvedUserResult.UserResolvedStatus.SUCCESS); - if (multiAttributeLoginEnabled) { User user = new User("123456", username, username); userResult.setUser(user); @@ -81,15 +98,42 @@ public void testResolveMultiAttributeLoginIdentifier(boolean multiAttributeLogin } when(multiAttributeLoginServiceMock.isEnabled(anyString())).thenReturn(multiAttributeLoginEnabled); - when(multiAttributeLoginServiceMock.resolveUser(loginIdentifier, "carbon.super")).thenReturn(userResult); + when(multiAttributeLoginServiceMock.resolveUser(loginIdentifier, "test_domain")).thenReturn(userResult); + + AuthenticationContext context = getAuthenticationContextForSP(loginIdentifier); + HttpServletRequest req = sequenceHandlerRunner.createHttpServletRequest(); + HttpServletResponse resp = sequenceHandlerRunner.createHttpServletResponse(); - String result = testFunction.resolveMultiAttributeLoginIdentifier(loginIdentifier, "carbon.super"); + sequenceHandlerRunner.handle(req, resp, context, "test_domain"); + String returnResult = context.getSelectedAcr(); + Assert.assertNotNull(returnResult); if (multiAttributeLoginEnabled) { - Assert.assertNotNull(result); - Assert.assertEquals(result, username); + Assert.assertEquals(returnResult, username); } else { - Assert.assertNull(result); + Assert.assertEquals(returnResult, "NONE"); } } + + private AuthenticationContext getAuthenticationContextForSP(String loginIdentifier) throws JsTestException { + + sequenceHandlerRunner.addSubjectAuthenticator("BasicMockAuthenticator", "test_user", Collections.emptyMap()); + ServiceProvider sp = sequenceHandlerRunner.loadServiceProviderFromResource( + "resolve-multi-attribute-login-sp.xml", this); + + LocalAndOutboundAuthenticationConfig authConfig = sp.getLocalAndOutBoundAuthenticationConfig(); + AuthenticationScriptConfig scriptConfig = authConfig.getAuthenticationScriptConfig(); + String content = scriptConfig.getContent(); + String newContent = String.format(content, loginIdentifier); + scriptConfig.setContent(newContent); + authConfig.setAuthenticationScriptConfig(scriptConfig); + sp.setLocalAndOutBoundAuthenticationConfig(authConfig); + + AuthenticationContext context = sequenceHandlerRunner.createAuthenticationContext(sp); + SequenceConfig sequenceConfig = sequenceHandlerRunner.getSequenceConfig(context, sp); + context.setSequenceConfig(sequenceConfig); + context.initializeAnalyticsData(); + + return context; + } } diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/test/resources/dbscripts/h2.sql b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/test/resources/dbscripts/h2.sql new file mode 100644 index 00000000..f26d41fc --- /dev/null +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/test/resources/dbscripts/h2.sql @@ -0,0 +1,50 @@ +CREATE TABLE IF NOT EXISTS IDN_CLAIM_DIALECT ( + ID INTEGER NOT NULL AUTO_INCREMENT, + DIALECT_URI VARCHAR (255) NOT NULL, + TENANT_ID INTEGER NOT NULL, + PRIMARY KEY (ID), + CONSTRAINT DIALECT_URI_CONSTRAINT UNIQUE (DIALECT_URI, TENANT_ID) +); + +CREATE TABLE IF NOT EXISTS IDN_CLAIM ( + ID INTEGER NOT NULL AUTO_INCREMENT, + DIALECT_ID INTEGER NOT NULL, + CLAIM_URI VARCHAR (255) NOT NULL, + TENANT_ID INTEGER NOT NULL, + PRIMARY KEY (ID), + FOREIGN KEY (DIALECT_ID) REFERENCES IDN_CLAIM_DIALECT(ID) ON DELETE CASCADE, + CONSTRAINT CLAIM_URI_CONSTRAINT UNIQUE (DIALECT_ID, CLAIM_URI, TENANT_ID) +); + +CREATE TABLE IF NOT EXISTS IDN_CLAIM_MAPPED_ATTRIBUTE ( + ID INTEGER NOT NULL AUTO_INCREMENT, + LOCAL_CLAIM_ID INTEGER, + USER_STORE_DOMAIN_NAME VARCHAR (255) NOT NULL, + ATTRIBUTE_NAME VARCHAR (255) NOT NULL, + TENANT_ID INTEGER NOT NULL, + PRIMARY KEY (ID), + FOREIGN KEY (LOCAL_CLAIM_ID) REFERENCES IDN_CLAIM(ID) ON DELETE CASCADE, + CONSTRAINT USER_STORE_DOMAIN_CONSTRAINT UNIQUE (LOCAL_CLAIM_ID, USER_STORE_DOMAIN_NAME, TENANT_ID) +); + +CREATE TABLE IF NOT EXISTS IDN_CLAIM_PROPERTY ( + ID INTEGER NOT NULL AUTO_INCREMENT, + LOCAL_CLAIM_ID INTEGER, + PROPERTY_NAME VARCHAR (255) NOT NULL, + PROPERTY_VALUE VARCHAR (255) NOT NULL, + TENANT_ID INTEGER NOT NULL, + PRIMARY KEY (ID), + FOREIGN KEY (LOCAL_CLAIM_ID) REFERENCES IDN_CLAIM(ID) ON DELETE CASCADE, + CONSTRAINT PROPERTY_NAME_CONSTRAINT UNIQUE (LOCAL_CLAIM_ID, PROPERTY_NAME, TENANT_ID) +); + +CREATE TABLE IF NOT EXISTS IDN_CLAIM_MAPPING ( + ID INTEGER NOT NULL AUTO_INCREMENT, + EXT_CLAIM_ID INTEGER NOT NULL, + MAPPED_LOCAL_CLAIM_ID INTEGER NOT NULL, + TENANT_ID INTEGER NOT NULL, + PRIMARY KEY (ID), + FOREIGN KEY (EXT_CLAIM_ID) REFERENCES IDN_CLAIM(ID) ON DELETE CASCADE, + FOREIGN KEY (MAPPED_LOCAL_CLAIM_ID) REFERENCES IDN_CLAIM(ID) ON DELETE CASCADE, + CONSTRAINT EXT_TO_LOC_MAPPING_CONSTRN UNIQUE (EXT_CLAIM_ID, TENANT_ID), +); diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/utils/resolve-multi-attribute-login-sp.xml b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/utils/resolve-multi-attribute-login-sp.xml new file mode 100644 index 00000000..58e4bc1d --- /dev/null +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.utils/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/utils/resolve-multi-attribute-login-sp.xml @@ -0,0 +1,74 @@ + + + 1 + default + Default Service Provider + + + + default + + + + + + + + + 1 + + + BasicMockAuthenticator + basicauth + true + + + true + true + + + + flow + + + + + + true + + +