Skip to content

Commit 5fd5de9

Browse files
author
Corneil du Plessis
authored
Sanitize audit data (spring-cloud#4955)
* Added failFast checks that report ERROR from the logs. * Refactor AwaitUtils for tracking log offset. * Fix properties test. * Ensure map data in audit record is sanitized. Fixes spring-cloud#4947
1 parent 3f6596b commit 5fd5de9

File tree

2 files changed

+353
-277
lines changed

2 files changed

+353
-277
lines changed

spring-cloud-dataflow-audit/src/main/java/org/springframework/cloud/dataflow/audit/service/DefaultAuditRecordService.java

+101-66
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package org.springframework.cloud.dataflow.audit.service;
1717

1818
import java.time.Instant;
19+
import java.util.HashMap;
1920
import java.util.Map;
2021
import java.util.Optional;
2122

@@ -26,6 +27,7 @@
2627
import org.slf4j.LoggerFactory;
2728

2829
import org.springframework.cloud.dataflow.audit.repository.AuditRecordRepository;
30+
import org.springframework.cloud.dataflow.core.ArgumentSanitizer;
2931
import org.springframework.cloud.dataflow.core.AuditActionType;
3032
import org.springframework.cloud.dataflow.core.AuditOperationType;
3133
import org.springframework.cloud.dataflow.core.AuditRecord;
@@ -38,74 +40,107 @@
3840
*
3941
* @author Gunnar Hillert
4042
* @author Daniel Serleg
43+
* @author Corneil du Plessis
4144
*/
4245
public class DefaultAuditRecordService implements AuditRecordService {
4346

44-
private static final Logger logger = LoggerFactory.getLogger(DefaultAuditRecordService.class);
45-
46-
private final AuditRecordRepository auditRecordRepository;
47-
48-
private final ObjectMapper objectMapper;
49-
50-
public DefaultAuditRecordService(AuditRecordRepository auditRecordRepository) {
51-
Assert.notNull(auditRecordRepository, "auditRecordRepository must not be null.");
52-
this.auditRecordRepository = auditRecordRepository;
53-
this.objectMapper = new ObjectMapper();
54-
this.objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
55-
}
56-
57-
public DefaultAuditRecordService(AuditRecordRepository auditRecordRepository, ObjectMapper objectMapper) {
58-
Assert.notNull(auditRecordRepository, "auditRecordRepository must not be null.");
59-
Assert.notNull(objectMapper, "objectMapper must not be null.");
60-
this.auditRecordRepository = auditRecordRepository;
61-
this.objectMapper = objectMapper;
62-
}
63-
64-
@Override
65-
public AuditRecord populateAndSaveAuditRecord(AuditOperationType auditOperationType,
66-
AuditActionType auditActionType,
67-
String correlationId, String data, String platformName) {
68-
Assert.notNull(auditActionType, "auditActionType must not be null.");
69-
Assert.notNull(auditOperationType, "auditOperationType must not be null.");
70-
71-
final AuditRecord auditRecord = new AuditRecord();
72-
auditRecord.setAuditAction(auditActionType);
73-
auditRecord.setAuditOperation(auditOperationType);
74-
auditRecord.setCorrelationId(correlationId);
75-
auditRecord.setAuditData(data);
76-
auditRecord.setPlatformName(platformName);
77-
return this.auditRecordRepository.save(auditRecord);
78-
}
79-
80-
@Override
81-
public AuditRecord populateAndSaveAuditRecordUsingMapData(AuditOperationType auditOperationType,
82-
AuditActionType auditActionType,
83-
String correlationId, Map<String, Object> data, String platformName) {
84-
String dataAsString;
85-
try {
86-
dataAsString = objectMapper.writeValueAsString(data);
87-
}
88-
catch (JsonProcessingException e) {
89-
logger.error("Error serializing audit record data. Data = " + data);
90-
dataAsString = "Error serializing audit record data. Data = " + data;
91-
}
92-
return this.populateAndSaveAuditRecord(auditOperationType, auditActionType, correlationId, dataAsString, platformName);
93-
}
94-
95-
@Override
96-
public Page<AuditRecord> findAuditRecordByAuditOperationTypeAndAuditActionTypeAndDate(
97-
Pageable pageable,
98-
AuditActionType[] actions,
99-
AuditOperationType[] operations,
100-
Instant fromDate,
101-
Instant toDate) {
102-
return this.auditRecordRepository.findByActionTypeAndOperationTypeAndDate(operations, actions, fromDate, toDate,
103-
pageable);
104-
}
105-
106-
@Override
107-
public Optional<AuditRecord> findById(Long id) {
108-
return this.auditRecordRepository.findById(id);
109-
}
47+
private static final Logger logger = LoggerFactory.getLogger(DefaultAuditRecordService.class);
48+
49+
private final AuditRecordRepository auditRecordRepository;
50+
51+
private final ObjectMapper objectMapper;
52+
53+
private final ArgumentSanitizer sanitizer;
54+
55+
public DefaultAuditRecordService(AuditRecordRepository auditRecordRepository) {
56+
57+
this(auditRecordRepository, null);
58+
}
59+
60+
public DefaultAuditRecordService(AuditRecordRepository auditRecordRepository, ObjectMapper objectMapper) {
61+
62+
Assert.notNull(auditRecordRepository, "auditRecordRepository must not be null.");
63+
this.auditRecordRepository = auditRecordRepository;
64+
if (objectMapper == null) {
65+
objectMapper = new ObjectMapper();
66+
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
67+
}
68+
this.objectMapper = objectMapper;
69+
this.sanitizer = new ArgumentSanitizer();
70+
}
71+
72+
@Override
73+
public AuditRecord populateAndSaveAuditRecord(AuditOperationType auditOperationType,
74+
AuditActionType auditActionType,
75+
String correlationId, String data, String platformName) {
76+
77+
Assert.notNull(auditActionType, "auditActionType must not be null.");
78+
Assert.notNull(auditOperationType, "auditOperationType must not be null.");
79+
80+
final AuditRecord auditRecord = new AuditRecord();
81+
auditRecord.setAuditAction(auditActionType);
82+
auditRecord.setAuditOperation(auditOperationType);
83+
auditRecord.setCorrelationId(correlationId);
84+
auditRecord.setAuditData(data);
85+
auditRecord.setPlatformName(platformName);
86+
return this.auditRecordRepository.save(auditRecord);
87+
}
88+
89+
@Override
90+
public AuditRecord populateAndSaveAuditRecordUsingMapData(
91+
AuditOperationType auditOperationType,
92+
AuditActionType auditActionType,
93+
String correlationId, Map<String, Object> data,
94+
String platformName
95+
) {
96+
97+
String dataAsString;
98+
try {
99+
Map<String, Object> sanitizedData = sanitizeMap(data);
100+
dataAsString = objectMapper.writeValueAsString(sanitizedData);
101+
} catch (JsonProcessingException e) {
102+
logger.error("Error serializing audit record data. Data = " + data);
103+
dataAsString = "Error serializing audit record data. Data = " + data;
104+
}
105+
return this.populateAndSaveAuditRecord(auditOperationType, auditActionType, correlationId, dataAsString, platformName);
106+
}
107+
108+
private Map<String, Object> sanitizeMap(Map<String, Object> data) {
109+
110+
final Map<String, Object> result = new HashMap<>();
111+
data.forEach((k, v) -> result.put(k, sanitize(k, v)));
112+
return result;
113+
}
114+
115+
private Object sanitize(String key, Object value) {
116+
117+
if (value instanceof String) {
118+
return sanitizer.sanitize(key, (String) value);
119+
} else if (value instanceof Map) {
120+
Map<String, Object> input = (Map) value;
121+
return sanitizeMap(input);
122+
} else {
123+
return value;
124+
}
125+
}
126+
127+
128+
@Override
129+
public Page<AuditRecord> findAuditRecordByAuditOperationTypeAndAuditActionTypeAndDate(
130+
Pageable pageable,
131+
AuditActionType[] actions,
132+
AuditOperationType[] operations,
133+
Instant fromDate,
134+
Instant toDate) {
135+
136+
return this.auditRecordRepository.findByActionTypeAndOperationTypeAndDate(operations, actions, fromDate, toDate,
137+
pageable);
138+
}
139+
140+
@Override
141+
public Optional<AuditRecord> findById(Long id) {
142+
143+
return this.auditRecordRepository.findById(id);
144+
}
110145

111146
}

0 commit comments

Comments
 (0)