Author: kwall
Date: Mon Jun 27 15:39:55 2016
New Revision: 1750361

URL: http://svn.apache.org/viewvc?rev=1750361&view=rev
Log:
QPID-7323: [Java Client] Improvements to the ObjectMessage implementation

Merged from trunk with command:

svn merge -c 1750359,1750360 ^/qpid/java/trunk


Added:
    
qpid/java/branches/6.0.x/client/src/test/java/org/apache/qpid/client/util/SimplePojo.java
      - copied unchanged from r1750359, 
qpid/java/trunk/client/src/test/java/org/apache/qpid/client/util/SimplePojo.java
    
qpid/java/branches/6.0.x/systests/src/test/java/org/apache/qpid/client/message/JmsObjectMessageTest.java
      - copied unchanged from r1750359, 
qpid/java/trunk/systests/src/test/java/org/apache/qpid/client/message/JmsObjectMessageTest.java
Modified:
    qpid/java/branches/6.0.x/   (props changed)
    
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/AMQConnection.java
    
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/AMQSession.java
    
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java
    
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessageFactory.java
    
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.java
    
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/util/ClassLoadingAwareObjectInputStream.java
    
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java
    
qpid/java/branches/6.0.x/client/src/test/java/org/apache/qpid/client/message/TestMessageHelper.java
    
qpid/java/branches/6.0.x/client/src/test/java/org/apache/qpid/client/util/ClassLoadingAwareObjectInputStreamTest.java
    
qpid/java/branches/6.0.x/common/src/main/java/org/apache/qpid/configuration/CommonProperties.java

Propchange: qpid/java/branches/6.0.x/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon Jun 27 15:39:55 2016
@@ -9,5 +9,5 @@
 /qpid/branches/java-broker-vhost-refactor/java:1493674-1494547
 /qpid/branches/java-network-refactor/qpid/java:805429-821809
 /qpid/branches/qpid-2935/qpid/java:1061302-1072333
-/qpid/java/trunk:1715445-1715447,1715586,1715940,1716086-1716087,1716127-1716128,1716141,1716153,1716155,1716194,1716204,1716209,1716227,1716277,1716357,1716368,1716370,1716374,1716432,1716444-1716445,1716455,1716461,1716474,1716489,1716497,1716515,1716555,1716602,1716606-1716610,1716619,1716636,1717269,1717299,1717401,1717446,1717449,1717626,1717691,1717735,1717780,1718744,1718889,1718893,1718918,1718922,1719026,1719028,1719033,1719037,1719047,1719051,1720340,1720664,1721151,1721198,1722019-1722020,1722246,1722339,1722416,1722674,1722678,1722683,1722711,1723064,1723194,1723563,1724216,1724251,1724257,1724292,1724375,1724397,1724432,1724582,1724603,1724780,1724843-1724844,1725295,1725569,1725760,1726176,1726244-1726246,1726249,1726358,1726436,1726449,1726456,1726646,1726653,1726755,1726778,1727532,1727555,1727608,1727951,1727954,1728089,1728167,1728302,1728497,1728501,1728524,1728639,1728651,1728772,1729215,1729297,1729347,1729356,1729406,1729408,1729412,1729515,1729638,1729656-1729
 
657,1729783,1729828,1729832,1729841,1729851,1729886,1729904,1729973,1730019,1730025,1730052,1730072,1730088,1730494,1730499,1730547,1730559,1730567,1730578,1730585,1730651,1730697,1730712-1730713,1730805,1731029,1731110,1731210,1731225,1731444,1731551,1731612,1732184,1732452,1732461,1732465,1732525,1732812,1733467,1734452,1736478,1736751,1736838,1737804,1737835,1737853,1737984,1737992,1738119,1738135,1738231,1738271,1738607,1738610,1738731,1738914,1741702,1742257,1742284,1742544,1742900,1742926,1743161,1743228,1743383,1743982,1744012-1744013,1744046,1744123,1744157,1744276,1744403,1745424,1745450,1746140,1746273,1747526,1748254,1748723,1748818,1749349,1749399,1749482,1749524
+/qpid/java/trunk:1715445-1715447,1715586,1715940,1716086-1716087,1716127-1716128,1716141,1716153,1716155,1716194,1716204,1716209,1716227,1716277,1716357,1716368,1716370,1716374,1716432,1716444-1716445,1716455,1716461,1716474,1716489,1716497,1716515,1716555,1716602,1716606-1716610,1716619,1716636,1717269,1717299,1717401,1717446,1717449,1717626,1717691,1717735,1717780,1718744,1718889,1718893,1718918,1718922,1719026,1719028,1719033,1719037,1719047,1719051,1720340,1720664,1721151,1721198,1722019-1722020,1722246,1722339,1722416,1722674,1722678,1722683,1722711,1723064,1723194,1723563,1724216,1724251,1724257,1724292,1724375,1724397,1724432,1724582,1724603,1724780,1724843-1724844,1725295,1725569,1725760,1726176,1726244-1726246,1726249,1726358,1726436,1726449,1726456,1726646,1726653,1726755,1726778,1727532,1727555,1727608,1727951,1727954,1728089,1728167,1728302,1728497,1728501,1728524,1728639,1728651,1728772,1729215,1729297,1729347,1729356,1729406,1729408,1729412,1729515,1729638,1729656-1729
 
657,1729783,1729828,1729832,1729841,1729851,1729886,1729904,1729973,1730019,1730025,1730052,1730072,1730088,1730494,1730499,1730547,1730559,1730567,1730578,1730585,1730651,1730697,1730712-1730713,1730805,1731029,1731110,1731210,1731225,1731444,1731551,1731612,1732184,1732452,1732461,1732465,1732525,1732812,1733467,1734452,1736478,1736751,1736838,1737804,1737835,1737853,1737984,1737992,1738119,1738135,1738231,1738271,1738607,1738610,1738731,1738914,1741702,1742257,1742284,1742544,1742900,1742926,1743161,1743228,1743383,1743982,1744012-1744013,1744046,1744123,1744157,1744276,1744403,1745424,1745450,1746140,1746273,1747526,1748254,1748723,1748818,1749349,1749399,1749482,1749524,1750359-1750360
 /qpid/trunk/qpid:796646-796653

Modified: 
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/AMQConnection.java
URL: 
http://svn.apache.org/viewvc/qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/AMQConnection.java?rev=1750361&r1=1750360&r2=1750361&view=diff
==============================================================================
--- 
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/AMQConnection.java
 (original)
+++ 
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/AMQConnection.java
 Mon Jun 27 15:39:55 2016
@@ -32,6 +32,7 @@ import java.security.KeyStore;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashMap;
@@ -58,6 +59,7 @@ import javax.naming.Referenceable;
 import javax.naming.StringRefAddr;
 
 import org.apache.qpid.client.state.AMQState;
+import org.apache.qpid.client.util.ClassLoadingAwareObjectInputStream;
 import org.apache.qpid.jndi.ObjectFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -86,7 +88,8 @@ import org.apache.qpid.protocol.AMQConst
 import org.apache.qpid.transport.ConnectionSettings;
 import org.apache.qpid.url.URLSyntaxException;
 
-public class AMQConnection extends Closeable implements CommonConnection, 
Referenceable
+public class AMQConnection extends Closeable implements CommonConnection, 
Referenceable,
+                                                        
ClassLoadingAwareObjectInputStream.TrustedClassFilter
 {
     public static final String JNDI_ADDRESS_CONNECTION_URL = "connectionURL";
 
@@ -103,6 +106,9 @@ public class AMQConnection extends Close
 
     private final long _connectionNumber = 
CONN_NUMBER_GENERATOR.incrementAndGet();
 
+    private final List<String> _whiteListedClassHierarchies;
+    private final List<String> _blackListedClassHierarchies;
+
     /**
      * This is the "root" mutex that must be held when doing anything that 
could be impacted by failover. This must be
      * held by any child objects of this connection such as the session, 
producers and consumers.
@@ -485,6 +491,28 @@ public class AMQConnection extends Close
         }
 
         _connectionMetaData = new QpidConnectionMetaData();
+
+        if 
(connectionURL.getOption(ConnectionURL.OPTIONS_OBJECT_MESSAGE_CLASS_HIERARCHY_WHITE_LIST)
 != null)
+        {
+            String whiteListedClassHierarchiesString = 
connectionURL.getOption(ConnectionURL.OPTIONS_OBJECT_MESSAGE_CLASS_HIERARCHY_WHITE_LIST);
+            _whiteListedClassHierarchies = 
Arrays.asList(whiteListedClassHierarchiesString.split(","));
+        }
+        else
+        {
+            final String defaultWhiteListedClassHierarchiesString = 
System.getProperty(CommonProperties.QPID_SECURITY_OBJECT_MESSAGE_CLASS_HIERARCHY_WHITE_LIST,
 "*");
+            _whiteListedClassHierarchies = 
Arrays.asList(defaultWhiteListedClassHierarchiesString.split(","));
+        }
+
+        if 
(connectionURL.getOption(ConnectionURL.OPTIONS_OBJECT_MESSAGE_CLASS_HIERARCHY_BLACK_LIST)
 != null)
+        {
+            String blackListedClassHierarchiesString = 
connectionURL.getOption(ConnectionURL.OPTIONS_OBJECT_MESSAGE_CLASS_HIERARCHY_BLACK_LIST);
+            _blackListedClassHierarchies = 
Arrays.asList(blackListedClassHierarchiesString.split(","));
+        }
+        else
+        {
+            final String defaultBlackListedClassHierarchiesString = 
System.getProperty(CommonProperties.QPID_SECURITY_OBJECT_MESSAGE_CLASS_HIERARCHY_BLACK_LIST,
 "");
+            _blackListedClassHierarchies = 
Arrays.asList(defaultBlackListedClassHierarchiesString.split(","));
+        }
     }
 
     private void makeConnection() throws QpidException
@@ -1917,4 +1945,55 @@ public class AMQConnection extends Close
     {
         return _connectionSettings;
     }
+
+    @Override
+    public boolean isTrusted(Class<?> clazz)
+    {
+        while (clazz.isArray())
+        {
+            clazz = clazz.getComponentType();
+        }
+
+        if (clazz.isPrimitive())
+        {
+            return true;
+        }
+
+        while (clazz != null && (clazz.isAnonymousClass() || 
clazz.isLocalClass()))
+        {
+            clazz = clazz.getEnclosingClass();
+        }
+
+        if (clazz == null || clazz.getCanonicalName() == null)
+        {
+            return false;
+        }
+
+        String className = clazz.getCanonicalName();
+
+        for (String blackListedClassHierarchy : _blackListedClassHierarchies)
+        {
+            if ("*".equals(blackListedClassHierarchy))
+            {
+                return false;
+            }
+            else if (className != null && 
(className.equals(blackListedClassHierarchy) || 
className.startsWith(blackListedClassHierarchy + ".")))
+            {
+                return false;
+            }
+        }
+
+        for (String whiteListedClassHierarchy : _whiteListedClassHierarchies)
+        {
+            if ("*".equals(whiteListedClassHierarchy))
+            {
+                return true;
+            }
+            else if (className != null && 
(className.equals(whiteListedClassHierarchy) || 
className.startsWith(whiteListedClassHierarchy + ".")))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
 }

Modified: 
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/AMQSession.java
URL: 
http://svn.apache.org/viewvc/qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/AMQSession.java?rev=1750361&r1=1750360&r2=1750361&view=diff
==============================================================================
--- 
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/AMQSession.java
 (original)
+++ 
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/AMQSession.java
 Mon Jun 27 15:39:55 2016
@@ -1252,7 +1252,7 @@ public abstract class AMQSession<C exten
     public ObjectMessage createObjectMessage() throws JMSException
     {
         checkNotClosed();
-         JMSObjectMessage msg = new 
JMSObjectMessage(getMessageDelegateFactory());
+         JMSObjectMessage msg = new JMSObjectMessage(getAMQConnection(), 
getMessageDelegateFactory());
          msg.setAMQSession(this);
          return msg;
     }

Modified: 
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java
URL: 
http://svn.apache.org/viewvc/qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java?rev=1750361&r1=1750360&r2=1750361&view=diff
==============================================================================
--- 
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java
 (original)
+++ 
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java
 Mon Jun 27 15:39:55 2016
@@ -38,6 +38,7 @@ public class JMSObjectMessage extends Ab
 {
     public static final String MIME_TYPE = "application/java-object-stream";
     private static final int DEFAULT_OUTPUT_BUFFER_SIZE = 256;
+    private final ClassLoadingAwareObjectInputStream.TrustedClassFilter 
_trustedClassFilter;
 
     private Serializable _readData;
     private ByteBuffer _data;
@@ -51,18 +52,20 @@ public class JMSObjectMessage extends Ab
      * Creates empty, writable message for use by producers
      * @param delegateFactory
      */
-    public JMSObjectMessage(AMQMessageDelegateFactory delegateFactory)
+    public JMSObjectMessage(final 
ClassLoadingAwareObjectInputStream.TrustedClassFilter trustedClassFilter, 
AMQMessageDelegateFactory delegateFactory)
     {
         super(delegateFactory, false);
+        _trustedClassFilter = trustedClassFilter;
     }
 
     /**
      * Creates read only message for delivery to consumers
      */
 
-      JMSObjectMessage(AMQMessageDelegate delegate, final ByteBuffer data) 
throws QpidException
+      JMSObjectMessage(final 
ClassLoadingAwareObjectInputStream.TrustedClassFilter trustedClassFilter, 
AMQMessageDelegate delegate, final ByteBuffer data) throws QpidException
       {
           super(delegate, data!=null);
+          _trustedClassFilter = trustedClassFilter;
 
           try
           {
@@ -193,15 +196,11 @@ public class JMSObjectMessage extends Ab
         Serializable result = null;
         if (data != null && data.hasRemaining())
         {
-            ClassLoadingAwareObjectInputStream in = new 
ClassLoadingAwareObjectInputStream(new ByteBufferInputStream(data));
-            try
+            try (ClassLoadingAwareObjectInputStream in = new 
ClassLoadingAwareObjectInputStream(new ByteBufferInputStream(data),
+                                                                               
                 _trustedClassFilter))
             {
                 result = (Serializable) in.readObject();
             }
-            finally
-            {
-                in.close();
-            }
         }
         return result;
     }

Modified: 
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessageFactory.java
URL: 
http://svn.apache.org/viewvc/qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessageFactory.java?rev=1750361&r1=1750360&r2=1750361&view=diff
==============================================================================
--- 
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessageFactory.java
 (original)
+++ 
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessageFactory.java
 Mon Jun 27 15:39:55 2016
@@ -21,15 +21,23 @@
 package org.apache.qpid.client.message;
 
 import org.apache.qpid.QpidException;
+import org.apache.qpid.client.util.ClassLoadingAwareObjectInputStream;
 
 import java.nio.ByteBuffer;
 
 public class JMSObjectMessageFactory extends AbstractJMSMessageFactory
 {
+    private final ClassLoadingAwareObjectInputStream.TrustedClassFilter 
_trustedClassFilter;
+
+    public JMSObjectMessageFactory(final 
ClassLoadingAwareObjectInputStream.TrustedClassFilter trustedClassFilter)
+    {
+        _trustedClassFilter = trustedClassFilter;
+    }
+
     protected AbstractJMSMessage createMessage(AbstractAMQMessageDelegate 
delegate, ByteBuffer data) throws
                                                                                
                      QpidException
     {
-        return new JMSObjectMessage(delegate, data);
+        return new JMSObjectMessage(_trustedClassFilter, delegate, data);
     }
 
 }

Modified: 
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.java
URL: 
http://svn.apache.org/viewvc/qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.java?rev=1750361&r1=1750360&r2=1750361&view=diff
==============================================================================
--- 
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.java
 (original)
+++ 
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.java
 Mon Jun 27 15:39:55 2016
@@ -71,7 +71,7 @@ public class MessageFactoryRegistry
         mf.registerFactory("text/plain", new JMSTextMessageFactory());
         mf.registerFactory("text/xml", new JMSTextMessageFactory());
         mf.registerFactory(JMSBytesMessage.MIME_TYPE, new 
JMSBytesMessageFactory());
-        mf.registerFactory(JMSObjectMessage.MIME_TYPE, new 
JMSObjectMessageFactory());
+        mf.registerFactory(JMSObjectMessage.MIME_TYPE, new 
JMSObjectMessageFactory(session.getAMQConnection()));
         mf.registerFactory(JMSStreamMessage.MIME_TYPE, new 
JMSStreamMessageFactory());
         mf.registerFactory(AMQPEncodedMapMessage.MIME_TYPE, new 
AMQPEncodedMapMessageFactory());
         mf.registerFactory(AMQPEncodedListMessage.MIME_TYPE, new 
AMQPEncodedListMessageFactory());

Modified: 
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/util/ClassLoadingAwareObjectInputStream.java
URL: 
http://svn.apache.org/viewvc/qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/util/ClassLoadingAwareObjectInputStream.java?rev=1750361&r1=1750360&r2=1750361&view=diff
==============================================================================
--- 
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/util/ClassLoadingAwareObjectInputStream.java
 (original)
+++ 
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/client/util/ClassLoadingAwareObjectInputStream.java
 Mon Jun 27 15:39:55 2016
@@ -44,11 +44,21 @@ public class ClassLoadingAwareObjectInpu
 
     /** <p>Maps primitive type names to corresponding class objects.</p> */
     private static final HashMap<String, Class> _primitives = new 
HashMap<String, Class>(8, 1.0F);
+    private final TrustedClassFilter _securityFilter;
 
+    /**
+     * Security Filter used to filter classes that the application deems to be 
insecure, this filter
+     * is not applied to the class instances for the primitive types.
+     */
+    public interface TrustedClassFilter
+    {
+        boolean isTrusted(Class<?> clazz);
+    }
 
-    public ClassLoadingAwareObjectInputStream(InputStream in) throws 
IOException
+    public ClassLoadingAwareObjectInputStream(InputStream in, 
TrustedClassFilter filter) throws IOException
     {
         super(in);
+        _securityFilter = filter;
     }
 
     @Override
@@ -58,8 +68,8 @@ public class ClassLoadingAwareObjectInpu
 
         // Here we use TTCL as our primary class loader to load the classes
         ClassLoader cl = Thread.currentThread().getContextClassLoader();
-
-        return load(classDesc.getName(), cl);
+        Class<?> clazz = load(classDesc.getName(), cl);
+        return checkSecurity(clazz);
     }
 
     @Override
@@ -75,14 +85,47 @@ public class ClassLoadingAwareObjectInpu
             cinterfaces[i] = load(interfaces[i], cl);
         }
 
+
+        Class<?> clazz = null;
+        Throwable failureCause = null;
+
         try
         {
-            return Proxy.getProxyClass(cinterfaces[0].getClassLoader(), 
cinterfaces);
+            clazz = Proxy.getProxyClass(cl, cinterfaces);
         }
         catch (IllegalArgumentException e)
         {
-            throw new ClassNotFoundException(null, e);
+            failureCause = e;
+
+            try
+            {
+                clazz = Proxy.getProxyClass(_ON_FAULT_CLASS_LOADER, 
cinterfaces);
+            }
+            catch (IllegalArgumentException e2)
+            {
+            }
         }
+
+        if (clazz != null)
+        {
+            return checkSecurity(clazz);
+        }
+
+        throw new ClassNotFoundException("Failed find class.", failureCause);
+    }
+
+    private Class<?> checkSecurity(Class<?> clazz) throws 
ClassNotFoundException
+    {
+        if (!clazz.isPrimitive() && _securityFilter != null)
+        {
+            if (!_securityFilter.isTrusted(clazz))
+            {
+                throw new ClassNotFoundException("Forbidden " + clazz + "! " +
+                                                 "This class is not trusted to 
be deserialized from ObjectMessage payloads.");
+            }
+        }
+
+        return clazz;
     }
 
     /**

Modified: 
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java
URL: 
http://svn.apache.org/viewvc/qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java?rev=1750361&r1=1750360&r2=1750361&view=diff
==============================================================================
--- 
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java
 (original)
+++ 
qpid/java/branches/6.0.x/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java
 Mon Jun 27 15:39:55 2016
@@ -81,12 +81,13 @@ public interface ConnectionURL
     String OPTIONS_TEMPORARY_TOPIC_EXCHANGE = "temporaryTopicExchange";
     String OPTIONS_TEMPORARY_QUEUE_EXCHANGE = "temporaryQueueExchange";
     String OPTIONS_VERIFY_QUEUE_ON_SEND = "verifyQueueOnSend";
+    String OPTIONS_OBJECT_MESSAGE_CLASS_HIERARCHY_WHITE_LIST = 
"objectMessageClassHierarchyWhiteList";
+    String OPTIONS_OBJECT_MESSAGE_CLASS_HIERARCHY_BLACK_LIST = 
"objectMessageClassHierarchyBlackList";
 
     /**
      * This option specifies whether User-ID should be attached to each 
message sent over the connection
      */
     String OPTIONS_POPULATE_USER_ID = "populateJMSXUserID";
-
     byte  URL_0_8 = 1;
     byte  URL_0_10 = 2;
 

Modified: 
qpid/java/branches/6.0.x/client/src/test/java/org/apache/qpid/client/message/TestMessageHelper.java
URL: 
http://svn.apache.org/viewvc/qpid/java/branches/6.0.x/client/src/test/java/org/apache/qpid/client/message/TestMessageHelper.java?rev=1750361&r1=1750360&r2=1750361&view=diff
==============================================================================
--- 
qpid/java/branches/6.0.x/client/src/test/java/org/apache/qpid/client/message/TestMessageHelper.java
 (original)
+++ 
qpid/java/branches/6.0.x/client/src/test/java/org/apache/qpid/client/message/TestMessageHelper.java
 Mon Jun 27 15:39:55 2016
@@ -22,6 +22,8 @@ package org.apache.qpid.client.message;
 
 import javax.jms.JMSException;
 
+import org.apache.qpid.client.util.ClassLoadingAwareObjectInputStream;
+
 public class TestMessageHelper
 {
     public static JMSTextMessage newJMSTextMessage() throws JMSException
@@ -46,6 +48,13 @@ public class TestMessageHelper
 
     public static JMSObjectMessage newJMSObjectMessage()
     {
-        return new JMSObjectMessage(AMQMessageDelegateFactory.FACTORY_0_8);
+        return new JMSObjectMessage(new 
ClassLoadingAwareObjectInputStream.TrustedClassFilter()
+        {
+            @Override
+            public boolean isTrusted(final Class<?> clazz)
+            {
+                return true;
+            }
+        }, AMQMessageDelegateFactory.FACTORY_0_8);
     }
 }

Modified: 
qpid/java/branches/6.0.x/client/src/test/java/org/apache/qpid/client/util/ClassLoadingAwareObjectInputStreamTest.java
URL: 
http://svn.apache.org/viewvc/qpid/java/branches/6.0.x/client/src/test/java/org/apache/qpid/client/util/ClassLoadingAwareObjectInputStreamTest.java?rev=1750361&r1=1750360&r2=1750361&view=diff
==============================================================================
--- 
qpid/java/branches/6.0.x/client/src/test/java/org/apache/qpid/client/util/ClassLoadingAwareObjectInputStreamTest.java
 (original)
+++ 
qpid/java/branches/6.0.x/client/src/test/java/org/apache/qpid/client/util/ClassLoadingAwareObjectInputStreamTest.java
 Mon Jun 27 15:39:55 2016
@@ -20,17 +20,41 @@
  */
 package org.apache.qpid.client.util;
 
-import org.apache.qpid.test.utils.QpidTestCase;
-
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.ObjectOutputStream;
+import java.lang.reflect.Array;
 import java.util.Arrays;
 import java.util.List;
+import java.util.UUID;
+
+import 
org.apache.qpid.client.util.ClassLoadingAwareObjectInputStream.TrustedClassFilter;
+import org.apache.qpid.test.utils.QpidTestCase;
 
 public class ClassLoadingAwareObjectInputStreamTest extends QpidTestCase
 {
+    private final TrustedClassFilter ACCEPTS_ALL_FILTER = new 
TrustedClassFilter()
+    {
+
+        @Override
+        public boolean isTrusted(Class<?> clazz)
+        {
+            return true;
+        }
+    };
+
+    private final TrustedClassFilter ACCEPTS_NONE_FILTER = new 
TrustedClassFilter()
+    {
+
+        @Override
+        public boolean isTrusted(Class<?> clazz)
+        {
+            return false;
+        }
+    };
+
     private InputStream _in;
     private ClassLoadingAwareObjectInputStream _claOIS;
 
@@ -44,10 +68,16 @@ public class ClassLoadingAwareObjectInpu
         out.flush();
         out.close();
 
-
         _in = new ByteArrayInputStream(baos.toByteArray());
 
-        _claOIS = new ClassLoadingAwareObjectInputStream(_in);
+        _claOIS = new ClassLoadingAwareObjectInputStream(_in, null);
+    }
+
+    @Override
+    public void tearDown() throws Exception
+    {
+        _claOIS.close();
+        super.tearDown();
     }
 
     /**
@@ -77,10 +107,358 @@ public class ClassLoadingAwareObjectInpu
             _claOIS.resolveProxyClass(new String[]{"java.lang.String"});
             fail("should have thrown an exception");
         }
-        catch(ClassNotFoundException cnfe)
+        catch (ClassNotFoundException cnfe)
         {
             //expected, but must verify it is wrapping an 
IllegalArgumentException
             assertTrue(cnfe.getCause() instanceof IllegalArgumentException);
         }
     }
+
+
+    public void testReadObject() throws Exception
+    {
+        // Expect to succeed
+        doTestReadObject(new SimplePojo("testString"), ACCEPTS_ALL_FILTER);
+
+        // Expect to fail
+        try
+        {
+            doTestReadObject(new SimplePojo("testString"), 
ACCEPTS_NONE_FILTER);
+            fail("Should have failed to read");
+        }
+        catch (ClassNotFoundException cnfe)
+        {
+            // Expected
+        }
+    }
+
+    public void testReadObjectByte() throws Exception
+    {
+        doTestReadObject(Byte.valueOf((byte) 255), ACCEPTS_ALL_FILTER);
+    }
+
+    public void testReadObjectShort() throws Exception
+    {
+        doTestReadObject(Short.valueOf((short) 255), ACCEPTS_ALL_FILTER);
+    }
+
+    public void testReadObjectInteger() throws Exception
+    {
+        doTestReadObject(Integer.valueOf(255), ACCEPTS_ALL_FILTER);
+    }
+
+    public void testReadObjectLong() throws Exception
+    {
+        doTestReadObject(Long.valueOf(255l), ACCEPTS_ALL_FILTER);
+    }
+
+    public void testReadObjectFloat() throws Exception
+    {
+        doTestReadObject(Float.valueOf(255.0f), ACCEPTS_ALL_FILTER);
+    }
+
+    public void testReadObjectDouble() throws Exception
+    {
+        doTestReadObject(Double.valueOf(255.0), ACCEPTS_ALL_FILTER);
+    }
+
+    public void testReadObjectBoolean() throws Exception
+    {
+        doTestReadObject(Boolean.FALSE, ACCEPTS_ALL_FILTER);
+    }
+
+    public void testReadObjectString() throws Exception
+    {
+        doTestReadObject(new String("testString"), ACCEPTS_ALL_FILTER);
+    }
+
+    public void testReadObjectIntArray() throws Exception
+    {
+        doTestReadObject(new int[]{1, 2, 3}, ACCEPTS_ALL_FILTER);
+    }
+
+    public void testPrimitiveByteNotFiltered() throws Exception
+    {
+        doTestReadPrimitive((byte) 255, ACCEPTS_NONE_FILTER);
+    }
+
+    public void testPrimitiveShortNotFiltered() throws Exception
+    {
+        doTestReadPrimitive((short) 255, ACCEPTS_NONE_FILTER);
+    }
+
+    public void testPrimitiveIntegerNotFiltered() throws Exception
+    {
+        doTestReadPrimitive((int) 255, ACCEPTS_NONE_FILTER);
+    }
+
+    public void testPrimitiveLongNotFiltered() throws Exception
+    {
+        doTestReadPrimitive((long) 255, ACCEPTS_NONE_FILTER);
+    }
+
+    public void testPrimitiveFloatNotFiltered() throws Exception
+    {
+        doTestReadPrimitive((float) 255.0, ACCEPTS_NONE_FILTER);
+    }
+
+    public void testPrimitiveDoubleNotFiltered() throws Exception
+    {
+        doTestReadPrimitive((double) 255.0, ACCEPTS_NONE_FILTER);
+    }
+
+    public void testPrimitiveBooleanNotFiltered() throws Exception
+    {
+        doTestReadPrimitive(false, ACCEPTS_NONE_FILTER);
+    }
+
+    public void testPrimitveCharNotFiltered() throws Exception
+    {
+        doTestReadPrimitive('c', ACCEPTS_NONE_FILTER);
+    }
+
+    public void testReadObjectStringNotFiltered() throws Exception
+    {
+        doTestReadObject(new String("testString"), ACCEPTS_NONE_FILTER);
+    }
+
+    public void testReadObjectFailsWithUntrustedType() throws Exception
+    {
+        byte[] serialized = serializeObject(new SimplePojo("testPayload"));
+
+        TrustedClassFilter myFilter = new TrustedClassFilter()
+        {
+
+            @Override
+            public boolean isTrusted(Class<?> clazz)
+            {
+                return !clazz.equals(SimplePojo.class);
+            }
+        };
+
+        ByteArrayInputStream input = new ByteArrayInputStream(serialized);
+        try (ClassLoadingAwareObjectInputStream reader = new 
ClassLoadingAwareObjectInputStream(input, myFilter))
+        {
+            try
+            {
+                reader.readObject();
+                fail("Should not be able to read the payload.");
+            }
+            catch (ClassNotFoundException ex)
+            {
+            }
+        }
+
+        serialized = serializeObject(UUID.randomUUID());
+        input = new ByteArrayInputStream(serialized);
+        try (ClassLoadingAwareObjectInputStream reader = new 
ClassLoadingAwareObjectInputStream(input, myFilter))
+        {
+            try
+            {
+                reader.readObject();
+            }
+            catch (ClassNotFoundException ex)
+            {
+                fail("Should be able to read the payload.");
+            }
+        }
+    }
+
+    public void testReadObjectFailsWithUntrustedContentInTrustedType() throws 
Exception
+    {
+        byte[] serialized = serializeObject(new SimplePojo(UUID.randomUUID()));
+
+        TrustedClassFilter myFilter = new TrustedClassFilter()
+        {
+
+            @Override
+            public boolean isTrusted(Class<?> clazz)
+            {
+                return clazz.equals(SimplePojo.class);
+            }
+        };
+
+        ByteArrayInputStream input = new ByteArrayInputStream(serialized);
+        try (ClassLoadingAwareObjectInputStream reader = new 
ClassLoadingAwareObjectInputStream(input, myFilter))
+        {
+            try
+            {
+                reader.readObject();
+                fail("Should not be able to read the payload.");
+            }
+            catch (ClassNotFoundException ex)
+            {
+            }
+        }
+
+        serialized = serializeObject(UUID.randomUUID());
+        input = new ByteArrayInputStream(serialized);
+        try (ClassLoadingAwareObjectInputStream reader = new 
ClassLoadingAwareObjectInputStream(input, myFilter))
+        {
+            try
+            {
+                reader.readObject();
+                fail("Should not be able to read the payload.");
+            }
+            catch (ClassNotFoundException ex)
+            {
+            }
+        }
+    }
+
+    private void doTestReadObject(Object value, TrustedClassFilter filter) 
throws Exception
+    {
+        byte[] serialized = serializeObject(value);
+
+        ByteArrayInputStream input = new ByteArrayInputStream(serialized);
+        try (ClassLoadingAwareObjectInputStream reader = new 
ClassLoadingAwareObjectInputStream(input, filter))
+        {
+            Object result = reader.readObject();
+            assertNotNull(result);
+            assertEquals(value.getClass(), result.getClass());
+            if (value.getClass().isArray())
+            {
+                assertEquals(Array.getLength(value), Array.getLength(result));
+                for (int i = 0; i < Array.getLength(value); ++i)
+                {
+                    assertEquals(Array.get(value, i), Array.get(result, i));
+                }
+            }
+            else
+            {
+                assertEquals(value, result);
+            }
+        }
+    }
+
+    private byte[] serializeObject(Object value) throws IOException
+    {
+        byte[] result = new byte[0];
+
+        if (value != null)
+        {
+            try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                 ObjectOutputStream oos = new ObjectOutputStream(baos))
+            {
+
+                oos.writeObject(value);
+                oos.flush();
+                oos.close();
+
+                result = baos.toByteArray();
+            }
+        }
+
+        return result;
+    }
+
+
+    private void doTestReadPrimitive(Object value, TrustedClassFilter filter) 
throws Exception
+    {
+        byte[] serialized = serializePrimitive(value);
+
+        ByteArrayInputStream input = new ByteArrayInputStream(serialized);
+        try (ClassLoadingAwareObjectInputStream reader = new 
ClassLoadingAwareObjectInputStream(input, filter))
+        {
+            Object result = null;
+
+            if (value instanceof Byte)
+            {
+                result = reader.readByte();
+            }
+            else if (value instanceof Short)
+            {
+                result = reader.readShort();
+            }
+            else if (value instanceof Integer)
+            {
+                result = reader.readInt();
+            }
+            else if (value instanceof Long)
+            {
+                result = reader.readLong();
+            }
+            else if (value instanceof Float)
+            {
+                result = reader.readFloat();
+            }
+            else if (value instanceof Double)
+            {
+                result = reader.readDouble();
+            }
+            else if (value instanceof Boolean)
+            {
+                result = reader.readBoolean();
+            }
+            else if (value instanceof Character)
+            {
+                result = reader.readChar();
+            }
+            else
+            {
+                throw new IllegalArgumentException("unsuitable type for 
primitive deserialization");
+            }
+
+            assertNotNull(result);
+            assertEquals(value.getClass(), result.getClass());
+            assertEquals(value, result);
+        }
+    }
+
+    private byte[] serializePrimitive(Object value) throws IOException
+    {
+        byte[] result = new byte[0];
+
+        if (value != null)
+        {
+            try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                 ObjectOutputStream oos = new ObjectOutputStream(baos))
+            {
+
+                if (value instanceof Byte)
+                {
+                    oos.writeByte((byte) value);
+                }
+                else if (value instanceof Short)
+                {
+                    oos.writeShort((short) value);
+                }
+                else if (value instanceof Integer)
+                {
+                    oos.writeInt((int) value);
+                }
+                else if (value instanceof Long)
+                {
+                    oos.writeLong((long) value);
+                }
+                else if (value instanceof Float)
+                {
+                    oos.writeFloat((float) value);
+                }
+                else if (value instanceof Double)
+                {
+                    oos.writeDouble((double) value);
+                }
+                else if (value instanceof Boolean)
+                {
+                    oos.writeBoolean((boolean) value);
+                }
+                else if (value instanceof Character)
+                {
+                    oos.writeChar((char) value);
+                }
+                else
+                {
+                    throw new IllegalArgumentException("unsuitable type for 
primitive serialization");
+                }
+
+                oos.flush();
+                oos.close();
+
+                result = baos.toByteArray();
+            }
+        }
+
+        return result;
+    }
 }

Modified: 
qpid/java/branches/6.0.x/common/src/main/java/org/apache/qpid/configuration/CommonProperties.java
URL: 
http://svn.apache.org/viewvc/qpid/java/branches/6.0.x/common/src/main/java/org/apache/qpid/configuration/CommonProperties.java?rev=1750361&r1=1750360&r2=1750361&view=diff
==============================================================================
--- 
qpid/java/branches/6.0.x/common/src/main/java/org/apache/qpid/configuration/CommonProperties.java
 (original)
+++ 
qpid/java/branches/6.0.x/common/src/main/java/org/apache/qpid/configuration/CommonProperties.java
 Mon Jun 27 15:39:55 2016
@@ -62,6 +62,9 @@ public class CommonProperties
     public static final String QPID_SECURITY_TLS_CIPHER_SUITE_BLACK_LIST = 
"qpid.security.tls.cipherSuiteBlackList";
     public static final String 
QPID_SECURITY_TLS_CIPHER_SUITE_BLACK_LIST_DEFAULT = "";
 
+    public static final String 
QPID_SECURITY_OBJECT_MESSAGE_CLASS_HIERARCHY_WHITE_LIST = 
"qpid.security.objectMessage.classHierarchyWhiteList";
+    public static final String 
QPID_SECURITY_OBJECT_MESSAGE_CLASS_HIERARCHY_BLACK_LIST = 
"qpid.security.objectMessage.classHierarchyBlackList";
+
     /** The name of the version properties file to load from the class path. */
     public static final String VERSION_RESOURCE = "qpidversion.properties";
 




---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to