diff --git a/src/main/java/org/akhq/utils/JsonMaskByDefaultMasker.java b/src/main/java/org/akhq/utils/JsonMaskByDefaultMasker.java index fdb83692b..78a26638f 100644 --- a/src/main/java/org/akhq/utils/JsonMaskByDefaultMasker.java +++ b/src/main/java/org/akhq/utils/JsonMaskByDefaultMasker.java @@ -6,7 +6,6 @@ import io.micronaut.context.annotation.Requires; import jakarta.inject.Singleton; import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; import org.akhq.configs.DataMasking; import org.akhq.configs.JsonMaskingFilter; import org.akhq.models.Record; @@ -14,7 +13,6 @@ import java.util.List; import java.util.Map; -@Slf4j @Singleton @Requires(property = "akhq.security.data-masking.mode", value = "json_mask_by_default") public class JsonMaskByDefaultMasker implements Masker { @@ -30,7 +28,7 @@ public JsonMaskByDefaultMasker(DataMasking dataMasking) { public Record maskRecord(Record record) { try { if(record.isTombstone()) { - log.debug("Record at topic {}, partition {}, offset {} is a tombstone, so not masking.", record.getTopic(), record.getPartition(), record.getOffset()); + LOG.debug("Record at topic {}, partition {}, offset {} is a tombstone, so not masking.", record.getTopic(), record.getPartition(), record.getOffset()); return record; } else if(record.isJson()) { return jsonMaskingFilters @@ -40,13 +38,14 @@ public Record maskRecord(Record record) { .map(filter -> applyMasking(record, filter.getKeys())) .orElseGet(() -> applyMasking(record, List.of())); } else { - log.debug("Record at topic {}, partition {}, offset {} is not JSON, so not masking.", record.getTopic(), record.getPartition(), record.getOffset()); + LOG.debug("Record at topic {}, partition {}, offset {} is not JSON, so not masking.", record.getTopic(), record.getPartition(), record.getOffset()); return record; } } catch (Exception e) { - LOG.error("Error masking record", e); + LOG.error("Error masking record at topic {}, partition {}, offset {} due to {}. Returning simply 'XXXX' for safety", record.getTopic(), record.getPartition(), record.getOffset(), e.getMessage()); + record.setValue("An exception occurred during an attempt to mask this record. This record is unavailable to view due to safety measures from json_mask_by_default to not leak sensitive data. Please contact akhq administrator."); + return record; } - return record; } @SneakyThrows diff --git a/src/test/java/org/akhq/utils/JsonMaskByDefaultMaskerTest.java b/src/test/java/org/akhq/utils/JsonMaskByDefaultMaskerTest.java index 40ede6b1c..128879f9d 100644 --- a/src/test/java/org/akhq/utils/JsonMaskByDefaultMaskerTest.java +++ b/src/test/java/org/akhq/utils/JsonMaskByDefaultMaskerTest.java @@ -1,12 +1,14 @@ package org.akhq.utils; +import com.google.gson.JsonParser; import io.micronaut.test.extensions.junit5.annotation.MicronautTest; import jakarta.inject.Inject; import org.akhq.models.Record; import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.*; @MicronautTest(environments = "json-mask-by-default-data-masking") class JsonMaskByDefaultMaskerTest extends MaskerTestHelper { @@ -99,6 +101,22 @@ void forNonJsonValueThatLooksLikeJsonValueShouldReturnItself() { ); } + @Test + void ifJsonParsingThrowsExceptionShouldReturnFalse() { + String sampleStringToParse = sampleValue(); + Record record = sampleRecord( + "different-topic", + "some-key", + sampleStringToParse + ); + + try (MockedStatic mockStatic = Mockito.mockStatic(JsonParser.class)) { + mockStatic.when(() -> JsonParser.parseString(sampleStringToParse)).thenThrow(new RuntimeException("Bad exception!")); + Record record1 = masker.maskRecord(record); + assertEquals("An exception occurred during an attempt to mask this record. This record is unavailable to view due to safety measures from json_mask_by_default to not leak sensitive data. Please contact akhq administrator.", record1.getValue()); + } + } + private String sampleValue() { return """ {