This is an automated email from the ASF dual-hosted git repository.
oscerd 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 8db602a5ee10 CAMEL-24421: camel-spring-redis - apply a deserialization
filter to the default JDK serializer (#25587)
8db602a5ee10 is described below
commit 8db602a5ee105403fa40c1b821157c8d9d0c1977
Author: Andrea Cosentino <[email protected]>
AuthorDate: Mon Aug 24 16:58:56 2026 +0200
CAMEL-24421: camel-spring-redis - apply a deserialization filter to the
default JDK serializer (#25587)
RedisConfiguration.createDefaultSerializer() built a bare
JdkSerializationRedisSerializer, whose read path runs through Spring's
ConfigurableObjectInputStream with no ObjectInputFilter installed. Every
other
component in the codebase that performs JDK deserialization -- camel-consul,
camel-leveldb, camel-mina, camel-netty, camel-netty-http, camel-vertx-http,
camel-jms, camel-sjms, camel-http-common, camel-cassandraql -- resolves a
filter
first, so camel-spring-redis was the one path left without one.
The default serializer now installs a filter resolved through
DeserializationFilterHelper: the new deserializationFilter option when set,
otherwise the JVM-wide jdk.serialFilter, otherwise the shared Camel
allow-list.
JdkSerializationRedisSerializer exposes no hook for a filter, so the
serializer
is built through its Converter-based constructor with a deserializing
converter
that sets one on the stream. Serialization is left untouched, and class
resolution is unchanged: the same null class loader Spring's
DefaultDeserializer
uses by default is passed through.
This covers the three places that share the default serializer -- the
consumer,
which deserializes the payload of every message published to the subscribed
channels; the producer read commands, through the default RedisTemplate; and
SpringRedisIdempotentRepository, which builds that same template. Note that
setting a custom redisTemplate does not reach the consumer, which reads
getSerializer() directly, so the option covers both paths.
Setting the serializer option to a custom RedisSerializer bypasses the
filter,
since Camel then no longer controls how the payload is read.
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
---
.../camel/catalog/components/spring-redis.json | 3 +-
.../camel-spring-parent/camel-spring-redis/pom.xml | 5 ++
.../component/redis/RedisEndpointConfigurer.java | 6 ++
.../component/redis/RedisEndpointUriFactory.java | 3 +-
.../apache/camel/component/redis/spring-redis.json | 3 +-
.../component/redis/FilteringDeserializer.java | 55 +++++++++++++
.../camel/component/redis/RedisConfiguration.java | 27 ++++++-
...edisConfigurationDeserializationFilterTest.java | 91 ++++++++++++++++++++++
.../ROOT/pages/camel-4x-upgrade-guide-4_23.adoc | 22 ++++++
.../endpoint/dsl/RedisEndpointBuilderFactory.java | 60 ++++++++++++++
10 files changed, 271 insertions(+), 4 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spring-redis.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spring-redis.json
index 07ccac575006..08c149fde23b 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spring-redis.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spring-redis.json
@@ -72,6 +72,7 @@
"exceptionHandler": { "index": 8, "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 def [...]
"exchangePattern": { "index": 9, "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." },
"listenerContainer": { "index": 10, "kind": "parameter", "displayName":
"Listener Container", "group": "consumer (advanced)", "label":
"consumer,advanced", "required": false, "type": "object", "javaType":
"org.springframework.data.redis.listener.RedisMessageListenerContainer",
"deprecated": false, "autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.redis.RedisConfiguration", "configurationField":
"configuration", "description": "Reference to a pre-c [...]
- "lazyStartProducer": { "index": 11, "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": 11, "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 [...]
+ "deserializationFilter": { "index": 12, "kind": "parameter",
"displayName": "Deserialization Filter", "group": "security", "label":
"advanced,security", "required": false, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"configurationClass": "org.apache.camel.component.redis.RedisConfiguration",
"configurationField": "configuration", "description": "Sets an
ObjectInputFilter pattern (jdk.serialFilter syntax) applied when the [...]
}
}
diff --git a/components/camel-spring-parent/camel-spring-redis/pom.xml
b/components/camel-spring-parent/camel-spring-redis/pom.xml
index baa76769faef..19bb14169e8b 100644
--- a/components/camel-spring-parent/camel-spring-redis/pom.xml
+++ b/components/camel-spring-parent/camel-spring-redis/pom.xml
@@ -62,6 +62,11 @@
<version>${mockito-version}</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.assertj</groupId>
+ <artifactId>assertj-core</artifactId>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
diff --git
a/components/camel-spring-parent/camel-spring-redis/src/generated/java/org/apache/camel/component/redis/RedisEndpointConfigurer.java
b/components/camel-spring-parent/camel-spring-redis/src/generated/java/org/apache/camel/component/redis/RedisEndpointConfigurer.java
index 6cfe69080332..de09d38e33a4 100644
---
a/components/camel-spring-parent/camel-spring-redis/src/generated/java/org/apache/camel/component/redis/RedisEndpointConfigurer.java
+++
b/components/camel-spring-parent/camel-spring-redis/src/generated/java/org/apache/camel/component/redis/RedisEndpointConfigurer.java
@@ -29,6 +29,8 @@ public class RedisEndpointConfigurer extends
PropertyConfigurerSupport implement
case "command":
target.getConfiguration().setCommand(property(camelContext,
org.apache.camel.component.redis.Command.class, value)); return true;
case "connectionfactory":
case "connectionFactory":
target.getConfiguration().setConnectionFactory(property(camelContext,
org.springframework.data.redis.connection.RedisConnectionFactory.class,
value)); return true;
+ case "deserializationfilter":
+ case "deserializationFilter":
target.getConfiguration().setDeserializationFilter(property(camelContext,
java.lang.String.class, value)); return true;
case "exceptionhandler":
case "exceptionHandler":
target.setExceptionHandler(property(camelContext,
org.apache.camel.spi.ExceptionHandler.class, value)); return true;
case "exchangepattern":
@@ -53,6 +55,8 @@ public class RedisEndpointConfigurer extends
PropertyConfigurerSupport implement
case "command": return org.apache.camel.component.redis.Command.class;
case "connectionfactory":
case "connectionFactory": return
org.springframework.data.redis.connection.RedisConnectionFactory.class;
+ case "deserializationfilter":
+ case "deserializationFilter": return java.lang.String.class;
case "exceptionhandler":
case "exceptionHandler": return
org.apache.camel.spi.ExceptionHandler.class;
case "exchangepattern":
@@ -78,6 +82,8 @@ public class RedisEndpointConfigurer extends
PropertyConfigurerSupport implement
case "command": return target.getConfiguration().getCommand();
case "connectionfactory":
case "connectionFactory": return
target.getConfiguration().getConnectionFactory();
+ case "deserializationfilter":
+ case "deserializationFilter": return
target.getConfiguration().getDeserializationFilter();
case "exceptionhandler":
case "exceptionHandler": return target.getExceptionHandler();
case "exchangepattern":
diff --git
a/components/camel-spring-parent/camel-spring-redis/src/generated/java/org/apache/camel/component/redis/RedisEndpointUriFactory.java
b/components/camel-spring-parent/camel-spring-redis/src/generated/java/org/apache/camel/component/redis/RedisEndpointUriFactory.java
index 8766549b4286..fb3b42176e45 100644
---
a/components/camel-spring-parent/camel-spring-redis/src/generated/java/org/apache/camel/component/redis/RedisEndpointUriFactory.java
+++
b/components/camel-spring-parent/camel-spring-redis/src/generated/java/org/apache/camel/component/redis/RedisEndpointUriFactory.java
@@ -24,11 +24,12 @@ public class RedisEndpointUriFactory extends
org.apache.camel.support.component.
private static final Set<String> ENDPOINT_IDENTITY_PROPERTY_NAMES;
private static final Map<String, String> MULTI_VALUE_PREFIXES;
static {
- Set<String> props = new HashSet<>(12);
+ Set<String> props = new HashSet<>(13);
props.add("bridgeErrorHandler");
props.add("channels");
props.add("command");
props.add("connectionFactory");
+ props.add("deserializationFilter");
props.add("exceptionHandler");
props.add("exchangePattern");
props.add("host");
diff --git
a/components/camel-spring-parent/camel-spring-redis/src/generated/resources/META-INF/org/apache/camel/component/redis/spring-redis.json
b/components/camel-spring-parent/camel-spring-redis/src/generated/resources/META-INF/org/apache/camel/component/redis/spring-redis.json
index 07ccac575006..08c149fde23b 100644
---
a/components/camel-spring-parent/camel-spring-redis/src/generated/resources/META-INF/org/apache/camel/component/redis/spring-redis.json
+++
b/components/camel-spring-parent/camel-spring-redis/src/generated/resources/META-INF/org/apache/camel/component/redis/spring-redis.json
@@ -72,6 +72,7 @@
"exceptionHandler": { "index": 8, "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 def [...]
"exchangePattern": { "index": 9, "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." },
"listenerContainer": { "index": 10, "kind": "parameter", "displayName":
"Listener Container", "group": "consumer (advanced)", "label":
"consumer,advanced", "required": false, "type": "object", "javaType":
"org.springframework.data.redis.listener.RedisMessageListenerContainer",
"deprecated": false, "autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.redis.RedisConfiguration", "configurationField":
"configuration", "description": "Reference to a pre-c [...]
- "lazyStartProducer": { "index": 11, "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": 11, "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 [...]
+ "deserializationFilter": { "index": 12, "kind": "parameter",
"displayName": "Deserialization Filter", "group": "security", "label":
"advanced,security", "required": false, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"configurationClass": "org.apache.camel.component.redis.RedisConfiguration",
"configurationField": "configuration", "description": "Sets an
ObjectInputFilter pattern (jdk.serialFilter syntax) applied when the [...]
}
}
diff --git
a/components/camel-spring-parent/camel-spring-redis/src/main/java/org/apache/camel/component/redis/FilteringDeserializer.java
b/components/camel-spring-parent/camel-spring-redis/src/main/java/org/apache/camel/component/redis/FilteringDeserializer.java
new file mode 100644
index 000000000000..d621937f42cd
--- /dev/null
+++
b/components/camel-spring-parent/camel-spring-redis/src/main/java/org/apache/camel/component/redis/FilteringDeserializer.java
@@ -0,0 +1,55 @@
+/*
+ * 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.redis;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputFilter;
+import java.io.ObjectInputStream;
+
+import org.apache.camel.support.DeserializationFilterHelper;
+import org.springframework.core.ConfigurableObjectInputStream;
+import org.springframework.core.serializer.Deserializer;
+
+/**
+ * A Spring {@link Deserializer} that installs an {@link ObjectInputFilter} on
the stream before the object graph is
+ * read.
+ * <p/>
+ * Spring's own {@code DefaultDeserializer} reads through a {@link
ConfigurableObjectInputStream} without any filter, so
+ * the default {@code JdkSerializationRedisSerializer} would otherwise
materialise arbitrary types. This deserializer is
+ * behaviourally identical apart from the filter, and in particular resolves
classes the same way by passing the same
+ * {@code null} class loader that {@code DefaultDeserializer} uses by default.
+ */
+class FilteringDeserializer implements Deserializer<Object> {
+
+ private final String deserializationFilter;
+
+ FilteringDeserializer(String deserializationFilter) {
+ this.deserializationFilter = deserializationFilter;
+ }
+
+ @Override
+ public Object deserialize(InputStream inputStream) throws IOException {
+ ObjectInputStream ois = new ConfigurableObjectInputStream(inputStream,
null);
+
ois.setObjectInputFilter(DeserializationFilterHelper.resolveDeserializationFilter(deserializationFilter));
+ try {
+ return ois.readObject();
+ } catch (ClassNotFoundException e) {
+ throw new IOException("Failed to deserialize object type", e);
+ }
+ }
+}
diff --git
a/components/camel-spring-parent/camel-spring-redis/src/main/java/org/apache/camel/component/redis/RedisConfiguration.java
b/components/camel-spring-parent/camel-spring-redis/src/main/java/org/apache/camel/component/redis/RedisConfiguration.java
index cfb72db8b32d..3c58b2ac5874 100644
---
a/components/camel-spring-parent/camel-spring-redis/src/main/java/org/apache/camel/component/redis/RedisConfiguration.java
+++
b/components/camel-spring-parent/camel-spring-redis/src/main/java/org/apache/camel/component/redis/RedisConfiguration.java
@@ -20,6 +20,8 @@ import org.apache.camel.spi.Metadata;
import org.apache.camel.spi.UriParam;
import org.apache.camel.spi.UriParams;
import org.apache.camel.spi.UriPath;
+import org.springframework.core.serializer.support.DeserializingConverter;
+import org.springframework.core.serializer.support.SerializingConverter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
@@ -50,6 +52,13 @@ public class RedisConfiguration {
private RedisConnectionFactory connectionFactory;
@UriParam
private RedisSerializer<?> serializer;
+ @UriParam(label = "advanced,security",
+ description = "Sets an ObjectInputFilter pattern
(jdk.serialFilter syntax) applied when the default"
+ + " JDK serializer deserializes Redis payloads,
both on the consumer and on producer read"
+ + " commands. When not set, the JVM-wide
jdk.serialFilter is used if present; otherwise a"
+ + " conservative default filter denying java.net.*
and otherwise allowing java.*, javax.*"
+ + " and org.apache.camel.* packages is applied.
Ignored when a custom serializer is set.")
+ private String deserializationFilter;
public Command getCommand() {
return command;
@@ -141,6 +150,19 @@ public class RedisConfiguration {
this.serializer = serializer;
}
+ public String getDeserializationFilter() {
+ return deserializationFilter;
+ }
+
+ /**
+ * Sets an {@link java.io.ObjectInputFilter} pattern ({@code
jdk.serialFilter} syntax) applied when the default JDK
+ * serializer deserializes Redis payloads. When not set, the JVM-wide
{@code jdk.serialFilter} is used if present,
+ * otherwise a conservative default filter is applied. Ignored when a
custom serializer is set.
+ */
+ public void setDeserializationFilter(String deserializationFilter) {
+ this.deserializationFilter = deserializationFilter;
+ }
+
private RedisConnectionFactory createDefaultConnectionFactory() {
JedisConnectionFactory jedisConnectionFactory = new
JedisConnectionFactory();
managedConnectionFactory = true;
@@ -174,7 +196,10 @@ public class RedisConfiguration {
}
private RedisSerializer<?> createDefaultSerializer() {
- serializer = new JdkSerializationRedisSerializer();
+ // JdkSerializationRedisSerializer exposes no hook to install an
ObjectInputFilter, so supply a deserializing
+ // converter that sets one on the stream. Serialization is left
untouched.
+ serializer = new JdkSerializationRedisSerializer(
+ new SerializingConverter(), new DeserializingConverter(new
FilteringDeserializer(deserializationFilter)));
return serializer;
}
diff --git
a/components/camel-spring-parent/camel-spring-redis/src/test/java/org/apache/camel/component/redis/RedisConfigurationDeserializationFilterTest.java
b/components/camel-spring-parent/camel-spring-redis/src/test/java/org/apache/camel/component/redis/RedisConfigurationDeserializationFilterTest.java
new file mode 100644
index 000000000000..29d61fc8b4a4
--- /dev/null
+++
b/components/camel-spring-parent/camel-spring-redis/src/test/java/org/apache/camel/component/redis/RedisConfigurationDeserializationFilterTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.redis;
+
+import java.io.InvalidClassException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.data.redis.serializer.SerializationException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+/**
+ * The default serializer must not materialise arbitrary types. Redis payloads
reach {@code RedisConsumer.setBody()} and
+ * the producer read commands straight from the wire, so the deserialization
filter is what stands between them and
+ * {@code readObject()}.
+ */
+class RedisConfigurationDeserializationFilterTest {
+
+ @SuppressWarnings("unchecked")
+ private static RedisSerializer<Object> serializerOf(RedisConfiguration
configuration) {
+ return (RedisSerializer<Object>) configuration.getSerializer();
+ }
+
+ @Test
+ void allowedTypeRoundTrips() {
+ RedisSerializer<Object> serializer = serializerOf(new
RedisConfiguration());
+ List<String> body = new ArrayList<>(List.of("a", "b"));
+
+
assertThat(serializer.deserialize(serializer.serialize(body))).isEqualTo(body);
+ }
+
+ @Test
+ void deniedJavaNetTypeIsRejected() {
+ RedisSerializer<Object> serializer = serializerOf(new
RedisConfiguration());
+ byte[] payload = serializer.serialize(URI.create("http://localhost/"));
+
+ assertThatThrownBy(() -> serializer.deserialize(payload))
+ .isInstanceOf(SerializationException.class)
+ .hasRootCauseInstanceOf(InvalidClassException.class);
+ }
+
+ @Test
+ void typeOutsideTheAllowListIsRejected() {
+ RedisSerializer<Object> serializer = serializerOf(new
RedisConfiguration());
+ // a Serializable type that is not java.*, javax.* or
org.apache.camel.*, so the trailing !* denies it
+ byte[] payload = serializer.serialize(new
SerializationException("outside the default allow-list"));
+
+ assertThatThrownBy(() -> serializer.deserialize(payload))
+ .isInstanceOf(SerializationException.class)
+ .hasRootCauseInstanceOf(InvalidClassException.class);
+ }
+
+ @Test
+ void configuredFilterOverridesTheDefault() {
+ RedisConfiguration configuration = new RedisConfiguration();
+
configuration.setDeserializationFilter("org.springframework.**;java.**;!*");
+ RedisSerializer<Object> serializer = serializerOf(configuration);
+ SerializationException outsideDefaultAllowList = new
SerializationException("allowed by the custom filter");
+
+
assertThat(serializer.deserialize(serializer.serialize(outsideDefaultAllowList)))
+ .isInstanceOf(SerializationException.class);
+ }
+
+ @Test
+ void customSerializerIsLeftAlone() {
+ RedisConfiguration configuration = new RedisConfiguration();
+ RedisSerializer<String> custom = RedisSerializer.string();
+ configuration.setSerializer(custom);
+
+ assertThat(configuration.getSerializer()).isSameAs(custom);
+ }
+}
diff --git
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
index 2dffea2c39f8..1887a8a86844 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
@@ -177,6 +177,28 @@ Requests that differ from the configured context-path only
by case are therefore
same constraint as the exact-case form. Deployments that relied on the
previous behaviour to reach a
route without a challenge will now receive `401`.
+=== camel-spring-redis - the default serializer applies a deserialization
filter
+
+The default serializer, `JdkSerializationRedisSerializer`, now installs a
JEP-290
+`java.io.ObjectInputFilter` while reading Redis payloads, resolved through
+`DeserializationFilterHelper`. Previously no filter was applied at all. This
affects both the
+consumer, which deserializes the payload of every message published to the
subscribed channels,
+and the producer read commands, which deserialize the values stored in Redis.
+
+When no explicit pattern is configured, the JVM-wide `jdk.serialFilter` is
honoured if set,
+otherwise the shared Camel default allow-list is applied (it permits standard
Java and Apache Camel
+types, denies `java.net.**`, and enforces JEP-290 graph-shape limits). Routes
that exchange classes
+outside that allow-list must widen it through the new `deserializationFilter`
endpoint option, for
+example:
+
+[source,java]
+----
+from("spring-redis://localhost:6379?command=SUBSCRIBE&channels=myChannel"
+ + "&deserializationFilter=com.example.model.**;java.**;!*")
+----
+
+Setting the `serializer` option to a custom `RedisSerializer` bypasses the
filter entirely, since
+Camel then no longer controls how the payload is read.
=== camel-langchain4j
The legacy `sse` `transportType` has been removed. It follows the support
removal in
diff --git
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/RedisEndpointBuilderFactory.java
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/RedisEndpointBuilderFactory.java
index 8799a97fbdb4..02f5bbb411e5 100644
---
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/RedisEndpointBuilderFactory.java
+++
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/RedisEndpointBuilderFactory.java
@@ -344,6 +344,26 @@ public interface RedisEndpointBuilderFactory {
doSetProperty("listenerContainer", listenerContainer);
return this;
}
+ /**
+ * Sets an ObjectInputFilter pattern (jdk.serialFilter syntax) applied
+ * when the default JDK serializer deserializes Redis payloads, both on
+ * the consumer and on producer read commands. When not set, the
+ * JVM-wide jdk.serialFilter is used if present; otherwise a
+ * conservative default filter denying java.net. and otherwise allowing
+ * java., javax. and org.apache.camel. packages is applied. Ignored
when
+ * a custom serializer is set.
+ *
+ * The option is a: <code>java.lang.String</code> type.
+ *
+ * Group: security
+ *
+ * @param deserializationFilter the value to set
+ * @return the dsl builder
+ */
+ default AdvancedRedisEndpointConsumerBuilder
deserializationFilter(String deserializationFilter) {
+ doSetProperty("deserializationFilter", deserializationFilter);
+ return this;
+ }
}
/**
@@ -553,6 +573,26 @@ public interface RedisEndpointBuilderFactory {
doSetProperty("lazyStartProducer", lazyStartProducer);
return this;
}
+ /**
+ * Sets an ObjectInputFilter pattern (jdk.serialFilter syntax) applied
+ * when the default JDK serializer deserializes Redis payloads, both on
+ * the consumer and on producer read commands. When not set, the
+ * JVM-wide jdk.serialFilter is used if present; otherwise a
+ * conservative default filter denying java.net. and otherwise allowing
+ * java., javax. and org.apache.camel. packages is applied. Ignored
when
+ * a custom serializer is set.
+ *
+ * The option is a: <code>java.lang.String</code> type.
+ *
+ * Group: security
+ *
+ * @param deserializationFilter the value to set
+ * @return the dsl builder
+ */
+ default AdvancedRedisEndpointProducerBuilder
deserializationFilter(String deserializationFilter) {
+ doSetProperty("deserializationFilter", deserializationFilter);
+ return this;
+ }
}
/**
@@ -720,6 +760,26 @@ public interface RedisEndpointBuilderFactory {
return (RedisEndpointBuilder) this;
}
+ /**
+ * Sets an ObjectInputFilter pattern (jdk.serialFilter syntax) applied
+ * when the default JDK serializer deserializes Redis payloads, both on
+ * the consumer and on producer read commands. When not set, the
+ * JVM-wide jdk.serialFilter is used if present; otherwise a
+ * conservative default filter denying java.net. and otherwise allowing
+ * java., javax. and org.apache.camel. packages is applied. Ignored
when
+ * a custom serializer is set.
+ *
+ * The option is a: <code>java.lang.String</code> type.
+ *
+ * Group: security
+ *
+ * @param deserializationFilter the value to set
+ * @return the dsl builder
+ */
+ default AdvancedRedisEndpointBuilder deserializationFilter(String
deserializationFilter) {
+ doSetProperty("deserializationFilter", deserializationFilter);
+ return this;
+ }
}
public interface RedisBuilders {