Skip to content

Commit

Permalink
Merge pull request #515 from ChanikaRuchini/master
Browse files Browse the repository at this point in the history
Support attributes and excludeAttributes query params for List roles v2 endpoint
  • Loading branch information
ChanikaRuchini committed Dec 14, 2023
2 parents 54135bd + 0749b10 commit 3720af8
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> systemRoles;
Expand Down Expand Up @@ -325,26 +329,26 @@ public void deleteRole(String roleID) throws CharonException, NotFoundException,
}

public RolesV2GetResponse listRolesWithGET(Node rootNode, Integer startIndex, Integer count, String sortBy,
String sortOrder)
String sortOrder, List<String> requiredAttributes)
throws CharonException, NotImplementedException, BadRequestException {

if (sortBy != null || sortOrder != null) {
throw new NotImplementedException("Sorting is not supported.");
} 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<String> requiredAttributes)
throws NotImplementedException, BadRequestException, CharonException {

return listRolesWithGET(searchRequest.getFilter(), searchRequest.getStartIndex(), searchRequest.getCount(),
searchRequest.getSortBy(), searchRequest.getSortOder());
searchRequest.getSortBy(), searchRequest.getSortOder(), requiredAttributes);
}

@Override
Expand Down Expand Up @@ -440,11 +444,11 @@ public RoleV2 patchRole(String roleId, Map<String, List<PatchOperation>> patchOp
* @throws CharonException Error filtering the roles.
*/
private RolesV2GetResponse filterRoles(Node node, Integer count, Integer startIndex, String sortBy,
String sortOrder)
String sortOrder, List<String> 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.");
}
Expand All @@ -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<String> requiredAttributes)
throws CharonException, BadRequestException {

String searchFilter = buildSearchFilter(node);
if (LOG.isDebugEnabled()) {
LOG.debug(String.format("Filtering roles from search filter: %s", searchFilter));
}
List<RoleBasicInfo> roles;
List<Role> 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<RoleV2> scimRoles = getScimRolesList(roles);
List<RoleV2> scimRoles = getScimRolesList(roles, requiredAttributes);
return new RolesV2GetResponse(scimRoles.size(), scimRoles);
}

Expand Down Expand Up @@ -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<String> requiredAttributes)
throws CharonException, BadRequestException {

List<RoleV2> rolesList = new ArrayList<>();
int rolesCount;
try {
List<RoleBasicInfo> roles =
roleManagementService.getRoles(count, startIndex, sortBy, sortOrder, tenantDomain);
List<RoleV2> scimRoles = getScimRolesList(roles);
List<Role> roles = roleManagementService.getRoles(count, startIndex, sortBy, sortOrder, tenantDomain,
requiredAttributes);
List<RoleV2> scimRoles = getScimRolesList(roles, requiredAttributes);
rolesCount = roleManagementService.getRolesCount(tenantDomain);
// Set total number of results to 0th index.
if (rolesCount == 0) {
Expand Down Expand Up @@ -593,19 +599,81 @@ private String getSearchFilter(String attributeName, String filterOperation, Str
return searchFilter;
}

private List<RoleV2> getScimRolesList(List<RoleBasicInfo> roles) throws BadRequestException, CharonException {
private List<RoleV2> getScimRolesList(List<Role> roles, List<String> requiredAttributes)
throws BadRequestException, CharonException {

List<RoleV2> 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<UserBasicInfo> 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<GroupBasicInfo> 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<IdpGroup> 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<MultiValuedComplexType> permissions =
convertPermissionsToMultiValuedComplexType(role.getPermissions());
scimRole.setPermissions(permissions);
}
if (requiredAttributes.contains(ASSOCIATED_APPLICATIONS)) {
// Set associated applications.
List<MultiValuedComplexType> associatedApps =
convertAssociatedAppsToMultivaluedComplexType(role.getAssociatedApplications());
if (CollectionUtils.isNotEmpty(associatedApps)) {
scimRole.setAssociatedApplications(associatedApps);
}
}
}
scimRoles.add(scimRole);
}
return scimRoles;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -285,11 +285,11 @@
<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>
<identity.framework.version>5.25.509</identity.framework.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>
<identity.governance.version>1.8.12</identity.governance.version>
<charon.version>4.0.15</charon.version>
<charon.version>4.0.16</charon.version>
<org.wso2.carbon.identity.organization.management.core.version>1.0.76
</org.wso2.carbon.identity.organization.management.core.version>
<org.wso2.carbon.identity.handler.event.account.lock.version>1.8.13
Expand Down
61 changes: 28 additions & 33 deletions scim2.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1353,6 +1353,16 @@ paths:
description: The order in which the "sortBy" parameter is applied.
required: false
type: string
- name: attributes
in: query
description: attributes parameter.
required: false
type: string
- name: excludedAttributes
in: query
description: excludedAttribute parameter.
required: false
type: string
responses:
200:
description: Valid roles are found
Expand Down Expand Up @@ -2760,7 +2770,7 @@ definitions:
Resources:
type: array
items:
$ref: "#/definitions/RoleObV2"
$ref: "#/definitions/RoleGetResponseObjectV2"
#-----------------------------------------------------
# The Roles Search Request Object
#-----------------------------------------------------
Expand All @@ -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
#-----------------------------------------------------
Expand All @@ -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
#-----------------------------------------------------
Expand Down

0 comments on commit 3720af8

Please sign in to comment.