This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 439a4e7f498e CAMEL-24716: fix serialization regression - resolve
algorithm names lazily at crypto call-sites (#26671)
439a4e7f498e is described below
commit 439a4e7f498e75ac4b499948cbdd30eb546cd4a0
Author: Guillaume Nodet <[email protected]>
AuthorDate: Mon Sep 21 13:24:16 2026 +0200
CAMEL-24716: fix serialization regression - resolve algorithm names lazily
at crypto call-sites (#26671)
CAMEL-24716: fix serialization regression - resolve algorithm names lazily
Resolving constant names (e.g. AES_256_GCM) to W3C URIs eagerly in
the four setters caused a serialization regression: the ModelWriter
compares getters against the constant-name defaults (e.g. "AES_256_GCM")
to decide whether to suppress the attribute in the marshalled XML.
After eager resolution, getters always returned W3C URIs, so the
equality check never matched and all four algorithm attributes were
written unconditionally, breaking round-trip serialization.
Fix: remove resolveAlgorithm() from the four setters so getters return
what was set. Add private resolvedXxx() helpers that apply
resolveAlgorithm() lazily and call those helpers at every actual crypto
call-site (marshal/unmarshal path).
This was caught during review of the camel-4.22.x backport of #26467.
---
.../xmlsecurity/XMLSecurityDataFormat.java | 100 +++++++++++++--------
.../xmlsecurity/XmlSecurityConstantNameTest.java | 30 +++----
2 files changed, 72 insertions(+), 58 deletions(-)
diff --git
a/components/camel-xmlsecurity/src/main/java/org/apache/camel/dataformat/xmlsecurity/XMLSecurityDataFormat.java
b/components/camel-xmlsecurity/src/main/java/org/apache/camel/dataformat/xmlsecurity/XMLSecurityDataFormat.java
index cfd735447c95..d49891116b3e 100644
---
a/components/camel-xmlsecurity/src/main/java/org/apache/camel/dataformat/xmlsecurity/XMLSecurityDataFormat.java
+++
b/components/camel-xmlsecurity/src/main/java/org/apache/camel/dataformat/xmlsecurity/XMLSecurityDataFormat.java
@@ -120,6 +120,26 @@ public class XMLSecurityDataFormat extends ServiceSupport
implements DataFormat,
return ALGORITHM_NAME_TO_URI.getOrDefault(nameOrUri, nameOrUri);
}
+ /** Returns the resolved (W3C URI) form of {@link #xmlCipherAlgorithm} for
use in crypto operations. */
+ private String resolvedXmlCipherAlgorithm() {
+ return resolveAlgorithm(xmlCipherAlgorithm);
+ }
+
+ /** Returns the resolved (W3C URI) form of {@link #keyCipherAlgorithm} for
use in crypto operations. */
+ private String resolvedKeyCipherAlgorithm() {
+ return resolveAlgorithm(keyCipherAlgorithm);
+ }
+
+ /** Returns the resolved (W3C URI) form of {@link #digestAlgorithm} for
use in crypto operations. */
+ private String resolvedDigestAlgorithm() {
+ return resolveAlgorithm(digestAlgorithm);
+ }
+
+ /** Returns the resolved (W3C URI) form of {@link #mgfAlgorithm} for use
in crypto operations. */
+ private String resolvedMgfAlgorithm() {
+ return resolveAlgorithm(mgfAlgorithm);
+ }
+
private String xmlCipherAlgorithm;
private String keyCipherAlgorithm;
@@ -334,8 +354,9 @@ public class XMLSecurityDataFormat extends ServiceSupport
implements DataFormat,
Document document =
exchange.getContext().getTypeConverter().convertTo(Document.class, exchange,
is);
if (null != keyCipherAlgorithm
- && (keyCipherAlgorithm.equals(XMLCipher.RSA_v1dot5) ||
keyCipherAlgorithm.equals(XMLCipher.RSA_OAEP)
- || keyCipherAlgorithm.equals(XMLCipher.RSA_OAEP_11))) {
+ && (resolvedKeyCipherAlgorithm().equals(XMLCipher.RSA_v1dot5)
+ ||
resolvedKeyCipherAlgorithm().equals(XMLCipher.RSA_OAEP)
+ ||
resolvedKeyCipherAlgorithm().equals(XMLCipher.RSA_OAEP_11))) {
encryptAsymmetric(exchange, document, stream);
} else if (null != recipientKeyAlias) {
encryptAsymmetric(exchange, document, stream);
@@ -381,9 +402,9 @@ public class XMLSecurityDataFormat extends ServiceSupport
implements DataFormat,
XMLCipher keyCipher;
if (null != this.getKeyCipherAlgorithm()) {
- keyCipher = XMLCipher.getInstance(this.getKeyCipherAlgorithm(),
null, digestAlgorithm);
+ keyCipher = XMLCipher.getInstance(resolvedKeyCipherAlgorithm(),
null, resolvedDigestAlgorithm());
} else {
- keyCipher = XMLCipher.getInstance(XMLCipher.RSA_OAEP, null,
digestAlgorithm);
+ keyCipher = XMLCipher.getInstance(XMLCipher.RSA_OAEP, null,
resolvedDigestAlgorithm());
}
keyCipher.init(XMLCipher.WRAP_MODE, keyEncryptionKey);
@@ -400,13 +421,13 @@ public class XMLSecurityDataFormat extends ServiceSupport
implements DataFormat,
private void encryptSymmetric(Exchange exchange, Document document,
OutputStream stream) throws Exception {
SecretKey keyEncryptionKey;
SecretKey dataEncryptionKey;
- if (xmlCipherAlgorithm.equals(XMLCipher.TRIPLEDES)) {
+ if (resolvedXmlCipherAlgorithm().equals(XMLCipher.TRIPLEDES)) {
keyEncryptionKey = generateKeyEncryptionKey("DESede");
dataEncryptionKey = generateDataEncryptionKey();
- } else if (xmlCipherAlgorithm.equals(XMLCipher.SEED_128)) {
+ } else if (resolvedXmlCipherAlgorithm().equals(XMLCipher.SEED_128)) {
keyEncryptionKey = generateKeyEncryptionKey("SEED");
dataEncryptionKey = generateDataEncryptionKey();
- } else if (xmlCipherAlgorithm.contains("camellia")) {
+ } else if (resolvedXmlCipherAlgorithm().contains("camellia")) {
keyEncryptionKey = generateKeyEncryptionKey("CAMELLIA");
dataEncryptionKey = generateDataEncryptionKey();
} else {
@@ -463,7 +484,7 @@ public class XMLSecurityDataFormat extends ServiceSupport
implements DataFormat,
Exchange exchange, Document document, OutputStream stream, Key
dataEncryptionKey,
XMLCipher keyCipher, Key keyEncryptionKey)
throws Exception {
- XMLCipher xmlCipher = XMLCipher.getInstance(xmlCipherAlgorithm);
+ XMLCipher xmlCipher =
XMLCipher.getInstance(resolvedXmlCipherAlgorithm());
xmlCipher.init(XMLCipher.ENCRYPT_MODE, dataEncryptionKey);
if (secureTag.equalsIgnoreCase("")) {
@@ -511,8 +532,9 @@ public class XMLSecurityDataFormat extends ServiceSupport
implements DataFormat,
}
if (null != keyCipherAlgorithm
- && (keyCipherAlgorithm.equals(XMLCipher.RSA_v1dot5) ||
keyCipherAlgorithm.equals(XMLCipher.RSA_OAEP)
- || keyCipherAlgorithm.equals(XMLCipher.RSA_OAEP_11))) {
+ && (resolvedKeyCipherAlgorithm().equals(XMLCipher.RSA_v1dot5)
+ ||
resolvedKeyCipherAlgorithm().equals(XMLCipher.RSA_OAEP)
+ ||
resolvedKeyCipherAlgorithm().equals(XMLCipher.RSA_OAEP_11))) {
return decodeWithAsymmetricKey(exchange, encodedDocument);
} else {
LOG.debug("No (known) asymmetric keyCipherAlgorithm specified.
Attempting to "
@@ -523,7 +545,7 @@ public class XMLSecurityDataFormat extends ServiceSupport
implements DataFormat,
private Object decodeWithSymmetricKey(Exchange exchange, Document
encodedDocument) throws Exception {
SecretKey keyEncryptionKey;
- if (xmlCipherAlgorithm.equals(XMLCipher.TRIPLEDES)) {
+ if (resolvedXmlCipherAlgorithm().equals(XMLCipher.TRIPLEDES)) {
keyEncryptionKey = generateKeyEncryptionKey("DESede");
} else {
keyEncryptionKey = generateKeyEncryptionKey("AES");
@@ -677,23 +699,23 @@ public class XMLSecurityDataFormat extends ServiceSupport
implements DataFormat,
private SecretKey generateDataEncryptionKey() throws Exception {
KeyGenerator keyGenerator = null;
- if (xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.TRIPLEDES)) {
+ if
(resolvedXmlCipherAlgorithm().equalsIgnoreCase(XMLCipher.TRIPLEDES)) {
keyGenerator = KeyGenerator.getInstance("DESede");
} else {
keyGenerator = KeyGenerator.getInstance("AES");
- if (xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_128)
- ||
xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_128_GCM)
- || xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.SEED_128)
- ||
xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.CAMELLIA_128)) {
+ if
(resolvedXmlCipherAlgorithm().equalsIgnoreCase(XMLCipher.AES_128)
+ ||
resolvedXmlCipherAlgorithm().equalsIgnoreCase(XMLCipher.AES_128_GCM)
+ ||
resolvedXmlCipherAlgorithm().equalsIgnoreCase(XMLCipher.SEED_128)
+ ||
resolvedXmlCipherAlgorithm().equalsIgnoreCase(XMLCipher.CAMELLIA_128)) {
keyGenerator.init(128);
- } else if (xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_192)
- ||
xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_192_GCM)
- ||
xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.CAMELLIA_192)) {
+ } else if
(resolvedXmlCipherAlgorithm().equalsIgnoreCase(XMLCipher.AES_192)
+ ||
resolvedXmlCipherAlgorithm().equalsIgnoreCase(XMLCipher.AES_192_GCM)
+ ||
resolvedXmlCipherAlgorithm().equalsIgnoreCase(XMLCipher.CAMELLIA_192)) {
keyGenerator.init(192);
- } else if (xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_256)
- ||
xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_256_GCM)
- ||
xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.CAMELLIA_256)) {
+ } else if
(resolvedXmlCipherAlgorithm().equalsIgnoreCase(XMLCipher.AES_256)
+ ||
resolvedXmlCipherAlgorithm().equalsIgnoreCase(XMLCipher.AES_256_GCM)
+ ||
resolvedXmlCipherAlgorithm().equalsIgnoreCase(XMLCipher.CAMELLIA_256)) {
keyGenerator.init(256);
}
}
@@ -706,7 +728,7 @@ public class XMLSecurityDataFormat extends ServiceSupport
implements DataFormat,
Key keyEncryptionKey)
throws XMLEncryptionException {
- EncryptedKey encryptedKey = keyCipher.encryptKey(document,
dataEncryptionkey, mgfAlgorithm, null);
+ EncryptedKey encryptedKey = keyCipher.encryptKey(document,
dataEncryptionkey, resolvedMgfAlgorithm(), null);
if (addKeyValueForEncryptedKey && keyEncryptionKey instanceof
PublicKey) {
KeyInfo keyInfo = new KeyInfo(document);
keyInfo.add((PublicKey) keyEncryptionKey);
@@ -721,24 +743,24 @@ public class XMLSecurityDataFormat extends ServiceSupport
implements DataFormat,
private String generateXmlCipherAlgorithmKeyWrap() {
String algorithmKeyWrap = null;
- if (xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.TRIPLEDES)) {
+ if
(resolvedXmlCipherAlgorithm().equalsIgnoreCase(XMLCipher.TRIPLEDES)) {
algorithmKeyWrap = XMLCipher.TRIPLEDES_KeyWrap;
- } else if (xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_128)
- || xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_128_GCM))
{
+ } else if
(resolvedXmlCipherAlgorithm().equalsIgnoreCase(XMLCipher.AES_128)
+ ||
resolvedXmlCipherAlgorithm().equalsIgnoreCase(XMLCipher.AES_128_GCM)) {
algorithmKeyWrap = XMLCipher.AES_128_KeyWrap;
- } else if (xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_192)
- || xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_192_GCM))
{
+ } else if
(resolvedXmlCipherAlgorithm().equalsIgnoreCase(XMLCipher.AES_192)
+ ||
resolvedXmlCipherAlgorithm().equalsIgnoreCase(XMLCipher.AES_192_GCM)) {
algorithmKeyWrap = XMLCipher.AES_192_KeyWrap;
- } else if (xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_256)
- || xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_256_GCM))
{
+ } else if
(resolvedXmlCipherAlgorithm().equalsIgnoreCase(XMLCipher.AES_256)
+ ||
resolvedXmlCipherAlgorithm().equalsIgnoreCase(XMLCipher.AES_256_GCM)) {
algorithmKeyWrap = XMLCipher.AES_256_KeyWrap;
- } else if (xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.SEED_128)) {
+ } else if
(resolvedXmlCipherAlgorithm().equalsIgnoreCase(XMLCipher.SEED_128)) {
algorithmKeyWrap = XMLCipher.SEED_128_KeyWrap;
- } else if
(xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.CAMELLIA_128)) {
+ } else if
(resolvedXmlCipherAlgorithm().equalsIgnoreCase(XMLCipher.CAMELLIA_128)) {
algorithmKeyWrap = XMLCipher.CAMELLIA_128_KeyWrap;
- } else if
(xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.CAMELLIA_192)) {
+ } else if
(resolvedXmlCipherAlgorithm().equalsIgnoreCase(XMLCipher.CAMELLIA_192)) {
algorithmKeyWrap = XMLCipher.CAMELLIA_192_KeyWrap;
- } else if
(xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.CAMELLIA_256)) {
+ } else if
(resolvedXmlCipherAlgorithm().equalsIgnoreCase(XMLCipher.CAMELLIA_256)) {
algorithmKeyWrap = XMLCipher.CAMELLIA_256_KeyWrap;
}
@@ -747,7 +769,7 @@ public class XMLSecurityDataFormat extends ServiceSupport
implements DataFormat,
// Check to see if the asymmetric key transport algorithm is allowed
private void checkEncryptionAlgorithm(Key keyEncryptionKey, Element
parentElement) throws Exception {
- if (XMLCipher.RSA_v1dot5.equals(keyCipherAlgorithm)
+ if (XMLCipher.RSA_v1dot5.equals(resolvedKeyCipherAlgorithm())
|| keyCipherAlgorithm == null
|| !(keyEncryptionKey instanceof PrivateKey)) {
// This only applies for Asymmetric Encryption
@@ -840,7 +862,7 @@ public class XMLSecurityDataFormat extends ServiceSupport
implements DataFormat,
}
public void setXmlCipherAlgorithm(String xmlCipherAlgorithm) {
- this.xmlCipherAlgorithm = resolveAlgorithm(xmlCipherAlgorithm);
+ this.xmlCipherAlgorithm = xmlCipherAlgorithm;
}
public String getKeyCipherAlgorithm() {
@@ -848,7 +870,7 @@ public class XMLSecurityDataFormat extends ServiceSupport
implements DataFormat,
}
public void setKeyCipherAlgorithm(String keyCipherAlgorithm) {
- this.keyCipherAlgorithm = resolveAlgorithm(keyCipherAlgorithm);
+ this.keyCipherAlgorithm = keyCipherAlgorithm;
}
public String getRecipientKeyAlias() {
@@ -908,7 +930,7 @@ public class XMLSecurityDataFormat extends ServiceSupport
implements DataFormat,
}
public void setDigestAlgorithm(String digestAlgorithm) {
- this.digestAlgorithm = resolveAlgorithm(digestAlgorithm);
+ this.digestAlgorithm = digestAlgorithm;
}
public String getMgfAlgorithm() {
@@ -916,7 +938,7 @@ public class XMLSecurityDataFormat extends ServiceSupport
implements DataFormat,
}
public void setMgfAlgorithm(String mgfAlgorithm) {
- this.mgfAlgorithm = resolveAlgorithm(mgfAlgorithm);
+ this.mgfAlgorithm = mgfAlgorithm;
}
public boolean isAddKeyValueForEncryptedKey() {
diff --git
a/components/camel-xmlsecurity/src/test/java/org/apache/camel/dataformat/xmlsecurity/XmlSecurityConstantNameTest.java
b/components/camel-xmlsecurity/src/test/java/org/apache/camel/dataformat/xmlsecurity/XmlSecurityConstantNameTest.java
index cfd842dd77a9..c5164a3d1c9b 100644
---
a/components/camel-xmlsecurity/src/test/java/org/apache/camel/dataformat/xmlsecurity/XmlSecurityConstantNameTest.java
+++
b/components/camel-xmlsecurity/src/test/java/org/apache/camel/dataformat/xmlsecurity/XmlSecurityConstantNameTest.java
@@ -106,15 +106,15 @@ class XmlSecurityConstantNameTest extends
CamelTestSupport {
df.setSecureTag("//cheesesites/italy/cheese");
// Use the constant name, not the URI
df.setXmlCipherAlgorithm("AES_256_GCM");
-
- // verify the setter resolved it to the URI
- assertEquals(XMLCipher.AES_256_GCM, df.getXmlCipherAlgorithm());
+ // The setter is a plain assignment; resolution from constant name to
W3C URI happens lazily at crypto
+ // call-sites via the private resolvedXxx() helpers. The
encrypt/decrypt at the end of
+ // this method is the real functional validation.
context.addRoutes(new RouteBuilder() {
public void configure() {
from("direct:start")
.marshal(df).to("mock:encrypted")
- .log("Body: + ${body}")
+ .log("Body: ${body}")
.unmarshal(df).to("mock:decrypted");
}
});
@@ -135,14 +135,13 @@ class XmlSecurityConstantNameTest extends
CamelTestSupport {
df.setSecureTagContents(true);
df.setSecureTag("//cheesesites/italy/cheese");
df.setXmlCipherAlgorithm("AES_128");
-
- assertEquals(XMLCipher.AES_128, df.getXmlCipherAlgorithm());
+ // Lazy resolution — getter returns the constant name; functional
validation is below.
context.addRoutes(new RouteBuilder() {
public void configure() {
from("direct:start")
.marshal(df).to("mock:encrypted")
- .log("Body: + ${body}")
+ .log("Body: ${body}")
.unmarshal(df).to("mock:decrypted");
}
});
@@ -160,9 +159,7 @@ class XmlSecurityConstantNameTest extends CamelTestSupport {
sendingDataFormat.setXmlCipherAlgorithm("AES_128"); // constant
name
sendingDataFormat.setKeyCipherAlgorithm("RSA_OAEP"); // constant
name
sendingDataFormat.setRecipientKeyAlias("recipient");
-
- assertEquals(XMLCipher.AES_128,
sendingDataFormat.getXmlCipherAlgorithm());
- assertEquals(XMLCipher.RSA_OAEP,
sendingDataFormat.getKeyCipherAlgorithm());
+ // Lazy resolution — getters return constant names; functional
validation is the encrypt/decrypt below.
KeyStoreParameters tsParameters = new KeyStoreParameters();
tsParameters.setPassword("password");
@@ -173,8 +170,7 @@ class XmlSecurityConstantNameTest extends CamelTestSupport {
receivingDataFormat.setKeyCipherAlgorithm("RSA_OAEP"); // constant
name
receivingDataFormat.setRecipientKeyAlias("recipient");
receivingDataFormat.setSecureTag("//cheesesites/italy/cheese");
-
- assertEquals(XMLCipher.RSA_OAEP,
receivingDataFormat.getKeyCipherAlgorithm());
+ // Lazy resolution — getter returns constant name; functional
validation is the encrypt/decrypt below.
KeyStoreParameters ksParameters = new KeyStoreParameters();
ksParameters.setPassword("password");
@@ -185,7 +181,7 @@ class XmlSecurityConstantNameTest extends CamelTestSupport {
public void configure() {
from("direct:start")
.marshal(sendingDataFormat).to("mock:encrypted")
- .log("Body: + ${body}")
+ .log("Body: ${body}")
.unmarshal(receivingDataFormat).to("mock:decrypted");
}
});
@@ -205,11 +201,7 @@ class XmlSecurityConstantNameTest extends CamelTestSupport
{
sendingDataFormat.setDigestAlgorithm("SHA256"); // constant
name
sendingDataFormat.setMgfAlgorithm("MGF1_SHA256"); // constant
name
sendingDataFormat.setRecipientKeyAlias("recipient");
-
- assertEquals(XMLCipher.AES_128,
sendingDataFormat.getXmlCipherAlgorithm());
- assertEquals(XMLCipher.RSA_OAEP_11,
sendingDataFormat.getKeyCipherAlgorithm());
- assertEquals(XMLCipher.SHA256, sendingDataFormat.getDigestAlgorithm());
- assertEquals(EncryptionConstants.MGF1_SHA256,
sendingDataFormat.getMgfAlgorithm());
+ // Lazy resolution — getters return constant names; functional
validation is the encrypt/decrypt below.
KeyStoreParameters tsParameters = new KeyStoreParameters();
tsParameters.setPassword("password");
@@ -232,7 +224,7 @@ class XmlSecurityConstantNameTest extends CamelTestSupport {
public void configure() {
from("direct:start")
.marshal(sendingDataFormat).to("mock:encrypted")
- .log("Body: + ${body}")
+ .log("Body: ${body}")
.unmarshal(receivingDataFormat).to("mock:decrypted");
}
});