You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ta...@apache.org on 2016/06/27 15:31:54 UTC
[2/2] qpid-jms git commit: QPIDJMS-188 Further improvements to the
ObjectMessage handling.
QPIDJMS-188 Further improvements to the ObjectMessage handling.
Project: http://git-wip-us.apache.org/repos/asf/qpid-jms/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-jms/commit/669cfff8
Tree: http://git-wip-us.apache.org/repos/asf/qpid-jms/tree/669cfff8
Diff: http://git-wip-us.apache.org/repos/asf/qpid-jms/diff/669cfff8
Branch: refs/heads/master
Commit: 669cfff838d2798fa89b9db546823e6245433d4e
Parents: b05d577
Author: Timothy Bish <ta...@gmail.com>
Authored: Mon Jun 27 11:31:44 2016 -0400
Committer: Timothy Bish <ta...@gmail.com>
Committed: Mon Jun 27 11:31:44 2016 -0400
----------------------------------------------------------------------
.../java/org/apache/qpid/jms/JmsConnection.java | 9 +
.../apache/qpid/jms/JmsConnectionFactory.java | 23 +
.../org/apache/qpid/jms/JmsMessageConsumer.java | 3 +
.../java/org/apache/qpid/jms/JmsSession.java | 6 +
.../apache/qpid/jms/meta/JmsConnectionInfo.java | 15 +
.../apache/qpid/jms/meta/JmsConsumerInfo.java | 15 +
.../apache/qpid/jms/meta/JmsSessionInfo.java | 15 +
.../policy/JmsDefaultDeserializationPolicy.java | 244 ++++++++
.../jms/policy/JmsDeserializationPolicy.java | 45 ++
.../amqp/message/AmqpJmsMessageFacade.java | 4 +
.../amqp/message/AmqpJmsMessageFactory.java | 3 +-
.../message/AmqpJmsObjectMessageFacade.java | 31 +-
.../amqp/message/AmqpObjectTypeDelegate.java | 10 +
.../message/AmqpSerializedObjectDelegate.java | 59 +-
.../amqp/message/AmqpTypedObjectDelegate.java | 58 +-
.../ClassLoadingAwareObjectInputStream.java | 57 +-
.../qpid/jms/JmsConnectionFactoryTest.java | 75 ++-
.../ObjectMessageIntegrationTest.java | 125 +++-
.../facade/test/JmsTestObjectMessageFacade.java | 2 +-
.../JmsDefaultDeserializationPolicyTest.java | 328 +++++++++++
.../amqp/message/AmqpJmsMessageBuilderTest.java | 5 +
.../amqp/message/AmqpJmsMessageFactoryTest.java | 11 +-
.../message/AmqpJmsMessageTypesTestCase.java | 15 +-
.../jms/util/AnonymousSimplePojoParent.java | 39 ++
.../ClassLoadingAwareObjectInputStreamTest.java | 569 +++++++++++++++++++
.../qpid/jms/util/LocalSimplePojoParent.java | 46 ++
.../apache/qpid/jms/util/PropertyUtilTest.java | 11 +
.../org/apache/qpid/jms/util/SimplePojo.java | 73 +++
.../apache/qpid/jms/util/URISupportTest.java | 45 +-
qpid-jms-docs/Configuration.md | 11 +-
30 files changed, 1897 insertions(+), 55 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnection.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnection.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnection.java
index 7375c3f..827da11 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnection.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnection.java
@@ -66,6 +66,7 @@ import org.apache.qpid.jms.meta.JmsSessionId;
import org.apache.qpid.jms.meta.JmsSessionInfo;
import org.apache.qpid.jms.meta.JmsTransactionId;
import org.apache.qpid.jms.meta.JmsTransactionInfo;
+import org.apache.qpid.jms.policy.JmsDeserializationPolicy;
import org.apache.qpid.jms.policy.JmsMessageIDPolicy;
import org.apache.qpid.jms.policy.JmsPrefetchPolicy;
import org.apache.qpid.jms.policy.JmsPresettlePolicy;
@@ -873,6 +874,14 @@ public class JmsConnection implements AutoCloseable, Connection, TopicConnection
connectionInfo.setPresettlePolicy(presettlePolicy);
}
+ public JmsDeserializationPolicy getDeserializationPolicy() {
+ return connectionInfo.getDeserializationPolicy();
+ }
+
+ public void setDeserializationPolicy(JmsDeserializationPolicy deserializationPolicy) {
+ connectionInfo.setDeserializationPolicy(deserializationPolicy);
+ }
+
public boolean isReceiveLocalOnly() {
return connectionInfo.isReceiveLocalOnly();
}
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnectionFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnectionFactory.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnectionFactory.java
index 32cb39a..0f2c1ba 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnectionFactory.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnectionFactory.java
@@ -35,10 +35,12 @@ import org.apache.qpid.jms.exceptions.JmsExceptionSupport;
import org.apache.qpid.jms.jndi.JNDIStorable;
import org.apache.qpid.jms.message.JmsMessageIDBuilder;
import org.apache.qpid.jms.meta.JmsConnectionInfo;
+import org.apache.qpid.jms.policy.JmsDefaultDeserializationPolicy;
import org.apache.qpid.jms.policy.JmsDefaultMessageIDPolicy;
import org.apache.qpid.jms.policy.JmsDefaultPrefetchPolicy;
import org.apache.qpid.jms.policy.JmsDefaultPresettlePolicy;
import org.apache.qpid.jms.policy.JmsDefaultRedeliveryPolicy;
+import org.apache.qpid.jms.policy.JmsDeserializationPolicy;
import org.apache.qpid.jms.policy.JmsMessageIDPolicy;
import org.apache.qpid.jms.policy.JmsPrefetchPolicy;
import org.apache.qpid.jms.policy.JmsPresettlePolicy;
@@ -96,6 +98,7 @@ public class JmsConnectionFactory extends JNDIStorable implements ConnectionFact
private JmsRedeliveryPolicy redeliveryPolicy = new JmsDefaultRedeliveryPolicy();
private JmsPresettlePolicy presettlePolicy = new JmsDefaultPresettlePolicy();
private JmsMessageIDPolicy messageIDPolicy = new JmsDefaultMessageIDPolicy();
+ private JmsDeserializationPolicy deserializationPolicy = new JmsDefaultDeserializationPolicy();
public JmsConnectionFactory() {
}
@@ -580,6 +583,26 @@ public class JmsConnectionFactory extends JNDIStorable implements ConnectionFact
}
/**
+ * @return the deserializationPolicy that is currently configured.
+ */
+ public JmsDeserializationPolicy getDeserializationPolicy() {
+ return deserializationPolicy;
+ }
+
+ /**
+ * Sets the JmsDeserializationPolicy that is applied when a new connection is created.
+ *
+ * @param deserializationPolicy
+ * the deserializationPolicy that will be applied to new connections.
+ */
+ public void setDeserializationPolicy(JmsDeserializationPolicy deserializationPolicy) {
+ if (deserializationPolicy == null) {
+ deserializationPolicy = new JmsDefaultDeserializationPolicy();
+ }
+ this.deserializationPolicy = deserializationPolicy;
+ }
+
+ /**
* @return the currently configured client ID prefix for auto-generated client IDs.
*/
public synchronized String getClientIDPrefix() {
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageConsumer.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageConsumer.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageConsumer.java
index d797918..893a576 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageConsumer.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageConsumer.java
@@ -34,6 +34,7 @@ import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
import org.apache.qpid.jms.message.JmsMessage;
import org.apache.qpid.jms.meta.JmsConsumerId;
import org.apache.qpid.jms.meta.JmsConsumerInfo;
+import org.apache.qpid.jms.policy.JmsDeserializationPolicy;
import org.apache.qpid.jms.policy.JmsPrefetchPolicy;
import org.apache.qpid.jms.policy.JmsRedeliveryPolicy;
import org.apache.qpid.jms.provider.Provider;
@@ -88,6 +89,7 @@ public class JmsMessageConsumer implements AutoCloseable, MessageConsumer, JmsMe
JmsPrefetchPolicy prefetchPolicy = session.getPrefetchPolicy();
JmsRedeliveryPolicy redeliveryPolicy = session.getRedeliveryPolicy().copy();
+ JmsDeserializationPolicy deserializationPolicy = session.getDeserializationPolicy().copy();
consumerInfo = new JmsConsumerInfo(consumerId);
consumerInfo.setClientId(connection.getClientID());
@@ -102,6 +104,7 @@ public class JmsMessageConsumer implements AutoCloseable, MessageConsumer, JmsMe
consumerInfo.setRedeliveryPolicy(redeliveryPolicy);
consumerInfo.setLocalMessageExpiry(connection.isLocalMessageExpiry());
consumerInfo.setPresettle(session.getPresettlePolicy().isConsumerPresttled(session, destination));
+ consumerInfo.setDeserializationPolicy(deserializationPolicy);
session.getConnection().createResource(consumerInfo);
}
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsSession.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsSession.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsSession.java
index ff28e59..b8aded8 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsSession.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsSession.java
@@ -68,6 +68,7 @@ import org.apache.qpid.jms.meta.JmsProducerId;
import org.apache.qpid.jms.meta.JmsProducerInfo;
import org.apache.qpid.jms.meta.JmsSessionId;
import org.apache.qpid.jms.meta.JmsSessionInfo;
+import org.apache.qpid.jms.policy.JmsDeserializationPolicy;
import org.apache.qpid.jms.policy.JmsMessageIDPolicy;
import org.apache.qpid.jms.policy.JmsPrefetchPolicy;
import org.apache.qpid.jms.policy.JmsPresettlePolicy;
@@ -123,6 +124,7 @@ public class JmsSession implements AutoCloseable, Session, QueueSession, TopicSe
sessionInfo.setPrefetchPolicy(connection.getPrefetchPolicy().copy());
sessionInfo.setPresettlePolicy(connection.getPresettlePolicy().copy());
sessionInfo.setRedeliveryPolicy(connection.getRedeliveryPolicy().copy());
+ sessionInfo.setDeserializationPolicy(connection.getDeserializationPolicy());
connection.createResource(sessionInfo);
@@ -942,6 +944,10 @@ public class JmsSession implements AutoCloseable, Session, QueueSession, TopicSe
return sessionInfo.getRedeliveryPolicy();
}
+ public JmsDeserializationPolicy getDeserializationPolicy() {
+ return sessionInfo.getDeserializationPolicy();
+ }
+
@Override
public void onInboundMessage(JmsInboundMessageDispatch envelope) {
if (started.get()) {
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConnectionInfo.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConnectionInfo.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConnectionInfo.java
index b98af14..bc723c0 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConnectionInfo.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConnectionInfo.java
@@ -19,10 +19,12 @@ package org.apache.qpid.jms.meta;
import java.net.URI;
import java.nio.charset.Charset;
+import org.apache.qpid.jms.policy.JmsDefaultDeserializationPolicy;
import org.apache.qpid.jms.policy.JmsDefaultMessageIDPolicy;
import org.apache.qpid.jms.policy.JmsDefaultPrefetchPolicy;
import org.apache.qpid.jms.policy.JmsDefaultPresettlePolicy;
import org.apache.qpid.jms.policy.JmsDefaultRedeliveryPolicy;
+import org.apache.qpid.jms.policy.JmsDeserializationPolicy;
import org.apache.qpid.jms.policy.JmsMessageIDPolicy;
import org.apache.qpid.jms.policy.JmsPrefetchPolicy;
import org.apache.qpid.jms.policy.JmsPresettlePolicy;
@@ -67,6 +69,7 @@ public final class JmsConnectionInfo implements JmsResource, Comparable<JmsConne
private JmsRedeliveryPolicy redeliveryPolicy;
private JmsPresettlePolicy presettlePolicy;
private JmsMessageIDPolicy messageIDPolicy;
+ private JmsDeserializationPolicy deserializationPolicy;
private volatile byte[] encodedUserId;
@@ -101,6 +104,7 @@ public final class JmsConnectionInfo implements JmsResource, Comparable<JmsConne
copy.prefetchPolicy = getPrefetchPolicy().copy();
copy.redeliveryPolicy = getRedeliveryPolicy().copy();
copy.presettlePolicy = getPresettlePolicy().copy();
+ copy.deserializationPolicy = getDeserializationPolicy().copy();
}
public boolean isForceAsyncSend() {
@@ -320,6 +324,17 @@ public final class JmsConnectionInfo implements JmsResource, Comparable<JmsConne
return encodedUserId;
}
+ public JmsDeserializationPolicy getDeserializationPolicy() {
+ if (deserializationPolicy == null) {
+ deserializationPolicy = new JmsDefaultDeserializationPolicy();
+ }
+ return deserializationPolicy;
+ }
+
+ public void setDeserializationPolicy(JmsDeserializationPolicy deserializationPolicy) {
+ this.deserializationPolicy = deserializationPolicy;
+ }
+
@Override
public String toString() {
return "JmsConnectionInfo { " + getId() +
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConsumerInfo.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConsumerInfo.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConsumerInfo.java
index ab72d7c..dd34397 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConsumerInfo.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConsumerInfo.java
@@ -17,7 +17,9 @@
package org.apache.qpid.jms.meta;
import org.apache.qpid.jms.JmsDestination;
+import org.apache.qpid.jms.policy.JmsDefaultDeserializationPolicy;
import org.apache.qpid.jms.policy.JmsDefaultRedeliveryPolicy;
+import org.apache.qpid.jms.policy.JmsDeserializationPolicy;
import org.apache.qpid.jms.policy.JmsRedeliveryPolicy;
public final class JmsConsumerInfo implements JmsResource, Comparable<JmsConsumerInfo> {
@@ -35,6 +37,7 @@ public final class JmsConsumerInfo implements JmsResource, Comparable<JmsConsume
private boolean presettle;
private JmsRedeliveryPolicy redeliveryPolicy;
+ private JmsDeserializationPolicy deserializationPolicy;
// Can be used to track the last consumed message.
private transient long lastDeliveredSequenceId;
@@ -71,6 +74,7 @@ public final class JmsConsumerInfo implements JmsResource, Comparable<JmsConsume
info.acknowledgementMode = acknowledgementMode;
info.lastDeliveredSequenceId = lastDeliveredSequenceId;
info.redeliveryPolicy = getRedeliveryPolicy().copy();
+ info.deserializationPolicy = getDeserializationPolicy().copy();
}
public boolean isDurable() {
@@ -177,6 +181,17 @@ public final class JmsConsumerInfo implements JmsResource, Comparable<JmsConsume
this.redeliveryPolicy = redeliveryPolicy;
}
+ public JmsDeserializationPolicy getDeserializationPolicy() {
+ if (deserializationPolicy == null) {
+ deserializationPolicy = new JmsDefaultDeserializationPolicy();
+ }
+ return deserializationPolicy;
+ }
+
+ public void setDeserializationPolicy(JmsDeserializationPolicy deserializationPolicy) {
+ this.deserializationPolicy = deserializationPolicy;
+ }
+
public boolean isPresettle() {
return presettle;
}
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsSessionInfo.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsSessionInfo.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsSessionInfo.java
index 6e87480..1b7c3da 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsSessionInfo.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsSessionInfo.java
@@ -18,10 +18,12 @@ package org.apache.qpid.jms.meta;
import javax.jms.Session;
+import org.apache.qpid.jms.policy.JmsDefaultDeserializationPolicy;
import org.apache.qpid.jms.policy.JmsDefaultMessageIDPolicy;
import org.apache.qpid.jms.policy.JmsDefaultPrefetchPolicy;
import org.apache.qpid.jms.policy.JmsDefaultPresettlePolicy;
import org.apache.qpid.jms.policy.JmsDefaultRedeliveryPolicy;
+import org.apache.qpid.jms.policy.JmsDeserializationPolicy;
import org.apache.qpid.jms.policy.JmsMessageIDPolicy;
import org.apache.qpid.jms.policy.JmsPrefetchPolicy;
import org.apache.qpid.jms.policy.JmsPresettlePolicy;
@@ -37,6 +39,7 @@ public final class JmsSessionInfo implements JmsResource, Comparable<JmsSessionI
private JmsPrefetchPolicy prefetchPolicy;
private JmsPresettlePolicy presettlePolicy;
private JmsRedeliveryPolicy redeliveryPolicy;
+ private JmsDeserializationPolicy deserializationPolicy;
public JmsSessionInfo(JmsConnectionInfo connectionInfo, long sessionId) {
if (connectionInfo == null) {
@@ -66,6 +69,7 @@ public final class JmsSessionInfo implements JmsResource, Comparable<JmsSessionI
copy.presettlePolicy = getPresettlePolicy().copy();
copy.prefetchPolicy = getPrefetchPolicy().copy();
copy.messageIDPolicy = getMessageIDPolicy().copy();
+ copy.deserializationPolicy = getDeserializationPolicy().copy();
}
@Override
@@ -172,4 +176,15 @@ public final class JmsSessionInfo implements JmsResource, Comparable<JmsSessionI
public void setRedeliveryPolicy(JmsRedeliveryPolicy redeliveryPolicy) {
this.redeliveryPolicy = redeliveryPolicy;
}
+
+ public JmsDeserializationPolicy getDeserializationPolicy() {
+ if (deserializationPolicy == null) {
+ deserializationPolicy = new JmsDefaultDeserializationPolicy();
+ }
+ return deserializationPolicy;
+ }
+
+ public void setDeserializationPolicy(JmsDeserializationPolicy deserializationPolicy) {
+ this.deserializationPolicy = deserializationPolicy;
+ }
}
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/policy/JmsDefaultDeserializationPolicy.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/policy/JmsDefaultDeserializationPolicy.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/policy/JmsDefaultDeserializationPolicy.java
new file mode 100644
index 0000000..2bcbed4
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/policy/JmsDefaultDeserializationPolicy.java
@@ -0,0 +1,244 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.jms.policy;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.qpid.jms.JmsDestination;
+
+/**
+ * Default implementation of the deserialization policy that can read white and black list of
+ * classes/packages from the environment, and be updated by the connection uri options.
+ *
+ * The policy reads a default blackList string value (comma separated) from the system property
+ * {@value #BLACKLIST_PROPERTY} which defaults to null which indicates an empty blacklist.
+ *
+ * The policy reads a default whitelist string value (comma separated) from the system property
+ * {@value #WHITELIST_PROPERTY} which defaults to a {@value #CATCH_ALL_WILDCARD} which
+ * indicates that all classes are whitelisted.
+ *
+ * The blacklist overrides the whitelist, entries that could match both are counted as blacklisted.
+ *
+ * If the policy should treat all classes as untrusted the blacklist should be set to
+ * {@value #CATCH_ALL_WILDCARD}".
+ */
+public class JmsDefaultDeserializationPolicy implements JmsDeserializationPolicy {
+
+ /**
+ * Value used to indicate that all classes should be white or black listed,
+ */
+ public static final String CATCH_ALL_WILDCARD = "*";
+
+ public static final String WHITELIST_PROPERTY = "org.apache.qpid.jms.deserialization.white_list";
+ public static final String BLACKLIST_PROPERTY = "org.apache.qpid.jms.deserialization.black_list";
+
+ private List<String> whiteList = new ArrayList<String>();
+ private List<String> blackList = new ArrayList<String>();
+
+ /**
+ * Creates an instance of this policy with default configuration.
+ */
+ public JmsDefaultDeserializationPolicy() {
+ String whitelist = System.getProperty(WHITELIST_PROPERTY, CATCH_ALL_WILDCARD);
+ setWhiteList(whitelist);
+
+ String blackList = System.getProperty(BLACKLIST_PROPERTY);
+ setBlackList(blackList);
+ }
+
+ /**
+ * @param source
+ * The instance whose configuration should be copied from.
+ */
+ public JmsDefaultDeserializationPolicy(JmsDefaultDeserializationPolicy source) {
+ this.whiteList.addAll(source.whiteList);
+ this.blackList.addAll(source.blackList);
+ }
+
+ @Override
+ public JmsDeserializationPolicy copy() {
+ return new JmsDefaultDeserializationPolicy(this);
+ }
+
+ @Override
+ public boolean isTrustedType(JmsDestination destination, Class<?> clazz) {
+ if (clazz == null) {
+ return true;
+ }
+
+ String className = clazz.getCanonicalName();
+ if (className == null) {
+ // Shouldn't happen as we pre-processed things, but just in case..
+ className = clazz.getName();
+ }
+
+ for (String blackListEntry : blackList) {
+ if (CATCH_ALL_WILDCARD.equals(blackListEntry)) {
+ return false;
+ } else if (isClassOrPackageMatch(className, blackListEntry)) {
+ return false;
+ }
+ }
+
+ for (String whiteListEntry : whiteList) {
+ if (CATCH_ALL_WILDCARD.equals(whiteListEntry)) {
+ return true;
+ } else if (isClassOrPackageMatch(className, whiteListEntry)) {
+ return true;
+ }
+ }
+
+ // Failing outright rejection or allow from above, reject.
+ return false;
+ }
+
+ private final boolean isClassOrPackageMatch(String className, String listEntry) {
+ if (className == null) {
+ return false;
+ }
+
+ // Check if class is an exact match of the entry
+ if (className.equals(listEntry)) {
+ return true;
+ }
+
+ // Check if class is from a [sub-]package matching the entry
+ int entryLength = listEntry.length();
+ if (className.length() > entryLength && className.startsWith(listEntry) && '.' == className.charAt(entryLength)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @return the whiteList configured on this policy instance.
+ */
+ public String getWhiteList() {
+ Iterator<String> entries = whiteList.iterator();
+ StringBuilder builder = new StringBuilder();
+
+ while (entries.hasNext()) {
+ builder.append(entries.next());
+ if (entries.hasNext()) {
+ builder.append(",");
+ }
+ }
+
+ return builder.toString();
+ }
+
+ /**
+ * @return the blackList configured on this policy instance.
+ */
+ public String getBlackList() {
+ Iterator<String> entries = blackList.iterator();
+ StringBuilder builder = new StringBuilder();
+
+ while (entries.hasNext()) {
+ builder.append(entries.next());
+ if (entries.hasNext()) {
+ builder.append(",");
+ }
+ }
+
+ return builder.toString();
+ }
+
+ /**
+ * Replaces the currently configured whiteList with a comma separated
+ * string containing the new whiteList. Null or empty string denotes
+ * no whiteList entries, {@value #CATCH_ALL_WILDCARD} indicates that
+ * all classes are whiteListed.
+ *
+ * @param whiteList
+ * the whiteList that this policy is configured to recognize.
+ */
+ public void setWhiteList(String whiteList) {
+ ArrayList<String> list = new ArrayList<String>();
+ if (whiteList != null && !whiteList.isEmpty()) {
+ list.addAll(Arrays.asList(whiteList.split(",")));
+ }
+
+ this.whiteList = list;
+ }
+
+ /**
+ * Replaces the currently configured blackList with a comma separated
+ * string containing the new blackList. Null or empty string denotes
+ * no blacklist entries, {@value #CATCH_ALL_WILDCARD} indicates that
+ * all classes are blacklisted.
+ *
+ * @param blackList
+ * the blackList that this policy is configured to recognize.
+ */
+ public void setBlackList(String blackList) {
+ ArrayList<String> list = new ArrayList<String>();
+ if (blackList != null && !blackList.isEmpty()) {
+ list.addAll(Arrays.asList(blackList.split(",")));
+ }
+
+ this.blackList = list;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((whiteList == null) ? 0 : whiteList.hashCode());
+ result = prime * result + ((blackList == null) ? 0 : blackList.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj == null) {
+ return false;
+ }
+
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ JmsDefaultDeserializationPolicy other = (JmsDefaultDeserializationPolicy) obj;
+
+ if (whiteList == null) {
+ if (other.whiteList != null) {
+ return false;
+ }
+ } else if (!whiteList.equals(other.whiteList)) {
+ return false;
+ }
+
+ if (blackList == null) {
+ if (other.blackList != null) {
+ return false;
+ }
+ } else if (!blackList.equals(other.blackList)) {
+ return false;
+ }
+
+ return true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/policy/JmsDeserializationPolicy.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/policy/JmsDeserializationPolicy.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/policy/JmsDeserializationPolicy.java
new file mode 100644
index 0000000..bb70947
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/policy/JmsDeserializationPolicy.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.jms.policy;
+
+import javax.jms.ObjectMessage;
+
+import org.apache.qpid.jms.JmsDestination;
+
+/**
+ * Defines the interface for a policy object that controls what types of message
+ * content are permissible when the body of an incoming ObjectMessage is being
+ * deserialized.
+ */
+public interface JmsDeserializationPolicy {
+
+ JmsDeserializationPolicy copy();
+
+ /**
+ * Returns whether the given class is a trusted type and can be deserialized
+ * by the client when calls to {@link ObjectMessage#getObject()} are made.
+ *
+ * @param destination
+ * the Destination for the message containing the type to be deserialized.
+ * @param clazz
+ * the Type of the object that is about to be read.
+ *
+ * @return true if the type is trusted or false if not.
+ */
+ boolean isTrustedType(JmsDestination destination, Class<?> clazz);
+
+}
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFacade.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFacade.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFacade.java
index a739999..ff36db7 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFacade.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFacade.java
@@ -857,6 +857,10 @@ public class AmqpJmsMessageFacade implements JmsMessageFacade {
this.message.setReplyTo(address);
}
+ JmsDestination getConsumerDestination() {
+ return this.consumerDestination;
+ }
+
private Long getAbsoluteExpiryTime() {
Long result = null;
if (message.getProperties() != null) {
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFactory.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFactory.java
index e0cc8c4..5b78556 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFactory.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFactory.java
@@ -95,7 +95,8 @@ public class AmqpJmsMessageFactory implements JmsMessageFactory {
@Override
public JmsObjectMessage createObjectMessage(Serializable payload) throws JMSException {
- JmsObjectMessageFacade facade = new AmqpJmsObjectMessageFacade(connection, connection.isObjectMessageUsesAmqpTypes());
+ JmsObjectMessageFacade facade = new AmqpJmsObjectMessageFacade(
+ connection, connection.isObjectMessageUsesAmqpTypes());
if (payload != null) {
try {
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsObjectMessageFacade.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsObjectMessageFacade.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsObjectMessageFacade.java
index 4db872a..fabefed 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsObjectMessageFacade.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsObjectMessageFacade.java
@@ -26,6 +26,7 @@ import javax.jms.JMSException;
import org.apache.qpid.jms.exceptions.JmsExceptionSupport;
import org.apache.qpid.jms.message.facade.JmsObjectMessageFacade;
+import org.apache.qpid.jms.policy.JmsDeserializationPolicy;
import org.apache.qpid.jms.provider.amqp.AmqpConnection;
import org.apache.qpid.jms.provider.amqp.AmqpConsumer;
import org.apache.qpid.proton.message.Message;
@@ -40,8 +41,10 @@ public class AmqpJmsObjectMessageFacade extends AmqpJmsMessageFacade implements
private AmqpObjectTypeDelegate delegate;
+ private final JmsDeserializationPolicy deserializationPolicy;
+
/**
- * Creates a new facade instance
+ * Creates a new facade instance for outgoing message
*
* @param connection
* the AmqpConnection that under which this facade was created.
@@ -49,9 +52,14 @@ public class AmqpJmsObjectMessageFacade extends AmqpJmsMessageFacade implements
* controls the type used to encode the body.
*/
public AmqpJmsObjectMessageFacade(AmqpConnection connection, boolean isAmqpTypeEncoded) {
+ this(connection, isAmqpTypeEncoded, null);
+ }
+
+ private AmqpJmsObjectMessageFacade(AmqpConnection connection, boolean isAmqpTypeEncoded, JmsDeserializationPolicy deserializationPolicy) {
super(connection);
- setMessageAnnotation(JMS_MSG_TYPE, JMS_OBJECT_MESSAGE);
+ this.deserializationPolicy = deserializationPolicy;
+ setMessageAnnotation(JMS_MSG_TYPE, JMS_OBJECT_MESSAGE);
initDelegate(isAmqpTypeEncoded, null);
}
@@ -68,6 +76,7 @@ public class AmqpJmsObjectMessageFacade extends AmqpJmsMessageFacade implements
*/
public AmqpJmsObjectMessageFacade(AmqpConsumer consumer, Message message, ByteBuf messageBytes) {
super(consumer, message);
+ deserializationPolicy = consumer.getResourceInfo().getDeserializationPolicy();
boolean javaSerialized = AmqpMessageSupport.SERIALIZED_JAVA_OBJECT_CONTENT_TYPE.equals(message.getContentType());
initDelegate(!javaSerialized, messageBytes);
@@ -87,15 +96,13 @@ public class AmqpJmsObjectMessageFacade extends AmqpJmsMessageFacade implements
@Override
public AmqpJmsObjectMessageFacade copy() throws JMSException {
- AmqpJmsObjectMessageFacade copy = new AmqpJmsObjectMessageFacade(connection, isAmqpTypedEncoding());
+ AmqpJmsObjectMessageFacade copy = new AmqpJmsObjectMessageFacade(connection, isAmqpTypedEncoding(), deserializationPolicy);
copyInto(copy);
-
try {
- copy.setObject(getObject());
- } catch (Exception e) {
- throw JmsExceptionSupport.create("Failed to copy object value", e);
+ delegate.copyInto(copy.delegate);
+ } catch (Exception ex) {
+ throw JmsExceptionSupport.create(ex);
}
-
return copy;
}
@@ -130,9 +137,9 @@ public class AmqpJmsObjectMessageFacade extends AmqpJmsMessageFacade implements
AmqpObjectTypeDelegate newDelegate = null;
if (useAmqpTypedEncoding) {
- newDelegate = new AmqpTypedObjectDelegate(message, null);
+ newDelegate = new AmqpTypedObjectDelegate(this, null);
} else {
- newDelegate = new AmqpSerializedObjectDelegate(message, null);
+ newDelegate = new AmqpSerializedObjectDelegate(this, null, deserializationPolicy);
}
newDelegate.setObject(existingObject);
@@ -146,9 +153,9 @@ public class AmqpJmsObjectMessageFacade extends AmqpJmsMessageFacade implements
private void initDelegate(boolean useAmqpTypes, ByteBuf messageBytes) {
if (!useAmqpTypes) {
- delegate = new AmqpSerializedObjectDelegate(getAmqpMessage(), messageBytes);
+ delegate = new AmqpSerializedObjectDelegate(this, messageBytes, deserializationPolicy);
} else {
- delegate = new AmqpTypedObjectDelegate(getAmqpMessage(), messageBytes);
+ delegate = new AmqpTypedObjectDelegate(this, messageBytes);
}
}
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpObjectTypeDelegate.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpObjectTypeDelegate.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpObjectTypeDelegate.java
index d14ff93..7657343 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpObjectTypeDelegate.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpObjectTypeDelegate.java
@@ -53,5 +53,15 @@ public interface AmqpObjectTypeDelegate {
*/
void onSend();
+ /**
+ * Copy the internal data into the given instance.
+ *
+ * @param copy
+ * the new delegate that will receive a copy of this instances object data.
+ *
+ * @throws Exception if an error occurs while copying the contents to the target.
+ */
+ void copyInto(AmqpObjectTypeDelegate copy) throws Exception;
+
boolean isAmqpTypeEncoded();
}
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpSerializedObjectDelegate.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpSerializedObjectDelegate.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpSerializedObjectDelegate.java
index 546060b..618d123 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpSerializedObjectDelegate.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpSerializedObjectDelegate.java
@@ -26,7 +26,9 @@ import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.concurrent.atomic.AtomicReference;
+import org.apache.qpid.jms.policy.JmsDeserializationPolicy;
import org.apache.qpid.jms.util.ClassLoadingAwareObjectInputStream;
+import org.apache.qpid.jms.util.ClassLoadingAwareObjectInputStream.TrustedClassFilter;
import org.apache.qpid.proton.amqp.Binary;
import org.apache.qpid.proton.amqp.messaging.Data;
import org.apache.qpid.proton.amqp.messaging.Section;
@@ -38,7 +40,7 @@ import io.netty.buffer.ByteBuf;
* Wrapper around an AMQP Message instance that will be treated as a JMS ObjectMessage
* type.
*/
-public class AmqpSerializedObjectDelegate implements AmqpObjectTypeDelegate {
+public class AmqpSerializedObjectDelegate implements AmqpObjectTypeDelegate, TrustedClassFilter {
static final Data NULL_OBJECT_BODY;
static
@@ -53,25 +55,32 @@ public class AmqpSerializedObjectDelegate implements AmqpObjectTypeDelegate {
NULL_OBJECT_BODY = new Data(new Binary(bytes));
}
+ private final AmqpJmsMessageFacade parent;
private final Message message;
private final AtomicReference<Section> cachedReceivedBody = new AtomicReference<Section>();
+ private final JmsDeserializationPolicy deserializationPolicy;
private ByteBuf messageBytes;
+ private boolean localContent;
/**
* Create a new delegate that uses Java serialization to store the message content.
*
- * @param message
- * the AMQP message instance where the object is to be stored / read.
+ * @param parent
+ * the AMQP message facade instance where the object is to be stored / read.
* @param messageBytes
* the raw bytes that comprise the message when it was received.
+ * @param deserializationPolicy
+ * the JmsDeserializationPolicy that is used to validate the security of message
+ * content, may be null (e.g on new outgoing messages).
*/
- public AmqpSerializedObjectDelegate(Message message, ByteBuf messageBytes) {
- this.message = message;
+ public AmqpSerializedObjectDelegate(AmqpJmsMessageFacade parent, ByteBuf messageBytes, JmsDeserializationPolicy deserializationPolicy) {
+ this.parent = parent;
+ this.message = parent.getAmqpMessage();
this.message.setContentType(SERIALIZED_JAVA_OBJECT_CONTENT_TYPE);
this.messageBytes = messageBytes;
+ this.deserializationPolicy = deserializationPolicy;
- // We will decode the body on each access, so clear the current value
- // so we don't carry along unneeded bloat.
+ // Cache the body so the first access can grab it without extra work.
if (messageBytes != null) {
cachedReceivedBody.set(message.getBody());
}
@@ -116,7 +125,7 @@ public class AmqpSerializedObjectDelegate implements AmqpObjectTypeDelegate {
Serializable serialized = null;
try (ByteArrayInputStream bais = new ByteArrayInputStream(bin.getArray(), bin.getArrayOffset(), bin.getLength());
- ClassLoadingAwareObjectInputStream objIn = new ClassLoadingAwareObjectInputStream(bais)) {
+ ClassLoadingAwareObjectInputStream objIn = new ClassLoadingAwareObjectInputStream(bais, this)) {
serialized = (Serializable) objIn.readObject();
}
@@ -137,6 +146,7 @@ public class AmqpSerializedObjectDelegate implements AmqpObjectTypeDelegate {
}
messageBytes = null;
+ localContent = true;
}
@Override
@@ -148,7 +158,40 @@ public class AmqpSerializedObjectDelegate implements AmqpObjectTypeDelegate {
}
@Override
+ public void copyInto(AmqpObjectTypeDelegate copy) throws Exception {
+ if (!(copy instanceof AmqpSerializedObjectDelegate)) {
+ copy.setObject(getObject());
+ } else {
+ AmqpSerializedObjectDelegate target = (AmqpSerializedObjectDelegate) copy;
+
+ // Swap our cached value to the copy, we will just decode it if we need it.
+ target.cachedReceivedBody.set(cachedReceivedBody.getAndSet(null));
+
+ // If we have the original bytes just copy those and let the next get
+ // decode them into the payload, otherwise we need to do a deep copy.
+ if (messageBytes != null) {
+ target.messageBytes = messageBytes.copy();
+ }
+
+ target.localContent = localContent;
+
+ // Copy the already encoded message body if it exists, subsequent gets
+ // will deserialize the data so no mutations can occur.
+ target.message.setBody(message.getBody());
+ }
+ }
+
+ @Override
public boolean isAmqpTypeEncoded() {
return false;
}
+
+ @Override
+ public boolean isTrusted(Class<?> clazz) {
+ if (!localContent && deserializationPolicy != null) {
+ return deserializationPolicy.isTrustedType(parent.getConsumerDestination(), clazz);
+ } else {
+ return true;
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpTypedObjectDelegate.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpTypedObjectDelegate.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpTypedObjectDelegate.java
index 99ab86b..cc1038f 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpTypedObjectDelegate.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpTypedObjectDelegate.java
@@ -48,18 +48,17 @@ public class AmqpTypedObjectDelegate implements AmqpObjectTypeDelegate {
/**
* Create a new delegate that uses Java serialization to store the message content.
*
- * @param message
- * the AMQP message instance where the object is to be stored / read.
+ * @param parent
+ * the AMQP message facade instance where the object is to be stored / read.
* @param messageBytes
* the raw bytes that comprise the AMQP message that was received.
*/
- public AmqpTypedObjectDelegate(Message message, ByteBuf messageBytes) {
- this.message = message;
+ public AmqpTypedObjectDelegate(AmqpJmsMessageFacade parent, ByteBuf messageBytes) {
+ this.message = parent.getAmqpMessage();
this.message.setContentType(null);
this.messageBytes = messageBytes;
- // We will decode the body on each access, so clear the current value
- // so we don't carry along unneeded bloat.
+ // Cache the body so the first access can grab it without extra work.
if (messageBytes != null) {
cachedReceivedBody.set(message.getBody());
}
@@ -108,15 +107,16 @@ public class AmqpTypedObjectDelegate implements AmqpObjectTypeDelegate {
Message transfer = Message.Factory.create();
// Exchange the incoming body value for one that is created from encoding
- // and decoding the value.
+ // and decoding the value. Save the bytes for subsequent getObject and
+ // copyInto calls to use.
transfer.setBody(new AmqpValue(value));
messageBytes = encodeMessage(transfer);
transfer = decodeMessage(messageBytes);
- messageBytes = null;
// This step requires a heavy-weight operation of both encoding and decoding the
// incoming body value in order to create a copy such that changes to the original
- // do not affect the stored value. In the future it makes sense to try to enhance
+ // do not affect the stored value, and also verifies we can actually encode it at all
+ // now instead of later during send. In the future it makes sense to try to enhance
// proton such that we can encode the body and use those bytes directly on the
// message as it is being sent.
@@ -135,6 +135,41 @@ public class AmqpTypedObjectDelegate implements AmqpObjectTypeDelegate {
}
}
+ @Override
+ public void copyInto(AmqpObjectTypeDelegate copy) throws Exception {
+ if (!(copy instanceof AmqpTypedObjectDelegate)) {
+ copy.setObject(getObject());
+ } else {
+ AmqpTypedObjectDelegate target = (AmqpTypedObjectDelegate) copy;
+
+ // Swap our cached value (if any) to the copy, we will just decode it if we need it later.
+ target.cachedReceivedBody.set(cachedReceivedBody.getAndSet(null));
+
+ if (messageBytes != null) {
+ // If we have the original bytes just copy those and let the next get
+ // decode them into the payload (or for the copy, use the cached
+ // body if it was swapped above).
+ target.messageBytes = messageBytes.copy();
+
+ // Internal message body copy to satisfy sends. This is safe since the body was set
+ // from a copy (decoded from the bytes) to ensure it is a snapshot. Also safe for
+ // gets as they will use the message bytes (or cached body if set) to return the object.
+ target.message.setBody(message.getBody());
+ } else {
+ // We have to deep get/set copy here, otherwise a get might return
+ // the object value carried by the original version.
+ copy.setObject(getObject());
+ }
+ }
+ }
+
+ @Override
+ public boolean isAmqpTypeEncoded() {
+ return true;
+ }
+
+ //----- Internal implementation ------------------------------------------//
+
private boolean isSupportedAmqpValueObjectType(Serializable serializable) {
// TODO: augment supported types to encode as an AmqpValue?
return serializable instanceof String ||
@@ -142,9 +177,4 @@ public class AmqpTypedObjectDelegate implements AmqpObjectTypeDelegate {
serializable instanceof List<?> ||
serializable.getClass().isArray();
}
-
- @Override
- public boolean isAmqpTypeEncoded() {
- return true;
- }
}
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/ClassLoadingAwareObjectInputStream.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/ClassLoadingAwareObjectInputStream.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/ClassLoadingAwareObjectInputStream.java
index 0432bc4..21562a8 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/ClassLoadingAwareObjectInputStream.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/ClassLoadingAwareObjectInputStream.java
@@ -31,16 +31,29 @@ public class ClassLoadingAwareObjectInputStream extends ObjectInputStream {
private static final ClassLoader FALLBACK_CLASS_LOADER = ClassLoadingAwareObjectInputStream.class.getClassLoader();
private final ClassLoader inLoader;
+ private final TrustedClassFilter securityFilter;
- public ClassLoadingAwareObjectInputStream(InputStream in) throws IOException {
+ /**
+ * 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, and array types are narrowed
+ * to the component type of the array before being passed into this filter.
+ */
+ public interface TrustedClassFilter {
+ boolean isTrusted(Class<?> clazz);
+ }
+
+ public ClassLoadingAwareObjectInputStream(InputStream in, TrustedClassFilter filter) throws IOException {
super(in);
+
inLoader = in.getClass().getClassLoader();
+ securityFilter = filter;
}
@Override
protected Class<?> resolveClass(ObjectStreamClass classDesc) throws IOException, ClassNotFoundException {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
- return load(classDesc.getName(), cl, inLoader);
+ Class<?> clazz = load(classDesc.getName(), cl, inLoader);
+ return checkSecurity(clazz);
}
@Override
@@ -51,20 +64,52 @@ public class ClassLoadingAwareObjectInputStream extends ObjectInputStream {
cinterfaces[i] = load(interfaces[i], cl);
}
+ Class<?> clazz = null;
+ Throwable failureCause = null;
+
try {
- return Proxy.getProxyClass(cl, cinterfaces);
+ clazz = Proxy.getProxyClass(cl, cinterfaces);
} catch (IllegalArgumentException e) {
+ failureCause = e;
+
try {
- return Proxy.getProxyClass(inLoader, cinterfaces);
+ clazz = Proxy.getProxyClass(inLoader, cinterfaces);
} catch (IllegalArgumentException e1) {
}
try {
- return Proxy.getProxyClass(FALLBACK_CLASS_LOADER, cinterfaces);
+ clazz = Proxy.getProxyClass(FALLBACK_CLASS_LOADER, cinterfaces);
} catch (IllegalArgumentException e2) {
}
+ }
- throw new ClassNotFoundException(null, e);
+ if (clazz != null) {
+ return checkSecurity(clazz);
}
+
+ throw new ClassNotFoundException("Failed find class.", failureCause);
+ }
+
+ private Class<?> checkSecurity(Class<?> clazz) throws ClassNotFoundException {
+
+ Class<?> target = clazz;
+
+ while (target.isArray()) {
+ target = target.getComponentType();
+ }
+
+ while (target.isAnonymousClass() || target.isLocalClass()) {
+ target = target.getEnclosingClass();
+ }
+
+ if (!target.isPrimitive() && securityFilter != null) {
+ if (!securityFilter.isTrusted(target)) {
+ throw new ClassNotFoundException("Forbidden " + clazz + "! " +
+ "This class is not trusted to be deserialized under the current configuration. " +
+ "Please refer to the documentation for more information on how to configure trusted classes.");
+ }
+ }
+
+ return clazz;
}
private Class<?> load(String className, ClassLoader... cl) throws ClassNotFoundException {
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/test/java/org/apache/qpid/jms/JmsConnectionFactoryTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/JmsConnectionFactoryTest.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/JmsConnectionFactoryTest.java
index efb29f5..48c668b 100644
--- a/qpid-jms-client/src/test/java/org/apache/qpid/jms/JmsConnectionFactoryTest.java
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/JmsConnectionFactoryTest.java
@@ -38,6 +38,7 @@ import javax.jms.Connection;
import javax.jms.ExceptionListener;
import javax.jms.JMSException;
+import org.apache.qpid.jms.policy.JmsDefaultDeserializationPolicy;
import org.apache.qpid.jms.policy.JmsDefaultPrefetchPolicy;
import org.apache.qpid.jms.policy.JmsDefaultPresettlePolicy;
import org.apache.qpid.jms.policy.JmsDefaultRedeliveryPolicy;
@@ -111,12 +112,16 @@ public class JmsConnectionFactoryTest extends QpidJmsTestCase {
public void testConnectionFactoryPrefetchPolicyIsAppliedToConnection() throws JMSException {
JmsConnectionFactory factory = new JmsConnectionFactory(USER, PASSWORD, "mock://localhost");
+ JmsDefaultPrefetchPolicy prefetchPolicy = (JmsDefaultPrefetchPolicy) factory.getPrefetchPolicy();
+
+ assertFalse(prefetchPolicy.getQueuePrefetch() == 1);
+
((JmsDefaultPrefetchPolicy) factory.getPrefetchPolicy()).setAll(1);
JmsConnection connection = (JmsConnection) factory.createConnection();
assertNotNull(connection);
- JmsDefaultPrefetchPolicy prefetchPolicy = (JmsDefaultPrefetchPolicy) connection.getPrefetchPolicy();
+ prefetchPolicy = (JmsDefaultPrefetchPolicy) connection.getPrefetchPolicy();
assertNotNull(prefetchPolicy);
assertNotSame(factory.getPrefetchPolicy(), prefetchPolicy);
@@ -132,6 +137,8 @@ public class JmsConnectionFactoryTest extends QpidJmsTestCase {
JmsDefaultPresettlePolicy presettlePolicy = (JmsDefaultPresettlePolicy) factory.getPresettlePolicy();
+ assertFalse(presettlePolicy.isPresettleAll());
+
presettlePolicy.setPresettleAll(true);
JmsConnection connection = (JmsConnection) factory.createConnection();
@@ -150,6 +157,8 @@ public class JmsConnectionFactoryTest extends QpidJmsTestCase {
JmsDefaultRedeliveryPolicy redeliveryPolicy = (JmsDefaultRedeliveryPolicy) factory.getRedeliveryPolicy();
+ assertFalse(redeliveryPolicy.getMaxRedeliveries() == 100);
+
redeliveryPolicy.setMaxRedeliveries(100);
JmsConnection connection = (JmsConnection) factory.createConnection();
@@ -163,6 +172,29 @@ public class JmsConnectionFactoryTest extends QpidJmsTestCase {
}
@Test
+ public void testConnectionFactoryDeserializationPolicyIsAppliedToConnection() throws JMSException {
+ JmsConnectionFactory factory = new JmsConnectionFactory(USER, PASSWORD, "mock://localhost");
+
+ final String TRUSTED_PACKAGES = "java.lang,java.util";
+
+ JmsDefaultDeserializationPolicy deserializationPolicy =
+ (JmsDefaultDeserializationPolicy) factory.getDeserializationPolicy();
+
+ assertFalse(deserializationPolicy.getWhiteList().equals(TRUSTED_PACKAGES));
+
+ deserializationPolicy.setWhiteList(TRUSTED_PACKAGES);
+
+ JmsConnection connection = (JmsConnection) factory.createConnection();
+ assertNotNull(connection);
+
+ deserializationPolicy = (JmsDefaultDeserializationPolicy) connection.getDeserializationPolicy();
+ assertNotNull(deserializationPolicy);
+ assertNotSame(factory.getDeserializationPolicy(), deserializationPolicy);
+
+ assertEquals(TRUSTED_PACKAGES, deserializationPolicy.getWhiteList());
+ }
+
+ @Test
public void testConnectionGetConfiguredURIApplied() throws Exception {
URI mock = new URI("mock://localhost");
@@ -529,6 +561,47 @@ public class JmsConnectionFactoryTest extends QpidJmsTestCase {
assertEquals("Properties were not equal", props, props2);
}
+ /**
+ * The deserialization policy is maintained in a child-object, which we extract the properties from
+ * when serializing the factory. Ensure this functions by doing a round trip on a factory
+ * configured with some new deserialization configuration via the URI.
+ *
+ * @throws Exception if an error occurs during the test.
+ */
+ @Test
+ public void testSerializeThenDeserializeMaintainsDeserializationPolicy() throws Exception {
+ String whiteListValue = "java.lang";
+ String whitelistKey = "deserializationPolicy.whiteList";
+
+ String blackListValue = "java.lang.foo";
+ String blacklistKey = "deserializationPolicy.blackList";
+
+ String uri = "amqp://localhost:1234?jms." + whitelistKey + "=" + whiteListValue + "&jms." + blacklistKey + "=" + blackListValue;
+
+ JmsConnectionFactory cf = new JmsConnectionFactory(uri);
+ Map<String, String> props = cf.getProperties();
+
+ assertTrue("Props dont contain expected deserialization policy change", props.containsKey(whitelistKey));
+ assertEquals("Unexpected value", whiteListValue, props.get(whitelistKey));
+
+ assertTrue("Props dont contain expected deserialization policy change", props.containsKey(blacklistKey));
+ assertEquals("Unexpected value", blackListValue, props.get(blacklistKey));
+
+ Object roundTripped = roundTripSerialize(cf);
+
+ assertNotNull("Null object returned", roundTripped);
+ assertEquals("Unexpected type", JmsConnectionFactory.class, roundTripped.getClass());
+
+ Map<String, String> props2 = ((JmsConnectionFactory)roundTripped).getProperties();
+ assertTrue("Props dont contain expected deserialization policy change", props2.containsKey(whitelistKey));
+ assertEquals("Unexpected value", whiteListValue, props2.get(whitelistKey));
+
+ assertTrue("Props dont contain expected deserialization policy change", props2.containsKey(blacklistKey));
+ assertEquals("Unexpected value", blackListValue, props2.get(blacklistKey));
+
+ assertEquals("Properties were not equal", props, props2);
+ }
+
@Test
public void testSetRemoteURIThrowsOnNullURI() throws Exception {
JmsConnectionFactory cf = new JmsConnectionFactory();
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/ObjectMessageIntegrationTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/ObjectMessageIntegrationTest.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/ObjectMessageIntegrationTest.java
index bae22c1..a9bc0c5 100644
--- a/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/ObjectMessageIntegrationTest.java
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/ObjectMessageIntegrationTest.java
@@ -23,11 +23,13 @@ import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.HashMap;
+import java.util.UUID;
import javax.jms.Connection;
import javax.jms.JMSException;
@@ -51,13 +53,18 @@ import org.apache.qpid.jms.test.testpeer.matchers.sections.MessagePropertiesSect
import org.apache.qpid.jms.test.testpeer.matchers.sections.TransferPayloadCompositeMatcher;
import org.apache.qpid.jms.test.testpeer.matchers.types.EncodedAmqpValueMatcher;
import org.apache.qpid.jms.test.testpeer.matchers.types.EncodedDataMatcher;
+import org.apache.qpid.jms.util.SimplePojo;
import org.apache.qpid.proton.amqp.Binary;
import org.apache.qpid.proton.amqp.DescribedType;
import org.apache.qpid.proton.amqp.Symbol;
import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ObjectMessageIntegrationTest extends QpidJmsTestCase {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ObjectMessageIntegrationTest.class);
-public class ObjectMessageIntegrationTest extends QpidJmsTestCase
-{
private final IntegrationTestFixture testFixture = new IntegrationTestFixture();
//==== Java serialization encoding ====
@@ -224,6 +231,120 @@ public class ObjectMessageIntegrationTest extends QpidJmsTestCase
}
}
+ @Test(timeout = 20000)
+ public void testReceiveBlockedSerializedContentFailsOnGetObject() throws Exception {
+ // We arent allowing the test class
+ doTestReceiveSerializedContentPolicyTest("java.lang,java.util", null, false);
+ }
+
+ @Test(timeout = 20000)
+ public void testReceiveBlockAllSerializedContentFailsOnGetObject() throws Exception {
+ // We are blocking everything
+ doTestReceiveSerializedContentPolicyTest(null, "*", false);
+ }
+
+ @Test(timeout = 20000)
+ public void testReceiveBlockSomeSerializedContentFailsOnGetObject() throws Exception {
+ // We arent allowing the UUID
+ doTestReceiveSerializedContentPolicyTest("org.apache.qpid.jms", null, false);
+ }
+
+ @Test(timeout = 20000)
+ public void testReceiveWithWrongUnblockedSerializedContentFailsOnGetObject() throws Exception {
+ // We arent allowing the UUID a different way
+ doTestReceiveSerializedContentPolicyTest("java.lang,org.apache.qpid.jms", null, false);
+ }
+
+ @Test(timeout = 20000)
+ public void testReceiveWithFullyWhitelistedSerializedContentSucceeds() throws Exception {
+ // We are allowing everything needed
+ doTestReceiveSerializedContentPolicyTest("java.lang,java.util,org.apache.qpid.jms", null, true);
+ }
+
+ @Test(timeout = 20000)
+ public void testReceiveWithFullyWhitelistedSerializedContentFailsDueToBlackList() throws Exception {
+ // We are whitelisting everything needed, but then the blacklist is overriding to block some
+ doTestReceiveSerializedContentPolicyTest("java.lang,java.util,org.apache.qpid.jms", "java.util", false);
+ }
+
+ private void doTestReceiveSerializedContentPolicyTest(String whiteList, String blackList, boolean succeed) throws Exception {
+ try (TestAmqpPeer testPeer = new TestAmqpPeer();) {
+ String options = null;
+ if(whiteList != null) {
+ options = "?jms.deserializationPolicy.whiteList=" + whiteList;
+ }
+
+ if(blackList != null) {
+ if(options == null) {
+ options = "?";
+ } else {
+ options += "&";
+ }
+
+ options +="jms.deserializationPolicy.blackList=" + blackList;
+ }
+
+ Connection connection = testFixture.establishConnecton(testPeer, options);
+
+ connection.start();
+
+ testPeer.expectBegin();
+
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Queue queue = session.createQueue("myQueue");
+
+ MessageAnnotationsDescribedType msgAnnotations = new MessageAnnotationsDescribedType();
+ msgAnnotations.setSymbolKeyedAnnotation(AmqpMessageSupport.JMS_MSG_TYPE, AmqpMessageSupport.JMS_OBJECT_MESSAGE);
+ PropertiesDescribedType properties = new PropertiesDescribedType();
+ properties.setContentType(Symbol.valueOf(AmqpMessageSupport.SERIALIZED_JAVA_OBJECT_CONTENT_TYPE));
+
+ SimplePojo expectedContent = new SimplePojo(UUID.randomUUID());
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ oos.writeObject(expectedContent);
+ oos.flush();
+ oos.close();
+ byte[] bytes = baos.toByteArray();
+
+ DescribedType dataContent = new DataDescribedType(new Binary(bytes));
+
+ testPeer.expectReceiverAttach();
+ testPeer.expectLinkFlowRespondWithTransfer(null, msgAnnotations, properties, null, dataContent);
+ testPeer.expectDispositionThatIsAcceptedAndSettled();
+
+ MessageConsumer messageConsumer = session.createConsumer(queue);
+ Message receivedMessage = messageConsumer.receive(3000);
+ testPeer.waitForAllHandlersToComplete(3000);
+
+ assertNotNull(receivedMessage);
+ assertTrue(receivedMessage instanceof ObjectMessage);
+
+ ObjectMessage objectMessage = (ObjectMessage) receivedMessage;
+ Object received = null;
+ try {
+ received = objectMessage.getObject();
+ if(!succeed) {
+ fail("Should not be able to read blocked content");
+ }
+ } catch (JMSException jmsEx) {
+ LOG.debug("Caught: ", jmsEx);
+ if(succeed) {
+ fail("Should have been able to read blocked content");
+ }
+ }
+
+ if(succeed) {
+ assertEquals("Content not as expected", expectedContent, received);
+ }
+
+ testPeer.expectClose();
+ connection.close();
+
+ testPeer.waitForAllHandlersToComplete(3000);
+ }
+ }
+
//==== AMQP type system encoding ====
@Test(timeout = 20000)
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/facade/test/JmsTestObjectMessageFacade.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/facade/test/JmsTestObjectMessageFacade.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/facade/test/JmsTestObjectMessageFacade.java
index 6b44f3c..44bab21 100644
--- a/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/facade/test/JmsTestObjectMessageFacade.java
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/facade/test/JmsTestObjectMessageFacade.java
@@ -71,7 +71,7 @@ public class JmsTestObjectMessageFacade extends JmsTestMessageFacade implements
Serializable serialized = null;
try (ByteArrayInputStream dataIn = new ByteArrayInputStream(object);
- ClassLoadingAwareObjectInputStream objIn = new ClassLoadingAwareObjectInputStream(dataIn)) {
+ ClassLoadingAwareObjectInputStream objIn = new ClassLoadingAwareObjectInputStream(dataIn, null)) {
serialized = (Serializable) objIn.readObject();
}
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/test/java/org/apache/qpid/jms/policy/JmsDefaultDeserializationPolicyTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/policy/JmsDefaultDeserializationPolicyTest.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/policy/JmsDefaultDeserializationPolicyTest.java
new file mode 100644
index 0000000..93ff466
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/policy/JmsDefaultDeserializationPolicyTest.java
@@ -0,0 +1,328 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.jms.policy;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.util.HashMap;
+import java.util.UUID;
+import java.util.Vector;
+
+import org.apache.qpid.jms.JmsDestination;
+import org.apache.qpid.jms.JmsQueue;
+import org.apache.qpid.jms.util.ClassLoadingAwareObjectInputStream;
+import org.apache.qpid.jms.util.ClassLoadingAwareObjectInputStream.TrustedClassFilter;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class JmsDefaultDeserializationPolicyTest {
+
+ private static final Logger LOG = LoggerFactory.getLogger(JmsDefaultDeserializationPolicyTest.class);
+
+ @Test
+ public void testIsTrustedType() {
+ JmsDestination destination = new JmsQueue("test-queue");
+ JmsDefaultDeserializationPolicy policy = new JmsDefaultDeserializationPolicy();
+
+ assertTrue(policy.isTrustedType(destination, null));
+ assertTrue(policy.isTrustedType(destination, UUID.class));
+ assertTrue(policy.isTrustedType(destination, String.class));
+ assertTrue(policy.isTrustedType(destination, Boolean.class));
+ assertTrue(policy.isTrustedType(destination, Double.class));
+ assertTrue(policy.isTrustedType(destination, Object.class));
+
+ // Only types in lang
+ policy.setWhiteList("java.lang");
+
+ assertTrue(policy.isTrustedType(destination, null));
+ assertFalse(policy.isTrustedType(destination, UUID.class));
+ assertTrue(policy.isTrustedType(destination, String.class));
+ assertTrue(policy.isTrustedType(destination, Boolean.class));
+ assertFalse(policy.isTrustedType(destination, getClass()));
+
+ // Entry must be complete package name prefix to match
+ // i.e while "java.n" is a prefix of "java.net", this
+ // wont match the socket class below.
+ policy.setWhiteList("java.n");
+ assertFalse(policy.isTrustedType(destination, UUID.class));
+ assertFalse(policy.isTrustedType(destination, String.class));
+ assertFalse(policy.isTrustedType(destination, java.net.Socket.class));
+
+ // add a non-core package
+ policy.setWhiteList("java.lang,org.apache.qpid.jms");
+
+ assertFalse(policy.isTrustedType(destination, UUID.class));
+ assertTrue(policy.isTrustedType(destination, String.class));
+ assertTrue(policy.isTrustedType(destination, getClass()));
+
+ // Try with a class-specific entry
+ policy.setWhiteList("java.lang.Integer");
+
+ assertTrue(policy.isTrustedType(destination, Integer.class));
+ assertFalse(policy.isTrustedType(destination, Boolean.class));
+
+ // Verify blacklist overrides whitelist
+ policy.setWhiteList("java.lang.Integer");
+ policy.setBlackList("java.lang.Integer");
+
+ assertFalse(policy.isTrustedType(destination, Integer.class));
+
+ // Verify blacklist entry prefix overrides whitelist
+ policy.setWhiteList("java.lang.Integer");
+ policy.setBlackList("java.lang");
+
+ assertFalse(policy.isTrustedType(destination, Integer.class));
+
+ // Verify blacklist catch-all overrides whitelist
+ policy.setWhiteList("java.lang.Integer");
+ policy.setBlackList("*");
+
+ assertFalse(policy.isTrustedType(destination, Integer.class));
+ }
+
+ @Test
+ public void testHashCode() {
+ JmsDeserializationPolicy policy1 = new JmsDefaultDeserializationPolicy();
+ JmsDeserializationPolicy policy2 = new JmsDefaultDeserializationPolicy();
+
+ assertTrue(policy1.hashCode() != 0);
+ assertEquals(policy1.hashCode(), policy2.hashCode());
+ assertEquals(policy2.hashCode(), policy1.hashCode());
+
+ ((JmsDefaultDeserializationPolicy) policy1).setWhiteList("java.util");
+
+ assertFalse(policy1.hashCode() == policy2.hashCode());
+ assertFalse(policy2.hashCode() == policy1.hashCode());
+
+ ((JmsDefaultDeserializationPolicy) policy2).setWhiteList("java.util");
+
+ assertTrue(policy1.hashCode() == policy2.hashCode());
+ assertTrue(policy2.hashCode() == policy1.hashCode());
+
+ ((JmsDefaultDeserializationPolicy) policy1).setBlackList("java.util");
+
+ assertFalse(policy1.hashCode() == policy2.hashCode());
+ assertFalse(policy2.hashCode() == policy1.hashCode());
+
+ ((JmsDefaultDeserializationPolicy) policy2).setBlackList("java.util");
+
+ assertTrue(policy1.hashCode() == policy2.hashCode());
+ assertTrue(policy2.hashCode() == policy1.hashCode());
+ }
+
+ @Test
+ public void testEqualsObject() {
+ JmsDefaultDeserializationPolicy policy1 = new JmsDefaultDeserializationPolicy();
+ JmsDefaultDeserializationPolicy policy2 = new JmsDefaultDeserializationPolicy();
+
+ assertTrue(policy1.equals(policy1));
+ assertTrue(policy1.equals(policy2));
+ assertTrue(policy2.equals(policy1));
+
+ policy1.setWhiteList("java.util");
+
+ assertFalse(policy1.equals(policy2));
+ assertFalse(policy2.equals(policy1));
+
+ assertFalse(policy1.equals(null));
+ assertFalse(policy1.equals(""));
+ assertFalse(policy1.equals(this));
+
+ policy2.setWhiteList("java.util");
+ assertTrue(policy1.equals(policy2));
+
+ policy1.setBlackList("java.util");
+
+ assertFalse(policy1.equals(policy2));
+ assertFalse(policy2.equals(policy1));
+
+ policy2.setBlackList("java.util");
+ assertTrue(policy1.equals(policy2));
+ assertTrue(policy2.equals(policy1));
+ }
+
+ @Test
+ public void testJmsDefaultDeserializationPolicy() {
+ JmsDefaultDeserializationPolicy policy = new JmsDefaultDeserializationPolicy();
+
+ assertFalse(policy.getWhiteList().isEmpty());
+ assertTrue(policy.getBlackList().isEmpty());
+ }
+
+ @Test
+ public void testJmsDefaultDeserializationPolicyCopyCtor() {
+ JmsDefaultDeserializationPolicy policy = new JmsDefaultDeserializationPolicy();
+
+ policy.setWhiteList("a.b.c");
+ policy.setBlackList("d.e.f");
+
+ JmsDefaultDeserializationPolicy copy = new JmsDefaultDeserializationPolicy(policy);
+
+ assertEquals("a.b.c", copy.getWhiteList());
+ assertEquals("d.e.f", copy.getBlackList());
+ }
+
+ @Test
+ public void testJmsDefaultDeserializationPolicyCopy() {
+ JmsDefaultDeserializationPolicy policy = new JmsDefaultDeserializationPolicy();
+
+ policy.setWhiteList("a.b.c");
+ policy.setBlackList("d.e.f");
+
+ JmsDefaultDeserializationPolicy copy = (JmsDefaultDeserializationPolicy) policy.copy();
+
+ assertEquals("a.b.c", copy.getWhiteList());
+ assertEquals("d.e.f", copy.getBlackList());
+ }
+
+ @Test
+ public void testSetWhiteList() {
+ JmsDefaultDeserializationPolicy policy = new JmsDefaultDeserializationPolicy();
+ assertNotNull(policy.getWhiteList());
+
+ policy.setWhiteList(null);
+ assertNotNull(policy.getWhiteList());
+ assertTrue(policy.getWhiteList().isEmpty());
+
+ policy.setWhiteList("*");
+ assertNotNull(policy.getWhiteList());
+ assertFalse(policy.getWhiteList().isEmpty());
+ }
+
+ @Test
+ public void testSetBlackList() {
+ JmsDefaultDeserializationPolicy policy = new JmsDefaultDeserializationPolicy();
+ assertNotNull(policy.getBlackList());
+
+ policy.setBlackList(null);
+ assertNotNull(policy.getBlackList());
+ assertTrue(policy.getBlackList().isEmpty());
+
+ policy.setBlackList("*");
+ assertNotNull(policy.getBlackList());
+ assertFalse(policy.getBlackList().isEmpty());
+ }
+
+ @Test
+ public void testDeserializeVectorUsingPolicy() throws Exception {
+ Vector<Object> vector = new Vector<Object>();
+ vector.add("pi");
+ vector.add(new Integer(314159));
+ vector.add(new Vector<String>());
+ vector.add(Boolean.FALSE);
+
+ final JmsDefaultDeserializationPolicy policy = new JmsDefaultDeserializationPolicy();
+ ByteArrayInputStream input = new ByteArrayInputStream(serializeObject(vector));
+ TrustedClassFilter filter = new TrustedClassFilter() {
+
+ @Override
+ public boolean isTrusted(Class<?> clazz) {
+ LOG.trace("Check for trust status of class: {}", clazz.getName());
+ return policy.isTrustedType(new JmsQueue(), clazz);
+ }
+ };
+
+ ClassLoadingAwareObjectInputStream reader = new ClassLoadingAwareObjectInputStream(input, filter);
+
+ Object result = null;
+ try {
+ result = reader.readObject();
+ } catch (Exception ex) {
+ fail("Should no throw any errors");
+ } finally {
+ reader.close();
+ }
+
+ assertNotNull(result);
+ assertTrue(result instanceof Vector);
+ assertEquals(4, ((Vector<?>) result).size());
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testDeserializeHashMapUsingPolicy() throws Exception {
+ HashMap<Object, Object> map = new HashMap<Object, Object>();
+
+ map.put("a", "Value");
+ map.put("b", new Integer(1));
+ map.put("c", new Vector<Object>());
+ map.put("d", Boolean.FALSE);
+
+ final JmsDefaultDeserializationPolicy policy = new JmsDefaultDeserializationPolicy();
+ ByteArrayInputStream input = new ByteArrayInputStream(serializeObject(map));
+ TrustedClassFilter filter = new TrustedClassFilter() {
+
+ @Override
+ public boolean isTrusted(Class<?> clazz) {
+ LOG.trace("Check for trust status of class: {}", clazz.getName());
+ return policy.isTrustedType(new JmsQueue(), clazz);
+ }
+ };
+
+ ClassLoadingAwareObjectInputStream reader = new ClassLoadingAwareObjectInputStream(input, filter);
+
+ Object result = null;
+ try {
+ result = reader.readObject();
+ } catch (Exception ex) {
+ fail("Should no throw any errors");
+ } finally {
+ reader.close();
+ }
+
+ assertNotNull(result);
+ assertTrue(result instanceof HashMap);
+
+ map = (HashMap<Object, Object>) result;
+
+ assertEquals(4, map.size());
+
+ assertEquals("Value", map.get("a"));
+ assertEquals(new Integer(1), map.get("b"));
+ assertEquals(new Vector<Object>(), map.get("c"));
+ assertEquals(Boolean.FALSE, map.get("d"));
+ }
+
+ //----- Internal methods -------------------------------------------------//
+
+ 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;
+ }
+}
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageBuilderTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageBuilderTest.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageBuilderTest.java
index a534de0..eee5f8e 100644
--- a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageBuilderTest.java
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageBuilderTest.java
@@ -41,6 +41,8 @@ import org.apache.qpid.jms.message.JmsObjectMessage;
import org.apache.qpid.jms.message.JmsStreamMessage;
import org.apache.qpid.jms.message.JmsTextMessage;
import org.apache.qpid.jms.message.facade.JmsMessageFacade;
+import org.apache.qpid.jms.meta.JmsConsumerId;
+import org.apache.qpid.jms.meta.JmsConsumerInfo;
import org.apache.qpid.jms.provider.amqp.AmqpConsumer;
import org.apache.qpid.jms.test.QpidJmsTestCase;
import org.apache.qpid.proton.Proton;
@@ -62,7 +64,10 @@ public class AmqpJmsMessageBuilderTest extends QpidJmsTestCase {
@Override
public void setUp() throws Exception {
super.setUp();
+
+ JmsConsumerId consumerId = new JmsConsumerId("ID:MOCK:1", 1, 1);
mockConsumer = Mockito.mock(AmqpConsumer.class);
+ Mockito.when(mockConsumer.getResourceInfo()).thenReturn(new JmsConsumerInfo(consumerId));
}
@Test
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFactoryTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFactoryTest.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFactoryTest.java
index 28530d9..4d28ec1 100644
--- a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFactoryTest.java
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFactoryTest.java
@@ -48,6 +48,8 @@ import org.apache.qpid.jms.message.facade.JmsMessageFacade;
import org.apache.qpid.jms.message.facade.JmsObjectMessageFacade;
import org.apache.qpid.jms.message.facade.JmsStreamMessageFacade;
import org.apache.qpid.jms.message.facade.JmsTextMessageFacade;
+import org.apache.qpid.jms.meta.JmsConnectionId;
+import org.apache.qpid.jms.meta.JmsConnectionInfo;
import org.apache.qpid.jms.provider.amqp.AmqpConnection;
import org.apache.qpid.jms.test.QpidJmsTestCase;
import org.junit.Test;
@@ -194,12 +196,19 @@ public class AmqpJmsMessageFactoryTest extends QpidJmsTestCase {
}
private AmqpConnection createMockAmqpConnectionAmqpTypes() {
+ JmsConnectionId connectionId = new JmsConnectionId("ID:MOCK:1");
AmqpConnection connection = Mockito.mock(AmqpConnection.class);
Mockito.when(connection.isObjectMessageUsesAmqpTypes()).thenReturn(true);
+ Mockito.when(connection.getResourceInfo()).thenReturn(new JmsConnectionInfo(connectionId));
+
return connection;
}
private AmqpConnection createMockAmqpConnection() {
- return Mockito.mock(AmqpConnection.class);
+ JmsConnectionId connectionId = new JmsConnectionId("ID:MOCK:1");
+ AmqpConnection connection = Mockito.mock(AmqpConnection.class);
+ Mockito.when(connection.getResourceInfo()).thenReturn(new JmsConnectionInfo(connectionId));
+
+ return connection;
}
}
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageTypesTestCase.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageTypesTestCase.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageTypesTestCase.java
index 3775269..48a78f6 100644
--- a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageTypesTestCase.java
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageTypesTestCase.java
@@ -22,6 +22,10 @@ import java.nio.charset.StandardCharsets;
import org.apache.qpid.jms.JmsDestination;
import org.apache.qpid.jms.JmsTopic;
+import org.apache.qpid.jms.meta.JmsConnectionId;
+import org.apache.qpid.jms.meta.JmsConnectionInfo;
+import org.apache.qpid.jms.meta.JmsConsumerId;
+import org.apache.qpid.jms.meta.JmsConsumerInfo;
import org.apache.qpid.jms.provider.amqp.AmqpConnection;
import org.apache.qpid.jms.provider.amqp.AmqpConsumer;
import org.apache.qpid.jms.test.QpidJmsTestCase;
@@ -91,13 +95,20 @@ public class AmqpJmsMessageTypesTestCase extends QpidJmsTestCase {
}
protected AmqpConsumer createMockAmqpConsumer() {
+ JmsConsumerId consumerId = new JmsConsumerId("ID:MOCK:1:1:1");
+ AmqpConnection connection = createMockAmqpConnection();
AmqpConsumer consumer = Mockito.mock(AmqpConsumer.class);
- Mockito.when(consumer.getConnection()).thenReturn(createMockAmqpConnection());
+ Mockito.when(consumer.getConnection()).thenReturn(connection);
Mockito.when(consumer.getDestination()).thenReturn(consumerDestination);
+ Mockito.when(consumer.getResourceInfo()).thenReturn(new JmsConsumerInfo(consumerId));
return consumer;
}
protected AmqpConnection createMockAmqpConnection() {
- return Mockito.mock(AmqpConnection.class);
+ JmsConnectionId connectionId = new JmsConnectionId("ID:MOCK:1");
+ AmqpConnection connection = Mockito.mock(AmqpConnection.class);
+ Mockito.when(connection.getResourceInfo()).thenReturn(new JmsConnectionInfo(connectionId));
+
+ return connection;
}
}
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/AnonymousSimplePojoParent.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/AnonymousSimplePojoParent.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/AnonymousSimplePojoParent.java
new file mode 100644
index 0000000..32eb3f9
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/AnonymousSimplePojoParent.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.jms.util;
+
+import java.io.Serializable;
+
+public class AnonymousSimplePojoParent implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private SimplePojo payload;
+
+ public AnonymousSimplePojoParent(Object simplePojoPayload) {
+ // Create an ANONYMOUS simple payload, itself serializable, like we
+ // have to be since the object references us and is used
+ // during the serialization.
+ payload = new SimplePojo(simplePojoPayload) {
+ private static final long serialVersionUID = 1L;
+ };
+ }
+
+ public SimplePojo getPayload() {
+ return payload;
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org