This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch backport/26108-to-camel-4.22.x in repository https://gitbox.apache.org/repos/asf/camel.git
commit 4c66e52b41b3a79f037b9a385322068ff3c59dc4 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"); + } + }; + } +}
