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

davsclaus pushed a commit to branch fix/CAMEL-24110
in repository https://gitbox.apache.org/repos/asf/camel.git

commit e6a2ad8b4c3147c1b45042b2bd2adf6fe42fa8fc
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Jul 16 12:07:10 2026 +0200

    CAMEL-24110: camel-xslt-saxon - fix saxonReaderProperties null-guard always 
true, DOMSource from URIResolver broken, unhardened SAXParser
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../component/xslt/saxon/XsltSaxonEndpoint.java    | 30 +++----
 .../saxon/XsltSaxonUriResolverDomSourceTest.java   | 92 ++++++++++++++++++++++
 2 files changed, 108 insertions(+), 14 deletions(-)

diff --git 
a/components/camel-xslt-saxon/src/main/java/org/apache/camel/component/xslt/saxon/XsltSaxonEndpoint.java
 
b/components/camel-xslt-saxon/src/main/java/org/apache/camel/component/xslt/saxon/XsltSaxonEndpoint.java
index 87b3fed7a42a..59157511c53d 100644
--- 
a/components/camel-xslt-saxon/src/main/java/org/apache/camel/component/xslt/saxon/XsltSaxonEndpoint.java
+++ 
b/components/camel-xslt-saxon/src/main/java/org/apache/camel/component/xslt/saxon/XsltSaxonEndpoint.java
@@ -24,6 +24,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import javax.xml.XMLConstants;
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.parsers.SAXParser;
 import javax.xml.parsers.SAXParserFactory;
@@ -282,9 +283,7 @@ public class XsltSaxonEndpoint extends XsltEndpoint {
         InputStream is = 
getCamelContext().getTypeConverter().mandatoryConvertTo(InputStream.class, 
exchange, template);
         XsltBuilder builder = createXsltBuilder();
         Source source = new StreamSource(is);
-        if (this.saxonReaderProperties != null) {
-            //for Saxon we need to create XMLReader for the coming source
-            //so that the features configuration can take effect
+        if (!this.saxonReaderProperties.isEmpty()) {
             source = createReaderForSource(source);
         }
         builder.setTransformerSource(source);
@@ -302,23 +301,27 @@ public class XsltSaxonEndpoint extends XsltEndpoint {
     protected void loadResource(String resourceUri, XsltBuilder xslt) throws 
TransformerException, IOException {
         LOG.trace("{} loading schema resource: {}", this, resourceUri);
         Source source = xslt.getUriResolver().resolve(resourceUri, null);
-        if (this.saxonReaderProperties != null) {
-            //for Saxon we need to create XMLReader for the coming source
-            //so that the features configuration can take effect
-            source = createReaderForSource(source);
-        }
         if (source == null) {
             throw new IOException("Cannot load schema resource " + 
resourceUri);
-        } else {
-            xslt.setTransformerSource(source);
         }
-        // now loaded so clear flag
+        if (!this.saxonReaderProperties.isEmpty()) {
+            source = createReaderForSource(source);
+        }
+        xslt.setTransformerSource(source);
         setCacheCleared(false);
     }
 
     private Source createReaderForSource(Source source) {
+        InputSource inputSource = SAXSource.sourceToInputSource(source);
+        if (inputSource == null) {
+            return source;
+        }
         try {
             SAXParserFactory factory = SAXParserFactory.newInstance();
+            factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+            
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl";, 
true);
+            
factory.setFeature("http://xml.org/sax/features/external-general-entities";, 
false);
+            
factory.setFeature("http://xml.org/sax/features/external-parameter-entities";, 
false);
             SAXParser saxParser = factory.newSAXParser();
             XMLReader xmlReader = saxParser.getXMLReader();
 
@@ -329,7 +332,7 @@ public class XsltSaxonEndpoint extends XsltEndpoint {
                     URI uri = new URI(key);
                     if (value != null
                             && (value.toString().equals("true") || 
(value.toString().equals("false")))) {
-                        xmlReader.setFeature(uri.toString(), 
Boolean.valueOf(value.toString()));
+                        xmlReader.setFeature(uri.toString(), 
Boolean.parseBoolean(value.toString()));
                     } else if (value != null) {
                         xmlReader.setProperty(uri.toString(), value);
                     }
@@ -337,11 +340,10 @@ public class XsltSaxonEndpoint extends XsltEndpoint {
                     LOG.debug("{} isn't a valid URI, so ignore it", key);
                 }
             }
-            InputSource inputSource = SAXSource.sourceToInputSource(source);
             return new SAXSource(xmlReader, inputSource);
         } catch (SAXException | ParserConfigurationException e) {
             LOG.info("Can't create XMLReader for source ", e);
-            return null;
+            return source;
         }
     }
 
diff --git 
a/components/camel-xslt-saxon/src/test/java/org/apache/camel/component/xslt/saxon/XsltSaxonUriResolverDomSourceTest.java
 
b/components/camel-xslt-saxon/src/test/java/org/apache/camel/component/xslt/saxon/XsltSaxonUriResolverDomSourceTest.java
new file mode 100644
index 000000000000..d147735b0025
--- /dev/null
+++ 
b/components/camel-xslt-saxon/src/test/java/org/apache/camel/component/xslt/saxon/XsltSaxonUriResolverDomSourceTest.java
@@ -0,0 +1,92 @@
+/*
+ * 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.xslt.saxon;
+
+import java.io.StringReader;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.Source;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.dom.DOMSource;
+
+import org.w3c.dom.Document;
+
+import org.xml.sax.InputSource;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.spi.Registry;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class XsltSaxonUriResolverDomSourceTest extends CamelTestSupport {
+
+    private static final String XSL = "<?xml version='1.0'?>"
+                                      + "<xsl:stylesheet 
xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='2.0'>"
+                                      + "  <xsl:output method='xml' 
indent='yes'/>"
+                                      + "  <xsl:template match='/'>"
+                                      + "    <transformed><xsl:copy-of 
select='*'/></transformed>"
+                                      + "  </xsl:template>"
+                                      + "</xsl:stylesheet>";
+
+    @Test
+    public void testUriResolverReturningDomSource() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedMessageCount(1);
+
+        template.sendBody("direct:start", "<hello>world</hello>");
+
+        MockEndpoint.assertIsSatisfied(context);
+
+        String xml = 
mock.getReceivedExchanges().get(0).getIn().getBody(String.class);
+        assertTrue(xml.contains("<transformed"), "Should contain transformed 
element");
+        assertTrue(xml.contains("<hello>world</hello>"), "Should contain 
original content");
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:start")
+                        .to("xslt-saxon:dummy.xsl?uriResolver=#domResolver")
+                        .to("mock:result");
+            }
+        };
+    }
+
+    @Override
+    protected void bindToRegistry(Registry registry) throws Exception {
+        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+        dbf.setNamespaceAware(true);
+        DocumentBuilder db = dbf.newDocumentBuilder();
+        Document xslDoc = db.parse(new InputSource(new StringReader(XSL)));
+
+        URIResolver domResolver = new URIResolver() {
+            @Override
+            public Source resolve(String href, String base) throws 
TransformerException {
+                return new DOMSource(xslDoc);
+            }
+        };
+
+        registry.bind("domResolver", domResolver);
+    }
+}

Reply via email to