Skip to content
Permalink
Browse files
[CXF-8699] Abillity to set sensitive filters on LoggingFeature (#945)
* [CXF-8699] Abillity to set sensitive filters on LoggingFeature

* [CXF-8699] Set<String> with trimmed values
  • Loading branch information
jgreffe committed May 9, 2022
1 parent 5d72c8d commit 940e4ee9b6b4e9768350cf6f8e79c8d466f27d64
Showing 5 changed files with 126 additions and 2 deletions.
@@ -86,10 +86,19 @@ public long getInMemThreshold() {
return threshold;
}

public void setSensitiveElementNames(final Set<String> sensitiveElementNames) {
maskSensitiveHelper.setSensitiveElementNames(sensitiveElementNames);
}

public void addSensitiveElementNames(final Set<String> sensitiveElementNames) {
maskSensitiveHelper.addSensitiveElementNames(sensitiveElementNames);
}

public void setSensitiveProtocolHeaderNames(final Set<String> protocolHeaderNames) {
this.sensitiveProtocolHeaderNames.clear();
addSensitiveProtocolHeaderNames(protocolHeaderNames);
}

public void addSensitiveProtocolHeaderNames(final Set<String> protocolHeaderNames) {
this.sensitiveProtocolHeaderNames.addAll(protocolHeaderNames);
}
@@ -147,6 +147,22 @@ public void addBinaryContentMediaTypes(String mediaTypes) {
* </pre>
* @param sensitiveElementNames set of sensitive element names to be replaced
*/
public void setSensitiveElementNames(final Set<String> sensitiveElementNames) {
delegate.setSensitiveElementNames(sensitiveElementNames);
}

/**
* Adds list of XML or JSON elements containing sensitive information to be masked.
* Corresponded data will be replaced with configured mask
* For example:
* <pre>
* sensitiveElementNames: {password}
*
* Initial logging statement: <user>my user</user><password>my secret password</password>
* Result logging statement: <user>my user</user><password>XXXX</password>
* </pre>
* @param sensitiveElementNames set of sensitive element names to be replaced
*/
public void addSensitiveElementNames(final Set<String> sensitiveElementNames) {
delegate.addSensitiveElementNames(sensitiveElementNames);
}
@@ -163,6 +179,22 @@ public void addSensitiveElementNames(final Set<String> sensitiveElementNames) {
* </pre>
* @param sensitiveProtocolHeaderNames set of sensitive element names to be replaced
*/
public void setSensitiveProtocolHeaderNames(final Set<String> sensitiveProtocolHeaderNames) {
delegate.setSensitiveProtocolHeaderNames(sensitiveProtocolHeaderNames);
}

/**
* Adds list of protocol headers containing sensitive information to be masked.
* Corresponded data will be replaced with configured mask
* For example:
* <pre>
* sensitiveHeaders: {Authorization}
*
* Initial logging statement: {Authorization=Basic QWxhZGRpbjpPcGVuU2VzYW1l}
* Result logging statement: {Authorization=XXX}
* </pre>
* @param sensitiveProtocolHeaderNames set of sensitive element names to be replaced
*/
public void addSensitiveProtocolHeaderNames(final Set<String> sensitiveProtocolHeaderNames) {
delegate.addSensitiveProtocolHeaderNames(sensitiveProtocolHeaderNames);
}
@@ -252,11 +284,21 @@ public void addBinaryContentMediaTypes(String mediaTypes) {
addOutBinaryContentMediaTypes(mediaTypes);
}

public void setSensitiveElementNames(final Set<String> sensitiveElementNames) {
in.setSensitiveElementNames(sensitiveElementNames);
out.setSensitiveElementNames(sensitiveElementNames);
}

public void addSensitiveElementNames(final Set<String> sensitiveElementNames) {
in.addSensitiveElementNames(sensitiveElementNames);
out.addSensitiveElementNames(sensitiveElementNames);
}

public void setSensitiveProtocolHeaderNames(final Set<String> sensitiveProtocolHeaderNames) {
in.setSensitiveProtocolHeaderNames(sensitiveProtocolHeaderNames);
out.setSensitiveProtocolHeaderNames(sensitiveProtocolHeaderNames);
}

public void addSensitiveProtocolHeaderNames(final Set<String> sensitiveProtocolHeaderNames) {
in.addSensitiveProtocolHeaderNames(sensitiveProtocolHeaderNames);
out.addSensitiveProtocolHeaderNames(sensitiveProtocolHeaderNames);
@@ -50,6 +50,12 @@ private static class ReplacementPair {
private final Set<ReplacementPair> replacementsXML = new HashSet<>();
private final Set<ReplacementPair> replacementsJSON = new HashSet<>();

public void setSensitiveElementNames(final Set<String> inSensitiveElementNames) {
replacementsXML.clear();
replacementsJSON.clear();
addSensitiveElementNames(inSensitiveElementNames);
}

public void addSensitiveElementNames(final Set<String> inSensitiveElementNames) {
for (final String sensitiveName : inSensitiveElementNames) {
addReplacementPair(MATCH_PATTERN_XML_TEMPLATE, REPLACEMENT_XML_TEMPLATE, sensitiveName, replacementsXML);
@@ -18,8 +18,12 @@
*/
package org.apache.cxf.ext.logging.osgi;

import java.util.Arrays;
import java.util.Dictionary;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.cxf.ext.logging.LoggingFeature;
import org.apache.cxf.feature.AbstractFeature;
@@ -33,6 +37,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static java.util.function.Predicate.not;

public class Activator implements BundleActivator {
private static final Logger LOG = LoggerFactory.getLogger(Activator.class);
private static final String CONFIG_PID = "org.apache.cxf.features.logging";
@@ -71,6 +77,8 @@ public void updated(Dictionary config) throws ConfigurationException {
Long inMemThreshold = Long.valueOf(getValue(config, "inMemThresHold", "-1"));
Boolean logMultipart = Boolean.valueOf(getValue(config, "logMultipart", "true"));
Boolean logBinary = Boolean.valueOf(getValue(config, "logBinary", "false"));
Set<String> sensitiveElementNames = getTrimmedSet(config, "sensitiveElementNames");
Set<String> sensitiveProtocolHeaderNames = getTrimmedSet(config, "sensitiveProtocolHeaderNames");

if (limit != null) {
logging.setLimit(limit);
@@ -91,6 +99,14 @@ public void updated(Dictionary config) throws ConfigurationException {
if (logBinary != null) {
logging.setLogBinary(logBinary);
}

if (!sensitiveElementNames.isEmpty()) {
logging.setSensitiveElementNames(sensitiveElementNames);
}

if (!sensitiveProtocolHeaderNames.isEmpty()) {
logging.setSensitiveProtocolHeaderNames(sensitiveProtocolHeaderNames);
}

if (intentReg == null) {
Dictionary<String, Object> properties = new Hashtable<>();
@@ -112,6 +128,15 @@ public void updated(Dictionary config) throws ConfigurationException {
}
}

@SuppressWarnings("rawtypes")
private Set<String> getTrimmedSet(Dictionary config, String propertyKey) {
return new HashSet<>(
Arrays.stream(String.valueOf(getValue(config, propertyKey, "")).split(","))
.map(String::trim)
.filter(not(String::isEmpty))
.collect(Collectors.toSet()));
}

@SuppressWarnings("rawtypes")
private String getValue(Dictionary config, String key, String defaultValue) {
if (config == null) {
@@ -92,7 +92,7 @@ public static Collection primeNumbers() {
}

@Test
public void shouldReplaceSensitiveDataIn() {
public void shouldReplaceSensitiveDataInWithAdd() {
// Arrange
final LoggingInInterceptor inInterceptor = new LoggingInInterceptor(logEventSender);
inInterceptor.addSensitiveElementNames(SENSITIVE_ELEMENTS);
@@ -113,7 +113,28 @@ public void shouldReplaceSensitiveDataIn() {
}

@Test
public void shouldReplaceSensitiveDataOut() throws IOException {
public void shouldReplaceSensitiveDataInWithSet() {
// Arrange
final LoggingInInterceptor inInterceptor = new LoggingInInterceptor(logEventSender);
inInterceptor.setSensitiveElementNames(SENSITIVE_ELEMENTS);

final Message message = prepareInMessage();

// Act
Collection<PhaseInterceptor<? extends Message>> interceptors = inInterceptor.getAdditionalInterceptors();
for (PhaseInterceptor intercept : interceptors) {
intercept.handleMessage(message);
}
inInterceptor.handleMessage(message);

// Verify
LogEvent event = logEventSender.getLogEvent();
assertNotNull(event);
assertEquals(maskedContent, event.getPayload());
}

@Test
public void shouldReplaceSensitiveDataOutWithAdd() throws IOException {
// Arrange
final LoggingOutInterceptor outInterceptor = new LoggingOutInterceptor(logEventSender);
outInterceptor.addSensitiveElementNames(SENSITIVE_ELEMENTS);
@@ -133,6 +154,27 @@ public void shouldReplaceSensitiveDataOut() throws IOException {
assertEquals(maskedContent, event.getPayload());
}

@Test
public void shouldReplaceSensitiveDataOutWithSet() throws IOException {
// Arrange
final LoggingOutInterceptor outInterceptor = new LoggingOutInterceptor(logEventSender);
outInterceptor.setSensitiveElementNames(SENSITIVE_ELEMENTS);

final Message message = prepareOutMessage();

// Act
outInterceptor.handleMessage(message);
byte[] payload = loggingContent.getBytes(StandardCharsets.UTF_8);
OutputStream out = message.getContent(OutputStream.class);
out.write(payload);
out.close();

// Verify
LogEvent event = logEventSender.getLogEvent();
assertNotNull(event);
assertEquals(maskedContent, event.getPayload());
}

@Test
public void shouldNotReplaceSensitiveDataEmptyExpression() throws IOException {
// Arrange

0 comments on commit 940e4ee

Please sign in to comment.