Skip to content

Commit 21c3489

Browse files
committed
wip
1 parent 0bf1268 commit 21c3489

File tree

7 files changed

+84
-38
lines changed

7 files changed

+84
-38
lines changed

core/src/main/java/com/predic8/membrane/core/interceptor/dlp/CsvFieldConfiguration.java

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,18 @@
33
import org.slf4j.Logger;
44
import org.slf4j.LoggerFactory;
55

6-
import java.io.BufferedReader;
7-
import java.io.IOException;
8-
import java.io.InputStream;
9-
import java.io.InputStreamReader;
6+
import java.io.*;
107
import java.util.*;
118

12-
/**
13-
* Loads field risk mappings from a CSV file with format:
14-
* field_name,description,risk_level
15-
* where risk_level must be one of: high, medium, low, unclassified
16-
*/
179
public class CsvFieldConfiguration implements FieldConfiguration {
1810

1911
private static final Logger log = LoggerFactory.getLogger(CsvFieldConfiguration.class);
2012

13+
private final Map<String, String> riskLevels = new HashMap<>();
14+
private final Map<String, String> categories = new HashMap<>();
15+
2116
@Override
2217
public Map<String, String> getFields(String fileName) {
23-
Map<String, String> riskDict = new HashMap<>();
24-
2518
try (InputStream inputStream = getResourceAsStream(fileName)) {
2619
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
2720
String line;
@@ -43,20 +36,27 @@ public Map<String, String> getFields(String fileName) {
4336
}
4437

4538
String field = parts[0].trim().toLowerCase(Locale.ROOT);
39+
String category = parts[1].trim();
4640
String riskLevel = parts[2].trim().toLowerCase(Locale.ROOT);
4741

4842
if (!isValidRiskLevel(riskLevel)) {
4943
log.warn("Invalid risk level '{}' for field '{}'. Defaulting to 'unclassified'", riskLevel, field);
5044
riskLevel = "unclassified";
5145
}
5246

53-
riskDict.put(field, riskLevel);
47+
riskLevels.put(field, riskLevel);
48+
categories.put(field, category);
5449
}
5550

5651
} catch (IOException e) {
5752
throw new RuntimeException("Error reading CSV field configuration: " + fileName, e);
5853
}
59-
return riskDict;
54+
55+
return riskLevels;
56+
}
57+
58+
public Map<String, String> getFieldCategories() {
59+
return categories;
6060
}
6161

6262
private InputStream getResourceAsStream(String fileName) {

core/src/main/java/com/predic8/membrane/core/interceptor/dlp/DLPAnalyzer.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@ public class DLPAnalyzer {
2525
private static final ObjectMapper MAPPER = new ObjectMapper(JSON_FACTORY);
2626

2727
private final Map<String, RiskReport.Category> riskDict;
28+
private final Map<String, String> categoryMap;
2829

29-
public DLPAnalyzer(Map<String, String> rawRiskMap) {
30+
public DLPAnalyzer(Map<String, String> rawRiskMap, Map<String, String> categoryMap) {
3031
this.riskDict = mapToEnumRiskLevels(rawRiskMap);
32+
this.categoryMap = categoryMap;
3133
}
3234

3335
private Map<String, RiskReport.Category> mapToEnumRiskLevels(Map<String, String> raw) {
@@ -66,7 +68,10 @@ private void traverse(JsonNode node, Deque<String> path, RiskReport report) {
6668
String lastSegment = path.peekLast() != null ? path.peekLast().toLowerCase(Locale.ROOT) : "";
6769

6870
RiskReport.Category level = classify(fullPath, lastSegment);
69-
report.recordField(fullPath, level.name());
71+
String riskLevel = level.name();
72+
String category = categoryMap.getOrDefault(fullPath, categoryMap.getOrDefault(lastSegment, "Unknown"));
73+
74+
report.recordField(fullPath, riskLevel, category);
7075
}
7176
}
7277

core/src/main/java/com/predic8/membrane/core/interceptor/dlp/DLPInterceptor.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,17 @@ public class DLPInterceptor extends AbstractInterceptor {
3333

3434
@Override
3535
public void init() {
36-
Map<String, String> config = fieldsConfig != null ?
37-
new CsvFieldConfiguration().getFields(fieldsConfig) :
38-
Map.of();
36+
if (fieldsConfig != null) {
37+
CsvFieldConfiguration csv = new CsvFieldConfiguration();
38+
Map<String, String> levels = csv.getFields(fieldsConfig);
39+
Map<String, String> cats = csv.getFieldCategories();
40+
this.dlpAnalyzer = new DLPAnalyzer(levels, cats);
41+
} else {
42+
this.dlpAnalyzer = new DLPAnalyzer(Map.of(), Map.of());
43+
}
3944
actions.addAll(masks);
4045
actions.addAll(filters);
4146
actions.addAll(reports);
42-
this.dlpAnalyzer = new DLPAnalyzer(config);
4347
super.init();
4448
}
4549

core/src/main/java/com/predic8/membrane/core/interceptor/dlp/Filter.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,16 @@
55
import com.jayway.jsonpath.JsonPath;
66
import com.jayway.jsonpath.Option;
77
import com.predic8.membrane.annot.MCElement;
8+
import org.slf4j.Logger;
9+
import org.slf4j.LoggerFactory;
810

911
import java.util.Set;
1012

1113
@MCElement(name = "filter")
1214
public class Filter extends Action {
1315

16+
private static final Logger log = LoggerFactory.getLogger(Filter.class);
17+
1418
private static final Configuration SAFE_CONFIG = Configuration.builder()
1519
.options(Set.of(Option.DEFAULT_PATH_LEAF_TO_NULL))
1620
.build();
@@ -26,9 +30,12 @@ public String apply(DLPContext context) {
2630
}
2731

2832
doc.delete(getField());
33+
34+
log.info("[Filter] Removed field {} with value: {}", getField(), value);
2935
return doc.jsonString();
3036

3137
} catch (Exception e) {
38+
log.error("[Filter] Failed to apply filter on field: {}", getField(), e);
3239
throw new RuntimeException("Failed to apply filter on field: " + getField(), e);
3340
}
3441
}

core/src/main/java/com/predic8/membrane/core/interceptor/dlp/Mask.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,15 @@ public String getKeepRight() {
3434

3535
@MCAttribute
3636
public void setKeepRight(String keepRight) {
37+
if (keepRight != null) {
38+
try {
39+
if (Integer.parseInt(keepRight) < 0) {
40+
throw new IllegalArgumentException("keepRight must be non-negative: " + keepRight);
41+
}
42+
} catch (NumberFormatException e) {
43+
throw new IllegalArgumentException("keepRight must be a valid integer: " + keepRight, e);
44+
}
45+
}
3746
this.keepRight = keepRight;
3847
}
3948
}

core/src/main/java/com/predic8/membrane/core/interceptor/dlp/Report.java

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import org.slf4j.Logger;
55
import org.slf4j.LoggerFactory;
66

7-
import java.util.Objects;
7+
import java.util.Locale;
88

99
@MCElement(name = "report")
1010
public class Report extends Action {
@@ -14,19 +14,33 @@ public class Report extends Action {
1414
@Override
1515
public String apply(DLPContext context) {
1616
if (context == null || !context.hasRiskReport()) {
17-
log.warn("No RiskReport provided. Skipping report logging.");
18-
return Objects.requireNonNull(context).getBody();
17+
log.warn("No RiskReport provided. Skipping field report.");
18+
return context.getBody();
1919
}
20-
RiskReport report = context.getRiskReport();
21-
log.info("DLP Risk Summary: Category={}, Counts={}",
22-
report.getCategory(), report.getRiskCounts());
23-
if (!report.getMatchedFields().isEmpty()) {
24-
StringBuilder sb = new StringBuilder("Matched fields:");
25-
report.getMatchedFields().forEach((field, category) ->
26-
sb.append("\n - ").append(field).append(" -> ").append(category));
27-
log.info(sb.toString());
20+
21+
String path = getField(); // e.g. $.first_name
22+
if (path == null || path.isBlank()) {
23+
log.warn("No field specified in <report />. Skipping.");
24+
return context.getBody();
2825
}
26+
27+
try {
28+
String normalized = path.replaceFirst("^\\$\\.", "").toLowerCase(Locale.ROOT);
29+
30+
String riskLevel = context.getRiskReport()
31+
.getMatchedFields()
32+
.getOrDefault(normalized, "UNCLASSIFIED");
33+
34+
String category = context.getRiskReport()
35+
.getCategoryOf(normalized);
36+
37+
log.info("DLP Field Report: Field='{}', Category='{}', Risk Level='{}'",
38+
normalized, category, riskLevel);
39+
40+
} catch (Exception e) {
41+
log.warn("Could not log field '{}': {}", getField(), e.getMessage());
42+
}
43+
2944
return context.getBody();
3045
}
31-
3246
}

core/src/main/java/com/predic8/membrane/core/interceptor/dlp/RiskReport.java

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,27 @@ public class RiskReport {
77
private static final List<String> LEVELS = List.of("high", "medium", "low", "unclassified");
88

99
private final Map<String, String> matchedFields = new LinkedHashMap<>();
10+
private final Map<String, String> fieldCategories = new LinkedHashMap<>();
1011
private final EnumMap<Category, Integer> riskCounts = new EnumMap<>(Category.class);
1112
private final EnumMap<Category, Map<String, Integer>> riskDetails = new EnumMap<>(Category.class);
1213

13-
public void recordField(String field, String riskLevel) {
14+
public void recordField(String field, String riskLevel, String category) {
1415
matchedFields.put(field, riskLevel);
15-
Category category = Category.fromString(riskLevel);
16-
riskCounts.merge(category, 1, Integer::sum);
17-
riskDetails.computeIfAbsent(category, r -> new LinkedHashMap<>()).merge(field, 1, Integer::sum);
16+
fieldCategories.put(field, category);
17+
18+
Category cat = Category.fromString(riskLevel);
19+
riskCounts.merge(cat, 1, Integer::sum);
20+
riskDetails.computeIfAbsent(cat, r -> new LinkedHashMap<>()).merge(field, 1, Integer::sum);
21+
}
22+
23+
public String getCategoryOf(String field) {
24+
return fieldCategories.getOrDefault(field, "Unknown");
1825
}
1926

2027
public Category getCategory() {
21-
if (riskCounts.getOrDefault("high", 0) > 0) return Category.HIGH;
22-
if (riskCounts.getOrDefault("medium", 0) > 0) return Category.MEDIUM;
23-
if (riskCounts.getOrDefault("low", 0) > 0) return Category.LOW;
28+
if (riskCounts.getOrDefault(Category.HIGH, 0) > 0) return Category.HIGH;
29+
if (riskCounts.getOrDefault(Category.MEDIUM, 0) > 0) return Category.MEDIUM;
30+
if (riskCounts.getOrDefault(Category.LOW, 0) > 0) return Category.LOW;
2431
return Category.UNCLASSIFIED;
2532
}
2633

0 commit comments

Comments
 (0)