This is an automated email from the ASF dual-hosted git repository.
davsclaus 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 209c67a851d3 CAMEL-24605: align FopProducer XML transformation with
Camel's standard secure XML processing configuration
209c67a851d3 is described below
commit 209c67a851d3c145583d25829b7ffac0c500674b
Author: Andrea Cosentino <[email protected]>
AuthorDate: Mon Sep 7 15:45:09 2026 +0200
CAMEL-24605: align FopProducer XML transformation with Camel's standard
secure XML processing configuration
FopProducer was creating a TransformerFactory with only
FEATURE_SECURE_PROCESSING
enabled. This change also sets ACCESS_EXTERNAL_DTD and
ACCESS_EXTERNAL_STYLESHEET
to empty strings, matching the secure XML processing pattern used in
XmlConverter
and elsewhere in the codebase, blocking external DTD and stylesheet access.
A new FopExternalEntityTest verifies the restriction is enforced: it uses a
real,
readable DTD in a @TempDir so the transformation would succeed if the DTD
were
fetched — failure proves the access was blocked. A second test renders the
same
document without a DOCTYPE to rule out false positives. Test is JDK-version
independent (no assertion on JDK error message text).
Closes #26108
Co-Authored-By: Claude Opus 5 <[email protected]>
---
.../apache/camel/component/fop/FopProducer.java | 11 ++++
.../camel/component/fop/FopExternalEntityTest.java | 70 ++++++++++++++++++++++
2 files changed, 81 insertions(+)
diff --git
a/components/camel-fop/src/main/java/org/apache/camel/component/fop/FopProducer.java
b/components/camel-fop/src/main/java/org/apache/camel/component/fop/FopProducer.java
index 89c8f5808425..4e340648c773 100644
---
a/components/camel-fop/src/main/java/org/apache/camel/component/fop/FopProducer.java
+++
b/components/camel-fop/src/main/java/org/apache/camel/component/fop/FopProducer.java
@@ -92,6 +92,17 @@ public class FopProducer extends DefaultProducer {
Fop fop = fopFactory.newFop(outputFormat, userAgent, out);
TransformerFactory transformerFactory =
TransformerFactory.newInstance();
transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING,
Boolean.TRUE);
+ // align with Camel's standard secure XML processing: do not allow
access to external DTD/stylesheet
+ try {
+ transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD,
"");
+ } catch (Exception e) {
+ // ignore if the factory does not support the attribute
+ }
+ try {
+
transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
+ } catch (Exception e) {
+ // ignore if the factory does not support the attribute
+ }
Transformer transformer = transformerFactory.newTransformer();
Result res = new SAXResult(fop.getDefaultHandler());
diff --git
a/components/camel-fop/src/test/java/org/apache/camel/component/fop/FopExternalEntityTest.java
b/components/camel-fop/src/test/java/org/apache/camel/component/fop/FopExternalEntityTest.java
new file mode 100644
index 000000000000..787666aa4ab3
--- /dev/null
+++
b/components/camel-fop/src/test/java/org/apache/camel/component/fop/FopExternalEntityTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.camel.component.fop;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * Verifies that the FOP producer configures its {@code TransformerFactory} to
not resolve external DTDs/stylesheets,
+ * consistent with Camel's standard secure XML processing configuration.
+ */
+public class FopExternalEntityTest extends CamelTestSupport {
+
+ @Test
+ public void externalDtdIsNotResolved(@TempDir Path tempDir) throws
IOException {
+ // the referenced DTD exists and is perfectly readable, so the
transformation would succeed if the
+ // producer resolved it. The failure below therefore proves the
external DTD was never fetched, without
+ // depending on the wording of the JDK error message (which differs
across JDK releases)
+ Path dtd = tempDir.resolve("external.dtd");
+ Files.writeString(dtd, "<!ELEMENT fo:root ANY>\n");
+
+ String body = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ + "<!DOCTYPE fo:root SYSTEM \"" + dtd.toUri() + "\">\n"
+ + FopHelper.decorateTextWithXSLFO("Hello");
+
+ assertThrows(CamelExecutionException.class, () ->
template.sendBody("direct:start", body));
+ }
+
+ @Test
+ public void documentWithoutExternalDtdIsRendered() {
+ // guards the test above from passing for the wrong reason: the very
same document renders fine as long
+ // as it does not point at an external DTD
+ assertDoesNotThrow(() -> template.sendBody("direct:start",
FopHelper.decorateTextWithXSLFO("Hello")));
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ public void configure() {
+ from("direct:start")
+ .to("fop:pdf")
+ .to("mock:result");
+ }
+ };
+ }
+}