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

oscerd pushed a commit to branch camel-4.18.x
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/camel-4.18.x by this push:
     new 89eefad0de2f [backport camel-4.18.x] CAMEL-24900: camel-jcr - apply 
header filtering when mapping node properties to Exchange headers (#27047)
89eefad0de2f is described below

commit 89eefad0de2f2966f19870d1fe8a360048fb227d
Author: Andrea Cosentino <[email protected]>
AuthorDate: Tue Sep 29 10:20:47 2026 +0200

    [backport camel-4.18.x] CAMEL-24900: camel-jcr - apply header filtering 
when mapping node properties to Exchange headers (#27047)
    
    Backport of #26748 to camel-4.18.x.
    
    On this release line DefaultHeaderFilterStrategy does not filter Camel/camel
    headers by default (that default arrived in CAMEL-23543, on 4.21.x and 
later),
    so the JCR endpoint configures the filter explicitly to keep the same 
behaviour.
    The upgrade-guide entry lives on main only and is not included here.
    
    Co-Authored-By: Claude Opus 4.8 <[email protected]>
    Signed-off-by: Andrea Cosentino <[email protected]>
---
 .../org/apache/camel/catalog/components/jcr.json   |  3 +-
 .../camel/component/jcr/JcrEndpointConfigurer.java |  6 ++
 .../camel/component/jcr/JcrEndpointUriFactory.java |  3 +-
 .../org/apache/camel/component/jcr/jcr.json        |  3 +-
 .../apache/camel/component/jcr/JcrEndpoint.java    | 31 ++++++-
 .../apache/camel/component/jcr/JcrProducer.java    | 16 +++-
 .../jcr/JcrGetNodeByIdHeaderInjectionTest.java     | 95 ++++++++++++++++++++++
 .../jcr/JcrInsertHeaderInjectionTest.java          | 78 ++++++++++++++++++
 .../endpoint/dsl/JcrEndpointBuilderFactory.java    | 32 ++++++++
 9 files changed, 262 insertions(+), 5 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/jcr.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/jcr.json
index 414945d6ebe1..82840b867452 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/jcr.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/jcr.json
@@ -50,6 +50,7 @@
     "bridgeErrorHandler": { "index": 12, "kind": "parameter", "displayName": 
"Bridge Error Handler", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Allows for bridging the consumer to the 
Camel routing Error Handler, which mean any exceptions (if possible) occurred 
while the Camel consumer is trying to pickup incoming [...]
     "exceptionHandler": { "index": 13, "kind": "parameter", "displayName": 
"Exception Handler", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "object", "javaType": 
"org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
let the consumer use a custom ExceptionHandler. Notice if the option 
bridgeErrorHandler is enabled then this option is not in use. By de [...]
     "exchangePattern": { "index": 14, "kind": "parameter", "displayName": 
"Exchange Pattern", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "enum", "javaType": 
"org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], 
"deprecated": false, "autowired": false, "secret": false, "description": "Sets 
the exchange pattern when the consumer creates an exchange." },
-    "lazyStartProducer": { "index": 15, "kind": "parameter", "displayName": 
"Lazy Start Producer", "group": "producer (advanced)", "label": 
"producer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Whether the producer should be started 
lazy (on the first message). By starting lazy you can use this to allow 
CamelContext and routes to startup in situations where a produ [...]
+    "lazyStartProducer": { "index": 15, "kind": "parameter", "displayName": 
"Lazy Start Producer", "group": "producer (advanced)", "label": 
"producer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Whether the producer should be started 
lazy (on the first message). By starting lazy you can use this to allow 
CamelContext and routes to startup in situations where a produ [...]
+    "headerFilterStrategy": { "index": 16, "kind": "parameter", "displayName": 
"Header Filter Strategy", "group": "filter", "label": "producer,filter", 
"required": false, "type": "object", "javaType": 
"org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": 
false, "secret": false, "description": "To use a custom 
org.apache.camel.spi.HeaderFilterStrategy to filter header to and from Camel 
message." }
   }
 }
diff --git 
a/components/camel-jcr/src/generated/java/org/apache/camel/component/jcr/JcrEndpointConfigurer.java
 
b/components/camel-jcr/src/generated/java/org/apache/camel/component/jcr/JcrEndpointConfigurer.java
index 3395318e319c..af12eb9156d3 100644
--- 
a/components/camel-jcr/src/generated/java/org/apache/camel/component/jcr/JcrEndpointConfigurer.java
+++ 
b/components/camel-jcr/src/generated/java/org/apache/camel/component/jcr/JcrEndpointConfigurer.java
@@ -32,6 +32,8 @@ public class JcrEndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "exceptionHandler": 
target.setExceptionHandler(property(camelContext, 
org.apache.camel.spi.ExceptionHandler.class, value)); return true;
         case "exchangepattern":
         case "exchangePattern": 
target.setExchangePattern(property(camelContext, 
org.apache.camel.ExchangePattern.class, value)); return true;
+        case "headerfilterstrategy":
+        case "headerFilterStrategy": 
target.setHeaderFilterStrategy(property(camelContext, 
org.apache.camel.spi.HeaderFilterStrategy.class, value)); return true;
         case "lazystartproducer":
         case "lazyStartProducer": 
target.setLazyStartProducer(property(camelContext, boolean.class, value)); 
return true;
         case "nolocal":
@@ -63,6 +65,8 @@ public class JcrEndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "exceptionHandler": return 
org.apache.camel.spi.ExceptionHandler.class;
         case "exchangepattern":
         case "exchangePattern": return org.apache.camel.ExchangePattern.class;
+        case "headerfilterstrategy":
+        case "headerFilterStrategy": return 
org.apache.camel.spi.HeaderFilterStrategy.class;
         case "lazystartproducer":
         case "lazyStartProducer": return boolean.class;
         case "nolocal":
@@ -95,6 +99,8 @@ public class JcrEndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "exceptionHandler": return target.getExceptionHandler();
         case "exchangepattern":
         case "exchangePattern": return target.getExchangePattern();
+        case "headerfilterstrategy":
+        case "headerFilterStrategy": return target.getHeaderFilterStrategy();
         case "lazystartproducer":
         case "lazyStartProducer": return target.isLazyStartProducer();
         case "nolocal":
diff --git 
a/components/camel-jcr/src/generated/java/org/apache/camel/component/jcr/JcrEndpointUriFactory.java
 
b/components/camel-jcr/src/generated/java/org/apache/camel/component/jcr/JcrEndpointUriFactory.java
index 5feb1880b01c..67c1f24223ee 100644
--- 
a/components/camel-jcr/src/generated/java/org/apache/camel/component/jcr/JcrEndpointUriFactory.java
+++ 
b/components/camel-jcr/src/generated/java/org/apache/camel/component/jcr/JcrEndpointUriFactory.java
@@ -23,13 +23,14 @@ public class JcrEndpointUriFactory extends 
org.apache.camel.support.component.En
     private static final Set<String> SECRET_PROPERTY_NAMES;
     private static final Map<String, String> MULTI_VALUE_PREFIXES;
     static {
-        Set<String> props = new HashSet<>(16);
+        Set<String> props = new HashSet<>(17);
         props.add("base");
         props.add("bridgeErrorHandler");
         props.add("deep");
         props.add("eventTypes");
         props.add("exceptionHandler");
         props.add("exchangePattern");
+        props.add("headerFilterStrategy");
         props.add("host");
         props.add("lazyStartProducer");
         props.add("noLocal");
diff --git 
a/components/camel-jcr/src/generated/resources/META-INF/org/apache/camel/component/jcr/jcr.json
 
b/components/camel-jcr/src/generated/resources/META-INF/org/apache/camel/component/jcr/jcr.json
index 414945d6ebe1..82840b867452 100644
--- 
a/components/camel-jcr/src/generated/resources/META-INF/org/apache/camel/component/jcr/jcr.json
+++ 
b/components/camel-jcr/src/generated/resources/META-INF/org/apache/camel/component/jcr/jcr.json
@@ -50,6 +50,7 @@
     "bridgeErrorHandler": { "index": 12, "kind": "parameter", "displayName": 
"Bridge Error Handler", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Allows for bridging the consumer to the 
Camel routing Error Handler, which mean any exceptions (if possible) occurred 
while the Camel consumer is trying to pickup incoming [...]
     "exceptionHandler": { "index": 13, "kind": "parameter", "displayName": 
"Exception Handler", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "object", "javaType": 
"org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
let the consumer use a custom ExceptionHandler. Notice if the option 
bridgeErrorHandler is enabled then this option is not in use. By de [...]
     "exchangePattern": { "index": 14, "kind": "parameter", "displayName": 
"Exchange Pattern", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "enum", "javaType": 
"org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], 
"deprecated": false, "autowired": false, "secret": false, "description": "Sets 
the exchange pattern when the consumer creates an exchange." },
-    "lazyStartProducer": { "index": 15, "kind": "parameter", "displayName": 
"Lazy Start Producer", "group": "producer (advanced)", "label": 
"producer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Whether the producer should be started 
lazy (on the first message). By starting lazy you can use this to allow 
CamelContext and routes to startup in situations where a produ [...]
+    "lazyStartProducer": { "index": 15, "kind": "parameter", "displayName": 
"Lazy Start Producer", "group": "producer (advanced)", "label": 
"producer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Whether the producer should be started 
lazy (on the first message). By starting lazy you can use this to allow 
CamelContext and routes to startup in situations where a produ [...]
+    "headerFilterStrategy": { "index": 16, "kind": "parameter", "displayName": 
"Header Filter Strategy", "group": "filter", "label": "producer,filter", 
"required": false, "type": "object", "javaType": 
"org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": 
false, "secret": false, "description": "To use a custom 
org.apache.camel.spi.HeaderFilterStrategy to filter header to and from Camel 
message." }
   }
 }
diff --git 
a/components/camel-jcr/src/main/java/org/apache/camel/component/jcr/JcrEndpoint.java
 
b/components/camel-jcr/src/main/java/org/apache/camel/component/jcr/JcrEndpoint.java
index 0a3b6727119c..f31d75075332 100644
--- 
a/components/camel-jcr/src/main/java/org/apache/camel/component/jcr/JcrEndpoint.java
+++ 
b/components/camel-jcr/src/main/java/org/apache/camel/component/jcr/JcrEndpoint.java
@@ -28,11 +28,14 @@ import org.apache.camel.Consumer;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
 import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.spi.HeaderFilterStrategy;
+import org.apache.camel.spi.HeaderFilterStrategyAware;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.spi.UriPath;
 import org.apache.camel.support.DefaultEndpoint;
+import org.apache.camel.support.DefaultHeaderFilterStrategy;
 import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.StringHelper;
 
@@ -42,7 +45,7 @@ import org.apache.camel.util.StringHelper;
 @UriEndpoint(firstVersion = "1.3.0", scheme = "jcr", title = "JCR", syntax = 
"jcr:host/base",
              alternativeSyntax = "jcr:username:password@host/base",
              category = { Category.DATABASE, Category.CMS }, headersClass = 
JcrConstants.class)
-public class JcrEndpoint extends DefaultEndpoint {
+public class JcrEndpoint extends DefaultEndpoint implements 
HeaderFilterStrategyAware {
 
     private Credentials credentials;
     private Repository repository;
@@ -72,6 +75,9 @@ public class JcrEndpoint extends DefaultEndpoint {
     private long sessionLiveCheckInterval = 60000L;
     @UriParam
     private String workspaceName;
+    @UriParam(label = "producer,filter",
+              description = "To use a custom 
org.apache.camel.spi.HeaderFilterStrategy to filter header to and from Camel 
message.")
+    private HeaderFilterStrategy headerFilterStrategy = 
createDefaultHeaderFilterStrategy();
 
     protected JcrEndpoint(String endpointUri, JcrComponent component) {
         super(endpointUri, component);
@@ -292,6 +298,29 @@ public class JcrEndpoint extends DefaultEndpoint {
         this.workspaceName = workspaceName;
     }
 
+    @Override
+    public HeaderFilterStrategy getHeaderFilterStrategy() {
+        return headerFilterStrategy;
+    }
+
+    /**
+     * To use a custom {@link org.apache.camel.spi.HeaderFilterStrategy} to 
filter header to and from Camel message.
+     */
+    @Override
+    public void setHeaderFilterStrategy(HeaderFilterStrategy 
headerFilterStrategy) {
+        this.headerFilterStrategy = headerFilterStrategy;
+    }
+
+    private static HeaderFilterStrategy createDefaultHeaderFilterStrategy() {
+        // Filter Camel internal headers (starting with Camel/camel) 
case-insensitively in both directions. On this
+        // release line DefaultHeaderFilterStrategy does not apply that filter 
by default, so it is configured
+        // explicitly here to keep the behaviour consistent with newer 
releases.
+        DefaultHeaderFilterStrategy strategy = new 
DefaultHeaderFilterStrategy();
+        
strategy.setInFilterStartsWith(DefaultHeaderFilterStrategy.CAMEL_FILTER_STARTS_WITH);
+        
strategy.setOutFilterStartsWith(DefaultHeaderFilterStrategy.CAMEL_FILTER_STARTS_WITH);
+        return strategy;
+    }
+
     /**
      * Gets the destination name which was configured from the endpoint uri.
      *
diff --git 
a/components/camel-jcr/src/main/java/org/apache/camel/component/jcr/JcrProducer.java
 
b/components/camel-jcr/src/main/java/org/apache/camel/component/jcr/JcrProducer.java
index c7f3c5aa86b8..1ead9b840321 100644
--- 
a/components/camel-jcr/src/main/java/org/apache/camel/component/jcr/JcrProducer.java
+++ 
b/components/camel-jcr/src/main/java/org/apache/camel/component/jcr/JcrProducer.java
@@ -34,6 +34,7 @@ import org.apache.camel.Exchange;
 import org.apache.camel.Message;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.TypeConverter;
+import org.apache.camel.spi.HeaderFilterStrategy;
 import org.apache.camel.support.DefaultProducer;
 import org.apache.camel.util.ObjectHelper;
 import org.apache.jackrabbit.util.Text;
@@ -49,6 +50,7 @@ public class JcrProducer extends DefaultProducer {
         TypeConverter converter = exchange.getContext().getTypeConverter();
         Session session = openSession();
         Message message = exchange.getIn();
+        HeaderFilterStrategy headerFilterStrategy = 
getJcrEndpoint().getHeaderFilterStrategy();
         String operation = determineOperation(message);
         try {
             if (JcrConstants.JCR_INSERT.equals(operation)) {
@@ -57,6 +59,10 @@ public class JcrProducer extends DefaultProducer {
                 Map<String, Object> headers = 
filterComponentHeaders(message.getHeaders());
                 for (String key : headers.keySet()) {
                     Object header = message.getHeader(key);
+                    if (headerFilterStrategy != null
+                            && 
headerFilterStrategy.applyFilterToCamelHeaders(key, header, exchange)) {
+                        continue;
+                    }
                     if (header != null && 
Object[].class.isAssignableFrom(header.getClass())) {
                         Value[] value = converter.convertTo(Value[].class, 
exchange, header);
                         node.setProperty(key, value);
@@ -81,7 +87,11 @@ public class JcrProducer extends DefaultProducer {
                     } else {
                         value = converter.convertTo(aClass, exchange, 
property.getValue());
                     }
-                    message.setHeader(property.getName(), value);
+                    String name = property.getName();
+                    if (headerFilterStrategy == null
+                            || 
!headerFilterStrategy.applyFilterToExternalHeaders(name, value, exchange)) {
+                        message.setHeader(name, value);
+                    }
                 }
             } else {
                 throw new RuntimeCamelException("Unsupported operation: " + 
operation);
@@ -93,6 +103,10 @@ public class JcrProducer extends DefaultProducer {
         }
     }
 
+    // Strips the JCR control keys (operation, node name, node type) 
unconditionally, independent of the configured
+    // HeaderFilterStrategy. The default strategy already filters these (they 
are Camel-prefixed), but a custom
+    // strategy that does not filter Camel* headers must still never persist 
these operational headers as node
+    // properties, so this filtering is kept as a separate, unconditional 
guard.
     private Map<String, Object> filterComponentHeaders(Map<String, Object> 
properties) {
         Map<String, Object> result = new HashMap<>(properties.size());
         for (Map.Entry<String, Object> entry : properties.entrySet()) {
diff --git 
a/components/camel-jcr/src/test/java/org/apache/camel/component/jcr/JcrGetNodeByIdHeaderInjectionTest.java
 
b/components/camel-jcr/src/test/java/org/apache/camel/component/jcr/JcrGetNodeByIdHeaderInjectionTest.java
new file mode 100644
index 000000000000..e5802ae60984
--- /dev/null
+++ 
b/components/camel-jcr/src/test/java/org/apache/camel/component/jcr/JcrGetNodeByIdHeaderInjectionTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.jcr;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+/**
+ * The JCR producer's {@code CamelJcrGetById} operation maps the properties of 
the retrieved node into Exchange headers.
+ * A content author must not be able to use a property named after a Camel 
internal header (in any casing) to inject
+ * that header, as those steer downstream processing (HTTP target URI, bean 
method dispatch, file names, and so on).
+ * Ordinary document properties must still be mapped.
+ */
+public class JcrGetNodeByIdHeaderInjectionTest extends JcrRouteTestSupport {
+
+    private static final String CONTENT = "content is here";
+
+    private static final String[] CAMEL_HEADER_VARIANTS = {
+            "CamelHttpUri", "camelHttpUri", "caMELHttpUri", "CAMELHTTPURI" };
+
+    @EndpointInject("mock:result")
+    private MockEndpoint result;
+
+    private String identifier;
+
+    @Override
+    public void doPreSetup() throws RepositoryException {
+        Session session = openSession();
+        Node node = 
session.getRootNode().addNode("injectionRoot").addNode("test");
+        node.setProperty("my.contents.property", CONTENT);
+        for (String variant : CAMEL_HEADER_VARIANTS) {
+            node.setProperty(variant, "malicious");
+        }
+        identifier = node.getIdentifier();
+
+        session.save();
+        session.logout();
+    }
+
+    @Test
+    public void camelHeadersInNodePropertiesAreFilteredRegardlessOfCase() 
throws Exception {
+        result.expectedMessageCount(1);
+
+        Exchange exchange = createExchangeWithBody(identifier);
+        template.send("direct:a", exchange);
+        MockEndpoint.assertIsSatisfied(context);
+
+        Message in = result.getReceivedExchanges().get(0).getIn();
+        for (String variant : CAMEL_HEADER_VARIANTS) {
+            // the Camel header map is case-insensitive, so this lookup also 
catches the other spellings
+            assertNull(in.getHeader(variant),
+                    "a Camel internal header must not be injectable through a 
JCR node property: " + variant);
+        }
+        assertEquals(CONTENT, in.getHeader("my.contents.property", 
String.class),
+                "an ordinary document property must still be mapped to a 
header");
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:a")
+                        .setHeader(JcrConstants.JCR_OPERATION, 
constant(JcrConstants.JCR_GET_BY_ID))
+                        .to("jcr://user:pass@repository")
+                        .to("mock:result");
+            }
+        };
+    }
+}
diff --git 
a/components/camel-jcr/src/test/java/org/apache/camel/component/jcr/JcrInsertHeaderInjectionTest.java
 
b/components/camel-jcr/src/test/java/org/apache/camel/component/jcr/JcrInsertHeaderInjectionTest.java
new file mode 100644
index 000000000000..628a5c124688
--- /dev/null
+++ 
b/components/camel-jcr/src/test/java/org/apache/camel/component/jcr/JcrInsertHeaderInjectionTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.jcr;
+
+import javax.jcr.Node;
+import javax.jcr.Session;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * The JCR producer's insert operation persists message headers as node 
properties. A Camel internal header carried on
+ * the message (in any casing) must not be persisted as a node property, as 
those are operational headers rather than
+ * document content; ordinary headers must still be stored.
+ */
+public class JcrInsertHeaderInjectionTest extends JcrRouteTestSupport {
+
+    private static final String CONTENT = "content is here";
+
+    private static final String[] CAMEL_HEADER_VARIANTS = {
+            "CamelHttpUri", "camelHttpUri", "caMELHttpUri", "CAMELHTTPURI" };
+
+    @Test
+    public void camelHeadersAreNotPersistedAsNodeProperties() throws Exception 
{
+        Exchange exchange = createExchangeWithBody("");
+        exchange.getIn().setHeader(JcrConstants.JCR_NODE_NAME, "node");
+        exchange.getIn().setHeader("my.contents.property", CONTENT);
+        for (String variant : CAMEL_HEADER_VARIANTS) {
+            exchange.getIn().setHeader(variant, "malicious");
+        }
+
+        Exchange out = template.send("direct:a", exchange);
+        String identifier = out.getMessage().getBody(String.class);
+
+        Session session = openSession();
+        try {
+            Node node = session.getNodeByIdentifier(identifier);
+            assertTrue(node.hasProperty("my.contents.property"),
+                    "an ordinary header must still be stored as a node 
property");
+            assertEquals(CONTENT, 
node.getProperty("my.contents.property").getString());
+            for (String variant : CAMEL_HEADER_VARIANTS) {
+                assertFalse(node.hasProperty(variant),
+                        "a Camel internal header must not be persisted as a 
node property: " + variant);
+            }
+        } finally {
+            session.logout();
+        }
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:a").to("jcr://user:pass@repository/home/test");
+            }
+        };
+    }
+}
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/JcrEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/JcrEndpointBuilderFactory.java
index 8852e458e848..4bba6bd7ac32 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/JcrEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/JcrEndpointBuilderFactory.java
@@ -657,6 +657,38 @@ public interface JcrEndpointBuilderFactory {
             doSetProperty("workspaceName", workspaceName);
             return this;
         }
+        /**
+         * To use a custom org.apache.camel.spi.HeaderFilterStrategy to filter
+         * header to and from Camel message.
+         * 
+         * The option is a:
+         * <code>org.apache.camel.spi.HeaderFilterStrategy</code> type.
+         * 
+         * Group: filter
+         * 
+         * @param headerFilterStrategy the value to set
+         * @return the dsl builder
+         */
+        default JcrEndpointProducerBuilder 
headerFilterStrategy(org.apache.camel.spi.HeaderFilterStrategy 
headerFilterStrategy) {
+            doSetProperty("headerFilterStrategy", headerFilterStrategy);
+            return this;
+        }
+        /**
+         * To use a custom org.apache.camel.spi.HeaderFilterStrategy to filter
+         * header to and from Camel message.
+         * 
+         * The option will be converted to a
+         * <code>org.apache.camel.spi.HeaderFilterStrategy</code> type.
+         * 
+         * Group: filter
+         * 
+         * @param headerFilterStrategy the value to set
+         * @return the dsl builder
+         */
+        default JcrEndpointProducerBuilder headerFilterStrategy(String 
headerFilterStrategy) {
+            doSetProperty("headerFilterStrategy", headerFilterStrategy);
+            return this;
+        }
     }
 
     /**

Reply via email to