INT-4342: White List for Payload Deserializer

JIRA: https://jira.spring.io/browse/INT-4342

Use similar code to Spring AMQP to add white list support for Integration's
use of the `DeserializingMessageConverter`; introduce the `WhiteListDeserializingMessageConverter`.

Polishing

Missed this change in PR.

Fix XSD attribute

# Conflicts:
#	spring-integration-core/src/main/java/org/springframework/integration/dsl/Transformers.java
#	spring-integration-core/src/test/java/org/springframework/integration/config/xml/PayloadDeserializingTransformerParserTests.java
#	spring-integration-core/src/test/java/org/springframework/integration/dsl/flows/IntegrationFlowTests.java
#	spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/store/JdbcChannelMessageStore.java
#	spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/store/channel/MessageRowMapper.java
#	spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/store/MongoDbMessageStore.java
#	spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/support/BinaryToMessageConverter.java
#	spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/support/MongoDbMessageBytesConverter.java
This commit is contained in:
Gary Russell
2017-09-08 13:58:59 -04:00
committed by Artem Bilan
parent 08bc97180c
commit 694d190bd2
13 changed files with 354 additions and 35 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@ import org.springframework.integration.transformer.PayloadDeserializingTransform
* Parser for the 'payload-deserializing-transformer' element.
*
* @author Mark Fisher
* @author Gary Russell
*/
public class PayloadDeserializingTransformerParser extends AbstractTransformerParser {
@@ -37,6 +38,7 @@ public class PayloadDeserializingTransformerParser extends AbstractTransformerPa
@Override
protected void parseTransformer(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "deserializer");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "white-list", "whiteListPatterns");
}
}

View File

@@ -0,0 +1,182 @@
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed 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.springframework.integration.support.converter;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.core.ConfigurableObjectInputStream;
import org.springframework.core.NestedIOException;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.serializer.DefaultDeserializer;
import org.springframework.core.serializer.Deserializer;
import org.springframework.core.serializer.support.SerializationFailedException;
import org.springframework.util.Assert;
import org.springframework.util.PatternMatchUtils;
/**
* A {@link Converter} that delegates to a
* {@link org.springframework.core.serializer.Deserializer} to convert data in a byte
* array to an object. By default, if using a {@link DefaultDeserializer} all
* classes/packages are deserialized. If you receive data from untrusted sources, consider
* adding trusted classes/packages using {@link #setWhiteListPatterns(String...)} or
* {@link #addWhiteListPatterns(String...)}.
*
* @author Gary Russell
* @author Mark Fisher
* @author Juergen Hoeller
* @since 4.2.13
*/
public class WhiteListDeserializingConverter implements Converter<byte[], Object> {
private final Deserializer<Object> deserializer;
private final ClassLoader defaultDeserializerClassLoader;
private final boolean usingDefaultDeserializer;
private final Set<String> whiteListPatterns = new LinkedHashSet<String>();
/**
* Create a {@code WhiteListDeserializingConverter} with default
* {@link java.io.ObjectInputStream} configuration, using the "latest user-defined
* ClassLoader".
*/
public WhiteListDeserializingConverter() {
this(new DefaultDeserializer());
}
/**
* Create a {@code WhiteListDeserializingConverter} for using an
* {@link java.io.ObjectInputStream} with the given {@code ClassLoader}.
* @param classLoader the class loader to use for deserialization.
*/
public WhiteListDeserializingConverter(ClassLoader classLoader) {
this(new DefaultDeserializer(classLoader));
}
/**
* Create a {@code WhiteListDeserializingConverter} that delegates to the provided
* {@link Deserializer}.
* @param deserializer the deserializer to use.
*/
public WhiteListDeserializingConverter(Deserializer<Object> deserializer) {
Assert.notNull(deserializer, "Deserializer must not be null");
this.deserializer = deserializer;
if (deserializer instanceof DefaultDeserializer) {
ClassLoader classLoader = null;
try {
classLoader = (ClassLoader) new DirectFieldAccessor(deserializer).getPropertyValue("classLoader");
}
catch (Exception e) {
// no-op
}
this.defaultDeserializerClassLoader = classLoader;
this.usingDefaultDeserializer = true;
}
else {
this.defaultDeserializerClassLoader = null;
this.usingDefaultDeserializer = false;
}
}
/**
* Set simple patterns for allowable packages/classes for deserialization.
* The patterns will be applied in order until a match is found.
* A class can be fully qualified or a wildcard '*' is allowed at the
* beginning or end of the class name.
* Examples: {@code com.foo.*}, {@code *.MyClass}.
* @param whiteListPatterns the patterns.
*/
public void setWhiteListPatterns(String... whiteListPatterns) {
this.whiteListPatterns.clear();
Collections.addAll(this.whiteListPatterns, whiteListPatterns);
}
/**
* Add package/class patterns to the white list.
* @param patterns the patterns to add.
* @see #setWhiteListPatterns(String...)
*/
public void addWhiteListPatterns(String... patterns) {
Collections.addAll(this.whiteListPatterns, patterns);
}
@Override
public Object convert(byte[] source) {
ByteArrayInputStream byteStream = new ByteArrayInputStream(source);
try {
if (this.usingDefaultDeserializer) {
return deserialize(byteStream);
}
else {
return this.deserializer.deserialize(byteStream);
}
}
catch (Throwable ex) {
throw new SerializationFailedException("Failed to deserialize payload. " +
"Is the byte array a result of corresponding serialization for " +
this.deserializer.getClass().getSimpleName() + "?", ex);
}
}
protected Object deserialize(ByteArrayInputStream inputStream) throws IOException {
try {
ObjectInputStream objectInputStream = new ConfigurableObjectInputStream(inputStream,
this.defaultDeserializerClassLoader) {
@Override
protected Class<?> resolveClass(ObjectStreamClass classDesc)
throws IOException, ClassNotFoundException {
Class<?> clazz = super.resolveClass(classDesc);
checkWhiteList(clazz);
return clazz;
}
};
return objectInputStream.readObject();
}
catch (ClassNotFoundException ex) {
throw new NestedIOException("Failed to deserialize object type", ex);
}
}
protected void checkWhiteList(Class<?> clazz) throws IOException {
if (this.whiteListPatterns.isEmpty()) {
return;
}
if (clazz.isArray() || clazz.isPrimitive() || clazz.equals(String.class)
|| Number.class.isAssignableFrom(clazz)) {
return;
}
String className = clazz.getName();
for (String pattern : this.whiteListPatterns) {
if (PatternMatchUtils.simpleMatch(pattern, className)) {
return;
}
}
throw new SecurityException("Attempt to deserialize unauthorized " + clazz);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,15 +16,18 @@
package org.springframework.integration.transformer;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.serializer.Deserializer;
import org.springframework.core.serializer.support.DeserializingConverter;
import org.springframework.integration.support.converter.WhiteListDeserializingConverter;
import org.springframework.util.Assert;
/**
* Transformer that deserializes the inbound byte array payload to an object by delegating to a
* Converter&lt;byte[], Object&gt;. Default delegate is a {@link DeserializingConverter} using
* Java serialization.
* Transformer that deserializes the inbound byte array payload to an object by delegating
* to a Converter&lt;byte[], Object&gt;. Default delegate is a
* {@link WhiteListDeserializingConverter} using Java serialization.
*
* <p>The byte array payload must be a result of equivalent serialization.
* <p>
* The byte array payload must be a result of equivalent serialization.
*
* @author Mark Fisher
* @author Gary Russell
@@ -32,15 +35,36 @@ import org.springframework.core.serializer.support.DeserializingConverter;
*/
public class PayloadDeserializingTransformer extends PayloadTypeConvertingTransformer<byte[], Object> {
public PayloadDeserializingTransformer() {
doSetConverter(new WhiteListDeserializingConverter());
}
private void doSetConverter(Converter<byte[], Object> converter) {
this.converter = converter;
}
public void setDeserializer(Deserializer<Object> deserializer) {
this.setConverter(new DeserializingConverter(deserializer));
setConverter(new WhiteListDeserializingConverter(deserializer));
}
/**
* When using a {@link WhiteListDeserializingConverter} (the default) add patterns
* for packages/classes that are allowed to be deserialized.
* A class can be fully qualified or a wildcard '*' is allowed at the
* beginning or end of the class name.
* Examples: {@code com.foo.*}, {@code *.MyClass}.
* @param patterns the patterns.
* @since 4.2.13
*/
public void setWhiteListPatterns(String... patterns) {
Assert.isTrue(this.converter instanceof WhiteListDeserializingConverter,
"Patterns can only be provided when using a 'WhiteListDeserializingConverter'");
((WhiteListDeserializingConverter) this.converter).setWhiteListPatterns(patterns);
}
@Override
protected Object transformPayload(byte[] payload) throws Exception {
if (this.converter == null) {
this.setConverter(new DeserializingConverter());
}
return this.converter.convert(payload);
}

View File

@@ -2674,7 +2674,7 @@
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element ref="poller" />
</xsd:choice>
<xsd:attribute name="deserializer" use="optional">
<xsd:attribute name="deserializer">
<xsd:annotation>
<xsd:documentation>
Reference to a Deserializer instance to convert from a byte array to an object.
@@ -2688,6 +2688,15 @@
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="white-list">
<xsd:annotation>
<xsd:documentation>
When using the default Deserializer, a list of package/class patterns indicating
classes that are allowed to be deserialized. Consider providing this if you receive
data from untrusted sources. Example: "com.mycom.*, com.yourcom.*".
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="id" type="xsd:string" />
</xsd:complexType>

View File

@@ -19,14 +19,17 @@
<queue capacity="1"/>
</channel>
<payload-deserializing-transformer input-channel="directInput" output-channel="output"/>
<payload-deserializing-transformer id="direct" input-channel="directInput" output-channel="output"
white-list="*" />
<payload-deserializing-transformer input-channel="queueInput" output-channel="output">
<poller fixed-delay="10000"/>
</payload-deserializing-transformer>
<payload-deserializing-transformer input-channel="customDeserializerInput" output-channel="output" deserializer="customDeserializer"/>
<payload-deserializing-transformer input-channel="customDeserializerInput" output-channel="output"
deserializer="customDeserializer"/>
<beans:bean id="customDeserializer" class="org.springframework.integration.config.xml.PayloadDeserializingTransformerParserTests$TestDeserializer"/>
<beans:bean id="customDeserializer"
class="org.springframework.integration.config.xml.PayloadDeserializingTransformerParserTests$TestDeserializer"/>
</beans:beans>

View File

@@ -16,8 +16,10 @@
package org.springframework.integration.config.xml;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayOutputStream;
@@ -26,17 +28,21 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Set;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.serializer.Deserializer;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.integration.transformer.MessageTransformationException;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.PollableChannel;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.integration.transformer.MessageTransformationException;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.FileCopyUtils;
@@ -60,6 +66,10 @@ public class PayloadDeserializingTransformerParserTests {
@Autowired
private PollableChannel output;
@Autowired
@Qualifier("direct.handler")
private MessageHandler handler;
@Test
public void directChannelWithSerializedStringMessage() throws Exception {
@@ -69,6 +79,10 @@ public class PayloadDeserializingTransformerParserTests {
assertNotNull(result);
assertTrue(result.getPayload() instanceof String);
assertEquals("foo", result.getPayload());
Set<?> patterns = TestUtils.getPropertyValue(this.handler, "transformer.converter.whiteListPatterns",
Set.class);
assertThat(patterns.size(), equalTo(1));
assertThat(patterns.iterator().next(), equalTo("*"));
}
@Test

View File

@@ -16,8 +16,12 @@
package org.springframework.integration.transformer;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
@@ -64,6 +68,31 @@ public class PayloadDeserializingTransformerTests {
assertEquals(testBean.name, ((TestBean) payload).name);
}
@Test
public void deserializeObjectWhiteList() throws Exception {
TestBean testBean = new TestBean("test");
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
ObjectOutputStream objectStream = new ObjectOutputStream(byteStream);
objectStream.writeObject(testBean);
byte[] serialized = byteStream.toByteArray();
PayloadDeserializingTransformer transformer = new PayloadDeserializingTransformer();
transformer.setWhiteListPatterns("com.*");
try {
transformer.transform(new GenericMessage<byte[]>(serialized));
fail("expected security exception");
}
catch (MessageTransformationException e) {
assertThat(e.getCause().getCause(), instanceOf(SecurityException.class));
assertThat(e.getCause().getCause().getMessage(), startsWith("Attempt to deserialize unauthorized"));
}
transformer.setWhiteListPatterns("org.*");
Message<?> result = transformer.transform(new GenericMessage<byte[]>(serialized));
Object payload = result.getPayload();
assertNotNull(payload);
assertEquals(TestBean.class, payload.getClass());
assertEquals(testBean.name, ((TestBean) payload).name);
}
@Test(expected = MessageTransformationException.class)
public void invalidPayload() {
byte[] bytes = new byte[] { 1, 2, 3 };

View File

@@ -40,7 +40,6 @@ import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.serializer.Deserializer;
import org.springframework.core.serializer.Serializer;
import org.springframework.core.serializer.support.DeserializingConverter;
import org.springframework.core.serializer.support.SerializingConverter;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.integration.jdbc.store.JdbcChannelMessageStore;
@@ -48,6 +47,7 @@ import org.springframework.integration.store.AbstractMessageGroupStore;
import org.springframework.integration.store.MessageGroup;
import org.springframework.integration.store.MessageStore;
import org.springframework.integration.store.SimpleMessageGroup;
import org.springframework.integration.support.converter.WhiteListDeserializingConverter;
import org.springframework.integration.util.UUIDConverter;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -194,7 +194,7 @@ public class JdbcMessageStore extends AbstractMessageGroupStore implements Messa
private volatile JdbcOperations jdbcTemplate;
private volatile DeserializingConverter deserializer;
private volatile WhiteListDeserializingConverter deserializer;
private volatile SerializingConverter serializer;
@@ -208,7 +208,7 @@ public class JdbcMessageStore extends AbstractMessageGroupStore implements Messa
*/
@Deprecated
public JdbcMessageStore() {
this.deserializer = new DeserializingConverter();
this.deserializer = new WhiteListDeserializingConverter();
this.serializer = new SerializingConverter();
}
@@ -229,7 +229,7 @@ public class JdbcMessageStore extends AbstractMessageGroupStore implements Messa
public JdbcMessageStore(JdbcOperations jdbcOperations) {
Assert.notNull(jdbcOperations, "'dataSource' must not be null");
this.jdbcTemplate = jdbcOperations;
this.deserializer = new DeserializingConverter();
this.deserializer = new WhiteListDeserializingConverter();
this.serializer = new SerializingConverter();
}
@@ -301,7 +301,18 @@ public class JdbcMessageStore extends AbstractMessageGroupStore implements Messa
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public void setDeserializer(Deserializer<? extends Message<?>> deserializer) {
this.deserializer = new DeserializingConverter((Deserializer) deserializer);
this.deserializer = new WhiteListDeserializingConverter((Deserializer) deserializer);
}
/**
* Add patterns for packages/classes that are allowed to be deserialized. A class can
* be fully qualified or a wildcard '*' is allowed at the beginning or end of the
* class name. Examples: {@code com.foo.*}, {@code *.MyClass}.
* @param patterns the patterns.
* @since 4.2.13
*/
public void addWhiteListPatterns(String... patterns) {
this.deserializer.addWhiteListPatterns(patterns);
}
/**

View File

@@ -41,7 +41,6 @@ import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.serializer.Deserializer;
import org.springframework.core.serializer.Serializer;
import org.springframework.core.serializer.support.DeserializingConverter;
import org.springframework.core.serializer.support.SerializingConverter;
import org.springframework.integration.IntegrationMessageHeaderAccessor;
import org.springframework.integration.jdbc.JdbcMessageStore;
@@ -56,6 +55,7 @@ import org.springframework.integration.store.PriorityCapableChannelMessageStore;
import org.springframework.integration.store.SimpleMessageGroupFactory;
import org.springframework.integration.support.DefaultMessageBuilderFactory;
import org.springframework.integration.support.MessageBuilderFactory;
import org.springframework.integration.support.converter.WhiteListDeserializingConverter;
import org.springframework.integration.support.utils.IntegrationUtils;
import org.springframework.integration.transaction.TransactionSynchronizationFactory;
import org.springframework.integration.util.UUIDConverter;
@@ -143,7 +143,7 @@ public class JdbcChannelMessageStore implements PriorityCapableChannelMessageSto
private volatile JdbcTemplate jdbcTemplate;
private volatile DeserializingConverter deserializer;
private volatile WhiteListDeserializingConverter deserializer;
private volatile SerializingConverter serializer;
@@ -165,7 +165,7 @@ public class JdbcChannelMessageStore implements PriorityCapableChannelMessageSto
* Convenient constructor for configuration use.
*/
public JdbcChannelMessageStore() {
this.deserializer = new DeserializingConverter();
this.deserializer = new WhiteListDeserializingConverter();
this.serializer = new SerializingConverter();
}
@@ -208,7 +208,18 @@ public class JdbcChannelMessageStore implements PriorityCapableChannelMessageSto
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public void setDeserializer(Deserializer<? extends Message<?>> deserializer) {
this.deserializer = new DeserializingConverter((Deserializer) deserializer);
this.deserializer = new WhiteListDeserializingConverter((Deserializer) deserializer);
}
/**
* Add patterns for packages/classes that are allowed to be deserialized. A class can
* be fully qualified or a wildcard '*' is allowed at the beginning or end of the
* class name. Examples: {@code com.foo.*}, {@code *.MyClass}.
* @param patterns the patterns.
* @since 4.2.13
*/
public void addWhiteListPatterns(String... patterns) {
this.deserializer.addWhiteListPatterns(patterns);
}
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,7 +19,7 @@ package org.springframework.integration.jdbc.store.channel;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.core.serializer.support.DeserializingConverter;
import org.springframework.integration.support.converter.WhiteListDeserializingConverter;
import org.springframework.messaging.Message;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.lob.LobHandler;
@@ -30,19 +30,21 @@ import org.springframework.jdbc.support.lob.LobHandler;
* that select clause ordering is unimportant.
*
* @author Gunnar Hillert
* @author Gary Russell
* @since 2.2
*
*/
public class MessageRowMapper implements RowMapper<Message<?>> {
private final DeserializingConverter deserializer;
private final WhiteListDeserializingConverter deserializer;
private final LobHandler lobHandler;
public MessageRowMapper(DeserializingConverter deserializer, LobHandler lobHandler) {
public MessageRowMapper(WhiteListDeserializingConverter deserializer, LobHandler lobHandler) {
this.deserializer = deserializer;
this.lobHandler = lobHandler;
}
@Override
public Message<?> mapRow(ResultSet rs, int rowNum) throws SQLException {
return (Message<?>) this.deserializer.convert(this.lobHandler.getBlobAsBytes(rs, "MESSAGE_BYTES"));
}

View File

@@ -33,7 +33,6 @@ import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.serializer.support.DeserializingConverter;
import org.springframework.core.serializer.support.SerializingConverter;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
@@ -63,6 +62,7 @@ import org.springframework.integration.store.MessageStore;
import org.springframework.integration.store.SimpleMessageGroup;
import org.springframework.integration.support.MutableMessage;
import org.springframework.integration.support.MutableMessageBuilder;
import org.springframework.integration.support.converter.WhiteListDeserializingConverter;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
@@ -133,6 +133,8 @@ public class MongoDbMessageStore extends AbstractMessageGroupStore
private ApplicationContext applicationContext;
private String[] whiteListPatterns;
/**
* Create a MongoDbMessageStore using the provided {@link MongoDbFactory}.and the default collection name.
@@ -166,6 +168,16 @@ public class MongoDbMessageStore extends AbstractMessageGroupStore
this.applicationContext = applicationContext;
}
/**
* Add patterns for packages/classes that are allowed to be deserialized. A class can
* be fully qualified or a wildcard '*' is allowed at the beginning or end of the
* class name. Examples: {@code com.foo.*}, {@code *.MyClass}.
* @param patterns the patterns.
*/
public void addWhiteListPatterns(String... patterns) {
this.whiteListPatterns = patterns;
}
@Override
public void afterPropertiesSet() throws Exception {
if (this.applicationContext != null) {
@@ -497,7 +509,12 @@ public class MongoDbMessageStore extends AbstractMessageGroupStore
customConverters.add(new MessageHistoryToDBObjectConverter());
customConverters.add(new DBObjectToGenericMessageConverter());
customConverters.add(new DBObjectToMutableMessageConverter());
customConverters.add(new DBObjectToErrorMessageConverter());
DBObjectToErrorMessageConverter docToErrorMessageConverter = new DBObjectToErrorMessageConverter();
if (MongoDbMessageStore.this.whiteListPatterns != null) {
docToErrorMessageConverter.deserializingConverter
.addWhiteListPatterns(MongoDbMessageStore.this.whiteListPatterns);
}
customConverters.add(docToErrorMessageConverter);
customConverters.add(new DBObjectToAdviceMessageConverter());
customConverters.add(new ThrowableToBytesConverter());
this.setCustomConversions(new CustomConversions(customConverters));
@@ -717,7 +734,7 @@ public class MongoDbMessageStore extends AbstractMessageGroupStore
private class DBObjectToErrorMessageConverter implements Converter<DBObject, ErrorMessage> {
private final Converter<byte[], Object> deserializingConverter = new DeserializingConverter();
private final WhiteListDeserializingConverter deserializingConverter = new WhiteListDeserializingConverter();
@Override
public ErrorMessage convert(DBObject source) {

View File

@@ -22,8 +22,8 @@ import java.util.Set;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.core.serializer.support.DeserializingConverter;
import org.springframework.core.serializer.support.SerializingConverter;
import org.springframework.integration.support.converter.WhiteListDeserializingConverter;
import org.springframework.messaging.Message;
/**
@@ -32,13 +32,14 @@ import org.springframework.messaging.Message;
* And vice versa - to convert {@link byte[]} from the MongoDB to the {@link Message}.
* @author Artem Bilan
* @author Gary Russell
* @since 4.2.10
*/
public class MongoDbMessageBytesConverter implements GenericConverter {
private final Converter<Object, byte[]> serializingConverter = new SerializingConverter();
private final Converter<byte[], Object> deserializingConverter = new DeserializingConverter();
private final WhiteListDeserializingConverter deserializingConverter = new WhiteListDeserializingConverter();
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
@@ -58,4 +59,14 @@ public class MongoDbMessageBytesConverter implements GenericConverter {
}
}
/**
* Add patterns for packages/classes that are allowed to be deserialized. A class can
* be fully qualified or a wildcard '*' is allowed at the beginning or end of the
* class name. Examples: {@code com.foo.*}, {@code *.MyClass}.
* @param patterns the patterns.
*/
public void addWhiteListPatterns(String... patterns) {
this.deserializingConverter.addWhiteListPatterns(patterns);
}
}

View File

@@ -116,9 +116,13 @@ These will use standard Java serialization by default, but you can provide an im
----
<int:payload-serializing-transformer input-channel="objectsIn" output-channel="bytesOut"/>
<int:payload-deserializing-transformer input-channel="bytesIn" output-channel="objectsOut"/>
<int:payload-deserializing-transformer input-channel="bytesIn" output-channel="objectsOut"
white-list="com.mycom.*,com.yourcom.*"/>
----
IMPORTANT: When deserializing data from untrusted sources, you should consider adding a `white-list` of package/class patterns.
By default, all classes will be deserialized.
====== Object-to-Map and Map-to-Object Transformers
Spring Integration also provides _Object-to-Map_ and _Map-to-Object_ transformers which utilize the Spring Expression Language (SpEL) to serialize and de-serialize the object graphs.