Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputFilter;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
Expand All @@ -37,13 +38,34 @@
*/
public final class JdkSerializer implements ObjectSerializer {

/**
* System property that, when set to a non-blank {@link ObjectInputFilter} pattern (as accepted by
* {@link ObjectInputFilter.Config#createFilter(String)}), installs a JEP-290 deserialization filter
* on every stream created by this serializer. Unset by default, which preserves the previous
* (unfiltered) behaviour.
*
* @since 5.2.0
*/
public static final String SERIAL_FILTER_PROPERTY = "micronaut.serializer.jdk.serial-filter";

private final ConversionService conversionService;
private final @Nullable ObjectInputFilter objectInputFilter;

/**
* @param conversionService The conversion service
*/
public JdkSerializer(ConversionService conversionService) {
this(conversionService, resolveDefaultFilter());
}

/**
* @param conversionService The conversion service
* @param objectInputFilter The {@link ObjectInputFilter} to apply when deserializing, or {@code null} to apply none
* @since 5.2.0
*/
public JdkSerializer(ConversionService conversionService, @Nullable ObjectInputFilter objectInputFilter) {
this.conversionService = conversionService;
this.objectInputFilter = objectInputFilter;
}

/**
Expand All @@ -53,6 +75,14 @@ public JdkSerializer() {
this(ConversionService.SHARED);
}

private static @Nullable ObjectInputFilter resolveDefaultFilter() {
String pattern = System.getProperty(SERIAL_FILTER_PROPERTY);
if (pattern == null || pattern.isBlank()) {
return null;
}
return ObjectInputFilter.Config.createFilter(pattern);
}
Comment thread
Nexory marked this conversation as resolved.

@Override
public void serialize(@Nullable Object object, OutputStream outputStream) throws SerializationException {
try {
Expand Down Expand Up @@ -125,7 +155,7 @@ private ObjectOutputStream createObjectOutput(OutputStream outputStream) throws
* @throws IOException if there is an error
*/
private ObjectInputStream createObjectInput(InputStream inputStream, Class<?> requiredType) throws IOException {
return new ObjectInputStream(inputStream) {
ObjectInputStream objectInput = new ObjectInputStream(inputStream) {
Comment thread
Nexory marked this conversation as resolved.
Outdated
@Override
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
Optional<Class<?>> aClass = ClassUtils.forName(desc.getName(), requiredType.getClassLoader());
Expand All @@ -135,5 +165,9 @@ protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, Clas
return super.resolveClass(desc);
}
};
if (objectInputFilter != null) {
objectInput.setObjectInputFilter(objectInputFilter);
}
return objectInput;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@
*/
package io.micronaut.core.serialize

import io.micronaut.core.convert.ConversionService
import io.micronaut.core.serialize.exceptions.SerializationException
import spock.lang.Specification

import java.io.ObjectInputFilter

/**
* @author Graeme Rocher
* @since 1.0
Expand All @@ -41,6 +45,32 @@ class JdkSerializerSpec extends Specification {
!foo.isPresent()
}

void 'test deserialization is rejected when an ObjectInputFilter disallows the class'() {
given:
ObjectInputFilter filter = ObjectInputFilter.Config.createFilter('java.lang.*;java.util.*;!*')
def serializer = new JdkSerializer(ConversionService.SHARED, filter)
def bytes = serializer.serialize(new Foo(name: "test")).get()

when:
serializer.deserialize(bytes, Foo)

then:
thrown(SerializationException)
}

void 'test deserialization succeeds when an ObjectInputFilter allows the required type'() {
given:
ObjectInputFilter filter = ObjectInputFilter.Config.createFilter('io.micronaut.core.serialize.JdkSerializerSpec$Foo;java.lang.*;java.util.*;!*')
def serializer = new JdkSerializer(ConversionService.SHARED, filter)
def bytes = serializer.serialize(new Foo(name: "test")).get()

when:
Foo foo = serializer.deserialize(bytes, Foo).get()

then:
foo.name == "test"
}

static class Foo implements Serializable {
String name
}
Expand Down
Loading