You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by go...@apache.org on 2017/11/10 17:58:44 UTC
[geode] branch whitelist_wip updated: Adding configuration
parameters to toggle whitelist behavior of serializable classes.
This is an automated email from the ASF dual-hosted git repository.
gosullivan pushed a commit to branch whitelist_wip
in repository https://gitbox.apache.org/repos/asf/geode.git
The following commit(s) were added to refs/heads/whitelist_wip by this push:
new 026ae92 Adding configuration parameters to toggle whitelist behavior of serializable classes.
026ae92 is described below
commit 026ae92fe2055c09762978696d53d9cd2679bd60
Author: Galen O'Sullivan <go...@pivotal.io>
AuthorDate: Thu Nov 9 17:02:56 2017 -0800
Adding configuration parameters to toggle whitelist behavior of serializable classes.
Open question about removing DataCommandRequest.java toData and fromData
Signed-off-by: Brian Rowe <br...@pivotal.io>
---
.../geode/distributed/ConfigurationProperties.java | 27 ++++
.../internal/AbstractDistributionConfig.java | 3 +
.../distributed/internal/DistributionConfig.java | 48 +++++++
.../internal/DistributionConfigImpl.java | 26 +++-
.../geode/internal/InternalDataSerializer.java | 40 +++---
.../internal/cli/domain/DataCommandRequest.java | 33 -----
.../AnalyzeSerializablesJUnitTest.java | 9 +-
.../internal/DistributionConfigJUnitTest.java | 6 +-
...alDataSerializerSerializationWhitelistTest.java | 140 +++++++++++++++++++++
9 files changed, 272 insertions(+), 60 deletions(-)
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/ConfigurationProperties.java b/geode-core/src/main/java/org/apache/geode/distributed/ConfigurationProperties.java
index aae7d8a..37f780c 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/ConfigurationProperties.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/ConfigurationProperties.java
@@ -2070,4 +2070,31 @@ public interface ConfigurationProperties {
* <U>Since</U>: Geode 1.0
*/
String SSL_WEB_SERVICE_REQUIRE_AUTHENTICATION = "ssl-web-require-authentication";
+ /**
+ * The static String definition of the <i>"validate-serializable-objects"</i> property
+ *
+ * <U>Description</U>If true checks incoming java serializable objects against a filter (allows
+ * internal Geode classes and any others provided in the serializable-object-filter property).
+ * </p>
+ * <U>Default</U>: "false"
+ * </p>
+ * <U>Since</U>: Geode 1.4
+ */
+ String VALIDATE_SERIALIZABLE_OBJECTS = "validate-serializable-objects";
+ /**
+ * The static String definition of the <i>"serializable-object-filter"</i> property
+ *
+ * <U>Description</U>A user provided whitelist of objects that the system will allow to serialize.
+ *
+ * <p>
+ * See java.io.ObjectInputFilter.Config for details on the syntax for creating filters.
+ * https://docs.oracle.com/javase/9/docs/api/java/io/ObjectInputFilter.Config.html
+ * </p>
+ * </p>
+ * <U>Default</U>: "!*"
+ * </p>
+ * <U>Since</U>: Geode 1.4
+ *
+ */
+ String SERIALIZABLE_OBJECT_FILTER = "serializable-object-filter";
}
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/AbstractDistributionConfig.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/AbstractDistributionConfig.java
index bfc5e1d..e143fed 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/AbstractDistributionConfig.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/AbstractDistributionConfig.java
@@ -1220,6 +1220,9 @@ public abstract class AbstractDistributionConfig extends AbstractConfig
m.put(SSL_DEFAULT_ALIAS, "The default certificate alias to be used in a multi-key keystore");
m.put(SSL_WEB_SERVICE_REQUIRE_AUTHENTICATION,
"This property determines is the HTTP service with use mutual ssl authentication.");
+ m.put(VALIDATE_SERIALIZABLE_OBJECTS,
+ "If true checks incoming java serializable objects against a filter");
+ m.put(SERIALIZABLE_OBJECT_FILTER, "The filter to check incoming java serializables against");
dcAttDescriptions = Collections.unmodifiableMap(m);
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfig.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfig.java
index 958ea15..200828c 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfig.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfig.java
@@ -4864,6 +4864,54 @@ public interface DistributionConfig extends Config, LogConfig {
*/
boolean DEFAULT_SSL_WEB_SERVICE_REQUIRE_AUTHENTICATION = false;
+ /**
+ * Returns the value of the {@link ConfigurationProperties#VALIDATE_SERIALIZABLE_OBJECTS} property
+ */
+ @ConfigAttributeGetter(name = VALIDATE_SERIALIZABLE_OBJECTS)
+ boolean getValidateSerializableObjects();
+
+ /**
+ * Sets the value of the {@link ConfigurationProperties#VALIDATE_SERIALIZABLE_OBJECTS} property
+ */
+ @ConfigAttributeSetter(name = VALIDATE_SERIALIZABLE_OBJECTS)
+ void setValidateSerializableObjects(boolean value);
+
+ /**
+ * The name of the {@link ConfigurationProperties#VALIDATE_SERIALIZABLE_OBJECTS} property
+ */
+ @ConfigAttribute(type = Boolean.class)
+ String VALIDATE_SERIALIZABLE_OBJECTS_NAME = VALIDATE_SERIALIZABLE_OBJECTS;
+
+ /**
+ * The default value of the {@link ConfigurationProperties#VALIDATE_SERIALIZABLE_OBJECTS}
+ * property.
+ */
+ boolean DEFAULT_VALIDATE_SERIALIZABLE_OBJECTS = false;
+
+ /**
+ * Returns the value of the {@link ConfigurationProperties#SERIALIZABLE_OBJECT_FILTER} property
+ */
+ @ConfigAttributeGetter(name = SERIALIZABLE_OBJECT_FILTER)
+ String getSerializableObjectFilter();
+
+ /**
+ * Sets the value of the {@link ConfigurationProperties#SERIALIZABLE_OBJECT_FILTER} property
+ */
+ @ConfigAttributeSetter(name = SERIALIZABLE_OBJECT_FILTER)
+ void setSerializableObjectFilter(String value);
+
+ /**
+ * The name of the {@link ConfigurationProperties#SERIALIZABLE_OBJECT_FILTER} property
+ */
+ @ConfigAttribute(type = String.class)
+ String SERIALIZABLE_OBJECT_FILTER_NAME = SERIALIZABLE_OBJECT_FILTER;
+
+ /**
+ * The default value of the {@link ConfigurationProperties#SERIALIZABLE_OBJECT_FILTER} property.
+ * Current value is a pattern for rejecting everything <code>"!*"</code>
+ */
+ String DEFAULT_SERIALIZABLE_OBJECT_FILTER = "!*";
+
// *************** Initializers to gather all the annotations in this class
// ************************
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfigImpl.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfigImpl.java
index abaa83c..502884a 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfigImpl.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfigImpl.java
@@ -627,6 +627,9 @@ public class DistributionConfigImpl extends AbstractDistributionConfig implement
protected String userCommandPackages = DEFAULT_USER_COMMAND_PACKAGES;
+ private boolean validateSerializableObjects = DEFAULT_VALIDATE_SERIALIZABLE_OBJECTS;
+ private String serializableObjectFilter = DEFAULT_SERIALIZABLE_OBJECT_FILTER;
+
/**
* "off-heap-memory-size" with value of "" or "<size>[g|m]"
*/
@@ -841,7 +844,8 @@ public class DistributionConfigImpl extends AbstractDistributionConfig implement
this.sslDefaultAlias = other.getSSLDefaultAlias();
this.sslWebServiceRequireAuthentication = other.getSSLWebRequireAuthentication();
-
+ this.validateSerializableObjects = other.getValidateSerializableObjects();
+ this.serializableObjectFilter = other.getSerializableObjectFilter();
}
/**
@@ -2853,6 +2857,26 @@ public class DistributionConfigImpl extends AbstractDistributionConfig implement
this.sslWebServiceRequireAuthentication = requiresAuthenatication;
}
+ @Override
+ public boolean getValidateSerializableObjects() {
+ return validateSerializableObjects;
+ }
+
+ @Override
+ public void setValidateSerializableObjects(boolean value) {
+ this.validateSerializableObjects = value;
+ }
+
+ @Override
+ public String getSerializableObjectFilter() {
+ return serializableObjectFilter;
+ }
+
+ @Override
+ public void setSerializableObjectFilter(String value) {
+ this.serializableObjectFilter = value;
+ }
+
/////////////////////// Utility Methods ///////////////////////
diff --git a/geode-core/src/main/java/org/apache/geode/internal/InternalDataSerializer.java b/geode-core/src/main/java/org/apache/geode/internal/InternalDataSerializer.java
index b591cd4..6e0b241 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/InternalDataSerializer.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/InternalDataSerializer.java
@@ -78,7 +78,6 @@ import java.io.DataInput;
import java.io.DataOutput;
import java.io.EOFException;
import java.io.File;
-import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -140,12 +139,23 @@ public abstract class InternalDataSerializer extends DataSerializer implements D
* serialization.
*/
private static final Map<String, DataSerializer> classesToSerializers = new ConcurrentHashMap<>();
+ private static final String SANCTIONED_SERIALIZABLES_DEPENDENCIES_PATTERN =
+ "java.**;javax.management.**" + ";javax.print.attribute.EnumSyntax" // used for some *old*
+ // enums
+ + ";antlr.**" // query AST objects
+ + ";org.apache.commons.modeler.AttributeInfo" // old Admin API
+ + ";org.apache.commons.modeler.FeatureInfo" // old Admin API
+ + ";org.apache.commons.modeler.ManagedBean" // old Admin API
+ + ";";
+
+
+ private static ObjectInputFilter defaultSerializationFilter =
+ ObjectInputFilter.Config.createFilter("**");
/**
* A deserialization filter for ObjectInputStreams
*/
- private static ObjectInputFilter serializationFilter =
- ObjectInputFilter.Config.createFilter("**");
+ private static ObjectInputFilter serializationFilter = defaultSerializationFilter;
private static final String serializationVersionTxt =
System.getProperty(DistributionConfig.GEMFIRE_PREFIX + "serializationVersion");
@@ -209,29 +219,21 @@ public abstract class InternalDataSerializer extends DataSerializer implements D
*/
public static void initialize(DistributionConfig distributionConfig,
Collection<DistributedSystemService> services) {
-
- String configSerializationSpec = ""; // distributionConfig.getSerializationSpecification()
- // if (configSerializationSpec == null || configSerializationSpec.trim().length() == 0) {
- // return;
- // }
-
- String serializationFilterSpec =
- "java.**;javax.management.**;javax.print.attribute.EnumSyntax" + ";antlr.**" // query AST
- // objects
- + ";org.apache.commons.modeler.AttributeInfo" // old Admin API
- + ";org.apache.commons.modeler.FeatureInfo" // old Admin API
- + ";org.apache.commons.modeler.ManagedBean" // old Admin API
- + ";" + configSerializationSpec + ";!*"; // everything else is black-listed
-
- if (serializationFilterSpec != null) {
+ if (distributionConfig.getValidateSerializableObjects()) {
if (!ClassUtils.isClassAvailable("sun.misc.ObjectInputFilter")) {
throw new GemFireConfigException(
"A serialization filter has been specified but this version of Java does not support serialization filters - sun.misc.ObjectInputFilter is not available");
}
- createSerializationFilter(serializationFilterSpec, services);
+ createSerializationFilter(SANCTIONED_SERIALIZABLES_DEPENDENCIES_PATTERN
+ + distributionConfig.getSerializableObjectFilter() + ";!*", services);
+ } else {
+ clearSerializationFilter();
}
}
+ private static void clearSerializationFilter() {
+ serializationFilter = defaultSerializationFilter;
+ }
private static void createSerializationFilter(String serializationFilterSpec,
Collection<DistributedSystemService> services) {
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/DataCommandRequest.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/DataCommandRequest.java
index 1b7557b..9c59bdb 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/DataCommandRequest.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/DataCommandRequest.java
@@ -194,37 +194,4 @@ public class DataCommandRequest implements /* Data */ Serializable {
public void setPrincipal(Object principal) {
this.principal = principal;
}
-
- // @Override
- public void toData(DataOutput out) throws IOException {
- DataSerializer.writeString(command, out);
- DataSerializer.writeString(key, out);
- DataSerializer.writeString(value, out);
- DataSerializer.writeBoolean(putIfAbsent, out);
- DataSerializer.writeString(keyClass, out);
- DataSerializer.writeString(valueClass, out);
- DataSerializer.writeString(regionName, out);
- DataSerializer.writeString(removeAllKeys, out);
- DataSerializer.writeBoolean(recursive, out);
- DataSerializer.writeBoolean(loadOnCacheMiss, out);
- DataSerializer.writeObject(principal, out);
- }
-
- // @Override
- public void fromData(DataInput in) throws IOException, ClassNotFoundException {
- command = DataSerializer.readString(in);
- key = DataSerializer.readString(in);
- value = DataSerializer.readString(in);
- putIfAbsent = DataSerializer.readBoolean(in);
- keyClass = DataSerializer.readString(in);
- valueClass = DataSerializer.readString(in);
- regionName = DataSerializer.readString(in);
- removeAllKeys = DataSerializer.readString(in);
- recursive = DataSerializer.readBoolean(in);
- loadOnCacheMiss = DataSerializer.readBoolean(in);
- principal = DataSerializer.readObject(in);
- }
-
-
-
}
diff --git a/geode-core/src/test/java/org/apache/geode/codeAnalysis/AnalyzeSerializablesJUnitTest.java b/geode-core/src/test/java/org/apache/geode/codeAnalysis/AnalyzeSerializablesJUnitTest.java
index 0ea8c69..2df8cf3 100644
--- a/geode-core/src/test/java/org/apache/geode/codeAnalysis/AnalyzeSerializablesJUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/codeAnalysis/AnalyzeSerializablesJUnitTest.java
@@ -60,10 +60,10 @@ import sun.reflect.ReflectionFactory;
import org.apache.geode.CancelException;
import org.apache.geode.DataSerializer;
-import org.apache.geode.ForcedDisconnectException;
import org.apache.geode.codeAnalysis.decode.CompiledClass;
import org.apache.geode.codeAnalysis.decode.CompiledField;
import org.apache.geode.codeAnalysis.decode.CompiledMethod;
+import org.apache.geode.distributed.ConfigurationProperties;
import org.apache.geode.distributed.internal.DistributedSystemService;
import org.apache.geode.distributed.internal.DistributionConfig;
import org.apache.geode.distributed.internal.DistributionConfigImpl;
@@ -191,9 +191,10 @@ public class AnalyzeSerializablesJUnitTest {
@Test
public void excludedClassesExistAndDoNotDeserialize() throws Exception {
List<String> excludedClasses = loadExcludedClasses(getResourceAsFile(EXCLUDED_CLASSES_TXT));
- DistributionConfig distributionConfig = new DistributionConfigImpl(new Properties());
- InternalDataSerializer.initialize(distributionConfig,
- new ArrayList<DistributedSystemService>());
+ Properties properties = new Properties();
+ properties.setProperty(ConfigurationProperties.VALIDATE_SERIALIZABLE_OBJECTS, "true");
+ DistributionConfig distributionConfig = new DistributionConfigImpl(properties);
+ InternalDataSerializer.initialize(distributionConfig, new ArrayList<>());
for (String filePath : excludedClasses) {
String className = filePath.replaceAll("/", ".");
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/internal/DistributionConfigJUnitTest.java b/geode-core/src/test/java/org/apache/geode/distributed/internal/DistributionConfigJUnitTest.java
index 7e5f83f..4b96bf2 100644
--- a/geode-core/src/test/java/org/apache/geode/distributed/internal/DistributionConfigJUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/distributed/internal/DistributionConfigJUnitTest.java
@@ -99,7 +99,7 @@ public class DistributionConfigJUnitTest {
@Test
public void testGetAttributeNames() {
String[] attNames = AbstractDistributionConfig._getAttNames();
- assertEquals(attNames.length, 157);
+ assertEquals(attNames.length, 159);
List boolList = new ArrayList();
List intList = new ArrayList();
@@ -133,9 +133,9 @@ public class DistributionConfigJUnitTest {
// TODO - This makes no sense. One has no idea what the correct expected number of attributes
// are.
- assertEquals(29, boolList.size());
+ assertEquals(30, boolList.size());
assertEquals(33, intList.size());
- assertEquals(86, stringList.size());
+ assertEquals(87, stringList.size());
assertEquals(5, fileList.size());
assertEquals(4, otherList.size());
}
diff --git a/geode-core/src/test/java/org/apache/geode/internal/InternalDataSerializerSerializationWhitelistTest.java b/geode-core/src/test/java/org/apache/geode/internal/InternalDataSerializerSerializationWhitelistTest.java
new file mode 100644
index 0000000..1064e2f
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/InternalDataSerializerSerializationWhitelistTest.java
@@ -0,0 +1,140 @@
+package org.apache.geode.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Properties;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.DataSerializer;
+import org.apache.geode.distributed.internal.DistributionConfig;
+import org.apache.geode.distributed.internal.DistributionConfigImpl;
+import org.apache.geode.test.junit.categories.UnitTest;
+
+/*
+ * 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.
+ */
+@Category(UnitTest.class)
+public class InternalDataSerializerSerializationWhitelistTest {
+ private HeapDataOutputStream outputStream;
+ private Object testSerializable;
+ private Properties properties;
+
+ @Before
+ public void setUp() {
+ outputStream = new HeapDataOutputStream(Version.CURRENT);
+ testSerializable = new TestSerializable();
+ properties = new Properties();
+ }
+
+ @AfterClass
+ public static void clearDataSerializerFilter() {
+ InternalDataSerializer.initialize(new DistributionConfigImpl(new Properties()),
+ new ArrayList<>());
+ }
+
+ @Test
+ public void distributionConfigDefaults() {
+ DistributionConfigImpl distributionConfig = new DistributionConfigImpl(new Properties());
+
+ assertFalse(distributionConfig.getValidateSerializableObjects());
+ assertEquals("!*", distributionConfig.getSerializableObjectFilter());
+ }
+
+ @Test
+ public void canSerializeWhenFilterIsDisabled() throws Exception {
+ trySerializingTestObject(new Properties());
+ }
+
+ @Test(expected = java.io.InvalidClassException.class)
+ public void notWhitelistedWithFilterCannotSerialize() throws Exception {
+ properties.setProperty(DistributionConfig.VALIDATE_SERIALIZABLE_OBJECTS_NAME, "true");
+
+ trySerializingTestObject(properties);
+ }
+
+ @Test
+ public void whitelistedWithFilterCanSerialize() throws Exception {
+ properties.setProperty(DistributionConfig.VALIDATE_SERIALIZABLE_OBJECTS_NAME, "true");
+ properties.setProperty(DistributionConfig.SERIALIZABLE_OBJECT_FILTER_NAME,
+ TestSerializable.class.getName());
+
+ trySerializingTestObject(properties);
+ }
+
+ @Test(expected = java.io.InvalidClassException.class)
+ public void whitelistedWithNonlMatchingFilterCannotSerialize() throws Exception {
+ trySerializingWithFilter("RabidMonkeyTurnip");
+ }
+
+ @Test(expected = java.io.InvalidClassException.class)
+ public void whitelistedWithPartialMatchingFilterCannotSerialize() throws Exception {
+ trySerializingWithFilter("TestSerializable"); // Not fully qualified class name
+ }
+
+ @Test(expected = java.io.InvalidClassException.class)
+ public void whitelistedWithEmptyFilterCannotSerialize() throws Exception {
+ trySerializingWithFilter("");
+ }
+
+ @Test(expected = java.io.InvalidClassException.class)
+ public void whitelistedWithIncorrectPathFilterCannotSerialize() throws Exception {
+ trySerializingWithFilter(
+ "org.apache.commons.InternalDataSerializerSerializationWhitelistTest$TestSerializable");
+ }
+
+ @Test(expected = java.io.InvalidClassException.class)
+ public void whitelistedWithWildcardPathFilterCannotSerialize() throws Exception {
+ trySerializingWithFilter("org.apache.*");
+ }
+
+ @Test
+ public void whitelistedWithWildcardSubpathFilterCanSerialize() throws Exception {
+ trySerializingWithFilter("org.apache.**");
+ }
+
+ private void trySerializingWithFilter(String filter) throws Exception {
+ properties.setProperty(DistributionConfig.VALIDATE_SERIALIZABLE_OBJECTS_NAME, "true");
+ properties.setProperty(DistributionConfig.SERIALIZABLE_OBJECT_FILTER_NAME, filter);
+
+ trySerializingTestObject(properties);
+ }
+
+ private void trySerializingTestObject(Properties properties)
+ throws IOException, ClassNotFoundException {
+ DistributionConfig distributionConfig = new DistributionConfigImpl(properties);
+ InternalDataSerializer.initialize(distributionConfig, new ArrayList<>());
+
+ DataSerializer.writeObject(testSerializable, outputStream);
+
+ // if this throws, we're good!
+ DataSerializer
+ .readObject(new DataInputStream(new ByteArrayInputStream(outputStream.toByteArray())));
+ }
+
+ private static class TestSerializable implements Serializable {
+
+ }
+
+}
--
To stop receiving notification emails like this one, please contact
['"commits@geode.apache.org" <co...@geode.apache.org>'].