Replace whitelist with allowlist

This commit is contained in:
Artem Bilan
2020-06-11 18:04:28 -04:00
committed by Gary Russell
parent 7ec1f5cc4b
commit 2419c03b25
18 changed files with 377 additions and 189 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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.
@@ -27,6 +27,7 @@ import org.springframework.integration.transformer.PayloadDeserializingTransform
*
* @author Mark Fisher
* @author Gary Russell
* @author Artem Bilan
*/
public class PayloadDeserializingTransformerParser extends AbstractTransformerParser {
@@ -38,7 +39,13 @@ 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");
// TODO remove in 5.5
if (element.hasAttribute("white-list")) {
parserContext.getReaderContext().error(
"the 'white-list' attribute is deprecated in favor of 'allow-list'", element);
}
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "white-list", "allowedPatterns");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "allow-list", "allowedPatterns");
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2019 the original author or authors.
* Copyright 2016-2020 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.
@@ -215,14 +215,15 @@ public abstract class Transformers {
return transformer;
}
public static PayloadDeserializingTransformer deserializer(String... whiteListPatterns) {
return deserializer(null, whiteListPatterns);
public static PayloadDeserializingTransformer deserializer(String... allowedPatterns) {
return deserializer(null, allowedPatterns);
}
public static PayloadDeserializingTransformer deserializer(@Nullable Deserializer<Object> deserializer,
String... whiteListPatterns) {
String... allowedPatterns) {
PayloadDeserializingTransformer transformer = new PayloadDeserializingTransformer();
transformer.setWhiteListPatterns(whiteListPatterns);
transformer.setAllowedPatterns(allowedPatterns);
if (deserializer != null) {
transformer.setDeserializer(deserializer);
}

View File

@@ -0,0 +1,184 @@
/*
* Copyright 2002-2020 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
*
* https://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 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 #setAllowedPatterns(String...)} or
* {@link #addAllowedPatterns(String...)}.
*
* @author Gary Russell
* @author Mark Fisher
* @author Juergen Hoeller
* @author Artem Bilan
*
* @since 5.4
*/
public class AllowListDeserializingConverter implements Converter<byte[], Object> {
private final Deserializer<Object> deserializer;
private final ClassLoader defaultDeserializerClassLoader;
private final boolean usingDefaultDeserializer;
private final Set<String> allowedPatterns = new LinkedHashSet<>();
/**
* Create a {@link AllowListDeserializingConverter} with default
* {@link ObjectInputStream} configuration, using the "latest user-defined
* ClassLoader".
*/
public AllowListDeserializingConverter() {
this(new DefaultDeserializer());
}
/**
* Create a {@link AllowListDeserializingConverter} for using an
* {@link ObjectInputStream} with the given {@code ClassLoader}.
* @param classLoader the class loader to use for deserialization.
*/
public AllowListDeserializingConverter(ClassLoader classLoader) {
this(new DefaultDeserializer(classLoader));
}
/**
* Create a {@link AllowListDeserializingConverter} that delegates to the provided
* {@link Deserializer}.
* @param deserializer the deserializer to use.
*/
public AllowListDeserializingConverter(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 allowedPatterns the patterns.
*/
public void setAllowedPatterns(String... allowedPatterns) {
this.allowedPatterns.clear();
Collections.addAll(this.allowedPatterns, allowedPatterns);
}
/**
* Add package/class patterns to the allow list.
* @param patterns the patterns to add.
* @see #setAllowedPatterns(String...)
*/
public void addAllowedPatterns(String... patterns) {
Collections.addAll(this.allowedPatterns, 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 (Exception 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);
checkAllowList(clazz);
return clazz;
}
};
return objectInputStream.readObject();
}
catch (ClassNotFoundException ex) {
throw new NestedIOException("Failed to deserialize object type", ex);
}
}
protected void checkAllowList(Class<?> clazz) {
if (this.allowedPatterns.isEmpty()) {
return;
}
if (clazz.isArray() || clazz.isPrimitive() || clazz.equals(String.class)
|| Number.class.isAssignableFrom(clazz)) {
return;
}
String className = clazz.getName();
for (String pattern : this.allowedPatterns) {
if (PatternMatchUtils.simpleMatch(pattern, className)) {
return;
}
}
throw new SecurityException("Attempt to deserialize unauthorized " + clazz);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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,23 +16,9 @@
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
@@ -45,18 +31,13 @@ import org.springframework.util.PatternMatchUtils;
* @author Gary Russell
* @author Mark Fisher
* @author Juergen Hoeller
*
* @since 4.2.13
*
* @deprecated since 5.4 in favor of AllowListDeserializingConverter
*/
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>();
@Deprecated
public class WhiteListDeserializingConverter extends AllowListDeserializingConverter {
/**
* Create a {@code WhiteListDeserializingConverter} with default
@@ -64,7 +45,7 @@ public class WhiteListDeserializingConverter implements Converter<byte[], Object
* ClassLoader".
*/
public WhiteListDeserializingConverter() {
this(new DefaultDeserializer());
super();
}
/**
@@ -73,7 +54,7 @@ public class WhiteListDeserializingConverter implements Converter<byte[], Object
* @param classLoader the class loader to use for deserialization.
*/
public WhiteListDeserializingConverter(ClassLoader classLoader) {
this(new DefaultDeserializer(classLoader));
super(classLoader);
}
/**
@@ -82,23 +63,7 @@ public class WhiteListDeserializingConverter implements Converter<byte[], Object
* @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;
}
super(deserializer);
}
/**
@@ -110,8 +75,7 @@ public class WhiteListDeserializingConverter implements Converter<byte[], Object
* @param whiteListPatterns the patterns.
*/
public void setWhiteListPatterns(String... whiteListPatterns) {
this.whiteListPatterns.clear();
Collections.addAll(this.whiteListPatterns, whiteListPatterns);
setAllowedPatterns(whiteListPatterns);
}
/**
@@ -120,63 +84,11 @@ public class WhiteListDeserializingConverter implements Converter<byte[], Object
* @see #setWhiteListPatterns(String...)
*/
public void addWhiteListPatterns(String... patterns) {
Collections.addAll(this.whiteListPatterns, patterns);
addAllowedPatterns(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 (Exception 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);
protected void checkWhiteList(Class<?> clazz) {
checkAllowList(clazz);
}
}

View File

@@ -67,7 +67,7 @@ public final class JacksonJsonUtils {
if (JacksonPresent.isJackson2Present()) {
ObjectMapper mapper = new Jackson2JsonObjectMapper().getObjectMapper();
mapper.setDefaultTyping(new WhitelistTypeResolverBuilder(trustedPackages));
mapper.setDefaultTyping(new AllowlistTypeResolverBuilder(trustedPackages));
GenericMessageJacksonDeserializer genericMessageDeserializer = new GenericMessageJacksonDeserializer();
genericMessageDeserializer.setMapper(mapper);
@@ -98,7 +98,7 @@ public final class JacksonJsonUtils {
/**
* An implementation of {@link ObjectMapper.DefaultTypeResolverBuilder}
* that wraps a default {@link TypeIdResolver} to the {@link WhitelistTypeIdResolver}.
* that wraps a default {@link TypeIdResolver} to the {@link AllowlistTypeIdResolver}.
*
* @author Rob Winch
* @author Artem Bilan
@@ -107,13 +107,13 @@ public final class JacksonJsonUtils {
*
* @since 4.3.11
*/
private static final class WhitelistTypeResolverBuilder extends ObjectMapper.DefaultTypeResolverBuilder {
private static final class AllowlistTypeResolverBuilder extends ObjectMapper.DefaultTypeResolverBuilder {
private static final long serialVersionUID = 1L;
private final String[] trustedPackages;
WhitelistTypeResolverBuilder(String... trustedPackages) {
AllowlistTypeResolverBuilder(String... trustedPackages) {
super(ObjectMapper.DefaultTyping.NON_FINAL,
//we do explicit validation in the TypeIdResolver
BasicPolymorphicTypeValidator.builder()
@@ -133,7 +133,7 @@ public final class JacksonJsonUtils {
PolymorphicTypeValidator subtypeValidator,
Collection<NamedType> subtypes, boolean forSer, boolean forDeser) {
TypeIdResolver result = super.idResolver(config, baseType, subtypeValidator, subtypes, forSer, forDeser);
return new WhitelistTypeIdResolver(result, this.trustedPackages);
return new AllowlistTypeIdResolver(result, this.trustedPackages);
}
}
@@ -148,7 +148,7 @@ public final class JacksonJsonUtils {
*
* @since 4.3.11
*/
private static final class WhitelistTypeIdResolver implements TypeIdResolver {
private static final class AllowlistTypeIdResolver implements TypeIdResolver {
private static final List<String> TRUSTED_PACKAGES =
Arrays.asList(
@@ -164,7 +164,7 @@ public final class JacksonJsonUtils {
private final Set<String> trustedPackages = new LinkedHashSet<>(TRUSTED_PACKAGES);
WhitelistTypeIdResolver(TypeIdResolver delegate, String... trustedPackages) {
AllowlistTypeIdResolver(TypeIdResolver delegate, String... trustedPackages) {
this.delegate = delegate;
if (trustedPackages != null) {
for (String whiteListPackage : trustedPackages) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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.
@@ -17,13 +17,14 @@
package org.springframework.integration.transformer;
import org.springframework.core.serializer.Deserializer;
import org.springframework.integration.support.converter.WhiteListDeserializingConverter;
import org.springframework.integration.support.converter.AllowListDeserializingConverter;
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 WhiteListDeserializingConverter} using Java serialization.
* {@link AllowListDeserializingConverter} using Java serialization.
*
* <p>
* The byte array payload must be a result of equivalent serialization.
@@ -37,30 +38,45 @@ import org.springframework.util.Assert;
public class PayloadDeserializingTransformer extends PayloadTypeConvertingTransformer<byte[], Object> {
/**
* Instantiate based on the {@link WhiteListDeserializingConverter} with the
* Instantiate based on the {@link AllowListDeserializingConverter} with the
* {@link org.springframework.core.serializer.DefaultDeserializer}.
*/
public PayloadDeserializingTransformer() {
doSetConverter(new WhiteListDeserializingConverter());
doSetConverter(new AllowListDeserializingConverter());
}
public void setDeserializer(Deserializer<Object> deserializer) {
setConverter(new WhiteListDeserializingConverter(deserializer));
setConverter(new AllowListDeserializingConverter(deserializer));
}
/**
* When using a {@link WhiteListDeserializingConverter} (the default) add patterns
* When using a {@link AllowListDeserializingConverter} (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
* @deprecated since 5.4 in favor of {@link #setAllowedPatterns(String...)}
*/
@Deprecated
public void setWhiteListPatterns(String... patterns) {
Assert.isTrue(getConverter() instanceof WhiteListDeserializingConverter,
"Patterns can only be provided when using a 'WhiteListDeserializingConverter'");
((WhiteListDeserializingConverter) getConverter()).setWhiteListPatterns(patterns);
setAllowedPatterns(patterns);
}
/**
* When using a {@link AllowListDeserializingConverter} (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 5.4
*/
public void setAllowedPatterns(String... patterns) {
Assert.isTrue(getConverter() instanceof AllowListDeserializingConverter,
"Patterns can only be provided when using a 'AllowListDeserializingConverter'");
((AllowListDeserializingConverter) getConverter()).setAllowedPatterns(patterns);
}
}

View File

@@ -2788,6 +2788,16 @@
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="white-list">
<xsd:annotation>
<xsd:documentation>
[DEPRECATED]
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="allow-list">
<xsd:annotation>
<xsd:documentation>
When using the default Deserializer, a list of package/class patterns indicating

View File

@@ -20,7 +20,7 @@
</channel>
<payload-deserializing-transformer id="direct" input-channel="directInput" output-channel="output"
white-list="*" />
allow-list="*" />
<payload-deserializing-transformer input-channel="queueInput" output-channel="output">
<poller fixed-delay="10000"/>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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.
@@ -17,6 +17,7 @@
package org.springframework.integration.config.xml;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -24,10 +25,10 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.util.Set;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
@@ -39,15 +40,14 @@ import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.PollableChannel;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.springframework.util.FileCopyUtils;
/**
* @author Mark Fisher
* @author Artem Bilan
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@SpringJUnitConfig
public class PayloadDeserializingTransformerParserTests {
@Autowired
@@ -75,8 +75,8 @@ public class PayloadDeserializingTransformerParserTests {
assertThat(result).isNotNull();
assertThat(result.getPayload() instanceof String).isTrue();
assertThat(result.getPayload()).isEqualTo("foo");
Set<?> patterns = TestUtils.getPropertyValue(this.handler, "transformer.converter.whiteListPatterns",
Set.class);
Set<?> patterns =
TestUtils.getPropertyValue(this.handler, "transformer.converter.allowedPatterns", Set.class);
assertThat(patterns.size()).isEqualTo(1);
assertThat(patterns.iterator().next()).isEqualTo("*");
}
@@ -84,7 +84,7 @@ public class PayloadDeserializingTransformerParserTests {
@Test
public void queueChannelWithSerializedStringMessage() throws Exception {
byte[] bytes = serialize("foo");
queueInput.send(new GenericMessage<byte[]>(bytes));
queueInput.send(new GenericMessage<>(bytes));
Message<?> result = output.receive(10000);
assertThat(result).isNotNull();
assertThat(result.getPayload() instanceof String).isTrue();
@@ -94,7 +94,7 @@ public class PayloadDeserializingTransformerParserTests {
@Test
public void directChannelWithSerializedObjectMessage() throws Exception {
byte[] bytes = serialize(new TestBean());
directInput.send(new GenericMessage<byte[]>(bytes));
directInput.send(new GenericMessage<>(bytes));
Message<?> result = output.receive(10000);
assertThat(result).isNotNull();
assertThat(result.getPayload().getClass()).isEqualTo(TestBean.class);
@@ -104,22 +104,23 @@ public class PayloadDeserializingTransformerParserTests {
@Test
public void queueChannelWithSerializedObjectMessage() throws Exception {
byte[] bytes = serialize(new TestBean());
queueInput.send(new GenericMessage<byte[]>(bytes));
queueInput.send(new GenericMessage<>(bytes));
Message<?> result = output.receive(10000);
assertThat(result).isNotNull();
assertThat(result.getPayload().getClass()).isEqualTo(TestBean.class);
assertThat(((TestBean) result.getPayload()).name).isEqualTo("test");
}
@Test(expected = MessageTransformationException.class)
@Test
public void invalidPayload() {
byte[] bytes = new byte[] { 1, 2, 3 };
directInput.send(new GenericMessage<byte[]>(bytes));
byte[] bytes = {1, 2, 3};
assertThatExceptionOfType(MessageTransformationException.class)
.isThrownBy(() -> directInput.send(new GenericMessage<>(bytes)));
}
@Test
public void customDeserializer() throws Exception {
customDeserializerInput.send(new GenericMessage<byte[]>("test".getBytes("UTF-8")));
public void customDeserializer() {
customDeserializerInput.send(new GenericMessage<>("test".getBytes(StandardCharsets.UTF_8)));
Message<?> result = output.receive(10000);
assertThat(result).isNotNull();
assertThat(result.getPayload().getClass()).isEqualTo(String.class);
@@ -151,7 +152,7 @@ public class PayloadDeserializingTransformerParserTests {
@Override
public Object deserialize(InputStream source) throws IOException {
return FileCopyUtils.copyToString(new InputStreamReader(source, "UTF-8")).toUpperCase();
return FileCopyUtils.copyToString(new InputStreamReader(source, StandardCharsets.UTF_8)).toUpperCase();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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.
@@ -17,13 +17,14 @@
package org.springframework.integration.transformer;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.fail;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.Message;
@@ -31,6 +32,7 @@ import org.springframework.messaging.support.GenericMessage;
/**
* @author Mark Fisher
* @author Artem Bilan
*/
public class PayloadDeserializingTransformerTests {
@@ -41,7 +43,7 @@ public class PayloadDeserializingTransformerTests {
objectStream.writeObject("foo");
byte[] serialized = byteStream.toByteArray();
PayloadDeserializingTransformer transformer = new PayloadDeserializingTransformer();
Message<?> result = transformer.transform(new GenericMessage<byte[]>(serialized));
Message<?> result = transformer.transform(new GenericMessage<>(serialized));
Object payload = result.getPayload();
assertThat(payload).isNotNull();
assertThat(payload.getClass()).isEqualTo(String.class);
@@ -56,7 +58,7 @@ public class PayloadDeserializingTransformerTests {
objectStream.writeObject(testBean);
byte[] serialized = byteStream.toByteArray();
PayloadDeserializingTransformer transformer = new PayloadDeserializingTransformer();
Message<?> result = transformer.transform(new GenericMessage<byte[]>(serialized));
Message<?> result = transformer.transform(new GenericMessage<>(serialized));
Object payload = result.getPayload();
assertThat(payload).isNotNull();
assertThat(payload.getClass()).isEqualTo(TestBean.class);
@@ -64,35 +66,36 @@ public class PayloadDeserializingTransformerTests {
}
@Test
public void deserializeObjectWhiteList() throws Exception {
public void deserializeObjectAllowList() 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.*");
transformer.setAllowedPatterns("com.*");
try {
transformer.transform(new GenericMessage<byte[]>(serialized));
transformer.transform(new GenericMessage<>(serialized));
fail("expected security exception");
}
catch (MessageTransformationException e) {
assertThat(e.getCause().getCause()).isInstanceOf(SecurityException.class);
assertThat(e.getCause().getCause().getMessage()).startsWith("Attempt to deserialize unauthorized");
}
transformer.setWhiteListPatterns("org.*");
Message<?> result = transformer.transform(new GenericMessage<byte[]>(serialized));
transformer.setAllowedPatterns("org.*");
Message<?> result = transformer.transform(new GenericMessage<>(serialized));
Object payload = result.getPayload();
assertThat(payload).isNotNull();
assertThat(payload.getClass()).isEqualTo(TestBean.class);
assertThat(((TestBean) payload).name).isEqualTo(testBean.name);
}
@Test(expected = MessageTransformationException.class)
@Test
public void invalidPayload() {
byte[] bytes = new byte[] { 1, 2, 3 };
byte[] bytes = {1, 2, 3};
PayloadDeserializingTransformer transformer = new PayloadDeserializingTransformer();
transformer.transform(new GenericMessage<byte[]>(bytes));
assertThatExceptionOfType(MessageTransformationException.class)
.isThrownBy(() -> transformer.transform(new GenericMessage<>(bytes)));
}
@Test
@@ -111,6 +114,7 @@ public class PayloadDeserializingTransformerTests {
TestBean(String name) {
this.name = name;
}
}
}