You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2019/11/08 09:01:38 UTC
[httpcomponents-client] 01/01: HTTPCLIENT-2023: Allow nested arrays
and all primitive types in DefaultHttpCacheEntrySerializer
This is an automated email from the ASF dual-hosted git repository.
olegk pushed a commit to branch 4.5.x
in repository https://gitbox.apache.org/repos/asf/httpcomponents-client.git
commit 3d09a430085eb05c4121ac619562daff33c43498
Author: Olof Larsson <ol...@sylt.nu>
AuthorDate: Wed Nov 6 18:02:20 2019 +0100
HTTPCLIENT-2023: Allow nested arrays and all primitive types in DefaultHttpCacheEntrySerializer
---
.../cache/DefaultHttpCacheEntrySerializer.java | 61 ++++---
.../cache/TestHttpCacheEntrySerializers.java | 193 ++++++++++++++++++---
2 files changed, 203 insertions(+), 51 deletions(-)
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/DefaultHttpCacheEntrySerializer.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/DefaultHttpCacheEntrySerializer.java
index 806b194..4751576 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/DefaultHttpCacheEntrySerializer.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/DefaultHttpCacheEntrySerializer.java
@@ -54,22 +54,6 @@ import org.apache.http.client.cache.HttpCacheEntrySerializer;
@Contract(threading = ThreadingBehavior.IMMUTABLE)
public class DefaultHttpCacheEntrySerializer implements HttpCacheEntrySerializer {
- private static final List<Pattern> ALLOWED_CLASS_PATTERNS = Collections.unmodifiableList(Arrays.asList(
- Pattern.compile("^(\\[L)?org\\.apache\\.http\\.(.*)"),
- Pattern.compile("^(\\[L)?java\\.util\\.(.*)"),
- Pattern.compile("^(\\[L)?java\\.lang\\.(.*)$"),
- Pattern.compile("^\\[B$")));
-
- private final List<Pattern> allowedClassPatterns;
-
- DefaultHttpCacheEntrySerializer(final Pattern... allowedClassPatterns) {
- this.allowedClassPatterns = Collections.unmodifiableList(Arrays.asList(allowedClassPatterns));
- }
-
- public DefaultHttpCacheEntrySerializer() {
- this.allowedClassPatterns = ALLOWED_CLASS_PATTERNS;
- }
-
@Override
public void writeTo(final HttpCacheEntry cacheEntry, final OutputStream os) throws IOException {
final ObjectOutputStream oos = new ObjectOutputStream(os);
@@ -82,7 +66,7 @@ public class DefaultHttpCacheEntrySerializer implements HttpCacheEntrySerializer
@Override
public HttpCacheEntry readFrom(final InputStream is) throws IOException {
- final ObjectInputStream ois = new RestrictedObjectInputStream(is, allowedClassPatterns);
+ final ObjectInputStream ois = new RestrictedObjectInputStream(is);
try {
return (HttpCacheEntry) ois.readObject();
} catch (final ClassNotFoundException ex) {
@@ -92,32 +76,47 @@ public class DefaultHttpCacheEntrySerializer implements HttpCacheEntrySerializer
}
}
- private static class RestrictedObjectInputStream extends ObjectInputStream {
+ // visible for testing
+ static class RestrictedObjectInputStream extends ObjectInputStream {
- private final List<Pattern> allowedClassPatterns;
+ private static final List<Pattern> ALLOWED_CLASS_PATTERNS = Collections.unmodifiableList(Arrays.asList(
+ Pattern.compile("^(?:\\[+L)?org\\.apache\\.http\\..*$"),
+ Pattern.compile("^(?:\\[+L)?java\\.util\\..*$"),
+ Pattern.compile("^(?:\\[+L)?java\\.lang\\..*$"),
+ Pattern.compile("^\\[+Z$"), // boolean
+ Pattern.compile("^\\[+B$"), // byte
+ Pattern.compile("^\\[+C$"), // char
+ Pattern.compile("^\\[+D$"), // double
+ Pattern.compile("^\\[+F$"), // float
+ Pattern.compile("^\\[+I$"), // int
+ Pattern.compile("^\\[+J$"), // long
+ Pattern.compile("^\\[+S$") // short
+ ));
- private RestrictedObjectInputStream(final InputStream in, final List<Pattern> patterns) throws IOException {
+ private RestrictedObjectInputStream(final InputStream in) throws IOException {
super(in);
- this.allowedClassPatterns = patterns;
}
@Override
- protected Class<?> resolveClass(final ObjectStreamClass desc) throws IOException, ClassNotFoundException {
- if (isProhibited(desc)) {
- throw new HttpCacheEntrySerializationException(String.format(
- "Class %s is not allowed for deserialization", desc.getName()));
+ protected Class<?> resolveClass(final ObjectStreamClass objectStreamClass) throws IOException, ClassNotFoundException {
+ final String className = objectStreamClass.getName();
+ if (!isAllowedClassName(className)) {
+ final String message = String.format("Class %s is not allowed for deserialization", className);
+ throw new HttpCacheEntrySerializationException(message);
}
- return super.resolveClass(desc);
+ return super.resolveClass(objectStreamClass);
}
- private boolean isProhibited(final ObjectStreamClass desc) {
- for (final Pattern pattern : allowedClassPatterns) {
- if (pattern.matcher(desc.getName()).matches()) {
- return false;
+ // visible for testing
+ static boolean isAllowedClassName(final String className) {
+ for (final Pattern allowedClassPattern : ALLOWED_CLASS_PATTERNS) {
+ if (allowedClassPattern.matcher(className).matches()) {
+ return true;
}
}
- return true;
+ return false;
}
+
}
}
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestHttpCacheEntrySerializers.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestHttpCacheEntrySerializers.java
index fd48dd2..83c7681 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestHttpCacheEntrySerializers.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestHttpCacheEntrySerializers.java
@@ -26,6 +26,7 @@
*/
package org.apache.http.impl.client.cache;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
@@ -38,7 +39,6 @@ import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
-import java.util.regex.Pattern;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.Header;
@@ -72,25 +72,182 @@ public class TestHttpCacheEntrySerializers {
readWriteVerify(makeCacheEntryWithVariantMap());
}
- @Test(expected = HttpCacheEntrySerializationException.class)
- public void throwExceptionIfUnsafeDeserialization() throws IOException {
- impl.readFrom(new ByteArrayInputStream(serializeProhibitedObject()));
+ @Test
+ public void isAllowedClassNameStringTrue() {
+ assertIsAllowedClassNameTrue(String.class.getName());
}
- @Test(expected = HttpCacheEntrySerializationException.class)
- public void allowClassesToBeDeserialized() throws IOException {
- impl = new DefaultHttpCacheEntrySerializer(
- Pattern.compile("javax.sql.rowset.BaseRowSet"),
- Pattern.compile("com.sun.rowset.JdbcRowSetImpl"));
- readVerify(serializeProhibitedObject());
+ @Test
+ public void isAllowedClassNameStringArrayTrue() {
+ assertIsAllowedClassNameTrue("[L" + String.class.getName());
+ }
+
+ @Test
+ public void isAllowedClassNameStringArrayArrayTrue() {
+ assertIsAllowedClassNameTrue("[[L" + String.class.getName());
+ }
+
+ @Test
+ public void isAllowedClassNameDataTrue() {
+ assertIsAllowedClassNameTrue(Date.class.getName());
+ }
+
+ @Test
+ public void isAllowedClassNameStatusLineTrue() {
+ assertIsAllowedClassNameTrue(StatusLine.class.getName());
+ }
+
+ @Test
+ public void isAllowedClassNameResourceTrue() {
+ assertIsAllowedClassNameTrue(Resource.class.getName());
+ }
+
+ @Test
+ public void isAllowedClassNameByteArrayTrue() {
+ assertIsAllowedClassNameTrue("[B");
+ }
+
+ @Test
+ public void isAllowedClassNameByteArrayArrayTrue() {
+ assertIsAllowedClassNameTrue("[[B");
+ }
+
+ @Test
+ public void isAllowedClassNameCharArrayTrue() {
+ assertIsAllowedClassNameTrue("[C");
+ }
+
+ @Test
+ public void isAllowedClassNameCharArrayArrayTrue() {
+ assertIsAllowedClassNameTrue("[[C");
+ }
+
+ @Test
+ public void isAllowedClassNameDoubleArrayTrue() {
+ assertIsAllowedClassNameTrue("[D");
+ }
+
+ @Test
+ public void isAllowedClassNameDoubleArrayArrayTrue() {
+ assertIsAllowedClassNameTrue("[[D");
+ }
+
+ @Test
+ public void isAllowedClassNameFloatArrayTrue() {
+ assertIsAllowedClassNameTrue("[F");
+ }
+
+ @Test
+ public void isAllowedClassNameFloatArrayArrayTrue() {
+ assertIsAllowedClassNameTrue("[[F");
+ }
+
+ @Test
+ public void isAllowedClassNameIntArrayTrue() {
+ assertIsAllowedClassNameTrue("[I");
+ }
+
+ @Test
+ public void isAllowedClassNameIntArrayArrayTrue() {
+ assertIsAllowedClassNameTrue("[[I");
+ }
+
+ @Test
+ public void isAllowedClassNameLongArrayTrue() {
+ assertIsAllowedClassNameTrue("[J");
+ }
+
+ @Test
+ public void isAllowedClassNameLongArrayArrayTrue() {
+ assertIsAllowedClassNameTrue("[[J");
+ }
+
+ @Test
+ public void isAllowedClassNameShortArrayTrue() {
+ assertIsAllowedClassNameTrue("[S");
+ }
+
+ @Test
+ public void isAllowedClassNameShortArrayArrayTrue() {
+ assertIsAllowedClassNameTrue("[[S");
+ }
+
+ @Test
+ public void isAllowedClassNameCollectionsInvokerTransformerFalse() {
+ assertIsAllowedClassNameFalse("org.apache.commons.collections.functors.InvokerTransformer");
+ }
+
+ @Test
+ public void isAllowedClassNameCollections4InvokerTransformerFalse() {
+ assertIsAllowedClassNameFalse("org.apache.commons.collections4.functors.InvokerTransformer");
+ }
+
+ @Test
+ public void isAllowedClassNameCollectionsInstantiateTransformerFalse() {
+ assertIsAllowedClassNameFalse("org.apache.commons.collections.functors.InstantiateTransformer");
+ }
+
+ @Test
+ public void isAllowedClassNameCollections4InstantiateTransformerFalse() {
+ assertIsAllowedClassNameFalse("org.apache.commons.collections4.functors.InstantiateTransformer");
+ }
+
+ @Test
+ public void isAllowedClassNameGroovyConvertedClosureFalse() {
+ assertIsAllowedClassNameFalse("org.codehaus.groovy.runtime.ConvertedClosure");
+ }
+
+ @Test
+ public void isAllowedClassNameGroovyMethodClosureFalse() {
+ assertIsAllowedClassNameFalse("org.codehaus.groovy.runtime.MethodClosure");
+ }
+
+ @Test
+ public void isAllowedClassNameSpringObjectFactoryFalse() {
+ assertIsAllowedClassNameFalse("org.springframework.beans.factory.ObjectFactory");
+ }
+
+ @Test
+ public void isAllowedClassNameCalanTemplatesImplFalse() {
+ assertIsAllowedClassNameFalse("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
+ }
+
+ @Test
+ public void isAllowedClassNameCalanTemplatesImplArrayFalse() {
+ assertIsAllowedClassNameFalse("[Lcom.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
+ }
+
+ @Test
+ public void isAllowedClassNameJavaRmiRegistryFalse() {
+ assertIsAllowedClassNameFalse("java.rmi.registry.Registry");
+ }
+
+ @Test
+ public void isAllowedClassNameJavaRmiServerRemoteObjectInvocationHandlerFalse() {
+ assertIsAllowedClassNameFalse("java.rmi.server.RemoteObjectInvocationHandler");
+ }
+
+ @Test
+ public void isAllowedClassNameJavaxXmlTransformTemplatesFalse() {
+ assertIsAllowedClassNameFalse("javax.xml.transform.Templates");
+ }
+
+ @Test
+ public void isAllowedClassNameJavaxManagementMBeanServerInvocationHandlerFalse() {
+ assertIsAllowedClassNameFalse("javax.management.MBeanServerInvocationHandler");
+ }
+
+ private static void assertIsAllowedClassNameTrue(final String className) {
+ assertTrue(DefaultHttpCacheEntrySerializer.RestrictedObjectInputStream.isAllowedClassName(className));
+ }
+
+ private static void assertIsAllowedClassNameFalse(final String className) {
+ assertFalse(DefaultHttpCacheEntrySerializer.RestrictedObjectInputStream.isAllowedClassName(className));
}
@Test(expected = HttpCacheEntrySerializationException.class)
- public void allowClassesToBeDeserializedByRegex() throws IOException {
- impl = new DefaultHttpCacheEntrySerializer(
- Pattern.compile(("^com\\.sun\\.rowset\\.(.*)")),
- Pattern.compile("^javax\\.sql\\.rowset\\.BaseRowSet$"));
- readVerify(serializeProhibitedObject());
+ public void throwExceptionIfUnsafeDeserialization() throws IOException {
+ impl.readFrom(new ByteArrayInputStream(serializeProhibitedObject()));
}
private byte[] serializeProhibitedObject() throws IOException {
@@ -105,11 +262,7 @@ public class TestHttpCacheEntrySerializers {
return baos.toByteArray();
}
- private void readVerify(final byte[] data) throws IOException {
- impl.readFrom(new ByteArrayInputStream(data));
- }
-
- public void readWriteVerify(final HttpCacheEntry writeEntry) throws IOException {
+ private void readWriteVerify(final HttpCacheEntry writeEntry) throws IOException {
// write the entry
final ByteArrayOutputStream out = new ByteArrayOutputStream();
impl.writeTo(writeEntry, out);