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]