From afcd8bc7413c9d5f2f890682071bf87872968ea1 Mon Sep 17 00:00:00 2001 From: Paras Dharwal Date: Thu, 3 Oct 2024 21:51:53 +0530 Subject: [PATCH] IMPL: Added new Pattern Builder and Unit Test (#19) --- README.md | 4 +- ejmask-api/pom.xml | 2 +- ejmask-bom/pom.xml | 2 +- ejmask-core/pom.xml | 2 +- ejmask-extensions/pom.xml | 2 +- .../JsonValueUnmaskFromEndPatternBuilder.java | 47 ++++++++ ...nValueUnmaskFromEndPatternBuilderTest.java | 105 ++++++++++++++++++ .../ejmask-spring-autoconfig/pom.xml | 2 +- ejmask-spring/ejmask-spring-boot/pom.xml | 2 +- ejmask-spring/ejmask-spring-core/pom.xml | 2 +- ejmask-spring/pom.xml | 2 +- pom.xml | 2 +- 12 files changed, 163 insertions(+), 11 deletions(-) create mode 100644 ejmask-extensions/src/main/java/com/ebay/ejmask/extenstion/builder/json/JsonValueUnmaskFromEndPatternBuilder.java create mode 100644 ejmask-extensions/src/test/java/com/ebay/ejmask/extenstion/builder/json/JsonValueUnmaskFromEndPatternBuilderTest.java diff --git a/README.md b/README.md index 622e0bb..0bacd76 100644 --- a/README.md +++ b/README.md @@ -233,14 +233,14 @@ Alternatively you can pull it from the central Maven repositories: com.ebay.ejmask ejmask-bom - 1.0.3 + 1.1.0-SNAPSHOT ``` ### Using in your Gradle Project. ```groovy -compile group: 'com.ebay.ejmask', name: 'ejmask-bom', version: '1.0.3' +compile group: 'com.ebay.ejmask', name: 'ejmask-bom', version: '1.1.0-SNAPSHOT' ``` ## Roadmap diff --git a/ejmask-api/pom.xml b/ejmask-api/pom.xml index bb9d04b..d734bc4 100644 --- a/ejmask-api/pom.xml +++ b/ejmask-api/pom.xml @@ -3,7 +3,7 @@ com.ebay.ejmask ejmask-parent - 1.0.3 + 1.1.0-SNAPSHOT ejmask-api diff --git a/ejmask-bom/pom.xml b/ejmask-bom/pom.xml index 2dc9ad2..5cb7a58 100644 --- a/ejmask-bom/pom.xml +++ b/ejmask-bom/pom.xml @@ -3,7 +3,7 @@ com.ebay.ejmask ejmask-parent - 1.0.3 + 1.1.0-SNAPSHOT ../pom.xml diff --git a/ejmask-core/pom.xml b/ejmask-core/pom.xml index e1c07fa..8c67437 100644 --- a/ejmask-core/pom.xml +++ b/ejmask-core/pom.xml @@ -3,7 +3,7 @@ com.ebay.ejmask ejmask-parent - 1.0.3 + 1.1.0-SNAPSHOT ejmask-core diff --git a/ejmask-extensions/pom.xml b/ejmask-extensions/pom.xml index c56039a..5a48825 100644 --- a/ejmask-extensions/pom.xml +++ b/ejmask-extensions/pom.xml @@ -3,7 +3,7 @@ com.ebay.ejmask ejmask-parent - 1.0.3 + 1.1.0-SNAPSHOT ejmask-extensions diff --git a/ejmask-extensions/src/main/java/com/ebay/ejmask/extenstion/builder/json/JsonValueUnmaskFromEndPatternBuilder.java b/ejmask-extensions/src/main/java/com/ebay/ejmask/extenstion/builder/json/JsonValueUnmaskFromEndPatternBuilder.java new file mode 100644 index 0000000..269ea69 --- /dev/null +++ b/ejmask-extensions/src/main/java/com/ebay/ejmask/extenstion/builder/json/JsonValueUnmaskFromEndPatternBuilder.java @@ -0,0 +1,47 @@ +package com.ebay.ejmask.extenstion.builder.json; + +import com.ebay.ejmask.extenstion.builder.AbstractRegexPatternBuilder; + +/** + * An implementation of IPatternBuilder to support high sensitive JSON field, whose value + * need to be partially masked with relative field from end of the field. + * + * @author parasdharwal33 + */ +public class JsonValueUnmaskFromEndPatternBuilder extends AbstractRegexPatternBuilder { + + //https://regex101.com/r/LL3EY7/1/ + private static final String PATTERN_TEMPLATE = "\\\"(%s)(\\\\*\\\"\\s*:\\s*\\\\*\\\")[^\\\"]*([^\\\\\"]{%d})(\\\\?\\\"|)"; + //group $1 = field name + //group $2 = ":" (with json serialization support) + //group $3 = sensitive information -> unmasked + //group $4 = ending qts + private static final String REPLACEMENT_TEMPLATE = "\"$1$2xxxx-$3$4"; + + /** + * Build pattern to match + * + * @param visibleCharacters as no of characters to be visible. + * @param fieldNames as list of field names + * @return match pattern + */ + @Override + public String buildPattern(int visibleCharacters, String... fieldNames) { + if (visibleCharacters < 0) { + throw new IllegalArgumentException("visibleCharacters must be a value greater than zero instead of " + visibleCharacters); + } + return String.format(PATTERN_TEMPLATE, super.buildFieldNamesForRegexOr(fieldNames), visibleCharacters); + } + + /** + * Build pattern to replace. + * + * @param visibleCharacters as no of characters to be visible. + * @param fieldNames as list of field names + * @return match pattern + */ + @Override + public String buildReplacement(int visibleCharacters, String... fieldNames) { + return REPLACEMENT_TEMPLATE; + } +} \ No newline at end of file diff --git a/ejmask-extensions/src/test/java/com/ebay/ejmask/extenstion/builder/json/JsonValueUnmaskFromEndPatternBuilderTest.java b/ejmask-extensions/src/test/java/com/ebay/ejmask/extenstion/builder/json/JsonValueUnmaskFromEndPatternBuilderTest.java new file mode 100644 index 0000000..c0304fd --- /dev/null +++ b/ejmask-extensions/src/test/java/com/ebay/ejmask/extenstion/builder/json/JsonValueUnmaskFromEndPatternBuilderTest.java @@ -0,0 +1,105 @@ +package com.ebay.ejmask.extenstion.builder.json; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.regex.Pattern; +import java.util.stream.Stream; + +public class JsonValueUnmaskFromEndPatternBuilderTest { + + public static final JsonValueUnmaskFromEndPatternBuilder instance = new JsonValueUnmaskFromEndPatternBuilder(); + public static final String[] fieldNames = new String[]{"ccNumber", "ssn"}; + + @Test + public void testBuildPattern() { + int visibleCharacters = 4; + String result = instance.buildPattern(visibleCharacters, fieldNames); + Assertions.assertEquals("\\\"(ccNumber|ssn)(\\\\*\\\"\\s*:\\s*\\\\*\\\")[^\\\"]*([^\\\\\"]{4})(\\\\?\\\"|)", result); + } + + @Test + public void testBuildPattern_withNegativeVisibleCharacters() { + int visibleCharacters = -1; + Assertions.assertThrows(IllegalArgumentException.class, () -> instance.buildPattern(visibleCharacters, fieldNames)); + } + + @Test + public void testBuildReplacement() { + int visibleCharacters = 4; + String result = instance.buildReplacement(visibleCharacters, fieldNames); + Assertions.assertEquals("\"$1$2xxxx-$3$4", result); + } + + @ParameterizedTest + @MethodSource("dataForTestMatch") + public void testMatch(String name, String data, String expected) { + String regex = instance.buildPattern(4, fieldNames); + String replacement = instance.buildReplacement(4, fieldNames); + Pattern pattern = Pattern.compile(regex); + String result = pattern.matcher(data).replaceAll(replacement); + Assertions.assertFalse(result.contains("1234567890")); + Assertions.assertEquals(expected, result); + } + + static Stream dataForTestMatch() { + return Stream.of( + Arguments.arguments( + "test with normal json", + "{\"ccNumber\":\"1234567890123456\",\"ssn\":\"123456789\",\"nonSensitiveData\":\"data\"}", + "{\"ccNumber\":\"xxxx-3456\",\"ssn\":\"xxxx-6789\",\"nonSensitiveData\":\"data\"}" + ), + Arguments.arguments( + "test with empty values", + "{\"ccNumber\":\"\",\"ssn\":null,\"nonSensitiveData\":\"data\"}", + "{\"ccNumber\":\"\",\"ssn\":null,\"nonSensitiveData\":\"data\"}" + ), + Arguments.arguments( + "test with space", + "{\"ccNumber\" : \"1234567890123456\", \"ssn\" :\"123456789\",\"nonSensitiveData\":\"data\"}", + "{\"ccNumber\" : \"xxxx-3456\", \"ssn\" :\"xxxx-6789\",\"nonSensitiveData\":\"data\"}" + ), + Arguments.arguments( + "test with line break", + "{\n" + + " \"ccNumber\": \"1234567890123456\",\n" + + " \"ssn\": \"123456789\",\n" + + " \"nonSensitiveData\": \"data\"\n" + + "}", + "{\n" + + " \"ccNumber\": \"xxxx-3456\",\n" + + " \"ssn\": \"xxxx-6789\",\n" + + " \"nonSensitiveData\": \"data\"\n" + + "}" + ), + Arguments.arguments( + "test with broken json", + "{\"ccNumber\":\"1234567890123456\",\"ssn\":\"123456789", + "{\"ccNumber\":\"xxxx-3456\",\"ssn\":\"xxxx-6789" + ), + Arguments.arguments( + "test with json encoded json", + "{\\\"ccNumber\\\":\\\"1234567890123456\\\",\\\"ssn\\\":\\\"123456789\\\",\\\"nonSensitiveData\\\":\\\"data\\\"}", + "{\\\"ccNumber\\\":\\\"xxxx-3456\\\",\\\"ssn\\\":\\\"xxxx-6789\\\",\\\"nonSensitiveData\\\":\\\"data\\\"}" + ), + Arguments.arguments( + "test with double json encoded json", + "{\\\\\\\"ccNumber\\\\\\\":\\\\\\\"1234567890123456\\\\\\\",\\\\\\\"ssn\\\\\\\":\\\\\\\"123456789\\\\\\\",\\\\\\\"nonSensitiveData\\\\\\\":\\\\\\\"data\\\\\\\"}", + "{\\\\\\\"ccNumber\\\\\\\":\\\\\\\"xxxx-3456\\\\\\\",\\\\\\\"ssn\\\\\\\":\\\\\\\"xxxx-6789\\\\\\\",\\\\\\\"nonSensitiveData\\\\\\\":\\\\\\\"data\\\\\\\"}" + ), + Arguments.arguments( + "test with encoded broken json", + "{\\\"ccNumber\\\":\\\"1234567890123456\\\",\\\"ssn\\\":\\\"123456789", + "{\\\"ccNumber\\\":\\\"xxxx-3456\\\",\\\"ssn\\\":\\\"xxxx-6789" + ), + Arguments.arguments( + "test with encoded broken json 2", + "{\\\"ccNumber\\\":\\\"1234567890123456\\\",\\\"ssn\\\":\\\"123456789\\", + "{\\\"ccNumber\\\":\\\"xxxx-3456\\\",\\\"ssn\\\":\\\"xxxx-6789\\" + ) + ); + } +} \ No newline at end of file diff --git a/ejmask-spring/ejmask-spring-autoconfig/pom.xml b/ejmask-spring/ejmask-spring-autoconfig/pom.xml index bfe10bb..ec85e8c 100644 --- a/ejmask-spring/ejmask-spring-autoconfig/pom.xml +++ b/ejmask-spring/ejmask-spring-autoconfig/pom.xml @@ -3,7 +3,7 @@ com.ebay.ejmask ejmask-spring - 1.0.3 + 1.1.0-SNAPSHOT ejmask-spring-autoconfig diff --git a/ejmask-spring/ejmask-spring-boot/pom.xml b/ejmask-spring/ejmask-spring-boot/pom.xml index 90e73d1..71ddea0 100644 --- a/ejmask-spring/ejmask-spring-boot/pom.xml +++ b/ejmask-spring/ejmask-spring-boot/pom.xml @@ -3,7 +3,7 @@ com.ebay.ejmask ejmask-spring - 1.0.3 + 1.1.0-SNAPSHOT ejmask-spring-boot diff --git a/ejmask-spring/ejmask-spring-core/pom.xml b/ejmask-spring/ejmask-spring-core/pom.xml index 4572fac..120cb40 100644 --- a/ejmask-spring/ejmask-spring-core/pom.xml +++ b/ejmask-spring/ejmask-spring-core/pom.xml @@ -3,7 +3,7 @@ com.ebay.ejmask ejmask-spring - 1.0.3 + 1.1.0-SNAPSHOT ejmask-spring-core diff --git a/ejmask-spring/pom.xml b/ejmask-spring/pom.xml index 7def6ac..3c61ab0 100644 --- a/ejmask-spring/pom.xml +++ b/ejmask-spring/pom.xml @@ -3,7 +3,7 @@ com.ebay.ejmask ejmask-parent - 1.0.3 + 1.1.0-SNAPSHOT ejmask-spring diff --git a/pom.xml b/pom.xml index 56771a8..071c081 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ com.ebay.ejmask ejmask-parent - 1.0.3 + 1.1.0-SNAPSHOT pom