-
-
Notifications
You must be signed in to change notification settings - Fork 660
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
24 changed files
with
582 additions
and
88 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package org.akhq.configs; | ||
|
||
public enum DataMaskingMode { | ||
// Use the existing regex-based filtering | ||
REGEX, | ||
// Use filtering where by default all fields of all records are masked, with fields to unmask defined in allowlists | ||
JSON_MASK_BY_DEFAULT, | ||
// Use filtering where by default no fields of any records are masked, with fields to mask explicitly denied | ||
JSON_SHOW_BY_DEFAULT, | ||
// No masker at all, best performance | ||
NONE | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package org.akhq.configs; | ||
|
||
import io.micronaut.context.annotation.EachProperty; | ||
import lombok.Data; | ||
|
||
import java.util.List; | ||
|
||
@EachProperty("jsonfilters") | ||
@Data | ||
public class JsonMaskingFilter { | ||
String description = "UNKNOWN"; | ||
String topic = "UNKNOWN"; | ||
List<String> keys = List.of("UNKNOWN"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package org.akhq.utils; | ||
|
||
import com.google.gson.JsonElement; | ||
import com.google.gson.JsonObject; | ||
import com.google.gson.JsonParser; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.SneakyThrows; | ||
import org.akhq.configs.JsonMaskingFilter; | ||
import org.akhq.models.Record; | ||
|
||
import java.util.List; | ||
import java.util.Map; | ||
|
||
@RequiredArgsConstructor | ||
public class JsonMaskByDefaultMasker implements Masker { | ||
|
||
private final List<JsonMaskingFilter> jsonMaskingFilters; | ||
private final String jsonMaskReplacement; | ||
|
||
public Record maskRecord(Record record) { | ||
try { | ||
if(record.getValue().trim().startsWith("{") && record.getValue().trim().endsWith("}")) { | ||
JsonMaskingFilter foundFilter = null; | ||
for (JsonMaskingFilter filter : jsonMaskingFilters) { | ||
if (record.getTopic().getName().equalsIgnoreCase(filter.getTopic())) { | ||
foundFilter = filter; | ||
} | ||
} | ||
if (foundFilter != null) { | ||
return applyMasking(record, foundFilter.getKeys()); | ||
} else { | ||
return applyMasking(record, List.of()); | ||
} | ||
} else { | ||
return record; | ||
} | ||
} catch (Exception e) { | ||
LOG.error("Error masking record", e); | ||
return record; | ||
} | ||
} | ||
|
||
@SneakyThrows | ||
private Record applyMasking(Record record, List<String> keys) { | ||
JsonObject jsonElement = JsonParser.parseString(record.getValue()).getAsJsonObject(); | ||
maskAllExcept(jsonElement, keys); | ||
record.setValue(jsonElement.toString()); | ||
return record; | ||
} | ||
|
||
private void maskAllExcept(JsonObject node, List<String> keys) { | ||
if (node.isJsonObject()) { | ||
JsonObject objectNode = node.getAsJsonObject(); | ||
for(Map.Entry<String, JsonElement> entry : objectNode.entrySet()) { | ||
if(entry.getValue().isJsonObject()) { | ||
maskAllExcept(entry.getValue().getAsJsonObject(), keys); | ||
} else { | ||
if(!keys.contains(entry.getKey())) { | ||
objectNode.addProperty(entry.getKey(), jsonMaskReplacement); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package org.akhq.utils; | ||
|
||
import com.google.gson.JsonElement; | ||
import com.google.gson.JsonObject; | ||
import com.google.gson.JsonParser; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.SneakyThrows; | ||
import org.akhq.configs.JsonMaskingFilter; | ||
import org.akhq.models.Record; | ||
|
||
import java.util.List; | ||
|
||
@RequiredArgsConstructor | ||
public class JsonShowByDefaultMasker implements Masker { | ||
|
||
private final List<JsonMaskingFilter> jsonMaskingFilters; | ||
private final String jsonMaskReplacement; | ||
|
||
public Record maskRecord(Record record) { | ||
try { | ||
if(record.getValue().trim().startsWith("{") && record.getValue().trim().endsWith("}")) { | ||
JsonMaskingFilter foundFilter = null; | ||
for (JsonMaskingFilter filter : jsonMaskingFilters) { | ||
if (record.getTopic().getName().equalsIgnoreCase(filter.getTopic())) { | ||
foundFilter = filter; | ||
} | ||
} | ||
if (foundFilter != null) { | ||
return applyMasking(record, foundFilter.getKeys()); | ||
} else { | ||
return record; | ||
} | ||
} else { | ||
return record; | ||
} | ||
} catch (Exception e) { | ||
LOG.error("Error masking record", e); | ||
return record; | ||
} | ||
} | ||
|
||
@SneakyThrows | ||
private Record applyMasking(Record record, List<String> keys) { | ||
JsonObject jsonElement = JsonParser.parseString(record.getValue()).getAsJsonObject(); | ||
for(String key : keys) { | ||
maskField(jsonElement, key.split("\\."), 0); | ||
} | ||
record.setValue(jsonElement.toString()); | ||
return record; | ||
} | ||
|
||
private void maskField(JsonObject node, String[] keys, int index) { | ||
if (index == keys.length - 1) { | ||
if (node.has(keys[index])) { | ||
node.addProperty(keys[index], jsonMaskReplacement); | ||
} | ||
} else { | ||
JsonElement childNode = node.get(keys[index]); | ||
if (childNode != null && childNode.isJsonObject()) { | ||
maskField(childNode.getAsJsonObject(), keys, index + 1); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package org.akhq.utils; | ||
|
||
import org.akhq.models.Record; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
public interface Masker { | ||
|
||
Logger LOG = LoggerFactory.getLogger(Masker.class); | ||
|
||
Record maskRecord(Record record); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package org.akhq.utils; | ||
|
||
import io.micronaut.context.annotation.Bean; | ||
import io.micronaut.context.annotation.Factory; | ||
import org.akhq.configs.DataMasking; | ||
|
||
@Factory | ||
public class MaskerFactory { | ||
|
||
@Bean | ||
public Masker createMaskingUtil(DataMasking dataMasking) { | ||
if(dataMasking == null) { | ||
return new NoOpMasker(); | ||
} | ||
return switch(dataMasking.getMode()) { | ||
case REGEX -> new RegexMasker(dataMasking.getFilters()); | ||
case JSON_MASK_BY_DEFAULT -> new JsonMaskByDefaultMasker(dataMasking.getJsonFilters(), dataMasking.getJsonMaskReplacement()); | ||
case JSON_SHOW_BY_DEFAULT -> new JsonShowByDefaultMasker(dataMasking.getJsonFilters(), dataMasking.getJsonMaskReplacement()); | ||
case NONE -> new NoOpMasker(); | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package org.akhq.utils; | ||
|
||
import org.akhq.models.Record; | ||
|
||
public class NoOpMasker implements Masker { | ||
|
||
@Override | ||
public Record maskRecord(Record record) { | ||
return record; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
src/test/java/org/akhq/utils/DefaultMaskerSettingTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package org.akhq.utils; | ||
|
||
import io.micronaut.test.extensions.junit5.annotation.MicronautTest; | ||
import jakarta.inject.Inject; | ||
import org.akhq.configs.DataMasking; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import static org.akhq.configs.DataMaskingMode.REGEX; | ||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertInstanceOf; | ||
|
||
@MicronautTest | ||
public class DefaultMaskerSettingTest { | ||
|
||
@Inject | ||
DataMasking dataMasking; | ||
|
||
@Inject | ||
Masker masker; | ||
|
||
@Test | ||
void defaultValuesShouldUseRegexForBackwardsCompatibility() { | ||
assertEquals( | ||
REGEX, | ||
dataMasking.getMode() | ||
); | ||
assertInstanceOf(RegexMasker.class, masker); | ||
} | ||
} |
Oops, something went wrong.