-
Notifications
You must be signed in to change notification settings - Fork 155
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Cursor pagination for SCIM resources.
Cursor pagination changes phase 1 formatting adjustments before PR Few changes after the code review Changes suggested in the code review Changed strings into constants Changing the response type from a List to UsersGetResponse type object Changes to support pagination with POST/.Search. Group filtering changes. Changes to SingleAttribute and MultiAttribute filtering to properly create the UsersGetResponse. Removing commented code Made changes for the ServiceProviderConfigEndpoint to show that cursor pagination is supported Wording updates to the ServiceProviderConfigEndpoint changes Making changes so that cursor pagination uses PRIMARY domain when a domain is not specified Removing unused parameters Adjusting the test cases broken due to changes made and introductig new test cases for the new flows Adding punctuation to the comments
- Loading branch information
1 parent
bd07897
commit 44d0b63
Showing
8 changed files
with
451 additions
and
138 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
359 changes: 225 additions & 134 deletions
359
...cim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/impl/SCIMUserManager.java
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,8 +47,9 @@ | |
import org.wso2.carbon.identity.scim2.common.extenstion.SCIMUserStoreErrorResolver; | ||
import org.wso2.carbon.identity.scim2.common.group.SCIMGroupHandler; | ||
import org.wso2.carbon.identity.scim2.common.internal.SCIMCommonComponentHolder; | ||
import org.wso2.charon3.core.objects.plainobjects.UsersGetResponse; | ||
import org.wso2.charon3.core.objects.plainobjects.Cursor; | ||
import org.wso2.charon3.core.objects.plainobjects.GroupsGetResponse; | ||
import org.wso2.charon3.core.objects.plainobjects.UsersGetResponse; | ||
import org.wso2.carbon.identity.scim2.common.test.utils.CommonTestUtils; | ||
import org.wso2.carbon.identity.scim2.common.utils.AttributeMapper; | ||
import org.wso2.carbon.identity.scim2.common.utils.SCIMCommonConstants; | ||
|
@@ -478,6 +479,200 @@ public void testListUsersWithGET(List<org.wso2.carbon.user.core.common.User> use | |
assertEquals(result.getUsers().size(), expectedResultCount); | ||
} | ||
|
||
@Test(dataProvider = "userInfoForCursorFiltering") | ||
public void testCursorFilteringUsersWithGET(String filter, int expectedResultCount, Object cursor, Integer count, | ||
List<org.wso2.carbon.user.core.common.User> filteredUsers) | ||
throws Exception { | ||
|
||
Map<String, String> scimToLocalClaimMap = new HashMap<>(); | ||
scimToLocalClaimMap.put("urn:ietf:params:scim:schemas:core:2.0:User:userName", | ||
"http://wso2.org/claims/username"); | ||
scimToLocalClaimMap.put("urn:ietf:params:scim:schemas:core:2.0:id", "http://wso2.org/claims/userid"); | ||
scimToLocalClaimMap.put("urn:ietf:params:scim:schemas:core:2.0:User:emails", | ||
"http://wso2.org/claims/emailaddress"); | ||
scimToLocalClaimMap.put("urn:ietf:params:scim:schemas:core:2.0:User:name.givenName", | ||
"http://wso2.org/claims/givenname"); | ||
|
||
mockStatic(SCIMCommonUtils.class); | ||
when(SCIMCommonUtils.getSCIMtoLocalMappings()).thenReturn(scimToLocalClaimMap); | ||
when(SCIMCommonUtils.convertLocalToSCIMDialect(anyMap(), anyMap())).thenReturn(new HashMap<String, String>() {{ | ||
put(SCIMConstants.CommonSchemaConstants.ID_URI, "1f70378a-69bb-49cf-aa51-a0493c09110c"); | ||
}}); | ||
|
||
mockedUserStoreManager = PowerMockito.mock(AbstractUserStoreManager.class); | ||
|
||
// Cursor filtering. | ||
when(mockedUserStoreManager.getUserListWithID(any(Condition.class), anyString(), anyString(), anyInt(), | ||
anyString(), anyString(), anyString(), anyString())).thenReturn(filteredUsers); | ||
|
||
whenNew(GroupDAO.class).withAnyArguments().thenReturn(mockedGroupDAO); | ||
when(mockedGroupDAO.listSCIMGroups(anyInt())).thenReturn(anySet()); | ||
when(mockedUserStoreManager.getSecondaryUserStoreManager("PRIMARY")).thenReturn(mockedUserStoreManager); | ||
when(mockedUserStoreManager.isSCIMEnabled()).thenReturn(true); | ||
when(mockedUserStoreManager.getSecondaryUserStoreManager("SECONDARY")).thenReturn(secondaryUserStoreManager); | ||
when(secondaryUserStoreManager.isSCIMEnabled()).thenReturn(true); | ||
|
||
when(mockedUserStoreManager.getRealmConfiguration()).thenReturn(mockedRealmConfig); | ||
when(mockedRealmConfig.getUserStoreProperty(UserCoreConstants.RealmConfig.PROPERTY_MAX_USER_LIST)) | ||
.thenReturn("100"); | ||
|
||
mockStatic(IdentityTenantUtil.class); | ||
when(IdentityTenantUtil.getRealmService()).thenReturn(mockRealmService); | ||
when(mockRealmService.getBootstrapRealmConfiguration()).thenReturn(mockedRealmConfig); | ||
mockStatic(IdentityUtil.class); | ||
when(IdentityUtil.isGroupsVsRolesSeparationImprovementsEnabled()).thenReturn(false); | ||
|
||
ClaimMapping[] claimMappings = getTestClaimMappings(); | ||
when(mockedClaimManager.getAllClaimMappings(anyString())).thenReturn(claimMappings); | ||
|
||
HashMap<String, Boolean> requiredClaimsMap = new HashMap<>(); | ||
requiredClaimsMap.put("urn:ietf:params:scim:schemas:core:2.0:User:userName", false); | ||
SCIMUserManager scimUserManager = new SCIMUserManager(mockedUserStoreManager, mockedClaimManager); | ||
|
||
Node node = null; | ||
if (StringUtils.isNotBlank(filter)) { | ||
SCIMResourceTypeSchema schema = SCIMResourceSchemaManager.getInstance().getUserResourceSchema(); | ||
FilterTreeManager filterTreeManager = new FilterTreeManager(filter, schema); | ||
node = filterTreeManager.buildTree(); | ||
} | ||
|
||
UsersGetResponse result = scimUserManager.listUsersWithGET(node, (Cursor) cursor, count, null, null, null, | ||
requiredClaimsMap); | ||
assertEquals(result.getUsers().size(), expectedResultCount); | ||
} | ||
|
||
@DataProvider(name = "userInfoForCursorFiltering") | ||
public Object[][] userInfoForCursorFiltering() { | ||
|
||
|
||
org.wso2.carbon.user.core.common.User testUser1 = new org.wso2.carbon.user.core.common.User(UUID.randomUUID() | ||
.toString(), "testUser1", "testUser1"); | ||
Map<String, String> testUser1Attributes = new HashMap<>(); | ||
testUser1Attributes.put("http://wso2.org/claims/givenname", "testUser"); | ||
testUser1Attributes.put("http://wso2.org/claims/emailaddress", "[email protected]"); | ||
testUser1.setAttributes(testUser1Attributes); | ||
|
||
org.wso2.carbon.user.core.common.User testUser2 = new org.wso2.carbon.user.core.common.User(UUID.randomUUID() | ||
.toString(), "testUser2", "testUser2"); | ||
Map<String, String> testUser2Attributes = new HashMap<>(); | ||
testUser2Attributes.put("http://wso2.org/claims/givenname", "testUser"); | ||
testUser2Attributes.put("http://wso2.org/claims/emailaddress", "[email protected]"); | ||
testUser2.setAttributes(testUser2Attributes); | ||
|
||
org.wso2.carbon.user.core.common.User testUser3 = new org.wso2.carbon.user.core.common.User(UUID.randomUUID() | ||
.toString(), "testUser3", "testUser3"); | ||
Map<String, String> testUser3Attributes = new HashMap<>(); | ||
testUser3Attributes.put("http://wso2.org/claims/givenname", "testUser"); | ||
testUser3Attributes.put("http://wso2.org/claims/emailaddress", "[email protected]"); | ||
testUser3.setAttributes(testUser3Attributes); | ||
|
||
org.wso2.carbon.user.core.common.User testUser4 = new org.wso2.carbon.user.core.common.User(UUID.randomUUID() | ||
.toString(), "testUser4", "testUser4"); | ||
Map<String, String> testUser4Attributes = new HashMap<>(); | ||
testUser4Attributes.put("http://wso2.org/claims/givenname", "testUser"); | ||
testUser4Attributes.put("http://wso2.org/claims/emailaddress", "[email protected]"); | ||
testUser4.setAttributes(testUser4Attributes); | ||
|
||
org.wso2.carbon.user.core.common.User fakeUser5 = new org.wso2.carbon.user.core.common.User(UUID.randomUUID() | ||
.toString(), "fakeUser5", "fakeUser5"); | ||
Map<String, String> testUser5Attributes = new HashMap<>(); | ||
testUser5Attributes.put("http://wso2.org/claims/givenname", "fakeUser"); | ||
testUser5Attributes.put("http://wso2.org/claims/emailaddress", "[email protected]"); | ||
fakeUser5.setAttributes(testUser5Attributes); | ||
|
||
org.wso2.carbon.user.core.common.User fakeUser6 = new org.wso2.carbon.user.core.common.User(UUID.randomUUID() | ||
.toString(), "fakeUser6", "fakeUser6"); | ||
Map<String, String> testUser6Attributes = new HashMap<>(); | ||
testUser6Attributes.put("http://wso2.org/claims/givenname", "fakeUser"); | ||
testUser6Attributes.put("http://wso2.org/claims/emailaddress", "[email protected]"); | ||
fakeUser6.setAttributes(testUser6Attributes); | ||
|
||
org.wso2.carbon.user.core.common.User fakeUser7 = new org.wso2.carbon.user.core.common.User(UUID.randomUUID() | ||
.toString(), "fakeUser7", "fakeUser7"); | ||
Map<String, String> testUser7Attributes = new HashMap<>(); | ||
testUser7Attributes.put("http://wso2.org/claims/givenname", "fakeUser"); | ||
testUser7Attributes.put("http://wso2.org/claims/emailaddress", "[email protected]"); | ||
fakeUser7.setAttributes(testUser7Attributes); | ||
|
||
return new Object[][]{ | ||
// Forwards pagination initial request. | ||
{"name.givenName eq testUser", 4, new Cursor("", "NEXT"), 5, | ||
new ArrayList<org.wso2.carbon.user.core.common.User>() {{ | ||
add(testUser1); | ||
add(testUser2); | ||
add(testUser3); | ||
add(testUser4); | ||
}}}, | ||
|
||
// Forwards pagination without filtering. | ||
{null, 5, new Cursor("fakeUser6", "NEXT"), 5, | ||
new ArrayList<org.wso2.carbon.user.core.common.User>() {{ | ||
add(fakeUser7); | ||
add(testUser1); | ||
add(testUser2); | ||
add(testUser3); | ||
add(testUser4); | ||
}}}, | ||
|
||
// Backwards pagination without filter. | ||
{null, 4, new Cursor("testUser2", "PREVIOUS"), 5, | ||
new ArrayList<org.wso2.carbon.user.core.common.User>() {{ | ||
add(fakeUser5); | ||
add(fakeUser6); | ||
add(fakeUser7); | ||
add(testUser1); | ||
}}}, | ||
|
||
// Forwards pagination with a filter. | ||
{"name.givenName eq testUser", 2, new Cursor("testUser2", "NEXT"), 5, | ||
new ArrayList<org.wso2.carbon.user.core.common.User>() {{ | ||
add(testUser3); | ||
add(testUser4); | ||
}}}, | ||
|
||
// Backwards pagination with a filter. | ||
{"name.givenName eq testUser", 2, new Cursor("testUser3", "PREVIOUS"), 5, | ||
new ArrayList<org.wso2.carbon.user.core.common.User>() {{ | ||
add(testUser1); | ||
add(testUser2); | ||
}}}, | ||
|
||
// Multi-attribute filtering - Forwards pagination - With a count. | ||
{"name.givenName eq testUser and emails co gmail", 2, new Cursor("", "NEXT"), 5, | ||
new ArrayList<org.wso2.carbon.user.core.common.User>() {{ | ||
add(testUser1); | ||
add(testUser3); | ||
}}}, | ||
|
||
// Multi-attribute filtering - Backwards pagination. | ||
{"name.givenName eq fakeUser and emails co wso2.com", 1, | ||
new Cursor("fakeUser7", "PREVIOUS"), 5, | ||
new ArrayList<org.wso2.carbon.user.core.common.User>() {{ | ||
add(fakeUser6); | ||
}}}, | ||
|
||
// Multi-attribute filtering - Forwards pagination - Without maxLimit calls | ||
// getMultiAttributeFilteredUsersWithMaxLimit. | ||
{"name.givenName eq testUser and emails co gmail", 2, new Cursor("", "NEXT"), null, | ||
new ArrayList<org.wso2.carbon.user.core.common.User>() {{ | ||
add(testUser1); | ||
add(testUser3); | ||
}}}, | ||
|
||
// Return empty list when count == 0. | ||
{"", 0, new Cursor("", "NEXT"), 0, | ||
new ArrayList<org.wso2.carbon.user.core.common.User>() {{ | ||
}}}, | ||
|
||
// Single attribute group filtering. | ||
{"groups eq Manager", 2, new Cursor("", "NEXT"), 5, | ||
new ArrayList<org.wso2.carbon.user.core.common.User>() {{ | ||
add(testUser1); | ||
add(testUser3); | ||
}}}, | ||
}; | ||
} | ||
|
||
@DataProvider(name = "listUser") | ||
public Object[][] listUser() throws Exception { | ||
|
||
|
@@ -1444,7 +1639,7 @@ public void testListUsersWithPost() throws Exception { | |
SCIMUserManager scimUserManager = spy(new SCIMUserManager(mockedUserStoreManager, | ||
mockClaimMetadataManagementService, MultitenantConstants.SUPER_TENANT_DOMAIN_NAME)); | ||
doReturn(usersGetResponse).when(scimUserManager) | ||
.listUsersWithGET(any(), any(), any(), anyString(), anyString(), anyString(), anyMap()); | ||
.listUsersWithGET(any(), (Integer) any(), any(), anyString(), anyString(), anyString(), anyMap()); | ||
UsersGetResponse users = scimUserManager.listUsersWithPost(searchRequest, requiredAttributes); | ||
assertEquals(users, usersGetResponse); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters