Skip to content

Commit

Permalink
Merge pull request #567 from sandushi/hard-limit
Browse files Browse the repository at this point in the history
  • Loading branch information
sandushi authored Nov 12, 2024
2 parents bd7702e + 811b667 commit f38747a
Show file tree
Hide file tree
Showing 9 changed files with 193 additions and 2 deletions.
5 changes: 5 additions & 0 deletions components/org.wso2.carbon.identity.scim2.common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@
<groupId>org.wso2.carbon.identity.event.handler.accountlock</groupId>
<artifactId>org.wso2.carbon.identity.handler.event.account.lock</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon.identity.framework</groupId>
<artifactId>org.wso2.carbon.identity.configuration.mgt.core</artifactId>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
Expand Down Expand Up @@ -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}",
</Import-Package>
<Export-Package>
!org.wso2.carbon.identity.scim2.common.internal,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -112,6 +113,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;
Expand Down Expand Up @@ -183,6 +185,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) {

Expand Down Expand Up @@ -624,11 +629,46 @@ public UsersGetResponse listUsersWithGET(Node rootNode, Integer startIndex, Inte
public UsersGetResponse listUsersWithPost(SearchRequest searchRequest, Map<String, Boolean> 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.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<SCIMUserStoreErrorResolver> scimUserStoreErrorResolvers = new ArrayList<>();

/**
Expand Down Expand Up @@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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/";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -92,6 +92,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;
Expand Down Expand Up @@ -143,6 +144,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;
Expand Down Expand Up @@ -192,6 +194,9 @@ public class SCIMUserManagerTest {
@Mock
private SCIMGroupHandler mockedSCIMGroupHandler;

@Mock
private ConfigurationManager mockedConfigurationManager;

@Mock
private RolePermissionManagementService mockedRolePermissionManagementService;
private MockedStatic<SCIMUserSchemaExtensionBuilder> scimUserSchemaExtensionBuilder;
Expand Down Expand Up @@ -1496,6 +1501,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);
}
Expand Down Expand Up @@ -1702,4 +1711,23 @@ private org.wso2.carbon.user.core.common.Group buildUserCoreGroupResponse(String
group.setUserStoreDomain(domainName);
return group;
}

private List<org.wso2.carbon.identity.configuration.mgt.core.model.Attribute> 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<org.wso2.carbon.identity.configuration.mgt.core.model.Attribute> 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -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());
}

}
}
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,11 @@
<scope>test</scope>
<version>${identity.framework.version}</version>
</dependency>
<dependency>
<groupId>org.wso2.carbon.identity.framework</groupId>
<artifactId>org.wso2.carbon.identity.configuration.mgt.core</artifactId>
<version>${identity.framework.version}</version>
</dependency>
<dependency>
<groupId>org.wso2.carbon.identity.organization.management.core</groupId>
<artifactId>org.wso2.carbon.identity.organization.management.service</artifactId>
Expand Down

0 comments on commit f38747a

Please sign in to comment.