This is an automated email from the ASF dual-hosted git repository.
martinweiler pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie.git
The following commit(s) were added to refs/heads/main by this push:
new 7f283f3d76c [incubator-kie#7253] Use the Drools deserialization class
allowlist for Java-serialized process variables (#7254)
7f283f3d76c is described below
commit 7f283f3d76c2fd402a4f441f946ba1271a70cc0f
Author: Andrea Cosentino <[email protected]>
AuthorDate: Thu Nov 5 18:27:34 2026 +0100
[incubator-kie#7253] Use the Drools deserialization class allowlist for
Java-serialized process variables (#7254)
* [incubator-kie#7253] Use the Drools deserialization class allowlist for
Java-serialized process variables
JavaSerializationUtils.deserialize, used by ProtobufObjectMarshallerStrategy
and SerializableProtostreamBaseMarshaller, now sets an ObjectInputFilter
when drools.serialization.enableDeserializationFilter is true (the
default). It accepts the classes DeserializationFilterHelper allows
(java.lang, java.util, java.math, java.time and the patterns in
drools.serialization.allowedDeserializationClassPatterns), the java.sql
date and time types, ProcessWorkItemHandlerException (stored by
WorkItemNodeInstance in the Error variable of an error handling
process), primitives and arrays of those, and keeps a JVM-wide
jdk.serialFilter in force.
Application classes stored in process variables through Java
serialization have to be added to
drools.serialization.allowedDeserializationClassPatterns; jbpm-tests
does so for its test model classes.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Andrea Cosentino <[email protected]>
* [incubator-kie#7253] Allow the MongoDB persistence test model classes in
the deserialization filter
MongoDBProcessInstancesIT keeps Address and PersonWithAddresses in
process variables through Java serialization. Add both classes to
drools.serialization.allowedDeserializationClassPatterns in the
module's failsafe configuration, as jbpm-tests does for its test model
classes.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Andrea Cosentino <[email protected]>
---------
Signed-off-by: Andrea Cosentino <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
---
kogito-addons/common/persistence/mongodb/pom.xml | 2 +
kogito-jbpm/jbpm-tests/pom.xml | 2 +
kogito-jbpm/process-serialization-protobuf/pom.xml | 4 +
.../flow/serialization/JavaSerializationUtils.java | 62 ++++++++++
.../DeserializationFilterTestSupport.java | 61 +++++++++
.../serialization/JavaSerializationUtilsTest.java | 137 +++++++++++++++++++++
.../serialization/ProcessInstanceMarshallTest.java | 11 ++
.../ProtobufObjectMarshallerStrategyTest.java | 79 ++++++++++++
.../SerializableProtostreamBaseMarshallerTest.java | 83 +++++++++++++
9 files changed, 441 insertions(+)
diff --git a/kogito-addons/common/persistence/mongodb/pom.xml
b/kogito-addons/common/persistence/mongodb/pom.xml
index 86ac3571937..407a950406f 100644
--- a/kogito-addons/common/persistence/mongodb/pom.xml
+++ b/kogito-addons/common/persistence/mongodb/pom.xml
@@ -132,6 +132,8 @@
<configuration>
<systemPropertyVariables combine.children="append">
<container.image.mongodb>${container.image.mongodb}</container.image.mongodb>
+ <!-- test model classes kept in process variables through Java
serialization -->
+
<drools.serialization.allowedDeserializationClassPatterns>org.kie.kogito.mongodb.Address;org.kie.kogito.mongodb.PersonWithAddresses</drools.serialization.allowedDeserializationClassPatterns>
</systemPropertyVariables>
</configuration>
<executions>
diff --git a/kogito-jbpm/jbpm-tests/pom.xml b/kogito-jbpm/jbpm-tests/pom.xml
index 5c91d7073a1..9547a817cf1 100644
--- a/kogito-jbpm/jbpm-tests/pom.xml
+++ b/kogito-jbpm/jbpm-tests/pom.xml
@@ -172,6 +172,8 @@
<!-- enforce strict variable checking for the sake of
tests -->
<org.jbpm.variable.strict>true</org.jbpm.variable.strict>
+ <!-- test model classes kept in process variables through Java
serialization -->
+
<drools.serialization.allowedDeserializationClassPatterns>org.jbpm.bpmn2.objects.*</drools.serialization.allowedDeserializationClassPatterns>
</systemPropertyVariables>
</configuration>
</plugin>
diff --git a/kogito-jbpm/process-serialization-protobuf/pom.xml
b/kogito-jbpm/process-serialization-protobuf/pom.xml
index 19b26ada89d..c763ca8cecd 100644
--- a/kogito-jbpm/process-serialization-protobuf/pom.xml
+++ b/kogito-jbpm/process-serialization-protobuf/pom.xml
@@ -44,6 +44,10 @@
<groupId>org.kie.kogito</groupId>
<artifactId>jbpm-flow</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.drools</groupId>
+ <artifactId>drools-core</artifactId>
+ </dependency>
<dependency>
<groupId>org.kie.kogito</groupId>
diff --git
a/kogito-jbpm/process-serialization-protobuf/src/main/java/org/jbpm/flow/serialization/JavaSerializationUtils.java
b/kogito-jbpm/process-serialization-protobuf/src/main/java/org/jbpm/flow/serialization/JavaSerializationUtils.java
index fddfcc20b8f..e278055c0a9 100644
---
a/kogito-jbpm/process-serialization-protobuf/src/main/java/org/jbpm/flow/serialization/JavaSerializationUtils.java
+++
b/kogito-jbpm/process-serialization-protobuf/src/main/java/org/jbpm/flow/serialization/JavaSerializationUtils.java
@@ -22,12 +22,34 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.ObjectInputFilter;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
+import java.util.Set;
+
+import org.drools.core.util.DeserializationFilterHelper;
+import org.drools.core.util.KeyStoreConstants;
+import org.kie.api.runtime.process.ProcessWorkItemHandlerException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public final class JavaSerializationUtils {
+ private static final Logger LOGGER =
LoggerFactory.getLogger(JavaSerializationUtils.class);
+
+ /**
+ * Process variable types outside the packages {@link
DeserializationFilterHelper} allows by default:
+ * the JDBC date and time types, and the exception that {@code
WorkItemNodeInstance} stores in the
+ * {@code Error} variable of a work item error handling process.
+ */
+ private static final Set<String> ALLOWED_CLASSES = Set.of(
+ java.sql.Date.class.getName(),
+ java.sql.Time.class.getName(),
+ java.sql.Timestamp.class.getName(),
+ ProcessWorkItemHandlerException.class.getName(),
+ ProcessWorkItemHandlerException.HandlingStrategy.class.getName());
+
private JavaSerializationUtils() {
}
@@ -50,6 +72,16 @@ public final class JavaSerializationUtils {
* Deserializes {@code data} using Java serialization, resolving classes
through the thread
* context classloader first so that application classes are found in
environments like Quarkus
* where the bootstrap classloader does not see deployment classes.
+ * <p>
+ * The classes that can be read are limited by an {@link
ObjectInputFilter} that shares its
+ * allowlist with Drools session marshalling ({@link
DeserializationFilterHelper}): the
+ * {@code java.lang}, {@code java.util}, {@code java.math} and {@code
java.time} packages, the
+ * {@code java.sql} date and time types, {@link
ProcessWorkItemHandlerException}, and the patterns
+ * listed in the {@value
KeyStoreConstants#PROP_ALLOWED_DESER_CLASS_PATTERNS} system property.
Application
+ * classes stored in process variables through Java serialization must be
added to that
+ * property, for example {@code
-Ddrools.serialization.allowedDeserializationClassPatterns=com.example.model.*}.
+ * The filter can be turned off with {@code -D}{@value
KeyStoreConstants#PROP_ENABLE_DESER_FILTER}{@code =false}.
+ * A JVM-wide filter set with {@code jdk.serialFilter} keeps applying as
well.
*/
public static Object deserialize(byte[] data) throws IOException,
ClassNotFoundException {
try (InputStream is = new ByteArrayInputStream(data);
ObjectInputStream ois = new ObjectInputStream(is) {
@@ -62,7 +94,37 @@ public final class JavaSerializationUtils {
}
}
}) {
+ if (DeserializationFilterHelper.isDeserializationFilterEnabled()) {
+ ois.setObjectInputFilter(createDeserializationFilter());
+ }
return ois.readObject();
}
}
+
+ private static ObjectInputFilter createDeserializationFilter() {
+ ObjectInputFilter filter = JavaSerializationUtils::checkInput;
+ ObjectInputFilter jvmWideFilter =
ObjectInputFilter.Config.getSerialFilter();
+ return jvmWideFilter == null ? filter :
ObjectInputFilter.merge(filter, jvmWideFilter);
+ }
+
+ private static ObjectInputFilter.Status
checkInput(ObjectInputFilter.FilterInfo filterInfo) {
+ Class<?> clazz = filterInfo.serialClass();
+ if (clazz == null) {
+ return ObjectInputFilter.Status.UNDECIDED;
+ }
+ while (clazz.isArray()) {
+ clazz = clazz.getComponentType();
+ }
+ if (clazz.isPrimitive()) {
+ return ObjectInputFilter.Status.ALLOWED;
+ }
+ String className = clazz.getName();
+ if (ALLOWED_CLASSES.contains(className) ||
DeserializationFilterHelper.isClassAllowed(className)) {
+ return ObjectInputFilter.Status.ALLOWED;
+ }
+ LOGGER.warn("Deserialization of class '{}' was rejected by the
ObjectInputFilter. "
+ + "If this is a legitimate process variable type, add it to
the allowlist via -D{}=<pattern>",
+ className,
KeyStoreConstants.PROP_ALLOWED_DESER_CLASS_PATTERNS);
+ return ObjectInputFilter.Status.REJECTED;
+ }
}
diff --git
a/kogito-jbpm/process-serialization-protobuf/src/test/java/org/jbpm/flow/serialization/DeserializationFilterTestSupport.java
b/kogito-jbpm/process-serialization-protobuf/src/test/java/org/jbpm/flow/serialization/DeserializationFilterTestSupport.java
new file mode 100644
index 00000000000..d86e66c2f73
--- /dev/null
+++
b/kogito-jbpm/process-serialization-protobuf/src/test/java/org/jbpm/flow/serialization/DeserializationFilterTestSupport.java
@@ -0,0 +1,61 @@
+/*
+ * 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.jbpm.flow.serialization;
+
+import org.drools.core.util.KeyStoreConstants;
+
+/**
+ * Saves and restores the deserialization filter system properties around a
test.
+ */
+public class DeserializationFilterTestSupport {
+
+ private String savedAllowedPatterns;
+ private String savedFilterEnabled;
+
+ /**
+ * Saves the current filter properties and resets them to their defaults:
filter enabled, no extra patterns.
+ */
+ public void setUp() {
+ savedAllowedPatterns =
System.getProperty(KeyStoreConstants.PROP_ALLOWED_DESER_CLASS_PATTERNS);
+ savedFilterEnabled =
System.getProperty(KeyStoreConstants.PROP_ENABLE_DESER_FILTER);
+
System.clearProperty(KeyStoreConstants.PROP_ALLOWED_DESER_CLASS_PATTERNS);
+ System.clearProperty(KeyStoreConstants.PROP_ENABLE_DESER_FILTER);
+ }
+
+ public void allow(String... patterns) {
+
System.setProperty(KeyStoreConstants.PROP_ALLOWED_DESER_CLASS_PATTERNS,
String.join(";", patterns));
+ }
+
+ public void disableFilter() {
+ System.setProperty(KeyStoreConstants.PROP_ENABLE_DESER_FILTER,
"false");
+ }
+
+ public void tearDown() {
+ restore(KeyStoreConstants.PROP_ALLOWED_DESER_CLASS_PATTERNS,
savedAllowedPatterns);
+ restore(KeyStoreConstants.PROP_ENABLE_DESER_FILTER,
savedFilterEnabled);
+ }
+
+ private static void restore(String key, String value) {
+ if (value == null) {
+ System.clearProperty(key);
+ } else {
+ System.setProperty(key, value);
+ }
+ }
+}
diff --git
a/kogito-jbpm/process-serialization-protobuf/src/test/java/org/jbpm/flow/serialization/JavaSerializationUtilsTest.java
b/kogito-jbpm/process-serialization-protobuf/src/test/java/org/jbpm/flow/serialization/JavaSerializationUtilsTest.java
index 7973fcf177d..e3d324c807c 100644
---
a/kogito-jbpm/process-serialization-protobuf/src/test/java/org/jbpm/flow/serialization/JavaSerializationUtilsTest.java
+++
b/kogito-jbpm/process-serialization-protobuf/src/test/java/org/jbpm/flow/serialization/JavaSerializationUtilsTest.java
@@ -19,11 +19,28 @@
package org.jbpm.flow.serialization;
import java.io.IOException;
+import java.io.InvalidClassException;
+import java.io.ObjectInputStream;
import java.io.Serializable;
+import java.math.BigDecimal;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
+import java.util.stream.Stream;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.kie.api.runtime.process.ProcessWorkItemHandlerException;
+import
org.kie.api.runtime.process.ProcessWorkItemHandlerException.HandlingStrategy;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
@@ -60,6 +77,36 @@ public class JavaSerializationUtilsTest {
// intentionally does not implement Serializable
}
+ /**
+ * Not covered by the default allowlist. Records whether its readObject
ran.
+ */
+ static class UnlistedValue implements Serializable {
+ private static final long serialVersionUID = 1L;
+ static volatile boolean readObjectInvoked;
+
+ private void readObject(ObjectInputStream in) throws IOException,
ClassNotFoundException {
+ in.defaultReadObject();
+ readObjectInvoked = true;
+ }
+ }
+
+ static class UnlistedException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+ }
+
+ private final DeserializationFilterTestSupport filterSupport = new
DeserializationFilterTestSupport();
+
+ @BeforeEach
+ void setUp() {
+ filterSupport.setUp();
+ UnlistedValue.readObjectInvoked = false;
+ }
+
+ @AfterEach
+ void tearDown() {
+ filterSupport.tearDown();
+ }
+
// -- tests --------------------------------------------------------------
@Test
@@ -72,6 +119,7 @@ public class JavaSerializationUtilsTest {
@Test
void roundTripCustomObject() throws Exception {
+ filterSupport.allow(Person.class.getName());
Person original = new Person("Alice", 30);
byte[] bytes = JavaSerializationUtils.serialize(original);
assertThat(bytes).isNotEmpty();
@@ -96,6 +144,7 @@ public class JavaSerializationUtilsTest {
void serializeBytesAreCompleteAndDeserializable() throws Exception {
// Regression: toByteArray() called before OOS.close() produced
truncated bytes
// causing EOFException on deserialization. Verify bytes are always
fully flushed.
+ filterSupport.allow(Person.class.getName());
Person original = new Person("Bob", 42);
byte[] bytes = JavaSerializationUtils.serialize(original);
// A valid Java serialization stream starts with the magic bytes 0xACED
@@ -122,6 +171,7 @@ public class JavaSerializationUtilsTest {
void deserializeUsesThreadContextClassLoader() throws Exception {
// Verify that deserialize resolves classes through the thread-context
classloader.
// We swap in a classloader that can see Person, confirm round-trip
still works.
+ filterSupport.allow(Person.class.getName());
ClassLoader original = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(Person.class.getClassLoader());
@@ -132,4 +182,91 @@ public class JavaSerializationUtilsTest {
Thread.currentThread().setContextClassLoader(original);
}
}
+
+ // -- deserialization filter ---------------------------------------------
+
+ static Stream<Arguments> jdkValueTypes() {
+ return Stream.of(
+ Arguments.of(BigDecimal.valueOf(10L)),
+ Arguments.of(LocalDate.of(2026, 1, 31)),
+ Arguments.of(new Timestamp(1_000L)),
+ Arguments.of(new java.sql.Date(1_000L)),
+ Arguments.of(new Time(1_000L)),
+ Arguments.of(new HashMap<>(Map.of("key", new
ArrayList<>(List.of("a", "b"))))),
+ Arguments.of((Object) new int[] { 1, 2, 3 }),
+ Arguments.of((Object) new String[][] { { "a" }, { "b" } }));
+ }
+
+ @ParameterizedTest
+ @MethodSource("jdkValueTypes")
+ void deserializeAllowsJdkValueTypesByDefault(Object original) throws
Exception {
+ byte[] bytes = JavaSerializationUtils.serialize(original);
+
assertThat(JavaSerializationUtils.deserialize(bytes)).isEqualTo(original);
+ }
+
+ @Test
+ void deserializeAllowsWorkItemHandlerExceptionByDefault() throws Exception
{
+ ProcessWorkItemHandlerException original =
+ new ProcessWorkItemHandlerException("errorHandlingProcess",
HandlingStrategy.RETRY, new IllegalStateException("handler failed"), 2);
+ byte[] bytes = JavaSerializationUtils.serialize(original);
+
+ Object deserialized = JavaSerializationUtils.deserialize(bytes);
+
+
assertThat(deserialized).isInstanceOfSatisfying(ProcessWorkItemHandlerException.class,
exception -> {
+
assertThat(exception.getProcessId()).isEqualTo("errorHandlingProcess");
+
assertThat(exception.getStrategy()).isEqualTo(HandlingStrategy.RETRY);
+ assertThat(exception.getRetries()).isEqualTo(2);
+
assertThat(exception.getCause()).isInstanceOf(IllegalStateException.class).hasMessage("handler
failed");
+ });
+ }
+
+ @Test
+ void deserializeRejectsWorkItemHandlerExceptionWithCauseNotInAllowlist()
throws Exception {
+ ProcessWorkItemHandlerException original =
+ new ProcessWorkItemHandlerException("errorHandlingProcess",
HandlingStrategy.ABORT, new UnlistedException());
+ byte[] bytes = JavaSerializationUtils.serialize(original);
+
+ assertThatThrownBy(() -> JavaSerializationUtils.deserialize(bytes))
+ .isInstanceOf(InvalidClassException.class);
+ }
+
+ @Test
+ void deserializeRejectsClassNotInAllowlist() throws Exception {
+ byte[] bytes = JavaSerializationUtils.serialize(new UnlistedValue());
+ assertThatThrownBy(() -> JavaSerializationUtils.deserialize(bytes))
+ .isInstanceOf(InvalidClassException.class);
+ assertThat(UnlistedValue.readObjectInvoked).isFalse();
+ }
+
+ @Test
+ void deserializeRejectsClassNotInAllowlistInsideAllowedCollection() throws
Exception {
+ byte[] bytes = JavaSerializationUtils.serialize(new
ArrayList<>(List.of("value", new UnlistedValue())));
+ assertThatThrownBy(() -> JavaSerializationUtils.deserialize(bytes))
+ .isInstanceOf(InvalidClassException.class);
+ assertThat(UnlistedValue.readObjectInvoked).isFalse();
+ }
+
+ @Test
+ void deserializeRejectsArrayOfClassNotInAllowlist() throws Exception {
+ byte[] bytes = JavaSerializationUtils.serialize(new UnlistedValue[] {
new UnlistedValue() });
+ assertThatThrownBy(() -> JavaSerializationUtils.deserialize(bytes))
+ .isInstanceOf(InvalidClassException.class);
+ assertThat(UnlistedValue.readObjectInvoked).isFalse();
+ }
+
+ @Test
+ void deserializeAllowsClassMatchingConfiguredPattern() throws Exception {
+ filterSupport.allow("com.example.unrelated.*",
JavaSerializationUtilsTest.class.getPackageName() + ".*");
+ byte[] bytes = JavaSerializationUtils.serialize(new UnlistedValue());
+
assertThat(JavaSerializationUtils.deserialize(bytes)).isInstanceOf(UnlistedValue.class);
+ assertThat(UnlistedValue.readObjectInvoked).isTrue();
+ }
+
+ @Test
+ void deserializeAcceptsAnyClassWhenFilterIsDisabled() throws Exception {
+ filterSupport.disableFilter();
+ byte[] bytes = JavaSerializationUtils.serialize(new UnlistedValue());
+
assertThat(JavaSerializationUtils.deserialize(bytes)).isInstanceOf(UnlistedValue.class);
+ assertThat(UnlistedValue.readObjectInvoked).isTrue();
+ }
}
diff --git
a/kogito-jbpm/process-serialization-protobuf/src/test/java/org/jbpm/flow/serialization/ProcessInstanceMarshallTest.java
b/kogito-jbpm/process-serialization-protobuf/src/test/java/org/jbpm/flow/serialization/ProcessInstanceMarshallTest.java
index 431c9982eeb..8c6850a913d 100644
---
a/kogito-jbpm/process-serialization-protobuf/src/test/java/org/jbpm/flow/serialization/ProcessInstanceMarshallTest.java
+++
b/kogito-jbpm/process-serialization-protobuf/src/test/java/org/jbpm/flow/serialization/ProcessInstanceMarshallTest.java
@@ -61,6 +61,7 @@ import org.jbpm.workflow.core.impl.WorkflowProcessImpl;
import org.jbpm.workflow.core.node.EndNode;
import org.jbpm.workflow.core.node.HumanTaskNode;
import org.jbpm.workflow.core.node.StartNode;
+import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
@@ -92,8 +93,13 @@ public class ProcessInstanceMarshallTest {
private static WorkflowProcessImpl workflow;
+ private static final DeserializationFilterTestSupport FILTER_SUPPORT = new
DeserializationFilterTestSupport();
+
@BeforeAll
public static void init() {
+ FILTER_SUPPORT.setUp();
+ FILTER_SUPPORT.allow(MarshableObject.class.getName());
+
workflow = new WorkflowProcessImpl();
workflow.setId("processId");
@@ -123,6 +129,11 @@ public class ProcessInstanceMarshallTest {
when(process.get()).thenReturn(workflow);
}
+ @AfterAll
+ public static void cleanUp() {
+ FILTER_SUPPORT.tearDown();
+ }
+
@XmlRootElement
public static class MarshableObject implements Serializable {
diff --git
a/kogito-jbpm/process-serialization-protobuf/src/test/java/org/jbpm/flow/serialization/impl/marshallers/ProtobufObjectMarshallerStrategyTest.java
b/kogito-jbpm/process-serialization-protobuf/src/test/java/org/jbpm/flow/serialization/impl/marshallers/ProtobufObjectMarshallerStrategyTest.java
new file mode 100644
index 00000000000..9ca0cce44ad
--- /dev/null
+++
b/kogito-jbpm/process-serialization-protobuf/src/test/java/org/jbpm/flow/serialization/impl/marshallers/ProtobufObjectMarshallerStrategyTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.jbpm.flow.serialization.impl.marshallers;
+
+import java.io.InvalidClassException;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jbpm.flow.serialization.DeserializationFilterTestSupport;
+import org.jbpm.flow.serialization.ProcessInstanceMarshallerException;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.google.protobuf.Any;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+public class ProtobufObjectMarshallerStrategyTest {
+
+ static class UnlistedValue implements Serializable {
+ private static final long serialVersionUID = 1L;
+ }
+
+ private final DeserializationFilterTestSupport filterSupport = new
DeserializationFilterTestSupport();
+
+ private final ProtobufObjectMarshallerStrategy strategy = new
ProtobufObjectMarshallerStrategy();
+
+ @BeforeEach
+ void setUp() {
+ filterSupport.setUp();
+ }
+
+ @AfterEach
+ void tearDown() {
+ filterSupport.tearDown();
+ }
+
+ @Test
+ void unmarshallReturnsAllowedValue() {
+ List<String> original = new ArrayList<>(List.of("a", "b"));
+ Any marshalled = strategy.marshall(original);
+ assertThat(strategy.acceptForUnmarshalling(marshalled)).isTrue();
+ assertThat(strategy.unmarshall(marshalled)).isEqualTo(original);
+ }
+
+ @Test
+ void unmarshallRejectsClassNotInAllowlist() {
+ Any marshalled = strategy.marshall(new UnlistedValue());
+ assertThatThrownBy(() -> strategy.unmarshall(marshalled))
+ .isInstanceOf(ProcessInstanceMarshallerException.class)
+ .hasCauseInstanceOf(InvalidClassException.class);
+ }
+
+ @Test
+ void unmarshallReturnsClassMatchingConfiguredPattern() {
+ filterSupport.allow(UnlistedValue.class.getName());
+ Any marshalled = strategy.marshall(new UnlistedValue());
+
assertThat(strategy.unmarshall(marshalled)).isInstanceOf(UnlistedValue.class);
+ }
+}
diff --git
a/kogito-jbpm/process-serialization-protobuf/src/test/java/org/jbpm/flow/serialization/marshaller/SerializableProtostreamBaseMarshallerTest.java
b/kogito-jbpm/process-serialization-protobuf/src/test/java/org/jbpm/flow/serialization/marshaller/SerializableProtostreamBaseMarshallerTest.java
new file mode 100644
index 00000000000..dc28c1383f4
--- /dev/null
+++
b/kogito-jbpm/process-serialization-protobuf/src/test/java/org/jbpm/flow/serialization/marshaller/SerializableProtostreamBaseMarshallerTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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.jbpm.flow.serialization.marshaller;
+
+import java.io.IOException;
+import java.io.InvalidClassException;
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+import org.infinispan.protostream.MessageMarshaller.ProtoStreamReader;
+import org.jbpm.flow.serialization.DeserializationFilterTestSupport;
+import org.jbpm.flow.serialization.JavaSerializationUtils;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class SerializableProtostreamBaseMarshallerTest {
+
+ static class UnlistedValue implements Serializable {
+ private static final long serialVersionUID = 1L;
+ }
+
+ private final DeserializationFilterTestSupport filterSupport = new
DeserializationFilterTestSupport();
+
+ private final SerializableProtostreamBaseMarshaller marshaller = new
SerializableProtostreamBaseMarshaller();
+
+ @BeforeEach
+ void setUp() {
+ filterSupport.setUp();
+ }
+
+ @AfterEach
+ void tearDown() {
+ filterSupport.tearDown();
+ }
+
+ @Test
+ void readFromReturnsAllowedValue() throws IOException {
+ ProtoStreamReader reader = readerOf(BigDecimal.TEN);
+ assertThat(marshaller.readFrom(reader)).isEqualTo(BigDecimal.TEN);
+ }
+
+ @Test
+ void readFromRejectsClassNotInAllowlist() throws IOException {
+ ProtoStreamReader reader = readerOf(new UnlistedValue());
+ assertThatThrownBy(() -> marshaller.readFrom(reader))
+ .isInstanceOf(InvalidClassException.class);
+ }
+
+ @Test
+ void readFromReturnsClassMatchingConfiguredPattern() throws IOException {
+ filterSupport.allow(UnlistedValue.class.getName());
+ ProtoStreamReader reader = readerOf(new UnlistedValue());
+
assertThat(marshaller.readFrom(reader)).isInstanceOf(UnlistedValue.class);
+ }
+
+ private static ProtoStreamReader readerOf(Serializable value) throws
IOException {
+ ProtoStreamReader reader = mock(ProtoStreamReader.class);
+
when(reader.readBytes("data")).thenReturn(JavaSerializationUtils.serialize(value));
+ return reader;
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]