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 48273f53b93d CAMEL-24108: camel-xslt-saxon - apply secureProcessing 
unconditionally (#24777)
48273f53b93d is described below

commit 48273f53b93d303a183f175d859bab312ef6adfe
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Jul 16 15:39:03 2026 +0200

    CAMEL-24108: camel-xslt-saxon - apply secureProcessing unconditionally 
(#24777)
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
---
 .../component/xslt/saxon/XsltSaxonEndpoint.java    | 38 +++++++----
 .../component/xslt/saxon/XsltSaxonHelper.java      |  9 ++-
 .../saxon/XsltSaxonConfigurationStrategyTest.java  | 64 +++++++++++++++++++
 .../xslt/saxon/XsltSaxonSecureProcessingTest.java  | 74 ++++++++++++++++++++++
 .../apache/camel/component/xslt/XsltEndpoint.java  | 14 ++--
 .../ROOT/pages/camel-4x-upgrade-guide-4_22.adoc    | 19 ++++++
 6 files changed, 196 insertions(+), 22 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..4b2e0cd44cd3 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;
@@ -45,6 +46,7 @@ import org.apache.camel.Component;
 import org.apache.camel.Exchange;
 import org.apache.camel.api.management.ManagedAttribute;
 import org.apache.camel.api.management.ManagedResource;
+import org.apache.camel.component.xslt.TransformerFactoryConfigurationStrategy;
 import org.apache.camel.component.xslt.XsltBuilder;
 import org.apache.camel.component.xslt.XsltEndpoint;
 import org.apache.camel.spi.ClassResolver;
@@ -225,28 +227,40 @@ public class XsltSaxonEndpoint extends XsltEndpoint {
         TransformerFactory factory = getTransformerFactory();
         if (factory == null) {
             if (getTransformerFactoryClass() == null) {
-                // create new saxon factory
                 factory = new TransformerFactoryImpl();
             } else {
-                // provide the class loader of this component to work in OSGi 
environments
                 Class<TransformerFactory> factoryClass = 
resolver.resolveMandatoryClass(getTransformerFactoryClass(),
                         TransformerFactory.class, 
XsltSaxonComponent.class.getClassLoader());
                 LOG.debug("Using TransformerFactoryClass {}", factoryClass);
                 factory = injector.newInstance(factoryClass);
             }
-        }
 
-        if (factory instanceof TransformerFactoryImpl) {
-            TransformerFactoryImpl tf = (TransformerFactoryImpl) factory;
-            XsltSaxonHelper.registerSaxonConfiguration(tf, saxonConfiguration);
-            XsltSaxonHelper.registerSaxonConfigurationProperties(tf, 
saxonConfigurationProperties);
-            XsltSaxonHelper.registerSaxonExtensionFunctions(tf, 
saxonExtensionFunctions, secureProcessing);
-        }
+            if (factory instanceof TransformerFactoryImpl tf) {
+                XsltSaxonHelper.configureSecureProcessing(tf, 
secureProcessing);
+                XsltSaxonHelper.registerSaxonConfiguration(tf, 
saxonConfiguration);
+                XsltSaxonHelper.registerSaxonConfigurationProperties(tf, 
saxonConfigurationProperties);
+                XsltSaxonHelper.registerSaxonExtensionFunctions(tf, 
saxonExtensionFunctions);
+            }
+
+            try {
+                factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
+            } catch (IllegalArgumentException e) {
+                LOG.debug("TransformerFactory does not support {}", 
XMLConstants.ACCESS_EXTERNAL_DTD);
+            }
+            try {
+                factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, 
"");
+            } catch (IllegalArgumentException e) {
+                LOG.debug("TransformerFactory does not support {}", 
XMLConstants.ACCESS_EXTERNAL_STYLESHEET);
+            }
 
-        if (factory != null) {
-            LOG.debug("Using TransformerFactory {}", factory);
-            xslt.setTransformerFactory(factory);
+            final TransformerFactoryConfigurationStrategy strategy = 
getTransformerFactoryConfigurationStrategy();
+            if (strategy != null) {
+                strategy.configure(factory, this);
+            }
         }
+
+        LOG.debug("Using TransformerFactory {}", factory);
+        xslt.setTransformerFactory(factory);
         if (getResultHandlerFactory() != null) {
             xslt.setResultHandlerFactory(getResultHandlerFactory());
         }
diff --git 
a/components/camel-xslt-saxon/src/main/java/org/apache/camel/component/xslt/saxon/XsltSaxonHelper.java
 
b/components/camel-xslt-saxon/src/main/java/org/apache/camel/component/xslt/saxon/XsltSaxonHelper.java
index 0a6f3be451f9..40e9ca881bba 100644
--- 
a/components/camel-xslt-saxon/src/main/java/org/apache/camel/component/xslt/saxon/XsltSaxonHelper.java
+++ 
b/components/camel-xslt-saxon/src/main/java/org/apache/camel/component/xslt/saxon/XsltSaxonHelper.java
@@ -50,13 +50,16 @@ final class XsltSaxonHelper {
         }
     }
 
+    public static void configureSecureProcessing(TransformerFactoryImpl 
factory, boolean secureProcessing)
+            throws Exception {
+        factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, 
secureProcessing);
+    }
+
     public static void registerSaxonExtensionFunctions(
             TransformerFactoryImpl factory,
-            List<Object> saxonExtensionFunctions,
-            boolean secureProcessing)
+            List<Object> saxonExtensionFunctions)
             throws Exception {
         if (saxonExtensionFunctions != null && 
!saxonExtensionFunctions.isEmpty()) {
-            factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, 
secureProcessing);
             for (Object extensionFunction : saxonExtensionFunctions) {
                 if (extensionFunction instanceof ExtensionFunctionDefinition) {
                     LOG.debug("Saxon.registerExtensionFunction {}", 
extensionFunction);
diff --git 
a/components/camel-xslt-saxon/src/test/java/org/apache/camel/component/xslt/saxon/XsltSaxonConfigurationStrategyTest.java
 
b/components/camel-xslt-saxon/src/test/java/org/apache/camel/component/xslt/saxon/XsltSaxonConfigurationStrategyTest.java
new file mode 100644
index 000000000000..4a14f6a70361
--- /dev/null
+++ 
b/components/camel-xslt-saxon/src/test/java/org/apache/camel/component/xslt/saxon/XsltSaxonConfigurationStrategyTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.util.concurrent.atomic.AtomicBoolean;
+
+import javax.xml.transform.TransformerFactory;
+
+import org.apache.camel.BindToRegistry;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.xslt.TransformerFactoryConfigurationStrategy;
+import org.apache.camel.component.xslt.XsltEndpoint;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class XsltSaxonConfigurationStrategyTest extends CamelTestSupport {
+
+    private final AtomicBoolean strategyCalled = new AtomicBoolean();
+
+    @BindToRegistry("myStrategy")
+    private final TransformerFactoryConfigurationStrategy strategy = new 
TransformerFactoryConfigurationStrategy() {
+        @Override
+        public void configure(TransformerFactory factory, XsltEndpoint 
endpoint) {
+            strategyCalled.set(true);
+        }
+    };
+
+    @Test
+    public void testConfigurationStrategyIsInvoked() throws Exception {
+        getMockEndpoint("mock:result").expectedMessageCount(1);
+        template.sendBody("direct:start", 
"<mail><subject>Hey</subject><body>Hello world!</body></mail>");
+        getMockEndpoint("mock:result").assertIsSatisfied();
+
+        assertTrue(strategyCalled.get(), 
"TransformerFactoryConfigurationStrategy should have been invoked");
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:start")
+                        
.to("xslt-saxon:xslt/transform.xsl?transformerFactoryConfigurationStrategy=#myStrategy")
+                        .to("mock:result");
+            }
+        };
+    }
+}
diff --git 
a/components/camel-xslt-saxon/src/test/java/org/apache/camel/component/xslt/saxon/XsltSaxonSecureProcessingTest.java
 
b/components/camel-xslt-saxon/src/test/java/org/apache/camel/component/xslt/saxon/XsltSaxonSecureProcessingTest.java
new file mode 100644
index 000000000000..c23a2bd15484
--- /dev/null
+++ 
b/components/camel-xslt-saxon/src/test/java/org/apache/camel/component/xslt/saxon/XsltSaxonSecureProcessingTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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 javax.xml.XMLConstants;
+
+import net.sf.saxon.TransformerFactoryImpl;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class XsltSaxonSecureProcessingTest extends CamelTestSupport {
+
+    @Test
+    public void testSecureProcessingEnabledByDefault() throws Exception {
+        XsltSaxonEndpoint endpoint
+                = context.getEndpoint("xslt-saxon:xslt/transform.xsl", 
XsltSaxonEndpoint.class);
+        assertTrue(endpoint.isSecureProcessing());
+
+        TransformerFactoryImpl factory = new TransformerFactoryImpl();
+        XsltSaxonHelper.configureSecureProcessing(factory, true);
+        assertTrue(factory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING));
+    }
+
+    @Test
+    public void testSecureProcessingCanBeDisabled() throws Exception {
+        XsltSaxonEndpoint endpoint
+                = 
context.getEndpoint("xslt-saxon:xslt/transform.xsl?secureProcessing=false", 
XsltSaxonEndpoint.class);
+        assertFalse(endpoint.isSecureProcessing());
+
+        TransformerFactoryImpl factory = new TransformerFactoryImpl();
+        XsltSaxonHelper.configureSecureProcessing(factory, false);
+        
assertFalse(factory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING));
+    }
+
+    @Test
+    public void testTransformWithSecureProcessing() throws Exception {
+        getMockEndpoint("mock:result").expectedMessageCount(1);
+        template.sendBody("direct:default", 
"<mail><subject>Hey</subject><body>Hello world!</body></mail>");
+        getMockEndpoint("mock:result").assertIsSatisfied();
+
+        String xml = 
getMockEndpoint("mock:result").getReceivedExchanges().get(0).getIn().getBody(String.class);
+        assertTrue(xml.contains("transformed"));
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:default")
+                        .to("xslt-saxon:xslt/transform.xsl")
+                        .to("mock:result");
+            }
+        };
+    }
+}
diff --git 
a/components/camel-xslt/src/main/java/org/apache/camel/component/xslt/XsltEndpoint.java
 
b/components/camel-xslt/src/main/java/org/apache/camel/component/xslt/XsltEndpoint.java
index 9e6500882af1..d074b26085a2 100644
--- 
a/components/camel-xslt/src/main/java/org/apache/camel/component/xslt/XsltEndpoint.java
+++ 
b/components/camel-xslt/src/main/java/org/apache/camel/component/xslt/XsltEndpoint.java
@@ -451,17 +451,17 @@ public class XsltEndpoint extends ProcessorEndpoint {
                         TransformerFactory.class, 
XsltComponent.class.getClassLoader());
                 LOG.debug("Using TransformerFactoryClass {}", factoryClass);
                 factory = injector.newInstance(factoryClass);
-
-                final TransformerFactoryConfigurationStrategy tfConfigStrategy 
= transformerFactoryConfigurationStrategy != null
-                        ? transformerFactoryConfigurationStrategy
-                        : ((XsltComponent) 
getComponent()).getTransformerFactoryConfigurationStrategy();
-                if (tfConfigStrategy != null) {
-                    tfConfigStrategy.configure(factory, this);
-                }
             }
         }
 
         if (factory != null) {
+            final TransformerFactoryConfigurationStrategy tfConfigStrategy = 
transformerFactoryConfigurationStrategy != null
+                    ? transformerFactoryConfigurationStrategy
+                    : ((XsltComponent) 
getComponent()).getTransformerFactoryConfigurationStrategy();
+            if (tfConfigStrategy != null) {
+                tfConfigStrategy.configure(factory, this);
+            }
+
             LOG.debug("Using TransformerFactory {}", factory);
             xslt.setTransformerFactory(factory);
         }
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc
index dde8b9d61593..86c29ff5905b 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc
@@ -525,3 +525,22 @@ Two behavior changes follow:
   not a per-poll cap; set it lower to reduce page sizes.
 * On startup the consumer tails events from the moment it starts, rather than 
first replaying the
   single most-recent historical event.
+
+=== camel-xslt-saxon - secure processing now applied unconditionally
+
+The `secureProcessing` option (default `true`) is now applied to the Saxon 
`TransformerFactory`
+unconditionally. Previously it was only set when `saxonExtensionFunctions` was 
configured,
+meaning the default configuration silently ran without 
`FEATURE_SECURE_PROCESSING`.
+
+Additionally, the Saxon factory now sets `ACCESS_EXTERNAL_DTD` and 
`ACCESS_EXTERNAL_STYLESHEET`
+to empty strings (matching the behavior of the plain `xslt` component), 
restricting
+stylesheet-driven external fetches.
+
+Users of Saxon Professional or Enterprise editions who rely on Java extension 
functions
+called from XSLT stylesheets must now explicitly set `secureProcessing=false` 
on the endpoint.
+
+=== camel-xslt / camel-xslt-saxon - transformerFactoryConfigurationStrategy 
now honored
+
+The `transformerFactoryConfigurationStrategy` option is now applied on all 
factory creation paths.
+Previously on `xslt-saxon` it was never invoked, and on plain `xslt` it was 
only invoked when
+`transformerFactoryClass` was explicitly set.

Reply via email to