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:37 UTC

[httpcomponents-client] branch 4.5.x updated (88abda2 -> 3d09a43)

This is an automated email from the ASF dual-hosted git repository.

olegk pushed a change to branch 4.5.x
in repository https://gitbox.apache.org/repos/asf/httpcomponents-client.git.


 discard 88abda2  Improve Tests for RestrictedObjectInputStream
    omit ed16362  HTTPCLIENT-2023: Allow nested arrays and all primitive types in DefaultHttpCacheEntrySerializer
     new 3d09a43  HTTPCLIENT-2023: Allow nested arrays and all primitive types in DefaultHttpCacheEntrySerializer

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (88abda2)
            \
             N -- N -- N   refs/heads/4.5.x (3d09a43)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:


[httpcomponents-client] 01/01: HTTPCLIENT-2023: Allow nested arrays and all primitive types in DefaultHttpCacheEntrySerializer

Posted by ol...@apache.org.
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);