You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by re...@apache.org on 2022/05/09 12:41:15 UTC

[cxf] branch master updated: [CXF-8699] Abillity to set sensitive filters on LoggingFeature (#945)

This is an automated email from the ASF dual-hosted git repository.

reta pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cxf.git


The following commit(s) were added to refs/heads/master by this push:
     new 940e4ee9b6 [CXF-8699] Abillity to set sensitive filters on LoggingFeature (#945)
940e4ee9b6 is described below

commit 940e4ee9b6b4e9768350cf6f8e79c8d466f27d64
Author: Julien Greffe <36...@users.noreply.github.com>
AuthorDate: Mon May 9 14:41:09 2022 +0200

    [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
---
 .../ext/logging/AbstractLoggingInterceptor.java    |  9 +++++
 .../org/apache/cxf/ext/logging/LoggingFeature.java | 42 ++++++++++++++++++++
 .../cxf/ext/logging/MaskSensitiveHelper.java       |  6 +++
 .../org/apache/cxf/ext/logging/osgi/Activator.java | 25 ++++++++++++
 .../cxf/ext/logging/MaskSensitiveHelperTest.java   | 46 +++++++++++++++++++++-
 5 files changed, 126 insertions(+), 2 deletions(-)

diff --git a/rt/features/logging/src/main/java/org/apache/cxf/ext/logging/AbstractLoggingInterceptor.java b/rt/features/logging/src/main/java/org/apache/cxf/ext/logging/AbstractLoggingInterceptor.java
index f6b48fd045..619ce5220b 100644
--- a/rt/features/logging/src/main/java/org/apache/cxf/ext/logging/AbstractLoggingInterceptor.java
+++ b/rt/features/logging/src/main/java/org/apache/cxf/ext/logging/AbstractLoggingInterceptor.java
@@ -86,10 +86,19 @@ public abstract class AbstractLoggingInterceptor extends AbstractPhaseIntercepto
         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);
     }
diff --git a/rt/features/logging/src/main/java/org/apache/cxf/ext/logging/LoggingFeature.java b/rt/features/logging/src/main/java/org/apache/cxf/ext/logging/LoggingFeature.java
index dff3e88bed..43bedc484a 100644
--- a/rt/features/logging/src/main/java/org/apache/cxf/ext/logging/LoggingFeature.java
+++ b/rt/features/logging/src/main/java/org/apache/cxf/ext/logging/LoggingFeature.java
@@ -147,6 +147,22 @@ public class LoggingFeature extends DelegatingFeature<LoggingFeature.Portable> {
      * </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 class LoggingFeature extends DelegatingFeature<LoggingFeature.Portable> {
      * </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 class LoggingFeature extends DelegatingFeature<LoggingFeature.Portable> {
             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);
diff --git a/rt/features/logging/src/main/java/org/apache/cxf/ext/logging/MaskSensitiveHelper.java b/rt/features/logging/src/main/java/org/apache/cxf/ext/logging/MaskSensitiveHelper.java
index 811a541254..062a0e4d4b 100644
--- a/rt/features/logging/src/main/java/org/apache/cxf/ext/logging/MaskSensitiveHelper.java
+++ b/rt/features/logging/src/main/java/org/apache/cxf/ext/logging/MaskSensitiveHelper.java
@@ -50,6 +50,12 @@ public class MaskSensitiveHelper {
     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);
diff --git a/rt/features/logging/src/main/java/org/apache/cxf/ext/logging/osgi/Activator.java b/rt/features/logging/src/main/java/org/apache/cxf/ext/logging/osgi/Activator.java
index 5845180add..6084bd7978 100644
--- a/rt/features/logging/src/main/java/org/apache/cxf/ext/logging/osgi/Activator.java
+++ b/rt/features/logging/src/main/java/org/apache/cxf/ext/logging/osgi/Activator.java
@@ -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.osgi.service.cm.ManagedService;
 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 class Activator implements BundleActivator {
             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 class Activator implements BundleActivator {
             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 class Activator implements BundleActivator {
             }
         }
 
+        @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) {
diff --git a/rt/features/logging/src/test/java/org/apache/cxf/ext/logging/MaskSensitiveHelperTest.java b/rt/features/logging/src/test/java/org/apache/cxf/ext/logging/MaskSensitiveHelperTest.java
index 44ebede0c1..c6f41ccade 100644
--- a/rt/features/logging/src/test/java/org/apache/cxf/ext/logging/MaskSensitiveHelperTest.java
+++ b/rt/features/logging/src/test/java/org/apache/cxf/ext/logging/MaskSensitiveHelperTest.java
@@ -92,7 +92,7 @@ public class MaskSensitiveHelperTest {
     }
 
     @Test
-    public void shouldReplaceSensitiveDataIn() {
+    public void shouldReplaceSensitiveDataInWithAdd() {
         // Arrange
         final LoggingInInterceptor inInterceptor = new LoggingInInterceptor(logEventSender);
         inInterceptor.addSensitiveElementNames(SENSITIVE_ELEMENTS);
@@ -113,7 +113,28 @@ public class MaskSensitiveHelperTest {
     }
 
     @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 class MaskSensitiveHelperTest {
         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