Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide Group UUID support for write operations #524

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,7 +2613,7 @@ 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);
Expand All @@ -2625,8 +2626,8 @@ public Group createGroup(Group group, Map<String, Boolean> requiredAttributes)
// 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 +2663,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 +2693,26 @@ public Group createGroup(Group group, Map<String, Boolean> requiredAttributes)
return group;
}

/**
* Convert the claimsInLocalDialect to a list of Claims. NOTE: This method drops the RESOURCE_TYPE_CLAIM claim
* dialect being added to the returned claims list.
*
* @param claimsInLocalDialect Map of claims in local dialect.
* @return List of claims.
*/
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;
}

@Override
public Group getGroup(String id, Map<String, Boolean> requiredAttributes) throws CharonException {

Expand Down Expand Up @@ -2810,11 +2824,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 +2837,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 +2858,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 +3350,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 +3370,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 +3460,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 +3517,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 +3550,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 +3635,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 +6263,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.10.1</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
Loading