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

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


The following commit(s) were added to refs/heads/main by this push:
     new e1718c5cd1 [CXF-9164]Logging Feature - Sensitive attributes (not 
elements) are n… (#2829)
e1718c5cd1 is described below

commit e1718c5cd1446c2d22a5d343bb4d25d3985de55b
Author: Freeman(Yue) Fang <[email protected]>
AuthorDate: Mon Jan 19 15:40:07 2026 -0500

    [CXF-9164]Logging Feature - Sensitive attributes (not elements) are n… 
(#2829)
    
    * [CXF-9164]Logging Feature - Sensitive attributes (not elements) are not 
masked
    
    * [CXF-9164]address review feedback
---
 .../ext/logging/AbstractLoggingInterceptor.java    |   8 ++
 .../cxf/ext/logging/AttributeMaskingHelper.java    | 116 ---------------------
 .../cxf/ext/logging/MaskSensitiveHelper.java       |  46 +++++++-
 .../logging/AttributeMaskSensitiveHelperTest.java  |  27 ++---
 4 files changed, 58 insertions(+), 139 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 67e27633d3..4f7c7c015a 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
@@ -94,6 +94,14 @@ public abstract class AbstractLoggingInterceptor extends 
AbstractPhaseIntercepto
     public void addSensitiveElementNames(final Set<String> 
sensitiveElementNames) {
         maskSensitiveHelper.addSensitiveElementNames(sensitiveElementNames);
     }
+    
+    public void setSensitiveAttributeNames(final Set<String> 
sensitiveAttributeNames) {
+        
maskSensitiveHelper.setSensitiveAttributeNames(sensitiveAttributeNames);
+    }
+    
+    public void addSensitiveAttributeNames(final Set<String> 
sensitiveAttributeNames) {
+        
maskSensitiveHelper.addSensitiveAttributeNames(sensitiveAttributeNames);
+    }
 
     public void setSensitiveProtocolHeaderNames(final Set<String> 
protocolHeaderNames) {
         this.sensitiveProtocolHeaderNames.clear();
diff --git 
a/rt/features/logging/src/main/java/org/apache/cxf/ext/logging/AttributeMaskingHelper.java
 
b/rt/features/logging/src/main/java/org/apache/cxf/ext/logging/AttributeMaskingHelper.java
deleted file mode 100644
index 742659f9b8..0000000000
--- 
a/rt/features/logging/src/main/java/org/apache/cxf/ext/logging/AttributeMaskingHelper.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.cxf.ext.logging;
-
-import java.util.HashSet;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-import org.apache.cxf.message.Message;
-
-
-/**
- * Adds XML/HTML attribute value masking on top of the parent 
MaskSensitiveHelper.
- * 
- */
-public class AttributeMaskingHelper extends MaskSensitiveHelper {
-
-    private static final String ATTR_NAME_TEMPLATE = "-ATTR_NAME-";
-
-    // Re-declare namespace prefix class per Namespaces in XML (private in 
parent; reproduce here)
-    private static final String PATTERN_XML_NAMESPACE_PREFIX = 
"[\\w.\\-\\u00B7\\u00C0-\\u00D6\\u00D8-\\u00F6"
-            + 
"\\u00F8-\\u02FF\\u0300-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u203F-\\u2040\\u2070-\\u218F"
-            + "\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD]+";
-
-    // Case-sensitive attribute pattern; supports optional namespace prefix; 
preserves original quotes
-    // Groups: 1=full attr name (w/ optional prefix), 2=open quote, 3=value, 
4=close quote (backref to 2)
-    private static final String MATCH_PATTERN_XML_ATTR_TEMPLATE =
-            "(\\b(?:" + PATTERN_XML_NAMESPACE_PREFIX + ":)?" + 
ATTR_NAME_TEMPLATE + ")\\s*=\\s*(\"|')(.*?)(\\2)";
-    private static final String REPLACEMENT_XML_ATTR_TEMPLATE = "$1=$2XXX$4";
-
-    private static final String XML_CONTENT = "xml";
-    private static final String HTML_CONTENT = "html";
-
-    private static class ReplacementPair {
-        private final Pattern matchPattern;
-        private final String replacement;
-        ReplacementPair(String matchPattern, String replacement) {
-            
-            this.matchPattern = Pattern.compile(matchPattern, Pattern.DOTALL);
-            this.replacement = replacement;
-        }
-    }
-
-    private final Set<ReplacementPair> replacementsXMLAttributes = new 
HashSet<>();
-
-    /** Adds attribute names to be masked in XML/HTML logs (values replaced 
with "XXX"). */
-    public void addSensitiveAttributeNames(final Set<String> 
inSensitiveAttirbuteNames) {
-        if (inSensitiveAttirbuteNames == null || 
inSensitiveAttirbuteNames.isEmpty()) {
-            return;
-        }
-        for (final String attr : inSensitiveAttirbuteNames) {
-            final String match = 
MATCH_PATTERN_XML_ATTR_TEMPLATE.replace(ATTR_NAME_TEMPLATE, 
Pattern.quote(attr));
-            final String repl  = 
REPLACEMENT_XML_ATTR_TEMPLATE.replace(ATTR_NAME_TEMPLATE, 
escapeForReplacement(attr));
-            replacementsXMLAttributes.add(new ReplacementPair(match, repl));
-        }
-    }
-
-    /** Optional convenience resetter if you want it. */
-    public void setSensitiveAttributeNames(final Set<String> 
inSensitiveAttributeNames) {
-        replacementsXMLAttributes.clear();
-        addSensitiveAttributeNames(inSensitiveAttributeNames);
-    }
-
-    @Override
-    public String maskSensitiveElements(final Message message, final String 
originalLogString) {
-        // First, do all base-class masking (elements/JSON/headers)
-        String masked = super.maskSensitiveElements(message, 
originalLogString);
-        if (masked == null || message == null) {
-            return masked;
-        }
-        final String contentType = (String) message.get(Message.CONTENT_TYPE);
-        if (contentType == null) {
-            return masked;
-        }
-        final String lower = contentType.toLowerCase();
-        if (lower.contains(XML_CONTENT) || lower.contains(HTML_CONTENT)) {
-            // Then apply attribute-value masking
-            return applyMasks(masked, replacementsXMLAttributes);
-        }
-        return masked;
-    }
-
-    // --- helpers (local copy; parent versions are private) ---
-
-    private static String escapeForReplacement(String s) {
-        if (s == null || s.isEmpty()) {
-            return s;
-        }
-        return s.replace("\\", "\\\\").replace("$", "\\$");
-    }
-
-    private String applyMasks(String input, Set<ReplacementPair> pairs) {
-        String out = input;
-        for (final ReplacementPair rp : pairs) {
-            out = rp.matchPattern.matcher(out).replaceAll(rp.replacement);
-        }
-        return out;
-    }
-}
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 0795038c62..f253c7b972 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
@@ -26,6 +26,7 @@ import java.util.regex.Pattern;
 import org.apache.cxf.message.Message;
 
 public class MaskSensitiveHelper {
+    private static final String ATTR_NAME_TEMPLATE = "-ATTR_NAME-";
     private static final String ELEMENT_NAME_TEMPLATE = "-ELEMENT_NAME-";
     // see https://www.w3.org/TR/REC-xml-names/#NT-NCName for allowed chars in 
namespace prefix
     private static final String PATTERN_XML_NAMESPACE_PREFIX = 
"[\\w.\\-\\u00B7\\u00C0-\\u00D6\\u00D8-\\u00F6"
@@ -42,6 +43,12 @@ public class MaskSensitiveHelper {
     private static final String MATCH_PATTERN_JSON_TEMPLATE = 
"\"-ELEMENT_NAME-\"[ \\t]*:[ \\t]*\"(.*?)\"";
     private static final String REPLACEMENT_JSON_TEMPLATE = 
"\"-ELEMENT_NAME-\": \"XXX\"";
     private static final String MASKED_HEADER_VALUE = "XXX";
+    
+    // Case-sensitive attribute pattern; supports optional namespace prefix; 
preserves original quotes
+    // Groups: 1=full attr name (w/ optional prefix), 2=open quote, 3=value, 
4=close quote (backref to 2)
+    private static final String MATCH_PATTERN_XML_ATTR_TEMPLATE =
+            "(\\b(?:" + PATTERN_XML_NAMESPACE_PREFIX + ":)?" + 
ATTR_NAME_TEMPLATE + ")\\s*=\\s*(\"|')(.*?)(\\2)";
+    private static final String REPLACEMENT_XML_ATTR_TEMPLATE = "$1=$2XXX$4";
 
     private static final String XML_CONTENT = "xml";
     private static final String HTML_CONTENT = "html";
@@ -57,11 +64,12 @@ public class MaskSensitiveHelper {
         }
     }
 
-    private final Set<ReplacementPair> replacementsXML = new HashSet<>();
+    private final Set<ReplacementPair> replacementsXMLElements = new 
HashSet<>();
     private final Set<ReplacementPair> replacementsJSON = new HashSet<>();
+    private final Set<ReplacementPair> replacementsXMLAttributes = new 
HashSet<>();
 
     public void setSensitiveElementNames(final Set<String> 
inSensitiveElementNames) {
-        replacementsXML.clear();
+        replacementsXMLElements.clear();
         replacementsJSON.clear();
         addSensitiveElementNames(inSensitiveElementNames);
     }
@@ -69,13 +77,31 @@ public class MaskSensitiveHelper {
     public void addSensitiveElementNames(final Set<String> 
inSensitiveElementNames) {
         for (final String sensitiveName : inSensitiveElementNames) {
             addReplacementPair(MATCH_PATTERN_XML_TEMPLATE, 
REPLACEMENT_XML_TEMPLATE,
-                sensitiveName, replacementsXML);
+                sensitiveName, replacementsXMLElements);
             addReplacementPair(MATCH_PATTERN_JSON_TEMPLATE_ARRAY, 
REPLACEMENT_JSON_TEMPLATE_ARRAY,
                 sensitiveName, replacementsJSON);
             addReplacementPair(MATCH_PATTERN_JSON_TEMPLATE, 
REPLACEMENT_JSON_TEMPLATE,
                 sensitiveName, replacementsJSON);
         }
     }
+    
+    /** Adds attribute names to be masked in XML/HTML logs (values replaced 
with "XXX"). */
+    public void addSensitiveAttributeNames(final Set<String> 
inSensitiveAttirbuteNames) {
+        if (inSensitiveAttirbuteNames == null || 
inSensitiveAttirbuteNames.isEmpty()) {
+            return;
+        }
+        for (final String attr : inSensitiveAttirbuteNames) {
+            final String match = 
MATCH_PATTERN_XML_ATTR_TEMPLATE.replace(ATTR_NAME_TEMPLATE, 
Pattern.quote(attr));
+            final String repl  = 
REPLACEMENT_XML_ATTR_TEMPLATE.replace(ATTR_NAME_TEMPLATE, 
escapeForReplacement(attr));
+            replacementsXMLAttributes.add(new ReplacementPair(match, repl));
+        }
+    }
+
+    /** Optional convenience resetter if you want it. */
+    public void setSensitiveAttributeNames(final Set<String> 
inSensitiveAttributeNames) {
+        replacementsXMLAttributes.clear();
+        addSensitiveAttributeNames(inSensitiveAttributeNames);
+    }
 
     private void addReplacementPair(final String matchPatternTemplate,
                                     final String replacementTemplate,
@@ -89,7 +115,8 @@ public class MaskSensitiveHelper {
     public String maskSensitiveElements(
             final Message message,
             final String originalLogString) {
-        if (replacementsXML.isEmpty() && replacementsJSON.isEmpty()
+        if (replacementsXMLElements.isEmpty() && replacementsJSON.isEmpty()
+            && replacementsXMLAttributes.isEmpty()
                 || originalLogString == null || message == null) {
             return originalLogString;
         }
@@ -100,7 +127,9 @@ public class MaskSensitiveHelper {
         final String lowerCaseContentType = contentType.toLowerCase();
         if (lowerCaseContentType.contains(XML_CONTENT)
                 || lowerCaseContentType.contains(HTML_CONTENT)) {
-            return applyMasks(originalLogString, replacementsXML);
+            String replacedElement = applyMasks(originalLogString, 
replacementsXMLElements);
+            return replacedElement == null ? replacedElement 
+                : applyMasks(replacedElement, replacementsXMLAttributes);
         } else if (lowerCaseContentType.contains(JSON_CONTENT)) {
             return applyMasks(originalLogString, replacementsJSON);
         }
@@ -123,4 +152,11 @@ public class MaskSensitiveHelper {
         }
         return resultString;
     }
+    
+    private static String escapeForReplacement(String s) {
+        if (s == null || s.isEmpty()) {
+            return s;
+        }
+        return s.replace("\\", "\\\\").replace("$", "\\$");
+    }
 }
diff --git 
a/rt/features/logging/src/test/java/org/apache/cxf/ext/logging/AttributeMaskSensitiveHelperTest.java
 
b/rt/features/logging/src/test/java/org/apache/cxf/ext/logging/AttributeMaskSensitiveHelperTest.java
index 1ff7db1242..925cc9b515 100644
--- 
a/rt/features/logging/src/test/java/org/apache/cxf/ext/logging/AttributeMaskSensitiveHelperTest.java
+++ 
b/rt/features/logging/src/test/java/org/apache/cxf/ext/logging/AttributeMaskSensitiveHelperTest.java
@@ -122,11 +122,9 @@ public class AttributeMaskSensitiveHelperTest {
     public void shouldReplaceSensitiveDataInWithAdd() {
         // Arrange
         final LoggingInInterceptor inInterceptor = new 
LoggingInInterceptor(logEventSender);
-        AttributeMaskingHelper attrMaskHelper = new AttributeMaskingHelper();
-        attrMaskHelper.setSensitiveAttributeNames(SENSITIVE_ATTRIBUTES);
-        attrMaskHelper.setSensitiveElementNames(SENSITIVE_ELEMENTS);
-        inInterceptor.setSensitiveDataHelper(attrMaskHelper);
-
+        inInterceptor.setSensitiveAttributeNames(SENSITIVE_ATTRIBUTES);
+        inInterceptor.setSensitiveElementNames(SENSITIVE_ELEMENTS);
+        
         final Message message = prepareInMessage();
 
         // Act
@@ -146,11 +144,8 @@ public class AttributeMaskSensitiveHelperTest {
     public void shouldReplaceSensitiveDataInWithSet() {
         // Arrange
         final LoggingInInterceptor inInterceptor = new 
LoggingInInterceptor(logEventSender);
-        
-        AttributeMaskingHelper attrMaskHelper = new AttributeMaskingHelper();
-        attrMaskHelper.setSensitiveAttributeNames(SENSITIVE_ATTRIBUTES);
-        attrMaskHelper.setSensitiveElementNames(SENSITIVE_ELEMENTS);
-        inInterceptor.setSensitiveDataHelper(attrMaskHelper);
+        inInterceptor.setSensitiveAttributeNames(SENSITIVE_ATTRIBUTES);
+        inInterceptor.setSensitiveElementNames(SENSITIVE_ELEMENTS);
         final Message message = prepareInMessage();
 
         // Act
@@ -170,10 +165,8 @@ public class AttributeMaskSensitiveHelperTest {
     public void shouldReplaceSensitiveDataOutWithAdd() throws IOException {
         // Arrange
         final LoggingOutInterceptor outInterceptor = new 
LoggingOutInterceptor(logEventSender);
-        AttributeMaskingHelper attrMaskHelper = new AttributeMaskingHelper();
-        attrMaskHelper.setSensitiveAttributeNames(SENSITIVE_ATTRIBUTES);
-        attrMaskHelper.setSensitiveElementNames(SENSITIVE_ELEMENTS);
-        outInterceptor.setSensitiveDataHelper(attrMaskHelper);
+        outInterceptor.setSensitiveAttributeNames(SENSITIVE_ATTRIBUTES);
+        outInterceptor.setSensitiveElementNames(SENSITIVE_ELEMENTS);
 
         final Message message = prepareOutMessage();
 
@@ -194,10 +187,8 @@ public class AttributeMaskSensitiveHelperTest {
     public void shouldReplaceSensitiveDataOutWithSet() throws IOException {
         // Arrange
         final LoggingOutInterceptor outInterceptor = new 
LoggingOutInterceptor(logEventSender);
-        AttributeMaskingHelper attrMaskHelper = new AttributeMaskingHelper();
-        attrMaskHelper.setSensitiveAttributeNames(SENSITIVE_ATTRIBUTES);
-        attrMaskHelper.setSensitiveElementNames(SENSITIVE_ELEMENTS);
-        outInterceptor.setSensitiveDataHelper(attrMaskHelper);
+        outInterceptor.setSensitiveAttributeNames(SENSITIVE_ATTRIBUTES);
+        outInterceptor.setSensitiveElementNames(SENSITIVE_ELEMENTS);
 
         final Message message = prepareOutMessage();
 

Reply via email to