From 8a5202a50aed508a2cb6ae2f6ea74184e0bcf62c Mon Sep 17 00:00:00 2001 From: Andrea Cosentino Date: Mon, 15 Jan 2024 09:32:15 +0100 Subject: [PATCH] CAMEL-20306 - Camel-CassandraQL: Add ObjectInputFilter String pattern parameter in CassandraAggregationRepository to be used in unmarshall operations (#12760) (#12790) * CAMEL-20306 - Camel-CassandraQL: Add ObjectInputFilter String pattern parameter in CassandraAggregationRepository to be used in unmarshall operations * CAMEL-20306 - Camel-CassandraQL: Add ObjectInputFilter String pattern parameter in CassandraAggregationRepository to be used in unmarshall operations - Docs --------- Signed-off-by: Andrea Cosentino --- .../src/main/docs/cql-component.adoc | 4 ++ .../CassandraAggregationRepository.java | 19 ++++++- .../cassandra/CassandraCamelCodec.java | 15 +++-- .../cassandra/CassandraCamelCodecTest.java | 56 +++++++++++++++++++ .../java/org/malicious/example/Employee.java | 46 +++++++++++++++ 5 files changed, 131 insertions(+), 9 deletions(-) create mode 100644 components/camel-cassandraql/src/test/java/org/apache/camel/processor/aggregate/cassandra/CassandraCamelCodecTest.java create mode 100644 components/camel-cassandraql/src/test/java/org/malicious/example/Employee.java diff --git a/components/camel-cassandraql/src/main/docs/cql-component.adoc b/components/camel-cassandraql/src/main/docs/cql-component.adoc index f5e342f5f3ad4..e08d7063bce1d 100644 --- a/components/camel-cassandraql/src/main/docs/cql-component.adoc +++ b/components/camel-cassandraql/src/main/docs/cql-component.adoc @@ -186,6 +186,10 @@ Alternatively, the `CassandraAggregationRepository` does not have a `LOCAL_QUORUM`… |======================================================================= +While deserializing it's important to notice that the the unmarshallExchange method will allow only all java packages and subpackages +and org.apache.camel packages and subpackages. The remaining classes will be blacklisted. So you'll need to change the filter in case of need. +This could be accomplished by changing the deserializationFilter field on the repository. + == Examples To insert something on a table you can use the following code: diff --git a/components/camel-cassandraql/src/main/java/org/apache/camel/processor/aggregate/cassandra/CassandraAggregationRepository.java b/components/camel-cassandraql/src/main/java/org/apache/camel/processor/aggregate/cassandra/CassandraAggregationRepository.java index 00277bbfccd68..b64653a96f1f7 100644 --- a/components/camel-cassandraql/src/main/java/org/apache/camel/processor/aggregate/cassandra/CassandraAggregationRepository.java +++ b/components/camel-cassandraql/src/main/java/org/apache/camel/processor/aggregate/cassandra/CassandraAggregationRepository.java @@ -121,6 +121,14 @@ public class CassandraAggregationRepository extends ServiceSupport implements Re private boolean allowSerializedHeaders; + /** + * 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. + */ + private String deserializationFilter = "java.**;org.apache.camel.**;!*"; + public CassandraAggregationRepository() { } @@ -211,7 +219,8 @@ public Exchange get(CamelContext camelContext, String key) { Exchange exchange = null; if (row != null) { try { - exchange = exchangeCodec.unmarshallExchange(camelContext, row.getByteBuffer(exchangeColumn)); + exchange = exchangeCodec.unmarshallExchange(camelContext, row.getByteBuffer(exchangeColumn), + deserializationFilter); } catch (IOException iOException) { throw new CassandraAggregationException("Failed to read exchange", exchange, iOException); } catch (ClassNotFoundException classNotFoundException) { @@ -468,4 +477,12 @@ public boolean isAllowSerializedHeaders() { public void setAllowSerializedHeaders(boolean allowSerializedHeaders) { this.allowSerializedHeaders = allowSerializedHeaders; } + + public String getDeserializationFilter() { + return deserializationFilter; + } + + public void setDeserializationFilter(String deserializationFilter) { + this.deserializationFilter = deserializationFilter; + } } diff --git a/components/camel-cassandraql/src/main/java/org/apache/camel/processor/aggregate/cassandra/CassandraCamelCodec.java b/components/camel-cassandraql/src/main/java/org/apache/camel/processor/aggregate/cassandra/CassandraCamelCodec.java index b2bcfbf0b1747..0c3d54387d457 100644 --- a/components/camel-cassandraql/src/main/java/org/apache/camel/processor/aggregate/cassandra/CassandraCamelCodec.java +++ b/components/camel-cassandraql/src/main/java/org/apache/camel/processor/aggregate/cassandra/CassandraCamelCodec.java @@ -16,11 +16,7 @@ */ package org.apache.camel.processor.aggregate.cassandra; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; +import java.io.*; import java.nio.ByteBuffer; import org.apache.camel.CamelContext; @@ -63,9 +59,10 @@ public ByteBuffer marshallExchange(Exchange exchange, boolean allowSerializedHea return ByteBuffer.wrap(serialize(pe)); } - public Exchange unmarshallExchange(CamelContext camelContext, ByteBuffer buffer) + public Exchange unmarshallExchange(CamelContext camelContext, ByteBuffer buffer, String deserializationFilter) throws IOException, ClassNotFoundException { - DefaultExchangeHolder pe = (DefaultExchangeHolder) deserialize(camelContext, new ByteBufferInputStream(buffer)); + DefaultExchangeHolder pe + = (DefaultExchangeHolder) deserialize(camelContext, new ByteBufferInputStream(buffer), deserializationFilter); Exchange answer = new DefaultExchange(camelContext); DefaultExchangeHolder.unmarshal(answer, pe); // restore the from endpoint @@ -87,9 +84,11 @@ private byte[] serialize(Object object) throws IOException { return bytesOut.toByteArray(); } - private Object deserialize(CamelContext camelContext, InputStream bytes) throws IOException, ClassNotFoundException { + private Object deserialize(CamelContext camelContext, InputStream bytes, String deserializationFilter) + throws IOException, ClassNotFoundException { ClassLoader classLoader = camelContext.getApplicationContextClassLoader(); ObjectInputStream objectIn = new ClassLoadingAwareObjectInputStream(classLoader, bytes); + objectIn.setObjectInputFilter(ObjectInputFilter.Config.createFilter(deserializationFilter)); Object object = objectIn.readObject(); objectIn.close(); return object; diff --git a/components/camel-cassandraql/src/test/java/org/apache/camel/processor/aggregate/cassandra/CassandraCamelCodecTest.java b/components/camel-cassandraql/src/test/java/org/apache/camel/processor/aggregate/cassandra/CassandraCamelCodecTest.java new file mode 100644 index 0000000000000..f7f08a7f6645c --- /dev/null +++ b/components/camel-cassandraql/src/test/java/org/apache/camel/processor/aggregate/cassandra/CassandraCamelCodecTest.java @@ -0,0 +1,56 @@ +/* + * 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.processor.aggregate.cassandra; + +import java.io.*; +import java.nio.ByteBuffer; + +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.malicious.example.Employee; + +public class CassandraCamelCodecTest extends CamelTestSupport { + + CassandraCamelCodec codec; + + @Override + protected void startCamelContext() throws Exception { + super.startCamelContext(); + codec = new CassandraCamelCodec(); + } + + @Test + public void shouldFailWithRejected() throws IOException, ClassNotFoundException { + Employee emp = new Employee("Mickey", "Mouse"); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + + oos.writeObject(emp); + + oos.flush(); + oos.close(); + + InputStream is = new ByteArrayInputStream(baos.toByteArray()); + InvalidClassException thrown = Assertions.assertThrows(InvalidClassException.class, () -> { + codec.unmarshallExchange(context, ByteBuffer.wrap(is.readAllBytes()), "java.**;org.apache.camel.**;!*"); + }); + + Assertions.assertEquals("filter status: REJECTED", thrown.getMessage()); + } +} diff --git a/components/camel-cassandraql/src/test/java/org/malicious/example/Employee.java b/components/camel-cassandraql/src/test/java/org/malicious/example/Employee.java new file mode 100644 index 0000000000000..3850218d128bd --- /dev/null +++ b/components/camel-cassandraql/src/test/java/org/malicious/example/Employee.java @@ -0,0 +1,46 @@ +/* + * 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.malicious.example; + +import java.io.Serializable; + +public class Employee implements Serializable { + + String name; + String surname; + + public Employee(String name, String surname) { + this.name = name; + this.surname = surname; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getSurname() { + return surname; + } + + public void setSurname(String surname) { + this.surname = surname; + } +}