Skip to content

Commit

Permalink
Provide Group UUID support for write operations
Browse files Browse the repository at this point in the history
  • Loading branch information
somindatommy committed Jan 31, 2024
1 parent be3843c commit d8c544d
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,6 @@ public void addSCIMGroupAttributes(int tenantId, String roleName, Map<String, St
}
prepStmt.executeBatch();
connection.commit();

} catch (SQLException e) {
throw new IdentitySCIMException("Error when adding SCIM attributes for the group: "
+ roleName, e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
import org.wso2.carbon.user.core.UserStoreManager;
import org.wso2.carbon.user.core.claim.ClaimManager;
import org.wso2.carbon.user.core.common.AbstractUserStoreManager;
import org.wso2.carbon.user.core.common.Claim;
import org.wso2.carbon.user.core.constants.UserCoreClaimConstants;
import org.wso2.carbon.user.core.constants.UserCoreErrorConstants;
import org.wso2.carbon.user.core.jdbc.JDBCUserStoreManager;
Expand Down Expand Up @@ -2612,21 +2613,22 @@ public Group createGroup(Group group, Map<String, Boolean> 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);
}

// 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<Object> userIds = group.getMembers();
List<String> userDisplayNames = group.getMembersWithDisplayName();
List<String> members = new ArrayList<>();
if (isNotEmpty(userIds)) {
List<String> members = new ArrayList<>();
for (Object userId : userIds) {
String userIdLocalClaim = SCIMCommonUtils.getSCIMtoLocalMappings().get(SCIMConstants
.CommonSchemaConstants.ID_URI);
Expand Down Expand Up @@ -2662,21 +2664,14 @@ public Group createGroup(Group group, Map<String, Boolean> 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<String, String> 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 {
Expand All @@ -2699,6 +2694,36 @@ public Group createGroup(Group group, Map<String, Boolean> requiredAttributes)
return group;
}

private List<Claim> buildGroupMetaClaimsList(Map<String, String> claimsInLocalDialect) {

List<Claim> claimsList = new ArrayList<>();
for (Map.Entry<String, String> 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<String, Boolean> requiredAttributes) throws CharonException {

Expand Down Expand Up @@ -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) {
Expand All @@ -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.");
Expand All @@ -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
Expand Down Expand Up @@ -3346,12 +3361,10 @@ private void doPatchGroup(String groupId, String currentGroupName, Map<String, L
if (log.isDebugEnabled()) {
log.debug("Updating group: " + currentGroupName);
}

try {
List<PatchOperation> displayNameOperations = new ArrayList<>();
List<PatchOperation> memberOperations = new ArrayList<>();
String newGroupName = currentGroupName;

for (List<PatchOperation> patchOperationList : patchOperations.values()) {
for (PatchOperation patchOperation : patchOperationList) {
if (StringUtils.equals(SCIMConstants.GroupSchemaConstants.DISPLAY_NAME,
Expand All @@ -3368,7 +3381,7 @@ private void doPatchGroup(String groupId, String currentGroupName, Map<String, L

if (CollectionUtils.isNotEmpty(displayNameOperations)) {
newGroupName = (String) displayNameOperations.get(0).getValues();
setGroupDisplayName(currentGroupName, newGroupName);
setGroupDisplayName(groupId, currentGroupName, newGroupName);
}

Collections.sort(memberOperations);
Expand Down Expand Up @@ -3458,7 +3471,6 @@ private void doPatchGroup(String groupId, String currentGroupName, Map<String, L

// Update the group name in UM_HYBRID_GROUP_ROLE table.
carbonUM.updateGroupName(currentGroupName, newGroupName);

} catch (UserStoreException e) {
if (e instanceof org.wso2.carbon.user.core.UserStoreException && StringUtils
.equals(UserCoreErrorConstants.ErrorMessages.ERROR_CODE_NON_EXISTING_USER.getCode(),
Expand Down Expand Up @@ -3516,7 +3528,7 @@ private void prepareAddedRemovedMemberLists(Set<String> addedMembers, Set<String
}
}

private void setGroupDisplayName(String oldGroupName, String newGroupName)
private void setGroupDisplayName(String groupId, String oldGroupName, String newGroupName)
throws IdentityApplicationManagementException, CharonException, BadRequestException, IdentitySCIMException,
UserStoreException {

Expand Down Expand Up @@ -3549,7 +3561,7 @@ private void setGroupDisplayName(String oldGroupName, String newGroupName)

if (!StringUtils.equals(oldGroupName, newGroupName)) {
// Update group name in carbon UM.
carbonUM.updateRoleName(oldGroupName, newGroupName);
carbonUM.renameGroup(groupId, newGroupName);
}
}

Expand Down Expand Up @@ -3634,18 +3646,16 @@ public boolean doUpdateGroup(Group oldGroup, Group newGroup) throws CharonExcept
boolean updated = false;
if (isGroupDisplayNameChanged(oldGroupDisplayName, newGroupDisplayName)) {
// Update group name in carbon UM
carbonUM.updateRoleName(oldGroupDisplayName, newGroupDisplayName);
carbonUM.renameGroup(oldGroup.getId(), newGroupDisplayName);
updated = true;
}

// Update the group with added members and deleted members.
if (isNotEmpty(addedMembers) || isNotEmpty(deletedMembers)) {
carbonUM.updateUserListOfRoleWithID(newGroupDisplayName,
deletedMemberIdsFromUserstore.toArray(new String[0]),
addedMemberIdsFromUserstore.toArray(new String[0]));
updated = true;
}

return updated;
}

Expand Down Expand Up @@ -6264,7 +6274,7 @@ private Group buildGroup(org.wso2.carbon.user.core.common.Group group) throws Ba
}
scimGroup.setId(group.getGroupID());
if (StringUtils.isBlank(group.getLocation())) {
// Location has not been sent from the user core. Therefore we need to use the group id to build location.
// Location has not been sent from the user core. Therefore, we need to use the group id to build location.
scimGroup.setLocation(SCIMCommonUtils.getSCIMGroupURL(group.getGroupID()));
} else {
scimGroup.setLocation(group.getLocation());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,11 @@
import org.wso2.carbon.user.core.model.ExpressionCondition;
import org.wso2.carbon.user.core.model.OperationalCondition;
import org.wso2.carbon.user.core.util.UserCoreUtil;
import org.wso2.charon3.core.exceptions.CharonException;
import org.wso2.charon3.core.schema.SCIMConstants;
import org.wso2.charon3.core.utils.AttributeUtil;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

Expand All @@ -67,6 +70,101 @@ public int getExecutionOrderId() {
return 1;
}

@Override
public boolean addGroup(Group group, 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;
}
String userstoreDomainName = group.getUserStoreDomain();
int tenantId = abstractUserStoreManager.getTenantId();
if (StringUtils.isBlank(userstoreDomainName)) {
userstoreDomainName = abstractUserStoreManager.getRealmConfiguration().
getUserStoreProperty(UserStoreConfigConstants.DOMAIN_NAME);
group.setUserStoreDomain(userstoreDomainName);
}
// 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(group.getGroupName(),
userstoreDomainName));
String groupId = group.getGroupID();
if (StringUtils.isBlank(groupId)) {
throw new UserStoreException(
String.format("Group id cannot be empty the group: %s in tenant: %s. ", groupWithDomain, tenantId));
}
Map<String, String> 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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@
<cxf-bundle.version>3.3.7</cxf-bundle.version>
<inbound.auth.oauth.version>6.5.3</inbound.auth.oauth.version>
<commons-collections.version>3.2.0.wso2v1</commons-collections.version>
<carbon.kernel.version>4.9.18</carbon.kernel.version>
<carbon.kernel.version>4.9.24</carbon.kernel.version>
<identity.framework.version>5.25.612</identity.framework.version>
<junit.version>4.13.1</junit.version>
<commons.lang.version>20030203.000129</commons.lang.version>
Expand Down

0 comments on commit d8c544d

Please sign in to comment.