From 7c411f814d58eef55342d61b1d8cda475d6af43b Mon Sep 17 00:00:00 2001 From: anjanasamindraperera Date: Tue, 5 Mar 2024 12:15:13 +0530 Subject: [PATCH 1/4] Add new event to track scim credential updates --- .../scim2/common/impl/SCIMUserManager.java | 35 +++++++++++++++++++ .../common/internal/SCIMCommonComponent.java | 27 ++++++++++++++ .../internal/SCIMCommonComponentHolder.java | 22 ++++++++++++ 3 files changed, 84 insertions(+) diff --git a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/impl/SCIMUserManager.java b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/impl/SCIMUserManager.java index efab848c8..3990234e8 100644 --- a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/impl/SCIMUserManager.java +++ b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/impl/SCIMUserManager.java @@ -41,7 +41,9 @@ import org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants; import org.wso2.carbon.identity.core.util.IdentityTenantUtil; import org.wso2.carbon.identity.core.util.IdentityUtil; +import org.wso2.carbon.identity.event.IdentityEventConstants; import org.wso2.carbon.identity.event.IdentityEventException; +import org.wso2.carbon.identity.event.event.Event; import org.wso2.carbon.identity.mgt.policy.PolicyViolationException; import org.wso2.carbon.identity.provisioning.IdentityProvisioningConstants; import org.wso2.carbon.identity.role.v2.mgt.core.exception.IdentityRoleManagementException; @@ -1114,6 +1116,7 @@ public User updateUser(User user, Map requiredAttributes) throw // If password is updated, set it separately. if (user.getPassword() != null) { carbonUM.updateCredentialByAdminWithID(user.getId(), user.getPassword()); + publishEvent(user, IdentityEventConstants.Event.POST_UPDATE_CREDENTIAL_BY_SCIM, false); } updateUserClaims(user, oldClaimList, claimValuesInLocalDialect); @@ -1299,6 +1302,7 @@ public User updateUser(User user, Map requiredAttributes, // If password is updated, set it separately. if (user.getPassword() != null) { carbonUM.updateCredentialByAdminWithID(user.getId(), user.getPassword()); + publishEvent(user, IdentityEventConstants.Event.POST_UPDATE_CREDENTIAL_BY_SCIM, true); } updateUserClaims(user, oldClaimList, claimValuesInLocalDialect, allSimpleMultiValuedClaimsList); @@ -6272,4 +6276,35 @@ private List addDomainToNames(String userStoreDomainName, List g return groupsList.stream().map(groupName -> UserCoreUtil.addDomainToName(groupName, userStoreDomainName)) .collect(Collectors.toList()); } + + /** + * Publish event for credential updates. + * + * @param user User object. + * @param eventName Name of the event. + * @param isAdminUpdate Indicates whether the user is an admin. + * @throws BadRequestException If the request is invalid. + * @throws UserStoreException If an error occurs related to the user store. + * @throws CharonException If an error occurs during the event handling. + */ + private void publishEvent(User user, String eventName, Boolean isAdminUpdate) + throws BadRequestException, UserStoreException, CharonException { + + HashMap properties = new HashMap<>(); + properties.put(IdentityEventConstants.EventProperty.USER_NAME, + UserCoreUtil.removeDomainFromName(user.getUsername())); + properties.put(IdentityEventConstants.EventProperty.TENANT_DOMAIN, tenantDomain); + properties.put(IdentityEventConstants.EventProperty.TENANT_ID, carbonUM.getTenantId()); + properties.put(IdentityEventConstants.EventProperty.USER_STORE_DOMAIN, + IdentityUtil.extractDomainFromName(user.getUsername())); + properties.put(IdentityEventConstants.EventProperty.CREDENTIAL, user.getPassword()); + properties.put(IdentityEventConstants.EventProperty.IS_ADMIN_UPDATE, isAdminUpdate); + + Event identityMgtEvent = new Event(eventName, properties); + try { + SCIMCommonComponentHolder.getIdentityEventService().handleEvent(identityMgtEvent); + } catch (IdentityEventException e) { + throw new BadRequestException("Error occurred publishing event", ResponseCodeConstants.INVALID_VALUE); + } + } } diff --git a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/internal/SCIMCommonComponent.java b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/internal/SCIMCommonComponent.java index 50b59bb77..2dd32edc3 100644 --- a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/internal/SCIMCommonComponent.java +++ b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/internal/SCIMCommonComponent.java @@ -32,6 +32,7 @@ import org.wso2.carbon.identity.core.util.IdentityCoreInitializedEvent; import org.wso2.carbon.identity.core.util.IdentityUtil; import org.wso2.carbon.identity.event.handler.AbstractEventHandler; +import org.wso2.carbon.identity.event.services.IdentityEventService; import org.wso2.carbon.identity.organization.management.service.OrganizationManager; import org.wso2.carbon.identity.role.mgt.core.RoleManagementService; import org.wso2.carbon.identity.scim2.common.extenstion.SCIMUserStoreErrorResolver; @@ -361,6 +362,32 @@ protected void unsetOrganizationManager(OrganizationManager organizationManager) SCIMCommonComponentHolder.setOrganizationManager(null); } + /** + * Unset identityEventService service implementation. + * + * @param identityEventService IdentityEventService + */ + protected void unsetIdentityEventService(IdentityEventService identityEventService) { + + SCIMCommonComponentHolder.setIdentityEventService(null); + } + + /** + * Set IdentityEventService implementation + * + * @param identityEventService IdentityEventService + */ + @Reference( + name = "IdentityEventService", + service = org.wso2.carbon.identity.event.services.IdentityEventService.class, + cardinality = ReferenceCardinality.MANDATORY, + policy = ReferencePolicy.DYNAMIC, + unbind = "unsetIdentityEventService") + protected void setIdentityEventService(IdentityEventService identityEventService) { + + SCIMCommonComponentHolder.setIdentityEventService(identityEventService); + } + @Deactivate protected void deactivate(ComponentContext context) { diff --git a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/internal/SCIMCommonComponentHolder.java b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/internal/SCIMCommonComponentHolder.java index b8f803b28..2a3459f8c 100644 --- a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/internal/SCIMCommonComponentHolder.java +++ b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/internal/SCIMCommonComponentHolder.java @@ -19,6 +19,7 @@ package org.wso2.carbon.identity.scim2.common.internal; import org.wso2.carbon.identity.claim.metadata.mgt.ClaimMetadataManagementService; +import org.wso2.carbon.identity.event.services.IdentityEventService; import org.wso2.carbon.identity.organization.management.service.OrganizationManager; import org.wso2.carbon.identity.scim2.common.extenstion.SCIMUserStoreErrorResolver; import org.wso2.carbon.idp.mgt.IdpManager; @@ -43,6 +44,7 @@ public class SCIMCommonComponentHolder { private static org.wso2.carbon.identity.role.v2.mgt.core.RoleManagementService roleManagementServiceV2; private static OrganizationManager organizationManager; private static IdpManager idpManager; + private static IdentityEventService identityEventService; private static final List scimUserStoreErrorResolvers = new ArrayList<>(); /** @@ -203,4 +205,24 @@ public static void removeScimUserStoreErrorResolver(SCIMUserStoreErrorResolver s scimUserStoreErrorResolvers.remove(scimUserStoreErrorResolver); scimUserStoreErrorResolvers.sort(Comparator.comparing(SCIMUserStoreErrorResolver::getOrder).reversed()); } + + /** + * Get IdentityEvent service. + * + * @return IdentityEventService. + */ + public static IdentityEventService getIdentityEventService() { + + return identityEventService; + } + + /** + * Set IdentityEvent service. + * + * @param identityEventService IdentityEventService. + */ + public static void setIdentityEventService(IdentityEventService identityEventService) { + + SCIMCommonComponentHolder.identityEventService = identityEventService; + } } From 9e461f989f956a95e9220fddcc78fa1b0130b443 Mon Sep 17 00:00:00 2001 From: anjanasamindraperera Date: Wed, 6 Mar 2024 12:45:31 +0530 Subject: [PATCH 2/4] Address comments --- .../scim2/common/impl/SCIMUserManager.java | 11 +++- .../common/utils/SCIMCommonConstants.java | 3 +- .../scim2/common/utils/Scenarios.java | 54 +++++++++++++++++++ 3 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/utils/Scenarios.java diff --git a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/impl/SCIMUserManager.java b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/impl/SCIMUserManager.java index 3990234e8..6f5a23dba 100644 --- a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/impl/SCIMUserManager.java +++ b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/impl/SCIMUserManager.java @@ -58,6 +58,7 @@ import org.wso2.carbon.identity.scim2.common.utils.AttributeMapper; import org.wso2.carbon.identity.scim2.common.utils.SCIMCommonConstants; import org.wso2.carbon.identity.scim2.common.utils.SCIMCommonUtils; +import org.wso2.carbon.identity.scim2.common.utils.Scenarios; import org.wso2.carbon.user.api.ClaimMapping; import org.wso2.carbon.user.api.UserStoreException; import org.wso2.carbon.user.core.PaginatedUserStoreManager; @@ -6287,7 +6288,7 @@ private List addDomainToNames(String userStoreDomainName, List g * @throws UserStoreException If an error occurs related to the user store. * @throws CharonException If an error occurs during the event handling. */ - private void publishEvent(User user, String eventName, Boolean isAdminUpdate) + private void publishEvent(User user, String eventName, boolean isAdminUpdate) throws BadRequestException, UserStoreException, CharonException { HashMap properties = new HashMap<>(); @@ -6298,7 +6299,13 @@ private void publishEvent(User user, String eventName, Boolean isAdminUpdate) properties.put(IdentityEventConstants.EventProperty.USER_STORE_DOMAIN, IdentityUtil.extractDomainFromName(user.getUsername())); properties.put(IdentityEventConstants.EventProperty.CREDENTIAL, user.getPassword()); - properties.put(IdentityEventConstants.EventProperty.IS_ADMIN_UPDATE, isAdminUpdate); + if (isAdminUpdate) { + properties.put(IdentityEventConstants.EventProperty.SCENARIO, + Scenarios.CREDENTIAL_UPDATE_BY_ADMIN_VIA_CONSOLE.name()); + } else { + properties.put(IdentityEventConstants.EventProperty.SCENARIO, + Scenarios.CREDENTIAL_UPDATE_BY_USER_VIA_MY_ACCOUNT.name()); + } Event identityMgtEvent = new Event(eventName, properties); try { diff --git a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/utils/SCIMCommonConstants.java b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/utils/SCIMCommonConstants.java index 8881f1f9b..cd10ae5cc 100644 --- a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/utils/SCIMCommonConstants.java +++ b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/utils/SCIMCommonConstants.java @@ -179,7 +179,8 @@ public enum ErrorMessages { ERROR_CODE_REGEX_VIOLATION("SUO-10001", "Regex validation error", "%s attribute value doesn't match with %s regex pattern"), ERROR_CODE_LENGTH_VIOLATION("SUO-10002", "Length validation error", - "%s attribute should be between %s and %s characters"); + "%s attribute should be between %s and %s characters"), + ERROR_CODE_INVALID_SCENARIO("SUO-10003","Invalid scenario","Invalid scenario: '%s'"); private final String code; private final String message; diff --git a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/utils/Scenarios.java b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/utils/Scenarios.java new file mode 100644 index 000000000..a6ad9732d --- /dev/null +++ b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/utils/Scenarios.java @@ -0,0 +1,54 @@ +/* + * 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.scim2.common.utils; + +import org.apache.commons.lang.StringUtils; +import org.wso2.carbon.identity.scim2.common.exceptions.IdentitySCIMException; + +/** + * Enum which contains the scenarios. + */ +public enum Scenarios { + + CREDENTIAL_UPDATE_BY_ADMIN_VIA_CONSOLE, + CREDENTIAL_UPDATE_BY_USER_VIA_MY_ACCOUNT; + + /** + * Get scenario which matches the given scenario name. + * + * @param scenarioName Name of the scenario + * @return Scenarios + * @throws IdentitySCIMException Invalid scenario + */ + public static Scenarios getScenario(String scenarioName) throws IdentitySCIMException { + + Scenarios[] scenarios = { + CREDENTIAL_UPDATE_BY_ADMIN_VIA_CONSOLE, CREDENTIAL_UPDATE_BY_USER_VIA_MY_ACCOUNT + }; + if (StringUtils.isNotEmpty(scenarioName)) { + for (Scenarios scenario : scenarios) { + if (scenarioName.equals(scenario.name())) { + return scenario; + } + } + } + throw new IdentitySCIMException(SCIMCommonConstants.ErrorMessages.ERROR_CODE_INVALID_SCENARIO.getMessage()); + } + +} From 36cd22cef2f287db887087ab25fb2e66e2d5cfe4 Mon Sep 17 00:00:00 2001 From: anjanasamindraperera Date: Fri, 8 Mar 2024 09:07:12 +0530 Subject: [PATCH 3/4] Bump framework --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1363b7cf6..39b5fa2d2 100644 --- a/pom.xml +++ b/pom.xml @@ -285,7 +285,7 @@ 6.5.3 3.2.0.wso2v1 4.10.2 - 5.25.612 + 7.0.89 4.13.1 20030203.000129 1.8.12 From dc5c26fe6b2fbd2f92bf2a8f464f6119259aed7e Mon Sep 17 00:00:00 2001 From: anjanasamindraperera Date: Fri, 8 Mar 2024 11:22:44 +0530 Subject: [PATCH 4/4] Remove unwanted error constant --- .../identity/scim2/common/utils/SCIMCommonConstants.java | 3 +-- .../org/wso2/carbon/identity/scim2/common/utils/Scenarios.java | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/utils/SCIMCommonConstants.java b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/utils/SCIMCommonConstants.java index cd10ae5cc..b372bd78b 100644 --- a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/utils/SCIMCommonConstants.java +++ b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/utils/SCIMCommonConstants.java @@ -179,8 +179,7 @@ public enum ErrorMessages { ERROR_CODE_REGEX_VIOLATION("SUO-10001", "Regex validation error", "%s attribute value doesn't match with %s regex pattern"), ERROR_CODE_LENGTH_VIOLATION("SUO-10002", "Length validation error", - "%s attribute should be between %s and %s characters"), - ERROR_CODE_INVALID_SCENARIO("SUO-10003","Invalid scenario","Invalid scenario: '%s'"); + "%s attribute should be between %s and %s characters"); private final String code; private final String message; diff --git a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/utils/Scenarios.java b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/utils/Scenarios.java index a6ad9732d..8ba5d2d52 100644 --- a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/utils/Scenarios.java +++ b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/utils/Scenarios.java @@ -48,7 +48,7 @@ public static Scenarios getScenario(String scenarioName) throws IdentitySCIMExce } } } - throw new IdentitySCIMException(SCIMCommonConstants.ErrorMessages.ERROR_CODE_INVALID_SCENARIO.getMessage()); + throw new IdentitySCIMException("Invalid scenario: " + scenarioName); } }