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

Support attributes and excludeAttributes query params for List roles v2 endpoint #515

Merged
merged 4 commits into from
Dec 14, 2023
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 @@ -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);
}
}
}
ChanikaRuchini marked this conversation as resolved.
Show resolved Hide resolved
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,
dewniMW marked this conversation as resolved.
Show resolved Hide resolved
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
Loading