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();