diff --git a/components/org.wso2.carbon.identity.scim2.common/pom.xml b/components/org.wso2.carbon.identity.scim2.common/pom.xml
index 8b5aa1f89..de8acd065 100644
--- a/components/org.wso2.carbon.identity.scim2.common/pom.xml
+++ b/components/org.wso2.carbon.identity.scim2.common/pom.xml
@@ -156,6 +156,10 @@
org.wso2.carbon.identity.event.handler.accountlock
org.wso2.carbon.identity.handler.event.account.lock
+
+ org.wso2.carbon.identity.framework
+ org.wso2.carbon.identity.configuration.mgt.core
+
commons-lang
commons-lang
@@ -251,6 +255,7 @@
org.wso2.carbon.identity.handler.event.account.lock.*;
version="${carbon.identity.account.lock.handler.imp.pkg.version.range}",
org.wso2.carbon.idp.mgt.*;version="${carbon.identity.framework.imp.pkg.version.range}",
+ org.wso2.carbon.identity.configuration.mgt.core.*; version="${carbon.identity.framework.imp.pkg.version.range}",
!org.wso2.carbon.identity.scim2.common.internal,
diff --git a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/impl/SCIMUserManager.java b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/impl/SCIMUserManager.java
index b892452d0..3ee2f27bf 100644
--- a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/impl/SCIMUserManager.java
+++ b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/impl/SCIMUserManager.java
@@ -39,6 +39,7 @@
import org.wso2.carbon.identity.claim.metadata.mgt.model.ExternalClaim;
import org.wso2.carbon.identity.claim.metadata.mgt.model.LocalClaim;
import org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants;
+import org.wso2.carbon.identity.configuration.mgt.core.exception.ConfigurationManagementException;
import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
import org.wso2.carbon.identity.core.util.IdentityUtil;
import org.wso2.carbon.identity.event.IdentityEventConstants;
@@ -111,6 +112,7 @@
import org.wso2.charon3.core.utils.codeutils.OperationNode;
import org.wso2.charon3.core.utils.codeutils.PatchOperation;
import org.wso2.charon3.core.utils.codeutils.SearchRequest;
+import org.wso2.carbon.identity.configuration.mgt.core.model.Resource;
import java.time.Instant;
import java.util.AbstractMap;
@@ -181,6 +183,9 @@ public class SCIMUserManager implements UserManager {
private static final String ROLE_CLAIM = "http://wso2.org/claims/role";
private boolean removeDuplicateUsersInUsersResponseEnabled = isRemoveDuplicateUsersInUsersResponseEnabled();
+ private static final String MAX_LIMIT_RESOURCE_TYPE_NAME = "response-max-limit-configurations";
+ private static final String MAX_LIMIT_RESOURCE_NAME = "user-response-limit";
+
@Deprecated
public SCIMUserManager(UserStoreManager carbonUserStoreManager, ClaimManager claimManager) {
@@ -622,11 +627,46 @@ public UsersGetResponse listUsersWithGET(Node rootNode, Integer startIndex, Inte
public UsersGetResponse listUsersWithPost(SearchRequest searchRequest, Map requiredAttributes)
throws CharonException, NotImplementedException, BadRequestException {
+ int count = searchRequest.getCount();
+
+ try {
+ if (!SCIMCommonUtils.isConsiderServerWideUserEndpointMaxLimitEnabled()) {
+ Resource maxLimitResource = getResourceByTenantId(carbonUM.getTenantId());
+ if (maxLimitResource != null) {
+ int maxLimit = maxLimitResource.getAttributes().stream()
+ .filter(item -> "userResponseMaxLimit".equals(item.getKey()))
+ .map(org.wso2.carbon.identity.configuration.mgt.core.model.Attribute::getValue)
+ .findFirst()
+ .map(Integer::parseInt)
+ .orElse(count); // Use the local count variable
+ count = Math.min(count, maxLimit);
+ }
+ } else {
+ count = SCIMCommonUtils.validateCountParameter(count);
+ }
+ } catch (org.wso2.carbon.user.core.UserStoreException e) {
+ log.error("Error occurred while getting the tenant name", e);
+ }
+
return listUsersWithGET(searchRequest.getFilter(), (Integer) searchRequest.getStartIndex(),
- (Integer) searchRequest.getCount(), searchRequest.getSortBy(), searchRequest.getSortOder(),
+ (Integer) count, searchRequest.getSortBy(), searchRequest.getSortOder(),
searchRequest.getDomainName(), requiredAttributes);
}
+ private Resource getResourceByTenantId(int tenantId) throws org.wso2.carbon.user.core.UserStoreException {
+
+ try {
+ return SCIMCommonComponentHolder.getConfigurationManager()
+ .getResourceByTenantId(tenantId, MAX_LIMIT_RESOURCE_TYPE_NAME, MAX_LIMIT_RESOURCE_NAME);
+ } catch (ConfigurationManagementException e) {
+ if (log.isDebugEnabled()) {
+ log.debug("The user response maximum limit is not configured for the tenant: " +
+ tenantId);
+ }
+ return null;
+ }
+ }
+
/**
* Method to list users for given conditions.
*
diff --git a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/internal/SCIMCommonComponent.java b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/internal/SCIMCommonComponent.java
index 2dd32edc3..daafe370b 100644
--- a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/internal/SCIMCommonComponent.java
+++ b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/internal/SCIMCommonComponent.java
@@ -29,6 +29,7 @@
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.wso2.carbon.identity.claim.metadata.mgt.ClaimMetadataManagementService;
+import org.wso2.carbon.identity.configuration.mgt.core.ConfigurationManager;
import org.wso2.carbon.identity.core.util.IdentityCoreInitializedEvent;
import org.wso2.carbon.identity.core.util.IdentityUtil;
import org.wso2.carbon.identity.event.handler.AbstractEventHandler;
@@ -388,6 +389,34 @@ protected void setIdentityEventService(IdentityEventService identityEventService
SCIMCommonComponentHolder.setIdentityEventService(identityEventService);
}
+ @Reference(
+ name = "resource.configuration.manager",
+ service = ConfigurationManager.class,
+ cardinality = ReferenceCardinality.MANDATORY,
+ policy = ReferencePolicy.DYNAMIC,
+ unbind = "unsetConfigurationManager"
+ )
+
+ /**
+ * This method is used to set the Configuration manager Service.
+ *
+ * @param configurationManager The Realm Service which needs to be set.
+ */
+ protected void setConfigurationManager(ConfigurationManager configurationManager) {
+
+ SCIMCommonComponentHolder.setConfigurationManager(configurationManager);
+ }
+
+ /**
+ * This method is used to unset the Configuration manager Service.
+ *
+ * @param configurationManager The Configuration manager Service which needs to unset.
+ */
+ protected void unsetConfigurationManager(ConfigurationManager configurationManager) {
+
+ SCIMCommonComponentHolder.setConfigurationManager(null);
+ }
+
@Deactivate
protected void deactivate(ComponentContext context) {
diff --git a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/internal/SCIMCommonComponentHolder.java b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/internal/SCIMCommonComponentHolder.java
index 2a3459f8c..f63697e38 100644
--- a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/internal/SCIMCommonComponentHolder.java
+++ b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/internal/SCIMCommonComponentHolder.java
@@ -19,6 +19,7 @@
package org.wso2.carbon.identity.scim2.common.internal;
import org.wso2.carbon.identity.claim.metadata.mgt.ClaimMetadataManagementService;
+import org.wso2.carbon.identity.configuration.mgt.core.ConfigurationManager;
import org.wso2.carbon.identity.event.services.IdentityEventService;
import org.wso2.carbon.identity.organization.management.service.OrganizationManager;
import org.wso2.carbon.identity.scim2.common.extenstion.SCIMUserStoreErrorResolver;
@@ -45,6 +46,7 @@ public class SCIMCommonComponentHolder {
private static OrganizationManager organizationManager;
private static IdpManager idpManager;
private static IdentityEventService identityEventService;
+ private static ConfigurationManager configurationManager;
private static final List scimUserStoreErrorResolvers = new ArrayList<>();
/**
@@ -225,4 +227,24 @@ public static void setIdentityEventService(IdentityEventService identityEventSer
SCIMCommonComponentHolder.identityEventService = identityEventService;
}
+
+ /**
+ * Get Configuration Manager.
+ *
+ * @return ConfigurationManager.
+ */
+ public static ConfigurationManager getConfigurationManager() {
+
+ return configurationManager;
+ }
+
+ /**
+ * Set Configuration manager.
+ *
+ * @param configurationManager Configuration Manager.
+ */
+ public static void setConfigurationManager(ConfigurationManager configurationManager) {
+
+ SCIMCommonComponentHolder.configurationManager = configurationManager;
+ }
}
diff --git a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/utils/SCIMCommonConstants.java b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/utils/SCIMCommonConstants.java
index 08a8147a0..a916e365c 100644
--- a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/utils/SCIMCommonConstants.java
+++ b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/utils/SCIMCommonConstants.java
@@ -114,6 +114,8 @@ public class SCIMCommonConstants {
"SCIM2.RemoveDuplicateUsersInUsersResponse";
public static final String SCIM2_COMPLEX_MULTI_ATTRIBUTE_FILTERING_ENABLED =
"SCIM2MultiAttributeFiltering.UsePagination";
+ public static final String CONSIDER_SERVER_WIDE_MAX_LIMIT_ENABLED=
+ "SCIM2.ConsiderServerWideUserEndpointMaxLimit";
public static final String URL_SEPERATOR = "/";
public static final String TENANT_URL_SEPERATOR = "/t/";
diff --git a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/utils/SCIMCommonUtils.java b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/utils/SCIMCommonUtils.java
index 2606fb4d5..8878f4647 100644
--- a/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/utils/SCIMCommonUtils.java
+++ b/components/org.wso2.carbon.identity.scim2.common/src/main/java/org/wso2/carbon/identity/scim2/common/utils/SCIMCommonUtils.java
@@ -966,4 +966,40 @@ public static boolean isOrganization(String tenantDomain) throws CharonException
throw new CharonException("Error occurred while checking the organization state.", e);
}
}
+
+ /**
+ * Validate the count query parameter.
+ *
+ * @param count Requested item count.
+ * @return Validated count parameter.
+ */
+ public static int validateCountParameter(Integer count) {
+
+ int maximumItemsPerPage = IdentityUtil.getMaximumItemPerPage();
+ if (count > maximumItemsPerPage) {
+ if (log.isDebugEnabled()) {
+ log.debug(String.format("Given limit exceeds the maximum limit. Therefore the limit is set to %s.",
+ maximumItemsPerPage));
+ }
+ return maximumItemsPerPage;
+ }
+
+ return count;
+ }
+
+ /**
+ * Read the SCIM User Endpoint Consider Server Wide config and returns it.
+ *
+ * @return If SCIM User Endpoint Consider Server Wise Config is enabled.
+ */
+ public static boolean isConsiderServerWideUserEndpointMaxLimitEnabled() {
+
+ String considerServerWideUserEndpointMaxLimitProperty =
+ IdentityUtil.getProperty(SCIMCommonConstants.CONSIDER_SERVER_WIDE_MAX_LIMIT_ENABLED);
+
+ if (StringUtils.isBlank(considerServerWideUserEndpointMaxLimitProperty)) {
+ return true;
+ }
+ return Boolean.parseBoolean(considerServerWideUserEndpointMaxLimitProperty);
+ }
}
diff --git a/components/org.wso2.carbon.identity.scim2.common/src/test/java/org/wso2/carbon/identity/scim2/common/impl/SCIMUserManagerTest.java b/components/org.wso2.carbon.identity.scim2.common/src/test/java/org/wso2/carbon/identity/scim2/common/impl/SCIMUserManagerTest.java
index 3dd0fb46f..61e29a8ef 100644
--- a/components/org.wso2.carbon.identity.scim2.common/src/test/java/org/wso2/carbon/identity/scim2/common/impl/SCIMUserManagerTest.java
+++ b/components/org.wso2.carbon.identity.scim2.common/src/test/java/org/wso2/carbon/identity/scim2/common/impl/SCIMUserManagerTest.java
@@ -30,7 +30,6 @@
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import org.wso2.carbon.CarbonConstants;
-import org.wso2.carbon.base.CarbonBaseConstants;
import org.wso2.carbon.base.MultitenantConstants;
import org.wso2.carbon.identity.application.common.model.InboundProvisioningConfig;
import org.wso2.carbon.identity.application.common.model.ServiceProvider;
@@ -40,6 +39,7 @@
import org.wso2.carbon.identity.claim.metadata.mgt.model.AttributeMapping;
import org.wso2.carbon.identity.claim.metadata.mgt.model.ExternalClaim;
import org.wso2.carbon.identity.claim.metadata.mgt.model.LocalClaim;
+import org.wso2.carbon.identity.configuration.mgt.core.ConfigurationManager;
import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
import org.wso2.carbon.identity.core.util.IdentityUtil;
import org.wso2.carbon.identity.scim2.common.DAO.GroupDAO;
@@ -91,6 +91,7 @@
import org.wso2.charon3.core.utils.codeutils.FilterTreeManager;
import org.wso2.charon3.core.utils.codeutils.Node;
import org.wso2.charon3.core.utils.codeutils.SearchRequest;
+import org.wso2.carbon.identity.configuration.mgt.core.model.Resource;
import java.lang.reflect.Field;
import java.util.ArrayList;
@@ -142,6 +143,7 @@ public class SCIMUserManagerTest {
private static final String ADDRESS_LOCAL_CLAIM = "http://wso2.org/claims/addresses";
private static final String USER_SCHEMA_ADDRESS_HOME = "urn:ietf:params:scim:schemas:core:2.0:User:addresses.home";
private static final String USER_SCHEMA_ADDRESS_WORK= "urn:ietf:params:scim:schemas:core:2.0:User:addresses.work";
+ private static final String MAX_LIMIT_RESOURCE_NAME = "user-response-limit";
@Mock
private AbstractUserStoreManager mockedUserStoreManager;
@@ -191,6 +193,9 @@ public class SCIMUserManagerTest {
@Mock
private SCIMGroupHandler mockedSCIMGroupHandler;
+ @Mock
+ private ConfigurationManager mockedConfigurationManager;
+
@Mock
private RolePermissionManagementService mockedRolePermissionManagementService;
private MockedStatic scimUserSchemaExtensionBuilder;
@@ -1479,6 +1484,10 @@ public void testListUsersWithPost() throws Exception {
mockClaimMetadataManagementService, MultitenantConstants.SUPER_TENANT_DOMAIN_NAME));
doReturn(usersGetResponse).when(scimUserManager)
.listUsersWithGET(any(), any(), any(), nullable(String.class), nullable(String.class), nullable(String.class), anyMap());
+ when(SCIMCommonComponentHolder.getConfigurationManager()).thenReturn(mockedConfigurationManager);
+ Resource resource = getResource();
+ when(mockedConfigurationManager.getResourceByTenantId( anyInt(), anyString(),
+ anyString() )).thenReturn(resource);
UsersGetResponse users = scimUserManager.listUsersWithPost(searchRequest, requiredAttributes);
assertEquals(users, usersGetResponse);
}
@@ -1685,4 +1694,23 @@ private org.wso2.carbon.user.core.common.Group buildUserCoreGroupResponse(String
group.setUserStoreDomain(domainName);
return group;
}
+
+ private List getResourceAttribute() {
+
+ org.wso2.carbon.identity.configuration.mgt.core.model.Attribute attribute =
+ new org.wso2.carbon.identity.configuration.mgt.core.model.Attribute();
+ attribute.setKey("userResponseMaxLimit");
+ attribute.setValue("100");
+
+ List attributes = new ArrayList<>();
+ attributes.add(attribute);
+ return attributes;
+ }
+
+ private Resource getResource() {
+ Resource resource = new Resource();
+ resource.setResourceName(MAX_LIMIT_RESOURCE_NAME);
+ resource.setAttributes(getResourceAttribute());
+ return resource;
+ }
}
diff --git a/components/org.wso2.carbon.identity.scim2.common/src/test/java/org/wso2/carbon/identity/scim2/common/utils/SCIMCommonUtilsTest.java b/components/org.wso2.carbon.identity.scim2.common/src/test/java/org/wso2/carbon/identity/scim2/common/utils/SCIMCommonUtilsTest.java
index 28886d844..1e496e70f 100644
--- a/components/org.wso2.carbon.identity.scim2.common/src/test/java/org/wso2/carbon/identity/scim2/common/utils/SCIMCommonUtilsTest.java
+++ b/components/org.wso2.carbon.identity.scim2.common/src/test/java/org/wso2/carbon/identity/scim2/common/utils/SCIMCommonUtilsTest.java
@@ -42,6 +42,8 @@
import static org.mockito.MockitoAnnotations.initMocks;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.assertFalse;
public class SCIMCommonUtilsTest {
@@ -267,4 +269,26 @@ public Object[][] tenantURLQualifyData() {
};
}
+ @DataProvider
+ public Object[][] getServerWideUserEndpointMaxLimitEnabledData() {
+ return new Object[][]{
+ {"", true},
+ {null, true},
+ {"true", true},
+ {"false", false},
+ };
+ }
+
+ @Test(dataProvider = "getServerWideUserEndpointMaxLimitEnabledData")
+ public void testIsConsiderServerWideUserEndpointMaxLimitEnabled(Object value, boolean isExpectedResultTrue) {
+
+ identityUtil.when(() -> IdentityUtil.getProperty(SCIMCommonConstants.CONSIDER_SERVER_WIDE_MAX_LIMIT_ENABLED))
+ .thenReturn(value);
+ if (isExpectedResultTrue) {
+ assertTrue(SCIMCommonUtils.isConsiderServerWideUserEndpointMaxLimitEnabled());
+ } else {
+ assertFalse(SCIMCommonUtils.isConsiderServerWideUserEndpointMaxLimitEnabled());
+ }
+
+ }
}
diff --git a/pom.xml b/pom.xml
index d6100d0bd..0b26e2a4d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -183,6 +183,11 @@
test
${identity.framework.version}
+
+ org.wso2.carbon.identity.framework
+ org.wso2.carbon.identity.configuration.mgt.core
+ ${identity.framework.version}
+
org.wso2.carbon.identity.organization.management.core
org.wso2.carbon.identity.organization.management.service