From d8c544d22e346d4ea2394c33ff1a68f542cee075 Mon Sep 17 00:00:00 2001 From: somindagamage Date: Wed, 31 Jan 2024 08:48:34 -0500 Subject: [PATCH] Provide Group UUID support for write operations --- .../identity/scim2/common/DAO/GroupDAO.java | 1 - .../scim2/common/impl/SCIMUserManager.java | 98 ++++++++++--------- .../common/listener/SCIMGroupResolver.java | 98 +++++++++++++++++++ .../listener/SCIMUserOperationListener.java | 6 +- pom.xml | 2 +- 5 files changed, 156 insertions(+), 49 deletions(-) diff --git a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/DAO/GroupDAO.java b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/DAO/GroupDAO.java index ec9d1b171..a97c6dcb0 100644 --- a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/DAO/GroupDAO.java +++ b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/DAO/GroupDAO.java @@ -195,7 +195,6 @@ public void addSCIMGroupAttributes(int tenantId, String roleName, Map requiredAttributes) throw charonException; } group.setDisplayName(roleNameWithDomain); - //check if the group already exists + // Check if the group already exists. if (carbonUM.isExistingRole(group.getDisplayName(), false)) { String error = "Group with name: " + group.getDisplayName() + " already exists in the system."; throw new ConflictException(error); @@ -2620,13 +2621,14 @@ public Group createGroup(Group group, Map requiredAttributes) // Set thread local property to signal the downstream SCIMUserOperationListener about the // provisioning route. + // TODO: 2024-01-29 Can we set this to false; SCIMCommonUtils.setThreadLocalIsManagedThroughSCIMEP(true); // If members are sent when creating the group, check whether users already exist in the user store. List userIds = group.getMembers(); List userDisplayNames = group.getMembersWithDisplayName(); + List members = new ArrayList<>(); if (isNotEmpty(userIds)) { - List members = new ArrayList<>(); for (Object userId : userIds) { String userIdLocalClaim = SCIMCommonUtils.getSCIMtoLocalMappings().get(SCIMConstants .CommonSchemaConstants.ID_URI); @@ -2662,21 +2664,14 @@ public Group createGroup(Group group, Map requiredAttributes) } } } - // Add other scim attributes in the identity DB since user store doesn't support some attributes. - SCIMGroupHandler scimGroupHandler = new SCIMGroupHandler(carbonUM.getTenantId()); - scimGroupHandler.createSCIMAttributes(group); - carbonUM.addRoleWithID(group.getDisplayName(), members.toArray(new String[0]), null, false); - if (log.isDebugEnabled()) { - log.debug("Group: " + group.getDisplayName() + " is created through SCIM."); - } - } else { - // Add other scim attributes in the identity DB since user store doesn't support some attributes. - SCIMGroupHandler scimGroupHandler = new SCIMGroupHandler(carbonUM.getTenantId()); - scimGroupHandler.createSCIMAttributes(group); - carbonUM.addRoleWithID(group.getDisplayName(), null, null, false); - if (log.isDebugEnabled()) { - log.debug("Group: " + group.getDisplayName() + " is created through SCIM."); - } + } + Map claimsInLocalDialect = + SCIMCommonUtils.convertSCIMtoLocalDialect(AttributeMapper.getClaimsMap(group)); + org.wso2.carbon.user.core.common.Group createdGroup = + carbonUM.addGroup(roleNameWithDomain, members, buildGroupMetaClaimsList(claimsInLocalDialect)); + group = buildGroup(createdGroup); + if (log.isDebugEnabled()) { + log.debug("Group: " + group.getDisplayName() + " is created through SCIM."); } } catch (UserStoreException e) { try { @@ -2699,6 +2694,36 @@ public Group createGroup(Group group, Map requiredAttributes) return group; } + private List buildGroupMetaClaimsList(Map claimsInLocalDialect) { + + List claimsList = new ArrayList<>(); + for (Map.Entry entry : claimsInLocalDialect.entrySet()) { + String claimUri = entry.getKey(); + if (RESOURCE_TYPE_CLAIM.equals(claimUri)) { + continue; + } + claimsList.add(new Claim(entry.getKey(), entry.getValue())); + } + return claimsList; + } + + /** + * Build Group object for user core from SCIM Group object. + * + * @param group SCIM Group object. + * @return Group object for user core. + */ + private org.wso2.carbon.user.core.common.Group buildGroupFromSCIMObject(Group group) { + + String displayName = group.getDisplayName(); + org.wso2.carbon.user.core.common.Group userGroup = + new org.wso2.carbon.user.core.common.Group(group.getId(), displayName); + userGroup.setCreatedDate(group.getCreatedDateTime().toString()); + userGroup.setLastModifiedDate(group.getLastModifiedDateTime().toString()); + userGroup.setLocation(group.getLocation()); + return userGroup; + } + @Override public Group getGroup(String id, Map requiredAttributes) throws CharonException { @@ -2810,11 +2835,9 @@ public void deleteGroup(String groupId) throws NotFoundException, CharonExceptio SCIMCommonUtils.setThreadLocalIsManagedThroughSCIMEP(true); // Get group name by id. - SCIMGroupHandler groupHandler = new SCIMGroupHandler(carbonUM.getTenantId()); - String groupName = groupHandler.getGroupName(groupId); - + String groupName = carbonUM.getGroupNameByGroupId(groupId); if (groupName != null) { - String userStoreDomainFromSP = null; + String userStoreDomainFromSP; try { userStoreDomainFromSP = getUserStoreDomainFromSP(); } catch (IdentityApplicationManagementException e) { @@ -2825,24 +2848,19 @@ public void deleteGroup(String groupId) throws NotFoundException, CharonExceptio throw new CharonException("Group :" + groupName + "is not belong to user store " + userStoreDomainFromSP + "Hence group updating fail"); } - String userStoreDomainName = IdentityUtil.extractDomainFromName(groupName); - if (!isInternalOrApplicationGroup(userStoreDomainName) && StringUtils.isNotBlank(userStoreDomainName) - && !isSCIMEnabled - (userStoreDomainName)) { + if (!isInternalOrApplicationGroup(userStoreDomainName) && StringUtils.isNotBlank(userStoreDomainName) && + !isSCIMEnabled(userStoreDomainName)) { throw new CharonException("Cannot delete group: " + groupName + " through scim from user store: " + userStoreDomainName + ". SCIM is not enabled for user store: " + userStoreDomainName); } - - //delete group in carbon UM - carbonUM.deleteRole(groupName); + // Delete group in carbon UM. + carbonUM.deleteGroup(groupId); carbonUM.removeGroupRoleMappingByGroupName(groupName); - - //we do not update Identity_SCIM DB here since it is updated in SCIMUserOperationListener's methods. + // We do not update Identity_SCIM DB here since it is updated in SCIMUserOperationListener's methods. if (log.isDebugEnabled()) { log.debug("Group: " + groupName + " is deleted through SCIM."); } - } else { if (log.isDebugEnabled()) { log.debug("Group with SCIM id: " + groupId + " doesn't exist in the system."); @@ -2851,10 +2869,7 @@ public void deleteGroup(String groupId) throws NotFoundException, CharonExceptio } } catch (UserStoreException e) { throw resolveError(e, "Error occurred while deleting group " + groupId); - } catch (IdentitySCIMException e) { - throw new CharonException("Error occurred while deleting group " + groupId, e); } - } @Override @@ -3346,12 +3361,10 @@ private void doPatchGroup(String groupId, String currentGroupName, Map displayNameOperations = new ArrayList<>(); List memberOperations = new ArrayList<>(); String newGroupName = currentGroupName; - for (List patchOperationList : patchOperations.values()) { for (PatchOperation patchOperation : patchOperationList) { if (StringUtils.equals(SCIMConstants.GroupSchemaConstants.DISPLAY_NAME, @@ -3368,7 +3381,7 @@ private void doPatchGroup(String groupId, String currentGroupName, Map addedMembers, Set attributes = new HashMap<>(); + attributes.put(SCIMConstants.CommonSchemaConstants.ID_URI, group.getGroupID()); + // Validate whether date time attributes are in the correct format. + try { + if (StringUtils.isNotBlank(group.getCreatedDate())) { + attributes.put(SCIMConstants.CommonSchemaConstants.CREATED_URI, + AttributeUtil.formatDateTime(AttributeUtil.parseDateTime(group.getCreatedDate()))); + } + if (StringUtils.isNotBlank(group.getLastModifiedDate())) { + attributes.put(SCIMConstants.CommonSchemaConstants.LAST_MODIFIED_URI, + AttributeUtil.formatDateTime(AttributeUtil.parseDateTime(group.getLastModifiedDate()))); + } + } catch (CharonException e) { + throw new UserStoreException(String.format("Error occurred while adding the group: %s in tenant: %s. " + + "Unsupported Datetime formats provided in the request", groupWithDomain, tenantId), e); + } + if (StringUtils.isNotBlank(group.getLastModifiedDate())) { + attributes.put(SCIMConstants.CommonSchemaConstants.LOCATION_URI, group.getLocation()); + } + // Update SCIM tables for storing meta information. + GroupDAO groupDAO = new GroupDAO(); + try { + groupDAO.addSCIMGroupAttributes(tenantId, groupWithDomain, attributes); + } catch (IdentitySCIMException e) { + throw new UserStoreException(String.format("Error occurred while adding the group: %s in tenant: %s", + groupWithDomain, tenantId), e); + } + return true; + } + + @Override + public boolean deleteGroupByName(String groupName, UserStoreManager userStoreManager) throws UserStoreException { + + AbstractUserStoreManager abstractUserStoreManager = ((AbstractUserStoreManager) userStoreManager); + boolean isGroupIdEnabled = abstractUserStoreManager.isUniqueGroupIdEnabled(); + if (isGroupIdEnabled) { + if (log.isDebugEnabled()) { + log.debug(String.format("SCIMGroupResolver will not be executed for userstore: %s in " + + "tenant %s since group id support is available in the userstore manager", + abstractUserStoreManager.getRealmConfiguration().getRealmProperty(PROPERTY_DOMAIN_NAME), + abstractUserStoreManager.getTenantId())); + } + return true; + } + int tenantId = abstractUserStoreManager.getTenantId(); + String domain = abstractUserStoreManager.getRealmConfiguration() + .getUserStoreProperty(UserStoreConfigConstants.DOMAIN_NAME); + // User core methods don't append primary domain name to the group name. Hence, we need to do it manually. + String groupWithDomain = + SCIMCommonUtils.getGroupNameWithDomain(UserCoreUtil.addDomainToName(groupName, domain)); + GroupDAO groupDAO = new GroupDAO(); + try { + if (!groupDAO.isExistingGroup(groupWithDomain, tenantId)) { + log.debug(String.format("No group with name: %s found in SCIM tables for tenant: %s", groupWithDomain, + tenantId)); + return true; + } + groupDAO.removeSCIMGroup(tenantId, groupWithDomain); + } catch (IdentitySCIMException e) { + throw new UserStoreException(String.format("Error occurred while removing the group: %s in tenant: %s", + groupWithDomain, tenantId), e); + } + return true; + } + @Override public boolean resolveGroupDomainByGroupId(Group group, int tenantId) throws UserStoreException { diff --git a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/listener/SCIMUserOperationListener.java b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/listener/SCIMUserOperationListener.java index be176a31e..3311f39c6 100644 --- a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/listener/SCIMUserOperationListener.java +++ b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/listener/SCIMUserOperationListener.java @@ -615,15 +615,15 @@ private boolean postAddRole(String roleName, UserStoreManager userStoreManager) !CarbonConstants.ENABLE_LEGACY_AUTHZ_RUNTIME) { scimGroupHandler.addRoleV2MandatoryAttributes(roleNameWithDomain); } else { - scimGroupHandler.addMandatoryAttributes(roleNameWithDomain); + if (!((AbstractUserStoreManager) userStoreManager).isUniqueGroupIdEnabled()) { + scimGroupHandler.addMandatoryAttributes(roleNameWithDomain); + } } } } catch (IdentitySCIMException e) { throw new UserStoreException("Error retrieving group information from SCIM Tables.", e); } - return true; - } catch (org.wso2.carbon.user.api.UserStoreException e) { throw new UserStoreException(e); } diff --git a/pom.xml b/pom.xml index f219e1c0d..3f7ef7d9d 100644 --- a/pom.xml +++ b/pom.xml @@ -284,7 +284,7 @@ 3.3.7 6.5.3 3.2.0.wso2v1 - 4.9.18 + 4.9.24 5.25.612 4.13.1 20030203.000129