From 396e4dd8316873470ae19d196e4004f398170fce Mon Sep 17 00:00:00 2001 From: Pavindu Lakshan Date: Sun, 17 Nov 2024 10:33:08 +0530 Subject: [PATCH 1/8] Add locale attribute validation for SCIM Patch --- .../protocol/endpoints/MeResourceManager.java | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/modules/charon-core/src/main/java/org/wso2/charon3/core/protocol/endpoints/MeResourceManager.java b/modules/charon-core/src/main/java/org/wso2/charon3/core/protocol/endpoints/MeResourceManager.java index 9f5714f8e..4bc46048a 100644 --- a/modules/charon-core/src/main/java/org/wso2/charon3/core/protocol/endpoints/MeResourceManager.java +++ b/modules/charon-core/src/main/java/org/wso2/charon3/core/protocol/endpoints/MeResourceManager.java @@ -16,6 +16,7 @@ package org.wso2.charon3.core.protocol.endpoints; +import org.json.JSONObject; import org.wso2.charon3.core.encoder.JSONDecoder; import org.wso2.charon3.core.encoder.JSONEncoder; import org.wso2.charon3.core.exceptions.BadRequestException; @@ -40,6 +41,7 @@ import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; /** @@ -347,6 +349,24 @@ public SCIMResponse updateWithPATCH(String existingId, String scimObjectString, copyOfOldUser = (User) CopyUtil.deepCopy(newUser); } } else if (operation.getOperation().equals(SCIMConstants.OperationalConstants.REPLACE)) { + + // Convert the object to a JSON string if needed + String jsonString = operation.getValues().toString(); + + // Parse the JSON string using JSONObject + JSONObject jsonObject = new JSONObject(jsonString); + + // Check if the "locale" key exists + if (jsonObject.has("locale")) { + String locale = jsonObject.getString("locale"); + System.out.println("Locale: " + locale); + + // Perform validation + if (!isValidLocale(locale)) { + throw new BadRequestException("Invalid locale value: ", ResponseCodeConstants.INVALID_SYNTAX); + } + } + if (newUser == null) { newUser = (User) PatchOperationUtil.doPatchReplace (operation, getDecoder(), oldUser, copyOfOldUser, schema); @@ -409,6 +429,40 @@ public SCIMResponse updateWithPATCH(String existingId, String scimObjectString, } } + public static boolean isValidLocale(String localeStr) { + if (localeStr == null || localeStr.isEmpty()) { + return false; + } + + // Split the locale string into parts (language and country) + String[] parts = localeStr.split("[-_]"); + if (parts.length != 2) { + return false; // Must have exactly two parts: language and country + } + + String language = parts[0]; + String country = parts[1]; + + // Validate language code: must be 2 lowercase letters + if (!language.matches("^[a-z]{2}$")) { + return false; + } + + // Validate country code: must be 2 uppercase letters + if (!country.matches("^[A-Z]{2}$")) { + return false; + } + + // Check if the locale is available in the system + for (Locale availableLocale : Locale.getAvailableLocales()) { + if (availableLocale.getLanguage().equals(language) && + availableLocale.getCountry().equals(country)) { + return true; + } + } + + return false; // If no matching locale is found + } public String getUserName(String scimObjectString) throws CharonException { From e14608bd6a1b2ebab8cbeca9ee7fe923ab4370e4 Mon Sep 17 00:00:00 2001 From: Pavindu Lakshan Date: Sun, 17 Nov 2024 15:10:08 +0530 Subject: [PATCH 2/8] Add locale attribute validation for SCIM Patch --- .../core/schema/ServerSideValidator.java | 55 +++++++++++++++++-- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/modules/charon-core/src/main/java/org/wso2/charon3/core/schema/ServerSideValidator.java b/modules/charon-core/src/main/java/org/wso2/charon3/core/schema/ServerSideValidator.java index f9405dd8e..5ffa2e158 100644 --- a/modules/charon-core/src/main/java/org/wso2/charon3/core/schema/ServerSideValidator.java +++ b/modules/charon-core/src/main/java/org/wso2/charon3/core/schema/ServerSideValidator.java @@ -15,6 +15,10 @@ */ package org.wso2.charon3.core.schema; +import org.apache.commons.lang.StringUtils; +import org.wso2.charon3.core.attributes.Attribute; +import org.wso2.charon3.core.attributes.ComplexAttribute; +import org.wso2.charon3.core.attributes.MultiValuedAttribute; import org.wso2.charon3.core.attributes.SimpleAttribute; import org.wso2.charon3.core.exceptions.BadRequestException; import org.wso2.charon3.core.exceptions.CharonException; @@ -23,14 +27,12 @@ import org.wso2.charon3.core.objects.Role; import org.wso2.charon3.core.objects.RoleV2; import org.wso2.charon3.core.objects.User; +import org.wso2.charon3.core.protocol.ResponseCodeConstants; import org.wso2.charon3.core.protocol.endpoints.AbstractResourceManager; import org.wso2.charon3.core.utils.AttributeUtil; import java.time.Instant; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.UUID; +import java.util.*; /** * Server Side Validator. @@ -248,11 +250,56 @@ public static AbstractSCIMObject validateUpdatedSCIMObject(AbstractSCIMObject ol // Check for required attributes. validateSCIMObjectForRequiredAttributes(newObject, resourceSchema); } + + Map attributes = validatedObject.getAttributeList(); + + for (Map.Entry entry : attributes.entrySet()) { + String key = entry.getKey(); + Attribute value = entry.getValue(); + + if (value instanceof SimpleAttribute && StringUtils.equals(key,SCIMConstants.UserSchemaConstants.LOCALE)) { + String localeAttributeValue = ((SimpleAttribute) value).getValue().toString(); + + if (!isValidLocale(localeAttributeValue)) { + throw new BadRequestException + ("Provided locale value " + localeAttributeValue + " is invalid"); + } + } + + } + + // Check for schema list. validateSchemaList(validatedObject, resourceSchema); return validatedObject; } + public static boolean isValidLocale(String localeStr) { + if (localeStr == null || localeStr.isEmpty()) { + return false; + } + + // Split the locale string into parts (language and country) + String[] parts = localeStr.split("-"); + + if (parts.length != 2) { + return false; // Must have exactly two parts: language and country + } + + String language = parts[0]; + String country = parts[1]; + + // Check if the locale is available in the system + for (Locale availableLocale : Locale.getAvailableLocales()) { + if (availableLocale.getLanguage().equals(language) && + availableLocale.getCountry().equals(country)) { + return true; + } + } + + return false; // If no matching locale is found + } + /* * This method is to add meta data to the resource type resource * From b4788cb34b8d049f2db00cc4e783610f8bb981cd Mon Sep 17 00:00:00 2001 From: Pavindu Lakshan Date: Sun, 17 Nov 2024 15:12:51 +0530 Subject: [PATCH 3/8] Remove redundant validation logic in resource manager --- .../protocol/endpoints/MeResourceManager.java | 53 ------------------- 1 file changed, 53 deletions(-) diff --git a/modules/charon-core/src/main/java/org/wso2/charon3/core/protocol/endpoints/MeResourceManager.java b/modules/charon-core/src/main/java/org/wso2/charon3/core/protocol/endpoints/MeResourceManager.java index 4bc46048a..3b53cb400 100644 --- a/modules/charon-core/src/main/java/org/wso2/charon3/core/protocol/endpoints/MeResourceManager.java +++ b/modules/charon-core/src/main/java/org/wso2/charon3/core/protocol/endpoints/MeResourceManager.java @@ -349,24 +349,6 @@ public SCIMResponse updateWithPATCH(String existingId, String scimObjectString, copyOfOldUser = (User) CopyUtil.deepCopy(newUser); } } else if (operation.getOperation().equals(SCIMConstants.OperationalConstants.REPLACE)) { - - // Convert the object to a JSON string if needed - String jsonString = operation.getValues().toString(); - - // Parse the JSON string using JSONObject - JSONObject jsonObject = new JSONObject(jsonString); - - // Check if the "locale" key exists - if (jsonObject.has("locale")) { - String locale = jsonObject.getString("locale"); - System.out.println("Locale: " + locale); - - // Perform validation - if (!isValidLocale(locale)) { - throw new BadRequestException("Invalid locale value: ", ResponseCodeConstants.INVALID_SYNTAX); - } - } - if (newUser == null) { newUser = (User) PatchOperationUtil.doPatchReplace (operation, getDecoder(), oldUser, copyOfOldUser, schema); @@ -429,41 +411,6 @@ public SCIMResponse updateWithPATCH(String existingId, String scimObjectString, } } - public static boolean isValidLocale(String localeStr) { - if (localeStr == null || localeStr.isEmpty()) { - return false; - } - - // Split the locale string into parts (language and country) - String[] parts = localeStr.split("[-_]"); - if (parts.length != 2) { - return false; // Must have exactly two parts: language and country - } - - String language = parts[0]; - String country = parts[1]; - - // Validate language code: must be 2 lowercase letters - if (!language.matches("^[a-z]{2}$")) { - return false; - } - - // Validate country code: must be 2 uppercase letters - if (!country.matches("^[A-Z]{2}$")) { - return false; - } - - // Check if the locale is available in the system - for (Locale availableLocale : Locale.getAvailableLocales()) { - if (availableLocale.getLanguage().equals(language) && - availableLocale.getCountry().equals(country)) { - return true; - } - } - - return false; // If no matching locale is found - } - public String getUserName(String scimObjectString) throws CharonException { try { From adfed33650ff0173d786df0e36c1b9304e19c531 Mon Sep 17 00:00:00 2001 From: Pavindu Lakshan Date: Sun, 17 Nov 2024 15:14:48 +0530 Subject: [PATCH 4/8] Remove unused imports --- .../wso2/charon3/core/protocol/endpoints/MeResourceManager.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/charon-core/src/main/java/org/wso2/charon3/core/protocol/endpoints/MeResourceManager.java b/modules/charon-core/src/main/java/org/wso2/charon3/core/protocol/endpoints/MeResourceManager.java index 3b53cb400..732046d27 100644 --- a/modules/charon-core/src/main/java/org/wso2/charon3/core/protocol/endpoints/MeResourceManager.java +++ b/modules/charon-core/src/main/java/org/wso2/charon3/core/protocol/endpoints/MeResourceManager.java @@ -16,7 +16,6 @@ package org.wso2.charon3.core.protocol.endpoints; -import org.json.JSONObject; import org.wso2.charon3.core.encoder.JSONDecoder; import org.wso2.charon3.core.encoder.JSONEncoder; import org.wso2.charon3.core.exceptions.BadRequestException; @@ -41,7 +40,6 @@ import java.util.HashMap; import java.util.List; -import java.util.Locale; import java.util.Map; /** From 2ca2cce7672253be9f95031334c9c37f1ce46879 Mon Sep 17 00:00:00 2001 From: Pavindu Lakshan Date: Sun, 17 Nov 2024 15:40:46 +0530 Subject: [PATCH 5/8] Address checkstyle warnings --- .../charon3/core/schema/ServerSideValidator.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/modules/charon-core/src/main/java/org/wso2/charon3/core/schema/ServerSideValidator.java b/modules/charon-core/src/main/java/org/wso2/charon3/core/schema/ServerSideValidator.java index 5ffa2e158..0fd3c1a71 100644 --- a/modules/charon-core/src/main/java/org/wso2/charon3/core/schema/ServerSideValidator.java +++ b/modules/charon-core/src/main/java/org/wso2/charon3/core/schema/ServerSideValidator.java @@ -17,8 +17,6 @@ import org.apache.commons.lang.StringUtils; import org.wso2.charon3.core.attributes.Attribute; -import org.wso2.charon3.core.attributes.ComplexAttribute; -import org.wso2.charon3.core.attributes.MultiValuedAttribute; import org.wso2.charon3.core.attributes.SimpleAttribute; import org.wso2.charon3.core.exceptions.BadRequestException; import org.wso2.charon3.core.exceptions.CharonException; @@ -27,12 +25,16 @@ import org.wso2.charon3.core.objects.Role; import org.wso2.charon3.core.objects.RoleV2; import org.wso2.charon3.core.objects.User; -import org.wso2.charon3.core.protocol.ResponseCodeConstants; import org.wso2.charon3.core.protocol.endpoints.AbstractResourceManager; import org.wso2.charon3.core.utils.AttributeUtil; import java.time.Instant; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.UUID; /** * Server Side Validator. @@ -257,7 +259,7 @@ public static AbstractSCIMObject validateUpdatedSCIMObject(AbstractSCIMObject ol String key = entry.getKey(); Attribute value = entry.getValue(); - if (value instanceof SimpleAttribute && StringUtils.equals(key,SCIMConstants.UserSchemaConstants.LOCALE)) { + if (value instanceof SimpleAttribute && StringUtils.equals(key, SCIMConstants.UserSchemaConstants.LOCALE)) { String localeAttributeValue = ((SimpleAttribute) value).getValue().toString(); if (!isValidLocale(localeAttributeValue)) { From 8a19b9ffd783b44b8cf29e8b3c0d9b3484570341 Mon Sep 17 00:00:00 2001 From: Pavindu Lakshan Date: Sun, 17 Nov 2024 16:54:17 +0530 Subject: [PATCH 6/8] Fix formatting issues --- .../org/wso2/charon3/core/schema/ServerSideValidator.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/charon-core/src/main/java/org/wso2/charon3/core/schema/ServerSideValidator.java b/modules/charon-core/src/main/java/org/wso2/charon3/core/schema/ServerSideValidator.java index 0fd3c1a71..c5c5e2f6e 100644 --- a/modules/charon-core/src/main/java/org/wso2/charon3/core/schema/ServerSideValidator.java +++ b/modules/charon-core/src/main/java/org/wso2/charon3/core/schema/ServerSideValidator.java @@ -267,16 +267,15 @@ public static AbstractSCIMObject validateUpdatedSCIMObject(AbstractSCIMObject ol ("Provided locale value " + localeAttributeValue + " is invalid"); } } - } - // Check for schema list. validateSchemaList(validatedObject, resourceSchema); return validatedObject; } - public static boolean isValidLocale(String localeStr) { + private static boolean isValidLocale(String localeStr) { + if (localeStr == null || localeStr.isEmpty()) { return false; } From 06c1403c1e9a4f13571667e751e8b14c515c5d77 Mon Sep 17 00:00:00 2001 From: Pavindu Lakshan Date: Sun, 17 Nov 2024 16:55:59 +0530 Subject: [PATCH 7/8] Address review comments --- .../java/org/wso2/charon3/core/schema/ServerSideValidator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/charon-core/src/main/java/org/wso2/charon3/core/schema/ServerSideValidator.java b/modules/charon-core/src/main/java/org/wso2/charon3/core/schema/ServerSideValidator.java index c5c5e2f6e..1b8c7a557 100644 --- a/modules/charon-core/src/main/java/org/wso2/charon3/core/schema/ServerSideValidator.java +++ b/modules/charon-core/src/main/java/org/wso2/charon3/core/schema/ServerSideValidator.java @@ -276,7 +276,7 @@ public static AbstractSCIMObject validateUpdatedSCIMObject(AbstractSCIMObject ol private static boolean isValidLocale(String localeStr) { - if (localeStr == null || localeStr.isEmpty()) { + if (localeStr == null || StringUtils.isEmpty(localeStr)) { return false; } From 47fe829a44027240cf620bf5f6ed567d4797a606 Mon Sep 17 00:00:00 2001 From: Pavindu Lakshan Date: Thu, 5 Dec 2024 11:34:08 +0530 Subject: [PATCH 8/8] Break the loop once the locale attribute validation is performed --- .../java/org/wso2/charon3/core/schema/ServerSideValidator.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/charon-core/src/main/java/org/wso2/charon3/core/schema/ServerSideValidator.java b/modules/charon-core/src/main/java/org/wso2/charon3/core/schema/ServerSideValidator.java index 1b8c7a557..5706f6826 100644 --- a/modules/charon-core/src/main/java/org/wso2/charon3/core/schema/ServerSideValidator.java +++ b/modules/charon-core/src/main/java/org/wso2/charon3/core/schema/ServerSideValidator.java @@ -266,6 +266,8 @@ public static AbstractSCIMObject validateUpdatedSCIMObject(AbstractSCIMObject ol throw new BadRequestException ("Provided locale value " + localeAttributeValue + " is invalid"); } + + break; } }