Skip to content

Commit

Permalink
add SCIM system schema
Browse files Browse the repository at this point in the history
  • Loading branch information
amanda-ariyaratne committed Jan 21, 2025
1 parent 9373bdf commit 957e474
Show file tree
Hide file tree
Showing 10 changed files with 867 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.wso2.carbon.identity.scim2.common.handlers.SCIMClaimOperationEventHandler;
import org.wso2.carbon.identity.scim2.common.utils.SCIMCommonUtils;
import org.wso2.charon3.core.attributes.MultiValuedAttribute;
import org.wso2.charon3.core.attributes.SimpleAttribute;
import org.wso2.charon3.core.encoder.JSONDecoder;
Expand Down Expand Up @@ -176,6 +177,8 @@ private AbstractSCIMObject buildCombinedResourceType(AbstractSCIMObject userObje
private String buildUserResourceTypeJsonBody() throws JSONException {

JSONObject userResourceTypeObject = new JSONObject();
SCIMResourceSchemaManager schemaManager = SCIMResourceSchemaManager.getInstance();

userResourceTypeObject.put(SCIMConstants.CommonSchemaConstants.SCHEMAS, SCIMConstants.RESOURCE_TYPE_SCHEMA_URI);
userResourceTypeObject.put(SCIMConstants.ResourceTypeSchemaConstants.ID, SCIMConstants.USER);
userResourceTypeObject.put(SCIMConstants.ResourceTypeSchemaConstants.NAME, SCIMConstants.USER);
Expand All @@ -185,16 +188,27 @@ private String buildUserResourceTypeJsonBody() throws JSONException {
userResourceTypeObject.put(SCIMConstants.ResourceTypeSchemaConstants.SCHEMA,
SCIMConstants.USER_CORE_SCHEMA_URI);

if (SCIMResourceSchemaManager.getInstance().isExtensionSet()) {
JSONObject extensionSchemaObject = new JSONObject();
extensionSchemaObject.put(SCIMConstants.ResourceTypeSchemaConstants.SCHEMA_EXTENSIONS_SCHEMA,
SCIMResourceSchemaManager.getInstance().getExtensionURI());
extensionSchemaObject.put(SCIMConstants.ResourceTypeSchemaConstants.SCHEMA_EXTENSIONS_REQUIRED,
SCIMResourceSchemaManager.getInstance().getExtensionRequired());

userResourceTypeObject.put(SCIMConstants.ResourceTypeSchemaConstants.SCHEMA_EXTENSIONS,
extensionSchemaObject);
if (Boolean.TRUE.equals(schemaManager.isExtensionSet())) {
JSONObject extensionSchemaObject = createSchemaExtensionObject(
schemaManager.getExtensionURI(), schemaManager.getExtensionRequired());
if (SCIMCommonUtils.isExtensionSchemasListingEnabledInResourceTypesAPI()) {
JSONArray schemaExtensions = new JSONArray();
schemaExtensions.put(extensionSchemaObject);
schemaExtensions.put(createSchemaExtensionObject(
schemaManager.getSystemSchemaExtensionURI(), schemaManager.getSystemSchemaExtensionRequired()));
userResourceTypeObject.put(SCIMConstants.ResourceTypeSchemaConstants.SCHEMA_EXTENSIONS, schemaExtensions);
} else {
userResourceTypeObject.put(SCIMConstants.ResourceTypeSchemaConstants.SCHEMA_EXTENSIONS, extensionSchemaObject);
}
}
return userResourceTypeObject.toString();
}

private JSONObject createSchemaExtensionObject(String schemaURI, boolean isRequired) throws JSONException {

JSONObject extensionSchemaObject = new JSONObject();
extensionSchemaObject.put(SCIMConstants.ResourceTypeSchemaConstants.SCHEMA_EXTENSIONS_SCHEMA, schemaURI);
extensionSchemaObject.put(SCIMConstants.ResourceTypeSchemaConstants.SCHEMA_EXTENSIONS_REQUIRED, isRequired);
return extensionSchemaObject;
}
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,16 @@
import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
import org.wso2.charon3.core.config.SCIMConfigConstants;
import org.wso2.charon3.core.config.SCIMCustomSchemaExtensionBuilder;
import org.wso2.charon3.core.config.SCIMSystemSchemaExtensionBuilder;
import org.wso2.charon3.core.config.SCIMUserSchemaExtensionBuilder;
import org.wso2.charon3.core.exceptions.CharonException;
import org.wso2.charon3.core.exceptions.InternalErrorException;
import org.wso2.carbon.idp.mgt.IdpManager;

import java.io.File;

import static org.wso2.carbon.identity.scim2.common.utils.SCIMCommonConstants.USER_SCHEMA_EXTENSION_ENABLED;

@Component(
name = "identity.scim2.common",
immediate = true
Expand All @@ -83,12 +86,13 @@ protected void activate(ComponentContext ctx) {
SCIMConfigProcessor scimConfigProcessor = SCIMConfigProcessor.getInstance();
scimConfigProcessor.buildConfigFromFile(filePath);

// reading user schema extension
if (Boolean.parseBoolean(scimConfigProcessor.getProperty("user-schema-extension-enabled"))) {
// Reading schema extensions.
if (Boolean.parseBoolean(scimConfigProcessor.getProperty(USER_SCHEMA_EXTENSION_ENABLED))) {
String schemaFilePath =
CarbonUtils.getCarbonConfigDirPath() + File.separator +
SCIMConfigConstants.SCIM_SCHEMA_EXTENSION_CONFIG;
SCIMUserSchemaExtensionBuilder.getInstance().buildUserSchemaExtension(schemaFilePath);
SCIMSystemSchemaExtensionBuilder.getInstance().buildSystemSchemaExtension(schemaFilePath);
}
// If custom schema is enabled, read it root attribute URI from the file config if it is configured.
if (SCIMCommonUtils.isCustomSchemaEnabled()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public class SCIMCommonConstants {
public static final String SCIM_USER_CLAIM_DIALECT = "urn:ietf:params:scim:schemas:core:2.0:User";
public static final String SCIM_ENTERPRISE_USER_CLAIM_DIALECT =
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User";
public static final String SCIM_SYSTEM_USER_CLAIM_DIALECT = "urn:scim:wso2:schema";

public static final String EQ = "eq";
public static final String NE = "ne";
Expand Down Expand Up @@ -78,7 +79,10 @@ public class SCIMCommonConstants {
public static final String BULK_MAX_OPERATIONS = "bulk-maxOperations";
public static final String BULK_MAX_PAYLOAD_SIZE = "bulk-maxPayloadSize";
public static final String FILTER_MAX_RESULTS = "filter-maxResults";
@Deprecated
public static final String ENTERPRISE_USER_EXTENSION_ENABLED = "user-schema-extension-enabled";
public static final String USER_SCHEMA_EXTENSION_ENABLED = "user-schema-extension-enabled";
public static final String LIST_USER_EXTENSION_SCHEMAS_ENABLED = "list-user-extension-schemas-enabled";
public static final String PAGINATION_DEFAULT_COUNT = "pagination-default-count";
public static final String CUSTOM_USER_SCHEMA_ENABLED = "custom-user-schema-enabled";
public static final String CUSTOM_USER_SCHEMA_URI = "custom-user-schema-uri";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
import org.wso2.charon3.core.attributes.SCIMCustomAttribute;
import org.wso2.charon3.core.config.SCIMCustomSchemaExtensionBuilder;
import org.wso2.charon3.core.config.SCIMSystemSchemaExtensionBuilder;
import org.wso2.charon3.core.config.SCIMUserSchemaExtensionBuilder;
import org.wso2.charon3.core.exceptions.CharonException;
import org.wso2.charon3.core.exceptions.InternalErrorException;
Expand All @@ -62,8 +63,6 @@
import java.util.Map;
import java.util.Optional;

import static org.wso2.charon3.core.schema.SCIMConstants.CUSTOM_USER_SCHEMA_URI;

/**
* This class is to be used as a Util class for SCIM common things.
* TODO:rename class name.
Expand Down Expand Up @@ -451,10 +450,16 @@ public static Map<String, String> getSCIMtoLocalMappings() throws UserStoreExcep

// Get the extension claims, if there are any extensions enabled.
if (SCIMUserSchemaExtensionBuilder.getInstance().getExtensionSchema() != null) {
Map<String, String> extensionClaims = ClaimMetadataHandler.getInstance()
Map<String, String> enterpriseExtensionClaims = ClaimMetadataHandler.getInstance()
.getMappingsMapFromOtherDialectToCarbon(SCIMUserSchemaExtensionBuilder.getInstance()
.getExtensionSchema().getURI(), null, tenantDomain, false);
scimToLocalClaimMap.putAll(extensionClaims);
scimToLocalClaimMap.putAll(enterpriseExtensionClaims);
}
if (SCIMSystemSchemaExtensionBuilder.getInstance().getExtensionSchema() != null) {
Map<String, String> systemExtensionClaims = ClaimMetadataHandler.getInstance()
.getMappingsMapFromOtherDialectToCarbon(SCIMSystemSchemaExtensionBuilder.getInstance()
.getExtensionSchema().getURI(), null, tenantDomain, false);
scimToLocalClaimMap.putAll(systemExtensionClaims);
}

String userTenantDomain = getTenantDomain();
Expand Down Expand Up @@ -614,11 +619,24 @@ public static boolean isHybridRole(String roleName) {
* Check if SCIM enterprise user extension has been enabled.
*
* @return True if enterprise user extension enabled
* @deprecated Use {@link #isUserExtensionEnabled()} instead.
*/
@Deprecated
public static boolean isEnterpriseUserExtensionEnabled() {

return Boolean.parseBoolean(SCIMConfigProcessor.getInstance()
.getProperty(SCIMCommonConstants.ENTERPRISE_USER_EXTENSION_ENABLED));
.getProperty(SCIMCommonConstants.USER_SCHEMA_EXTENSION_ENABLED));
}

/**
* Check if SCIM enterprise user extension has been enabled.
*
* @return True if enterprise user extension enabled
*/
public static boolean isUserExtensionEnabled() {

return Boolean.parseBoolean(SCIMConfigProcessor.getInstance()
.getProperty(SCIMCommonConstants.USER_SCHEMA_EXTENSION_ENABLED));
}

/**
Expand Down Expand Up @@ -728,7 +746,17 @@ public static String getCustomSchemaURI() {
if (StringUtils.isNotBlank(customSchemaURI)) {
return customSchemaURI;
}
return CUSTOM_USER_SCHEMA_URI;
return SCIMConstants.CUSTOM_EXTENSION_SCHEMA_URI;
}

public static boolean isExtensionSchemasListingEnabledInResourceTypesAPI() {

String isExtensionSchemasListingEnabled =
SCIMConfigProcessor.getInstance().getProperty(SCIMCommonConstants.LIST_USER_EXTENSION_SCHEMAS_ENABLED);
if (StringUtils.isNotBlank(isExtensionSchemasListingEnabled)) {
return Boolean.parseBoolean(isExtensionSchemasListingEnabled);
}
return true;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import org.wso2.carbon.user.core.UserStoreClientException;
import org.wso2.carbon.user.core.common.PaginatedUserResponse;
import org.wso2.carbon.user.core.model.UniqueIDUserClaimSearchEntry;
import org.wso2.charon3.core.config.SCIMSystemSchemaExtensionBuilder;
import org.wso2.charon3.core.exceptions.NotImplementedException;
import org.wso2.charon3.core.extensions.UserManager;
import org.wso2.charon3.core.objects.plainobjects.UsersGetResponse;
Expand Down Expand Up @@ -127,7 +128,10 @@
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import static org.wso2.charon3.core.schema.SCIMConstants.CUSTOM_EXTENSION_SCHEMA_URI;
import static org.wso2.charon3.core.schema.SCIMConstants.ENTERPRISE_USER_SCHEMA_URI;

/*
* Unit tests for SCIMUserManager
Expand Down Expand Up @@ -207,6 +211,7 @@ public class SCIMUserManagerTest {
@Mock
private RolePermissionManagementService mockedRolePermissionManagementService;
private MockedStatic<SCIMUserSchemaExtensionBuilder> scimUserSchemaExtensionBuilder;
private MockedStatic<SCIMSystemSchemaExtensionBuilder> scimSystemSchemaExtensionBuilder;
private MockedStatic<IdentityUtil> identityUtil;
private MockedStatic<SCIMCommonUtils> scimCommonUtils;
private MockedStatic<AttributeMapper> attributeMapper;
Expand All @@ -228,11 +233,17 @@ public void setUpMethod() {
applicationManagementServiceMockedStatic = mockStatic(ApplicationManagementService.class);
scimCommonComponentHolder = mockStatic(SCIMCommonComponentHolder.class);
scimUserSchemaExtensionBuilder = mockStatic(SCIMUserSchemaExtensionBuilder.class);
scimSystemSchemaExtensionBuilder = mockStatic(SCIMSystemSchemaExtensionBuilder.class);
claimMetadataHandler = mockStatic(ClaimMetadataHandler.class);
resourceManagerUtil = mockStatic(ResourceManagerUtil.class);
SCIMUserSchemaExtensionBuilder mockSCIMUserSchemaExtensionBuilder = mock(SCIMUserSchemaExtensionBuilder.class);
SCIMSystemSchemaExtensionBuilder mockSCIMSystemSchemaExtensionBuilder = mock(SCIMSystemSchemaExtensionBuilder.class);
scimUserSchemaExtensionBuilder.when(SCIMUserSchemaExtensionBuilder::getInstance).thenReturn(mockSCIMUserSchemaExtensionBuilder);
when(mockSCIMUserSchemaExtensionBuilder.getExtensionSchema()).thenReturn(mockedSCIMAttributeSchema);
when(mockedSCIMAttributeSchema.getURI()).thenReturn(ENTERPRISE_USER_SCHEMA_URI)
.thenReturn(CUSTOM_EXTENSION_SCHEMA_URI);
scimSystemSchemaExtensionBuilder.when(SCIMSystemSchemaExtensionBuilder::getInstance).thenReturn(mockSCIMSystemSchemaExtensionBuilder);
when(mockSCIMSystemSchemaExtensionBuilder.getExtensionSchema()).thenReturn(mockedSCIMAttributeSchema);
}

@AfterMethod
Expand All @@ -244,6 +255,7 @@ public void tearDown() {
applicationManagementServiceMockedStatic.close();
scimCommonComponentHolder.close();
scimUserSchemaExtensionBuilder.close();
scimSystemSchemaExtensionBuilder.close();
claimMetadataHandler.close();
resourceManagerUtil.close();
}
Expand Down Expand Up @@ -1180,7 +1192,7 @@ public void testGetEnterpriseUserSchemaWhenEnabled() throws Exception {
MultitenantConstants.SUPER_TENANT_DOMAIN_NAME)).thenReturn(externalClaimMap);
when(mockClaimMetadataManagementService.getLocalClaims(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME))
.thenReturn(localClaimMap);
scimCommonUtils.when(() -> SCIMCommonUtils.isEnterpriseUserExtensionEnabled()).thenReturn(true);
scimCommonUtils.when(() -> SCIMCommonUtils.isUserExtensionEnabled()).thenReturn(true);

SCIMUserSchemaExtensionBuilder sb = spy(new SCIMUserSchemaExtensionBuilder());
scimUserSchemaExtensionBuilder.when(() -> SCIMUserSchemaExtensionBuilder.getInstance()).thenReturn(sb);
Expand All @@ -1196,10 +1208,10 @@ public void testGetEnterpriseUserSchemaWhenEnabled() throws Exception {
@Test
public void testGetEnterpriseUserSchemaWhenDisabled() throws Exception {

scimCommonUtils.when(() -> SCIMCommonUtils.isEnterpriseUserExtensionEnabled()).thenReturn(false);
scimCommonUtils.when(SCIMCommonUtils::isUserExtensionEnabled).thenReturn(false);
SCIMUserManager userManager = new SCIMUserManager(mockedUserStoreManager, mockClaimMetadataManagementService,
MultitenantConstants.SUPER_TENANT_DOMAIN_NAME);
assertEquals(userManager.getEnterpriseUserSchema(), null);
assertNull(userManager.getEnterpriseUserSchema());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<provisioning-config>
<Property name="user-schema-extension-enabled">true</Property>
<Property name="custom-user-schema-enabled">true</Property>
<Property name="custom-user-schema-uri">urn:scim:wso2:schema</Property>
<Property name="custom-user-schema-uri">urn:scim:schemas:extension:custom:User</Property>
<Property name="patch-supported">true</Property>
<Property name="documentationUri">http://example.com/help/scim.html</Property>
<Property name="bulk-supported">true</Property>
Expand All @@ -31,6 +31,7 @@
<Property name="sort-supported">false</Property>
<Property name="etag-supported">false</Property>
<Property name="pagination-default-count">100</Property>
<Property name="list-user-extension-schemas-enabled">true</Property>
<authenticationSchemes>
<schema id="1">
<Property name="name">OAuth Bearer Token</Property>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
<Property name="sort-supported">false</Property>
<Property name="etag-supported">false</Property>
<Property name="pagination-default-count">100</Property>
<Property name="list-user-extension-schemas-enabled">scim2.enable_list_user_schemas</Property>
<authenticationSchemes>
<schema id="1">
<Property name="name">OAuth Bearer Token</Property>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"scim2.enable_schema_extension": true,
"scim2.enable_custom_schema_extension": true,
"scim2.custom_user_schema_uri": "urn:scim:wso2:schema",
"scim2.custom_user_schema_uri": "urn:scim:schemas:extension:custom:User",
"scim2.max_bulk_operations": "1000",
"scim2.max_bulk_payload": "1048576",
"scim2.documentation_uri": "https://is.docs.wso2.com/en/latest/apis/scim2/",
"scim2.oauth_bearer.primary": true,
"scim2.http_basic.primary": false,
"scim2.basic_auth_documentation_uri": "$ref{scim2.documentation_uri}",
"scim2.oauth_bearer_auth_documentation_uri": "$ref{scim2.documentation_uri}"
"scim2.enable_list_user_schemas": true
}
Loading

0 comments on commit 957e474

Please sign in to comment.