From b7746f460c2f3586a055250e35c63a4b3450c314 Mon Sep 17 00:00:00 2001 From: ChanikaRuchini Date: Tue, 5 Dec 2023 15:32:43 +0530 Subject: [PATCH 1/2] Support attributes and excludeAttributes query params for List roles v2 endpoint --- .../scim2/common/impl/SCIMRoleManagerV2.java | 116 ++++++++++++++---- .../provider/resources/RoleResourceV2.java | 7 +- scim2.yaml | 61 +++++---- 3 files changed, 125 insertions(+), 59 deletions(-) diff --git a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/impl/SCIMRoleManagerV2.java b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/impl/SCIMRoleManagerV2.java index 12da79976..2d3a04aa2 100644 --- a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/impl/SCIMRoleManagerV2.java +++ b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/impl/SCIMRoleManagerV2.java @@ -96,6 +96,10 @@ public class SCIMRoleManagerV2 implements RoleV2Manager { private static final String ROLE_NAME_FILTER_ATTRIBUTE = "name"; private static final String ROLE_AUDIENCE_TYPE_FILTER_ATTRIBUTE = "audience"; private static final String ROLE_AUDIENCE_ID_FILTER_ATTRIBUTE = "audienceId"; + private final String USERS = "users"; + private final String GROUPS = "groups"; + private final String PERMISSIONS = "permissions"; + private final String ASSOCIATED_APPLICATIONS = "associatedApplications"; private RoleManagementService roleManagementService; private String tenantDomain; private Set systemRoles; @@ -325,7 +329,7 @@ public void deleteRole(String roleID) throws CharonException, NotFoundException, } public RolesV2GetResponse listRolesWithGET(Node rootNode, Integer startIndex, Integer count, String sortBy, - String sortOrder) + String sortOrder, List requiredAttributes) throws CharonException, NotImplementedException, BadRequestException { if (sortBy != null || sortOrder != null) { @@ -333,18 +337,18 @@ public RolesV2GetResponse listRolesWithGET(Node rootNode, Integer startIndex, In } else if (count != null && count == 0) { return new RolesV2GetResponse(0, Collections.emptyList()); } else if (rootNode != null) { - return filterRoles(rootNode, count, startIndex, null, null); + return filterRoles(rootNode, count, startIndex, null, null, requiredAttributes); } else { - return listRoles(count, startIndex, null, null); + return listRoles(count, startIndex, null, null, requiredAttributes); } } @Override - public RolesV2GetResponse listRolesWithPost(SearchRequest searchRequest) + public RolesV2GetResponse listRolesWithPost(SearchRequest searchRequest, List requiredAttributes) throws NotImplementedException, BadRequestException, CharonException { return listRolesWithGET(searchRequest.getFilter(), searchRequest.getStartIndex(), searchRequest.getCount(), - searchRequest.getSortBy(), searchRequest.getSortOder()); + searchRequest.getSortBy(), searchRequest.getSortOder(), requiredAttributes); } @Override @@ -440,11 +444,11 @@ public RoleV2 patchRole(String roleId, Map> patchOp * @throws CharonException Error filtering the roles. */ private RolesV2GetResponse filterRoles(Node node, Integer count, Integer startIndex, String sortBy, - String sortOrder) + String sortOrder, List requiredAttributes) throws CharonException, NotImplementedException, BadRequestException { if (node instanceof ExpressionNode || node instanceof OperationNode) { - return filterRolesByAttributes(node, count, startIndex, sortBy, sortOrder); + return filterRolesByAttributes(node, count, startIndex, sortBy, sortOrder, requiredAttributes); } throw new CharonException("Unknown operation. Not either an expression node or an operation node."); } @@ -460,23 +464,24 @@ private RolesV2GetResponse filterRoles(Node node, Integer count, Integer startIn * @return Filtered roles. * @throws CharonException Error filtering the roles. */ - private RolesV2GetResponse filterRolesByAttributes(Node node, Integer count, Integer startIndex, - String sortBy, String sortOrder) + private RolesV2GetResponse filterRolesByAttributes(Node node, Integer count, Integer startIndex, String sortBy, + String sortOrder, List requiredAttributes) throws CharonException, BadRequestException { String searchFilter = buildSearchFilter(node); if (LOG.isDebugEnabled()) { LOG.debug(String.format("Filtering roles from search filter: %s", searchFilter)); } - List roles; + List roles; try { - roles = roleManagementService.getRoles(searchFilter, count, startIndex, sortBy, sortOrder, tenantDomain); + roles = roleManagementService.getRoles(searchFilter, count, startIndex, sortBy, sortOrder, tenantDomain, + requiredAttributes); } catch (IdentityRoleManagementException e) { throw new CharonException( String.format("Error occurred while listing roles based on the search filter: %s", searchFilter), e); } - List scimRoles = getScimRolesList(roles); + List scimRoles = getScimRolesList(roles, requiredAttributes); return new RolesV2GetResponse(scimRoles.size(), scimRoles); } @@ -528,15 +533,16 @@ private String combineFilters(OperationNode operationNode, String leftFilter, St * @return List of roles matching to the criteria. * @throws CharonException Error while listing users. */ - private RolesV2GetResponse listRoles(Integer count, Integer startIndex, String sortBy, String sortOrder) + private RolesV2GetResponse listRoles(Integer count, Integer startIndex, String sortBy, String sortOrder, + List requiredAttributes) throws CharonException, BadRequestException { List rolesList = new ArrayList<>(); int rolesCount; try { - List roles = - roleManagementService.getRoles(count, startIndex, sortBy, sortOrder, tenantDomain); - List scimRoles = getScimRolesList(roles); + List roles = roleManagementService.getRoles(count, startIndex, sortBy, sortOrder, tenantDomain, + requiredAttributes); + List scimRoles = getScimRolesList(roles, requiredAttributes); rolesCount = roleManagementService.getRolesCount(tenantDomain); // Set total number of results to 0th index. if (rolesCount == 0) { @@ -593,19 +599,81 @@ private String getSearchFilter(String attributeName, String filterOperation, Str return searchFilter; } - private List getScimRolesList(List roles) throws BadRequestException, CharonException { + private List getScimRolesList(List roles, List requiredAttributes) + throws BadRequestException, CharonException { List scimRoles = new ArrayList<>(); - for (RoleBasicInfo roleBasicInfo : roles) { + for (Role role : roles) { RoleV2 scimRole = new RoleV2(); - scimRole.setDisplayName(roleBasicInfo.getName()); - scimRole.setId(roleBasicInfo.getId()); - scimRole.setLocation(SCIMCommonUtils.getSCIMRoleV2URL(roleBasicInfo.getId())); - scimRole.setAudience(roleBasicInfo.getAudienceId(), roleBasicInfo.getAudienceName(), - roleBasicInfo.getAudience()); - if (systemRoles.contains(roleBasicInfo.getName())) { + scimRole.setDisplayName(role.getName()); + scimRole.setId(role.getId()); + scimRole.setSchemas(); + scimRole.setLocation(SCIMCommonUtils.getSCIMRoleV2URL(role.getId())); + scimRole.setAudience(role.getAudienceId(), role.getAudienceName(), + role.getAudience()); + if (systemRoles.contains(role.getName())) { scimRole.setSystemRole(true); } + if (requiredAttributes != null) { + if (requiredAttributes.contains(USERS)) { + // Set role's assigned users. + List assignedUsers = role.getUsers(); + if (assignedUsers != null) { + for (UserBasicInfo userInfo : assignedUsers) { + userInfo.getId(); + String userLocationURI = SCIMCommonUtils.getSCIMUserURL(userInfo.getId()); + User user = new User(); + user.setUserName(userInfo.getName()); + user.setId(userInfo.getId()); + user.setLocation(userLocationURI); + scimRole.setUser(user); + } + } + } + if (requiredAttributes.contains(GROUPS)) { + // Set role's assigned userstore groups. + List assignedUserstoreGroups = role.getGroups(); + if (assignedUserstoreGroups != null) { + for (GroupBasicInfo groupInfo : assignedUserstoreGroups) { + String groupId = groupInfo.getId(); + String groupLocationURI = SCIMCommonUtils.getSCIMGroupURL(groupId); + Group group = new Group(); + group.setDisplayName(groupInfo.getName()); + group.setId(groupId); + group.setLocation(groupLocationURI); + scimRole.setGroup(group); + } + } + + // Set role's assigned idp groups. + List assignedIdpGroups = role.getIdpGroups(); + if (assignedIdpGroups != null) { + for (IdpGroup idpGroup : assignedIdpGroups) { + String idpGroupId = idpGroup.getGroupId(); + String idpGroupLocationURI = + SCIMCommonUtils.getIdpGroupURL(idpGroup.getIdpId(), idpGroupId); + Group group = new Group(); + group.setDisplayName(idpGroup.getGroupName()); + group.setId(idpGroupId); + group.setLocation(idpGroupLocationURI); + scimRole.setGroup(group); + } + } + } + if (requiredAttributes.contains(PERMISSIONS)) { + List permissions = + convertPermissionsToMultiValuedComplexType(role.getPermissions()); + scimRole.setPermissions(permissions); + } + if (requiredAttributes.contains(ASSOCIATED_APPLICATIONS)) { + // Set associated applications. + List associatedApps = + convertAssociatedAppsToMultivaluedComplexType(role.getAssociatedApplications()); + if (CollectionUtils.isNotEmpty(associatedApps)) { + scimRole.setAssociatedApplications(associatedApps); + } + } + } scimRoles.add(scimRole); } return scimRoles; diff --git a/components/org.wso2.carbon.identity.scim2.provider/src/main/java/org/wso2/carbon/identity/scim2/provider/resources/RoleResourceV2.java b/components/org.wso2.carbon.identity.scim2.provider/src/main/java/org/wso2/carbon/identity/scim2/provider/resources/RoleResourceV2.java index d692fafcb..976f92b4c 100644 --- a/components/org.wso2.carbon.identity.scim2.provider/src/main/java/org/wso2/carbon/identity/scim2/provider/resources/RoleResourceV2.java +++ b/components/org.wso2.carbon.identity.scim2.provider/src/main/java/org/wso2/carbon/identity/scim2/provider/resources/RoleResourceV2.java @@ -146,7 +146,9 @@ public Response getRoles(@HeaderParam(SCIMProviderConstants.ACCEPT_HEADER) Strin @QueryParam(SCIMProviderConstants.START_INDEX) Integer startIndex, @QueryParam(SCIMProviderConstants.COUNT) Integer count, @QueryParam(SCIMProviderConstants.SORT_BY) String sortBy, - @QueryParam(SCIMProviderConstants.SORT_ORDER) String sortOrder) { + @QueryParam(SCIMProviderConstants.SORT_ORDER) String sortOrder, + @QueryParam(SCIMProviderConstants.ATTRIBUTES) String attribute, + @QueryParam(SCIMProviderConstants.EXCLUDE_ATTRIBUTES) String excludedAttributes) { try { // Defaults to application/scim+json. @@ -162,7 +164,8 @@ public Response getRoles(@HeaderParam(SCIMProviderConstants.ACCEPT_HEADER) Strin // Create charon-SCIM role endpoint and hand-over the request. RoleResourceV2Manager roleResourceManager = new RoleResourceV2Manager(); SCIMResponse scimResponse = roleResourceManager - .listWithGETRole(roleManager, filter, startIndex, count, sortBy, sortOrder); + .listWithGETRole(roleManager, filter, startIndex, count, sortBy, sortOrder, attribute, + excludedAttributes); return SupportUtils.buildResponse(scimResponse); } catch (CharonException e) { return handleCharonException(e); diff --git a/scim2.yaml b/scim2.yaml index 2f924fe30..ff91f042f 100644 --- a/scim2.yaml +++ b/scim2.yaml @@ -1353,6 +1353,16 @@ paths: description: The order in which the "sortBy" parameter is applied. required: false type: string + - name: attributes + in: query + description: SCIM defined attributes parameter. + required: false + type: string + - name: excludedAttributes + in: query + description: SCIM defined excludedAttribute parameter. + required: false + type: string responses: 200: description: Valid roles are found @@ -2760,7 +2770,7 @@ definitions: Resources: type: array items: - $ref: "#/definitions/RoleObV2" + $ref: "#/definitions/RoleGetResponseObjectV2" #----------------------------------------------------- # The Roles Search Request Object #----------------------------------------------------- @@ -2780,7 +2790,21 @@ definitions: filter: type: string example: 'displayName eq loginRole' - + attributes: + type: array + items: + type: string + example: + - displayName + - users + - groups + excludedAttributes: + type: array + items: + type: string + example: + - permissions + - associatedApplications #----------------------------------------------------- # The Roles Search Response Object #----------------------------------------------------- @@ -2804,37 +2828,8 @@ definitions: Resources: type: array items: - $ref: "#/definitions/RoleObV2" - #----------------------------------------------------- - # The Roles List Response Object - #----------------------------------------------------- - RoleObV2: - type: object - properties: - displayName: - type: string - example: 'loginRole' - meta: - type: object - properties: - location: - type: string - example: 'https://localhost:9443/scim2/Roles/4645709c-ea8c-4495-8590-e1fa0efe3de0' - id: - type: string - example: '4645709c-ea8c-4495-8590-e1fa0efe3de0' - audience: - type: object - properties: - value: - type: string - example: '3645709f-ea8d-5595-7690-e1fa0efe3df9' - display: - type: string - example: 'My Org' - type: - type: string - example: 'organization' + $ref: "#/definitions/RoleGetResponseObjectV2" + #----------------------------------------------------- # The Role Creation Object #----------------------------------------------------- From 0749b106b48d5cbd3ace865698aa91c63109085c Mon Sep 17 00:00:00 2001 From: ChanikaRuchini Date: Wed, 13 Dec 2023 12:14:20 +0530 Subject: [PATCH 2/2] Upgrade framework version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 44653a178..01af3ecee 100644 --- a/pom.xml +++ b/pom.xml @@ -285,7 +285,7 @@ 6.5.3 3.2.0.wso2v1 4.9.18 - 5.25.602 + 5.25.612 4.13.1 20030203.000129 1.8.12