Skip to content

Commit

Permalink
Removed configuration to disable array or object value masking
Browse files Browse the repository at this point in the history
  • Loading branch information
breus committed Dec 17, 2023
1 parent 3319f14 commit 87a85e4
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 133 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ private static void skipWhitespaceCharacters(MaskingState maskingState) {
*/
private boolean isStartOfMaskableValue(MaskingState maskingState) {
return isDoubleQuote(maskingState.byteAtCurrentIndex()) ||
(maskingConfig.isArrayMaskingEnabled() && AsciiJsonUtil.isArrayStart(maskingState.byteAtCurrentIndex()))
AsciiJsonUtil.isArrayStart(maskingState.byteAtCurrentIndex())
|| (maskingConfig.isNumberMaskingEnabled()
&& AsciiJsonUtil.isFirstNumberChar(maskingState.byteAtCurrentIndex())) || (
AsciiJsonUtil.isObjectStart(maskingState.byteAtCurrentIndex()));
Expand Down Expand Up @@ -314,6 +314,7 @@ private static void maskArrayValueInPlace(MaskingState maskingState, JsonMasking

/**
* Masks all values (depending on the {@link JsonMaskingConfig} in the object.
*
* @param maskingState the current masking state
* @param maskingConfig the masking configuration
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,6 @@ public class JsonMaskingConfig {
* @see JsonMaskingConfig.Builder#maskNumberValuesWith
*/
private final int maskNumericValuesWith;
/**
* @see JsonMaskingConfig.Builder#maskObjectValues
*/
private final boolean maskObjectValues;
/**
* @see JsonMaskingConfig.Builder#maskArrayValues
*/
private final boolean maskArrayValues;
/**
* @see JsonMaskingConfig.Builder#obfuscationLength(int)
*/
Expand All @@ -42,29 +34,20 @@ public class JsonMaskingConfig {
*/
private final boolean caseSensitiveTargetKeys;

/**
* By default, the correct {@link JsonMaskerAlgorithmType} is resolved based on the input of the builder. The logic
* for this is as follows:
* <p>
* If an algorithm type override is set, this will always be the algorithm used.
* <p>
*
* @param builder the builder object
*/
JsonMaskingConfig(Builder builder) {
Set<String> targets = builder.targets;
targetKeyMode = builder.targetKeyMode;
algorithmType = JsonMaskerAlgorithmType.KEYS_CONTAIN;
obfuscationLength = builder.obfuscationLength;
maskArrayValues = builder.maskArrayValues;
maskObjectValues = builder.maskObjectValues;
if (builder.obfuscationLength == 0 && !(builder.maskNumberValuesWith == 0
|| builder.maskNumberValuesWith == -1)) {
throw new IllegalArgumentException(
"If obfuscation length is set to 0, numeric values are replaced with a single 0, so mask number values with must be 0 or number masking must be disabled");
}
targetKeyMode = builder.targetKeyMode;
Set<String> targets = builder.targets;
if (targetKeyMode == TargetKeyMode.MASK && targets.isEmpty()) {
throw new IllegalArgumentException("Target keys set in mask mode must contain at least a single target key");
}
caseSensitiveTargetKeys = builder.caseSensitiveTargetKeys;
if (!caseSensitiveTargetKeys) {
targets = targets.stream().map(String::toLowerCase).collect(Collectors.toSet());
}
targetKeys = targets;
maskNumericValuesWith = builder.maskNumberValuesWith;
if (builder.maskNumberValuesWith == 0) {
if (builder.obfuscationLength < 0 || builder.obfuscationLength > 1) {
throw new IllegalArgumentException(
Expand All @@ -77,21 +60,10 @@ public class JsonMaskingConfig {
"Mask number values with must be a digit between 1 and 9 when length obfuscation is disabled or obfuscation length is larger than than 0");
}
}
maskNumericValuesWith = builder.maskNumberValuesWith;

caseSensitiveTargetKeys = builder.caseSensitiveTargetKeys;
if (!caseSensitiveTargetKeys) {
targets = targets.stream().map(String::toLowerCase).collect(Collectors.toSet());
}

if (builder.algorithmTypeOverride != null) {
algorithmType = builder.algorithmTypeOverride;
} else {
algorithmType = JsonMaskerAlgorithmType.KEYS_CONTAIN;
}
switch (algorithmType) {
case KEYS_CONTAIN -> targetKeys = targets;
default -> throw new IllegalStateException("Unknown JSON masking algorithm");
if (builder.obfuscationLength == 0 && !(builder.maskNumberValuesWith == 0
|| builder.maskNumberValuesWith == -1)) {
throw new IllegalArgumentException(
"If obfuscation length is set to 0, numeric values are replaced with a single 0, so mask number values with must be 0 or number masking must be disabled");
}
}

Expand Down Expand Up @@ -133,22 +105,6 @@ public boolean isNumberMaskingEnabled() {
return maskNumericValuesWith != -1;
}

/**
* Tests if object values masking is enabled
*/
public boolean isObjectValuesMaskingEnabled() {
return maskObjectValues;
}

/**
* Tests if array values masking is enabled
*
* @return true if array value masking is enabled and false otherwise.
*/
public boolean isArrayMaskingEnabled() {
return maskArrayValues;
}

public TargetKeyMode getTargetKeyMode() {
return targetKeyMode;
}
Expand Down Expand Up @@ -193,9 +149,6 @@ public static class Builder {
private final TargetKeyMode targetKeyMode;
private int maskNumberValuesWith;

private boolean maskArrayValues;

private boolean maskObjectValues;
private JsonMaskerAlgorithmType algorithmTypeOverride;
private int obfuscationLength;
private boolean caseSensitiveTargetKeys;
Expand All @@ -206,10 +159,6 @@ public Builder(Set<String> targets, TargetKeyMode targetKeyMode) {
this.targetKeyMode = targetKeyMode;
// by default, mask number values with is -1 which means number value masking is disabled
this.maskNumberValuesWith = -1;
// by default, array value masking is enabled
this.maskArrayValues = true;
// by default, object value masking is enabled
this.maskObjectValues = true;
// by default, length obfuscation is disabled
this.obfuscationLength = -1;
// by default, target keys are considered case-insensitive
Expand All @@ -229,17 +178,6 @@ public Builder maskNumericValuesWith(int maskNumericValuesWith) {
return this;
}

/**
* Overrides the automatically chosen masking algorithm {@link JsonMaskerAlgorithmType#KEYS_CONTAIN}.
*
* @param algorithmType the override algorithm which will be used
* @return the builder instance
*/
public Builder algorithmTypeOverride(JsonMaskerAlgorithmType algorithmType) {
this.algorithmTypeOverride = algorithmType;
return this;
}

/**
* @param obfuscationLength specifies the fixed length of the mask when target value lengths is obfuscated. E.g.
* masking any string value with obfuscation length 2 results in "**".
Expand All @@ -264,25 +202,6 @@ public Builder caseSensitiveTargetKeys() {
return this;
}

/**
* Disable array value masking, which is enabled by default
* <p>
* Default value: array value masking is enabled by default
*/
public Builder disableArrayValueMasking() {
this.maskArrayValues = false;
return this;
}

/**
* Disable object value masking, which is enabled by default
* <p>
* Default value: object value masking is enabled by default
*/
public Builder disableObjectValueMasking() {
this.maskObjectValues = false;
return this;
}

/**
* Creates a new {@link JsonMaskingConfig} instance.
Expand Down
11 changes: 7 additions & 4 deletions src/test/java/dev/blaauwendraad/masker/json/FuzzingTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@
import com.fasterxml.jackson.databind.JsonNode;
import dev.blaauwendraad.masker.json.config.JsonMaskingConfig;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import randomgen.json.RandomJsonGenerator;
import randomgen.json.RandomJsonGeneratorConfig;

import java.util.Set;

//TODO
@Disabled("Have to implement objecta and array masking first in the Jackson masker")
final class FuzzingTest {
private static final int SECONDS_FOR_EACH_TEST_TO_RUN = 10;

@ValueSource(ints = { SECONDS_FOR_EACH_TEST_TO_RUN })
@ValueSource(ints = {SECONDS_FOR_EACH_TEST_TO_RUN})
// duration in seconds the tests runs for
void fuzzing_NoArrayNoObjectValueMasking(int secondsToRunTest) {
long startTime = System.currentTimeMillis();
Expand All @@ -23,7 +26,7 @@ void fuzzing_NoArrayNoObjectValueMasking(int secondsToRunTest) {
JsonMasker keyContainsMasker = new KeyContainsMasker(JsonMaskingConfig.custom(
targetKeys,
JsonMaskingConfig.TargetKeyMode.MASK
).disableObjectValueMasking().disableArrayValueMasking().build());
).build());
RandomJsonGenerator randomJsonGenerator =
new RandomJsonGenerator(RandomJsonGeneratorConfig.builder().createConfig());
JsonNode randomJsonNode = randomJsonGenerator.createRandomJsonNode();
Expand All @@ -49,7 +52,7 @@ void fuzzing_NoArrayNoObjectValueMasking(int secondsToRunTest) {
}

@ParameterizedTest
@ValueSource(ints = { SECONDS_FOR_EACH_TEST_TO_RUN })
@ValueSource(ints = {SECONDS_FOR_EACH_TEST_TO_RUN})
// duration in seconds the tests runs for
void fuzzing_AllowKeys_NoObjectArrayValuesMasking(int secondsToRunTest) {
long startTime = System.currentTimeMillis();
Expand All @@ -59,7 +62,7 @@ void fuzzing_AllowKeys_NoObjectArrayValuesMasking(int secondsToRunTest) {
JsonMasker keyContainsMasker = new KeyContainsMasker(JsonMaskingConfig.custom(
targetKeys,
JsonMaskingConfig.TargetKeyMode.ALLOW
).disableArrayValueMasking().disableObjectValueMasking().build());
).build());
RandomJsonGenerator randomJsonGenerator =
new RandomJsonGenerator(RandomJsonGeneratorConfig.builder().createConfig());
JsonNode randomJsonNode = randomJsonGenerator.createRandomJsonNode();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,15 @@
import java.util.stream.Stream;

@ParametersAreNonnullByDefault
final class NoObjectValueMaskingTest {
final class MaskObjectInNonMaskedArray {
@ParameterizedTest
@MethodSource("noObjectMaskingFile")
void multiTargetKey(JsonMaskerTestInstance testInstance) {
@MethodSource("objectInNonMaskedArrayValues")
void maskObjectInNonMaskedArray(JsonMaskerTestInstance testInstance) {
Assertions.assertEquals(testInstance.expectedOutput(), testInstance.jsonMasker().mask(testInstance.input()));
}

private static Stream<JsonMaskerTestInstance> noObjectMaskingFile() throws IOException {
return JsonMaskerTestUtil.getJsonMaskerTestInstancesFromFile("test-no-object-value-masking.json", Set.of(
private static Stream<JsonMaskerTestInstance> objectInNonMaskedArrayValues() throws IOException {
return JsonMaskerTestUtil.getJsonMaskerTestInstancesFromFile("test-object-in-non-masked-array.json", Set.of(
JsonMaskerAlgorithmType.values())).stream();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
*/
@ParametersAreNonnullByDefault
final class NoFailingExecutionFuzzingTest {
private static final Duration DEFAULT_TEST_INSTANCE_DURATION = Duration.ofSeconds(3);
private static final Duration DEFAULT_TEST_INSTANCE_DURATION = Duration.ofSeconds(2);

@ParameterizedTest
@MethodSource("failureFuzzingConfigurations")
Expand All @@ -43,7 +43,7 @@ void defaultJsonMasker(JsonMaskingConfig jsonMaskingConfig, Duration durationToR
while (Instant.ofEpochMilli(System.currentTimeMillis()).isBefore(startTime.plus(durationToRunEachTest))) {
KeyContainsMasker keyContainsMasker = new KeyContainsMasker(jsonMaskingConfig);
RandomJsonGenerator randomJsonGenerator =
new RandomJsonGenerator(RandomJsonGeneratorConfig.builder().setMaxArraySize(3).setMaxNodeDepth(3).setMaxObjectKeys(2).createConfig());
new RandomJsonGenerator(RandomJsonGeneratorConfig.builder().createConfig());
JsonNode randomJsonNode = randomJsonGenerator.createRandomJsonNode();
String jsonString = randomJsonNode.toPrettyString();
lastExecutedJson.set(jsonString);
Expand All @@ -54,7 +54,7 @@ void defaultJsonMasker(JsonMaskingConfig jsonMaskingConfig, Duration durationToR
randomTestExecuted.incrementAndGet();
}
});
threadPoolExecutor.awaitTermination(4, TimeUnit.SECONDS);
threadPoolExecutor.awaitTermination(durationToRunEachTest.getSeconds(), TimeUnit.SECONDS);
System.out.printf(
"Executed %d randomly generated test scenarios in %d seconds%n",
randomTestExecuted.get(),
Expand All @@ -77,12 +77,13 @@ private static Stream<Arguments> failureFuzzingConfigurations() {
.caseSensitiveTargetKeys().build(), DEFAULT_TEST_INSTANCE_DURATION
),
Arguments.of(
JsonMaskingConfig.custom(targetKeys, JsonMaskingConfig.TargetKeyMode.MASK)
.disableArrayValueMasking().build(), DEFAULT_TEST_INSTANCE_DURATION
JsonMaskingConfig.custom(targetKeys, JsonMaskingConfig.TargetKeyMode.MASK).maskNumericValuesWith(1).build(), DEFAULT_TEST_INSTANCE_DURATION
),
Arguments.of(
JsonMaskingConfig.custom(targetKeys, JsonMaskingConfig.TargetKeyMode.MASK)
.build(), DEFAULT_TEST_INSTANCE_DURATION
JsonMaskingConfig.custom(targetKeys, JsonMaskingConfig.TargetKeyMode.MASK).obfuscationLength(1).maskNumericValuesWith(1).build(), DEFAULT_TEST_INSTANCE_DURATION
),
Arguments.of(
JsonMaskingConfig.custom(targetKeys, JsonMaskingConfig.TargetKeyMode.MASK).obfuscationLength(2).build(), DEFAULT_TEST_INSTANCE_DURATION
)
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,7 @@
import java.util.Set;
import java.util.stream.Stream;

class JsonMaskingConfigTest {

@ParameterizedTest
@MethodSource("buildersWithAlgorithmType")
void algorithmTypeSelection(JsonMaskingConfig.Builder builder, JsonMaskerAlgorithmType expectedAlgorithmType) {
Assertions.assertEquals(expectedAlgorithmType, new JsonMaskingConfig(builder).getAlgorithmType());
}
final class JsonMaskingConfigTest {

@ParameterizedTest
@MethodSource("invalidBuilders")
Expand All @@ -31,18 +25,4 @@ private static Stream<JsonMaskingConfig.Builder> invalidBuilders() {
).maskNumericValuesWith(1).obfuscationLength(0)
);
}

private static Stream<Arguments> buildersWithAlgorithmType() {
return Stream.of(
Arguments.of(
JsonMaskingConfig.custom(Set.of("oneKey", "secondKey"), JsonMaskingConfig.TargetKeyMode.MASK),
JsonMaskerAlgorithmType.KEYS_CONTAIN
),
Arguments.of(
JsonMaskingConfig.custom(Set.of("$.path", "otherKey"), JsonMaskingConfig.TargetKeyMode.MASK)
.algorithmTypeOverride(JsonMaskerAlgorithmType.KEYS_CONTAIN),
JsonMaskerAlgorithmType.KEYS_CONTAIN
)
);
}
}
Loading

0 comments on commit 87a85e4

Please sign in to comment.