260 lines
11 KiB
Diff
260 lines
11 KiB
Diff
From 8f1f8a20376a5f30d187db78c218e1cd97202b38 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Galder=20Zamarren=CC=83o?= <galder@zamarreno.com>
|
|
Date: Wed, 13 Dec 2017 11:34:14 +0100
|
|
Subject: [PATCH] ISPN-8624 White list unmarshalling for GenericJBossMarshaller
|
|
|
|
---
|
|
.../client/hotrod/RemoteCacheManager.java | 7 +++-
|
|
.../hotrod/marshall/MarshallerUtil.java | 16 +-------
|
|
.../marshall/WhiteListMarshallingTest.java | 39 +++++++++++++++++++
|
|
.../org/infinispan/commons/logging/Log.java | 5 +++
|
|
.../commons/marshall/MarshallUtil.java | 30 ++++++++++++++
|
|
.../jboss/GenericJBossMarshaller.java | 32 +++++++++++++++
|
|
6 files changed, 114 insertions(+), 15 deletions(-)
|
|
create mode 100644 client/hotrod-client/src/test/java/org/infinispan/client/hotrod/marshall/WhiteListMarshallingTest.java
|
|
|
|
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/RemoteCacheManager.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/RemoteCacheManager.java
|
|
index f266c7e4447..235a62fc284 100644
|
|
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/RemoteCacheManager.java
|
|
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/RemoteCacheManager.java
|
|
@@ -33,6 +33,7 @@
|
|
import org.infinispan.commons.api.BasicCacheContainer;
|
|
import org.infinispan.commons.executors.ExecutorFactory;
|
|
import org.infinispan.commons.marshall.Marshaller;
|
|
+import org.infinispan.commons.marshall.jboss.GenericJBossMarshaller;
|
|
import org.infinispan.commons.util.FileLookupFactory;
|
|
import org.infinispan.commons.util.TypedProperties;
|
|
import org.infinispan.commons.util.Util;
|
|
@@ -562,7 +563,11 @@ public void start() {
|
|
if (marshaller == null) {
|
|
marshaller = configuration.marshaller();
|
|
if (marshaller == null) {
|
|
- marshaller = Util.getInstance(configuration.marshallerClass());
|
|
+ Class<? extends Marshaller> clazz = configuration.marshallerClass();
|
|
+ if (clazz == GenericJBossMarshaller.class && !configuration.serialWhitelist().isEmpty())
|
|
+ marshaller = new GenericJBossMarshaller(configuration.serialWhitelist());
|
|
+ else
|
|
+ marshaller = Util.getInstance(clazz);
|
|
}
|
|
}
|
|
|
|
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/marshall/MarshallerUtil.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/marshall/MarshallerUtil.java
|
|
index 876fa6de338..990a1082132 100644
|
|
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/marshall/MarshallerUtil.java
|
|
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/marshall/MarshallerUtil.java
|
|
@@ -5,6 +5,7 @@
|
|
import org.infinispan.client.hotrod.logging.Log;
|
|
import org.infinispan.client.hotrod.logging.LogFactory;
|
|
import org.infinispan.commons.CacheException;
|
|
+import org.infinispan.commons.marshall.MarshallUtil;
|
|
import org.infinispan.commons.marshall.Marshaller;
|
|
import org.infinispan.commons.util.Util;
|
|
|
|
@@ -15,8 +16,6 @@
|
|
import java.io.ObjectStreamClass;
|
|
import java.io.ObjectStreamConstants;
|
|
import java.util.List;
|
|
-import java.util.regex.Matcher;
|
|
-import java.util.regex.Pattern;
|
|
|
|
/**
|
|
* @author Galder Zamarreño
|
|
@@ -100,18 +99,7 @@ public CheckedInputStream(InputStream in, List<String> whitelist) throws IOExcep
|
|
@Override
|
|
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
|
|
//Enforce SerialKiller's whitelist
|
|
- boolean safeClass = false;
|
|
- for (String whiteRegExp : whitelist) {
|
|
- Pattern whitePattern = Pattern.compile(whiteRegExp);
|
|
- Matcher whiteMatcher = whitePattern.matcher(desc.getName());
|
|
- if (whiteMatcher.find()) {
|
|
- safeClass = true;
|
|
-
|
|
- if (log.isTraceEnabled())
|
|
- log.tracef("Whitelist match: '%s'", desc.getName());
|
|
- }
|
|
- }
|
|
-
|
|
+ boolean safeClass = MarshallUtil.isSafeClass(desc.getName(), whitelist);
|
|
if (!safeClass)
|
|
throw log.classNotInWhitelist(desc.getName());
|
|
|
|
diff --git a/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/marshall/WhiteListMarshallingTest.java b/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/marshall/WhiteListMarshallingTest.java
|
|
new file mode 100644
|
|
index 00000000000..2a83b083645
|
|
--- /dev/null
|
|
+++ b/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/marshall/WhiteListMarshallingTest.java
|
|
@@ -0,0 +1,39 @@
|
|
+package org.infinispan.client.hotrod.marshall;
|
|
+
|
|
+import org.infinispan.client.hotrod.RemoteCacheManager;
|
|
+import org.infinispan.client.hotrod.configuration.ConfigurationBuilder;
|
|
+import org.infinispan.client.hotrod.exceptions.HotRodClientException;
|
|
+import org.infinispan.client.hotrod.test.InternalRemoteCacheManager;
|
|
+import org.infinispan.client.hotrod.test.SingleHotRodServerTest;
|
|
+import org.infinispan.test.data.Person;
|
|
+import org.testng.annotations.Test;
|
|
+
|
|
+import java.io.Serializable;
|
|
+
|
|
+@Test(testName = "client.hotrod.marshall.WhiteListMarshallingTest", groups = {"functional", "smoke"} )
|
|
+public class WhiteListMarshallingTest extends SingleHotRodServerTest {
|
|
+
|
|
+ @Override
|
|
+ protected RemoteCacheManager getRemoteCacheManager() {
|
|
+ ConfigurationBuilder builder = new ConfigurationBuilder();
|
|
+ builder.addJavaSerialWhiteList(".*Person.*");
|
|
+ builder.addServer().host("127.0.0.1").port(hotrodServer.getPort());
|
|
+ return new InternalRemoteCacheManager(builder.build());
|
|
+ }
|
|
+
|
|
+ @Test(expectedExceptions = HotRodClientException.class,
|
|
+ expectedExceptionsMessageRegExp = ".*ISPN004034:.*")
|
|
+ public void testUnsafeClassNotAllowed() {
|
|
+ remoteCacheManager.getCache().put("unsafe", new UnsafeClass());
|
|
+ remoteCacheManager.getCache().get("unsafe");
|
|
+ }
|
|
+
|
|
+ public void testSafeClassAllowed() {
|
|
+ remoteCacheManager.getCache().put("safe", new Person());
|
|
+ remoteCacheManager.getCache().get("safe");
|
|
+ }
|
|
+
|
|
+ private static final class UnsafeClass implements Serializable {
|
|
+ }
|
|
+
|
|
+}
|
|
diff --git a/commons/src/main/java/org/infinispan/commons/logging/Log.java b/commons/src/main/java/org/infinispan/commons/logging/Log.java
|
|
index 1054f40cba6..34d7345777d 100644
|
|
--- a/commons/src/main/java/org/infinispan/commons/logging/Log.java
|
|
+++ b/commons/src/main/java/org/infinispan/commons/logging/Log.java
|
|
@@ -4,6 +4,7 @@
|
|
import static org.jboss.logging.Logger.Level.WARN;
|
|
|
|
import org.infinispan.commons.CacheConfigurationException;
|
|
+import org.infinispan.commons.CacheException;
|
|
import org.jboss.logging.BasicLogger;
|
|
import org.jboss.logging.annotations.Cause;
|
|
import org.jboss.logging.annotations.LogMessage;
|
|
@@ -107,5 +108,9 @@
|
|
|
|
@Message(value = "Cannot find resource '%s'", id = 918)
|
|
IOException cannotFindResource(String fileName);
|
|
+
|
|
+ @Message(value = "Class '%s' blocked by deserialization white list. Adjust the client configuration serialization white list regular expression to include this class.", id = 28023)
|
|
+ CacheException classNotInWhitelist(String className);
|
|
+
|
|
}
|
|
|
|
diff --git a/commons/src/main/java/org/infinispan/commons/marshall/MarshallUtil.java b/commons/src/main/java/org/infinispan/commons/marshall/MarshallUtil.java
|
|
index f8b39af35aa..fa2f2ed3804 100644
|
|
--- a/commons/src/main/java/org/infinispan/commons/marshall/MarshallUtil.java
|
|
+++ b/commons/src/main/java/org/infinispan/commons/marshall/MarshallUtil.java
|
|
@@ -1,15 +1,20 @@
|
|
package org.infinispan.commons.marshall;
|
|
|
|
import net.jcip.annotations.Immutable;
|
|
+import org.infinispan.commons.logging.Log;
|
|
+import org.infinispan.commons.logging.LogFactory;
|
|
import org.infinispan.commons.util.Util;
|
|
|
|
import java.io.IOException;
|
|
import java.io.ObjectInput;
|
|
import java.io.ObjectOutput;
|
|
import java.util.Collection;
|
|
+import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Objects;
|
|
import java.util.UUID;
|
|
+import java.util.regex.Matcher;
|
|
+import java.util.regex.Pattern;
|
|
|
|
/**
|
|
* MarshallUtil.
|
|
@@ -22,6 +27,8 @@
|
|
|
|
private static final byte NULL_VALUE = -1;
|
|
|
|
+ private static final Log log = LogFactory.getLog(MarshallUtil.class);
|
|
+
|
|
/**
|
|
* Marshall the {@code map} to the {@code ObjectOutput}.
|
|
* <p>
|
|
@@ -365,6 +372,29 @@ public static int unmarshallInt(ObjectInput in) throws IOException {
|
|
}
|
|
}
|
|
|
|
+ /**
|
|
+ * Checks whether class name is matched by the class name white list regular expressions provided.
|
|
+ *
|
|
+ * @param className class to verify
|
|
+ * @param whitelist list of regular expressions to match class name against
|
|
+ * @return true if the class matched at least one of the regular expressions,
|
|
+ * false otherwise
|
|
+ */
|
|
+ public static boolean isSafeClass(String className, List<String> whitelist) {
|
|
+ for (String whiteRegExp : whitelist) {
|
|
+ Pattern whitePattern = Pattern.compile(whiteRegExp);
|
|
+ Matcher whiteMatcher = whitePattern.matcher(className);
|
|
+ if (whiteMatcher.find()) {
|
|
+ if (log.isTraceEnabled())
|
|
+ log.tracef("Whitelist match: '%s'", className);
|
|
+
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+ }
|
|
+
|
|
public interface ArrayBuilder<E> {
|
|
E[] build(int size);
|
|
}
|
|
diff --git a/commons/src/main/java/org/infinispan/commons/marshall/jboss/GenericJBossMarshaller.java b/commons/src/main/java/org/infinispan/commons/marshall/jboss/GenericJBossMarshaller.java
|
|
index d623a408cdf..eada3cda0a6 100644
|
|
--- a/commons/src/main/java/org/infinispan/commons/marshall/jboss/GenericJBossMarshaller.java
|
|
+++ b/commons/src/main/java/org/infinispan/commons/marshall/jboss/GenericJBossMarshaller.java
|
|
@@ -1,5 +1,11 @@
|
|
package org.infinispan.commons.marshall.jboss;
|
|
|
|
+import org.infinispan.commons.marshall.MarshallUtil;
|
|
+import org.jboss.marshalling.Unmarshaller;
|
|
+
|
|
+import java.io.IOException;
|
|
+import java.util.List;
|
|
+
|
|
/**
|
|
* A marshaller that makes use of <a href="http://www.jboss.org/jbossmarshalling">JBoss Marshalling</a>
|
|
* to serialize and deserialize objects. This marshaller is oriented at external,
|
|
@@ -23,4 +29,30 @@ public GenericJBossMarshaller(ClassLoader classLoader) {
|
|
new DefaultContextClassResolver(classLoader != null ? classLoader : this.getClass().getClassLoader()));
|
|
}
|
|
|
|
+ public GenericJBossMarshaller(List<String> whitelist) {
|
|
+ super();
|
|
+ baseCfg.setClassResolver(
|
|
+ new CheckedClassResolver(whitelist, this.getClass().getClassLoader()));
|
|
+ }
|
|
+
|
|
+ private static final class CheckedClassResolver extends DefaultContextClassResolver {
|
|
+
|
|
+ private final List<String> whitelist;
|
|
+
|
|
+ CheckedClassResolver(List<String> whitelist, ClassLoader defaultClassLoader) {
|
|
+ super(defaultClassLoader);
|
|
+ this.whitelist = whitelist;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Class<?> resolveClass(Unmarshaller unmarshaller, String name, long serialVersionUID) throws IOException, ClassNotFoundException {
|
|
+ boolean safeClass = MarshallUtil.isSafeClass(name, whitelist);
|
|
+ if (!safeClass)
|
|
+ throw log.classNotInWhitelist(name);
|
|
+
|
|
+ return super.resolveClass(unmarshaller, name, serialVersionUID);
|
|
+ }
|
|
+
|
|
+ }
|
|
+
|
|
}
|