This is an automated email from the ASF dual-hosted git repository. acosentino pushed a commit to branch CAMEL-22966-4.14.x in repository https://gitbox.apache.org/repos/asf/camel.git
commit 0e3ac39e20416c91af6df2cfce3f7d795e75ad89 Author: Andrea Cosentino <[email protected]> AuthorDate: Fri Feb 6 10:21:36 2026 +0100 CAMEL-22966 - Camel-LevelDB: Add ObjectInputFilter String pattern parameter in LevelDBAggregationRepository to be used in unmarshall operations Signed-off-by: Andrea Cosentino <[email protected]> --- .../beans/LevelDBAggregationRepository.json | 2 +- .../LevelDBAggregationRepositoryConfigurer.java | 6 ++++ .../camel/bean/LevelDBAggregationRepository.json | 2 +- .../camel-leveldb/src/main/docs/leveldb.adoc | 8 +++++ .../leveldb/LevelDBAggregationRepository.java | 34 ++++++++++++++++++---- .../camel/component/leveldb/LevelDBCamelCodec.java | 15 ++++++++++ .../camel/component/leveldb/LevelDBSerializer.java | 18 ++++++++++++ .../serializer/DefaultLevelDBSerializer.java | 18 ++++++++++++ 8 files changed, 95 insertions(+), 8 deletions(-) diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/beans/LevelDBAggregationRepository.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/beans/LevelDBAggregationRepository.json index dbb9bb84be7d..0e03e18ef95e 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/beans/LevelDBAggregationRepository.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/beans/LevelDBAggregationRepository.json @@ -10,7 +10,7 @@ "groupId": "org.apache.camel", "artifactId": "camel-leveldb", "version": "4.14.5-SNAPSHOT", - "properties": { "persistentFileName": { "index": 0, "kind": "property", "displayName": "Persistent File Name", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of file to use for storing data" }, "repositoryName": { "index": 1, "kind": "property", "displayName": "Repository Name", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, [...] + "properties": { "persistentFileName": { "index": 0, "kind": "property", "displayName": "Persistent File Name", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of file to use for storing data" }, "repositoryName": { "index": 1, "kind": "property", "displayName": "Repository Name", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, [...] } } diff --git a/components/camel-leveldb/src/generated/java/org/apache/camel/component/leveldb/LevelDBAggregationRepositoryConfigurer.java b/components/camel-leveldb/src/generated/java/org/apache/camel/component/leveldb/LevelDBAggregationRepositoryConfigurer.java index 6a8069a14c33..5cc2934338f9 100644 --- a/components/camel-leveldb/src/generated/java/org/apache/camel/component/leveldb/LevelDBAggregationRepositoryConfigurer.java +++ b/components/camel-leveldb/src/generated/java/org/apache/camel/component/leveldb/LevelDBAggregationRepositoryConfigurer.java @@ -27,6 +27,8 @@ public class LevelDBAggregationRepositoryConfigurer extends org.apache.camel.sup case "allowSerializedHeaders": target.setAllowSerializedHeaders(property(camelContext, boolean.class, value)); return true; case "deadletteruri": case "deadLetterUri": target.setDeadLetterUri(property(camelContext, java.lang.String.class, value)); return true; + case "deserializationfilter": + case "deserializationFilter": target.setDeserializationFilter(property(camelContext, java.lang.String.class, value)); return true; case "maximumredeliveries": case "maximumRedeliveries": target.setMaximumRedeliveries(property(camelContext, int.class, value)); return true; case "persistentfilename": @@ -52,6 +54,8 @@ public class LevelDBAggregationRepositoryConfigurer extends org.apache.camel.sup case "allowSerializedHeaders": return boolean.class; case "deadletteruri": case "deadLetterUri": return java.lang.String.class; + case "deserializationfilter": + case "deserializationFilter": return java.lang.String.class; case "maximumredeliveries": case "maximumRedeliveries": return int.class; case "persistentfilename": @@ -78,6 +82,8 @@ public class LevelDBAggregationRepositoryConfigurer extends org.apache.camel.sup case "allowSerializedHeaders": return target.isAllowSerializedHeaders(); case "deadletteruri": case "deadLetterUri": return target.getDeadLetterUri(); + case "deserializationfilter": + case "deserializationFilter": return target.getDeserializationFilter(); case "maximumredeliveries": case "maximumRedeliveries": return target.getMaximumRedeliveries(); case "persistentfilename": diff --git a/components/camel-leveldb/src/generated/resources/META-INF/services/org/apache/camel/bean/LevelDBAggregationRepository.json b/components/camel-leveldb/src/generated/resources/META-INF/services/org/apache/camel/bean/LevelDBAggregationRepository.json index dbb9bb84be7d..15d6036bb244 100644 --- a/components/camel-leveldb/src/generated/resources/META-INF/services/org/apache/camel/bean/LevelDBAggregationRepository.json +++ b/components/camel-leveldb/src/generated/resources/META-INF/services/org/apache/camel/bean/LevelDBAggregationRepository.json @@ -10,7 +10,7 @@ "groupId": "org.apache.camel", "artifactId": "camel-leveldb", "version": "4.14.5-SNAPSHOT", - "properties": { "persistentFileName": { "index": 0, "kind": "property", "displayName": "Persistent File Name", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of file to use for storing data" }, "repositoryName": { "index": 1, "kind": "property", "displayName": "Repository Name", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, [...] + "properties": { "persistentFileName": { "index": 0, "kind": "property", "displayName": "Persistent File Name", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of file to use for storing data" }, "repositoryName": { "index": 1, "kind": "property", "displayName": "Repository Name", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, [...] } } diff --git a/components/camel-leveldb/src/main/docs/leveldb.adoc b/components/camel-leveldb/src/main/docs/leveldb.adoc index 0508f7f05a4d..c7556f69432f 100644 --- a/components/camel-leveldb/src/main/docs/leveldb.adoc +++ b/components/camel-leveldb/src/main/docs/leveldb.adoc @@ -71,6 +71,14 @@ option must also be provided. |`deadLetterUri` |String |An endpoint uri for a Dead Letter Channel where exhausted recovered Exchanges will be moved. If this option is used then the `maximumRedeliveries` option must also be provided. + +|`deserializationFilter` |String |A deserialization filter used when +deserializing exchange data from the LevelDB store. The filter uses the +standard Java `ObjectInputFilter` pattern syntax. By default, the filter +is set to `java.**;org.apache.camel.**;!*` which allows Java platform +classes and Apache Camel classes. If your application stores custom objects, +you can adjust this filter to include additional packages +(e.g., `java.**;org.apache.camel.**;com.mycompany.**;!*`). |======================================================================= The `repositoryName` option must be provided. Then either the diff --git a/components/camel-leveldb/src/main/java/org/apache/camel/component/leveldb/LevelDBAggregationRepository.java b/components/camel-leveldb/src/main/java/org/apache/camel/component/leveldb/LevelDBAggregationRepository.java index e31372a57949..fed5c0dffb60 100644 --- a/components/camel-leveldb/src/main/java/org/apache/camel/component/leveldb/LevelDBAggregationRepository.java +++ b/components/camel-leveldb/src/main/java/org/apache/camel/component/leveldb/LevelDBAggregationRepository.java @@ -78,6 +78,20 @@ public class LevelDBAggregationRepository extends ServiceSupport implements Reco description = "To use a custom serializer for LevelDB") private LevelDBSerializer serializer; + /** + * Sets a deserialization filter while reading Object from Aggregation Repository. By default the filter will allow + * all java packages and subpackages and all org.apache.camel packages and subpackages, while the remaining will be + * blacklisted and not deserialized. This parameter should be customized if you're using classes you trust to be + * deserialized. + */ + @Metadata(label = "advanced", + description = "Sets a deserialization filter while reading Object from Aggregation Repository." + + " By default the filter will allow all java packages and subpackages and all org.apache.camel packages and subpackages," + + " while the remaining will be blacklisted and not deserialized." + + " This parameter should be customized if you're using classes you trust to be deserialized.", + defaultValue = "java.**;org.apache.camel.**;!*") + private String deserializationFilter = "java.**;org.apache.camel.**;!*"; + /** * Creates an aggregation repository */ @@ -142,9 +156,9 @@ public class LevelDBAggregationRepository extends ServiceSupport implements Reco // only return old exchange if enabled if (isReturnOldExchange()) { - return codec().unmarshallExchange(camelContext, rc); + return codec().unmarshallExchange(camelContext, rc, deserializationFilter); } - } catch (IOException e) { + } catch (IOException | ClassNotFoundException e) { throw new RuntimeCamelException("Error adding to repository " + repositoryName + " with key " + key, e); } @@ -161,9 +175,9 @@ public class LevelDBAggregationRepository extends ServiceSupport implements Reco byte[] rc = levelDBFile.getDb().get(lDbKey); if (rc != null) { - answer = codec().unmarshallExchange(camelContext, rc); + answer = codec().unmarshallExchange(camelContext, rc, deserializationFilter); } - } catch (IOException e) { + } catch (IOException | ClassNotFoundException e) { throw new RuntimeCamelException("Error getting key " + key + " from repository " + repositoryName, e); } @@ -308,9 +322,9 @@ public class LevelDBAggregationRepository extends ServiceSupport implements Reco byte[] rc = levelDBFile.getDb().get(completedLDBKey); if (rc != null) { - answer = codec().unmarshallExchange(camelContext, rc); + answer = codec().unmarshallExchange(camelContext, rc, deserializationFilter); } - } catch (IOException e) { + } catch (IOException | ClassNotFoundException e) { throw new RuntimeCamelException( "Error recovering exchangeId " + exchangeId + " from repository " + repositoryName, e); } @@ -496,6 +510,14 @@ public class LevelDBAggregationRepository extends ServiceSupport implements Reco this.serializer = serializer; } + public String getDeserializationFilter() { + return deserializationFilter; + } + + public void setDeserializationFilter(String deserializationFilter) { + this.deserializationFilter = deserializationFilter; + } + public LevelDBCamelCodec codec() { if (codec == null) { codec = new LevelDBCamelCodec(serializer); diff --git a/components/camel-leveldb/src/main/java/org/apache/camel/component/leveldb/LevelDBCamelCodec.java b/components/camel-leveldb/src/main/java/org/apache/camel/component/leveldb/LevelDBCamelCodec.java index a468c0fd0a50..72ac3c50840b 100644 --- a/components/camel-leveldb/src/main/java/org/apache/camel/component/leveldb/LevelDBCamelCodec.java +++ b/components/camel-leveldb/src/main/java/org/apache/camel/component/leveldb/LevelDBCamelCodec.java @@ -62,4 +62,19 @@ public final class LevelDBCamelCodec { } return answer; } + + public Exchange unmarshallExchange(CamelContext camelContext, byte[] buffer, String deserializationFilter) + throws IOException, ClassNotFoundException { + Exchange answer = serializer.deserializeExchange(camelContext, buffer, deserializationFilter); + + // restore the from endpoint + String fromEndpointUri = (String) answer.removeProperty("CamelAggregatedFromEndpoint"); + if (fromEndpointUri != null) { + Endpoint fromEndpoint = camelContext.hasEndpoint(fromEndpointUri); + if (fromEndpoint != null) { + answer.getExchangeExtension().setFromEndpoint(fromEndpoint); + } + } + return answer; + } } diff --git a/components/camel-leveldb/src/main/java/org/apache/camel/component/leveldb/LevelDBSerializer.java b/components/camel-leveldb/src/main/java/org/apache/camel/component/leveldb/LevelDBSerializer.java index 8b6bbc6e124f..6cffe4aec4f2 100644 --- a/components/camel-leveldb/src/main/java/org/apache/camel/component/leveldb/LevelDBSerializer.java +++ b/components/camel-leveldb/src/main/java/org/apache/camel/component/leveldb/LevelDBSerializer.java @@ -31,4 +31,22 @@ public interface LevelDBSerializer { throws IOException; Exchange deserializeExchange(CamelContext camelContext, byte[] buffer) throws IOException; + + /** + * Deserializes an exchange from a byte buffer with a deserialization filter for security. + * + * @param camelContext the CamelContext + * @param buffer the byte buffer containing serialized exchange data + * @param deserializationFilter the deserialization filter pattern to apply (e.g., + * "java.**;org.apache.camel.**;!*") + * @return the deserialized Exchange + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a class cannot be found during deserialization + */ + default Exchange deserializeExchange(CamelContext camelContext, byte[] buffer, String deserializationFilter) + throws IOException, ClassNotFoundException { + // Default implementation for backward compatibility - delegates to the original method + // Subclasses should override this to apply the filter + return deserializeExchange(camelContext, buffer); + } } diff --git a/components/camel-leveldb/src/main/java/org/apache/camel/component/leveldb/serializer/DefaultLevelDBSerializer.java b/components/camel-leveldb/src/main/java/org/apache/camel/component/leveldb/serializer/DefaultLevelDBSerializer.java index 1bf227527215..723a5859a65d 100644 --- a/components/camel-leveldb/src/main/java/org/apache/camel/component/leveldb/serializer/DefaultLevelDBSerializer.java +++ b/components/camel-leveldb/src/main/java/org/apache/camel/component/leveldb/serializer/DefaultLevelDBSerializer.java @@ -19,12 +19,14 @@ package org.apache.camel.component.leveldb.serializer; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.ObjectInputFilter; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import org.apache.camel.CamelContext; import org.apache.camel.Exchange; import org.apache.camel.support.DefaultExchangeHolder; +import org.apache.camel.util.ClassLoadingAwareObjectInputStream; public class DefaultLevelDBSerializer extends AbstractLevelDBSerializer { @@ -70,4 +72,20 @@ public class DefaultLevelDBSerializer extends AbstractLevelDBSerializer { } }); } + + @Override + public Exchange deserializeExchange(CamelContext camelContext, byte[] buffer, String deserializationFilter) + throws IOException, ClassNotFoundException { + return deserializeExchange(camelContext, buffer, b -> { + ClassLoader classLoader = camelContext.getApplicationContextClassLoader(); + try (final ObjectInputStream ois = new ClassLoadingAwareObjectInputStream( + classLoader, + new ByteArrayInputStream(buffer))) { + ois.setObjectInputFilter(ObjectInputFilter.Config.createFilter(deserializationFilter)); + return (DefaultExchangeHolder) ois.readObject(); + } catch (ClassNotFoundException e) { + throw new IOException("Failed to deserialize exchange", e); + } + }); + } }
