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
commit 731ac2b4206615fb6bdaa54db371c7f8b7956fd4 Author: Galen O'Sullivan <gosulli...@pivotal.io> AuthorDate: Wed Nov 15 10:55:23 2017 -0800 Whitelist: Work with older versions of Java 8 and achieve this by moving references to ObjectInputFilter out of InternalDataSerializer. Signed-off-by: Dan Smith <dsm...@pivotal.io> --- .../geode/internal/EmptyInputStreamFilter.java | 24 +++ .../apache/geode/internal/InputStreamFilter.java | 21 +++ .../geode/internal/InternalDataSerializer.java | 176 ++++++++------------- .../internal/ObjectInputStreamFilterWrapper.java | 92 +++++++++++ ...alDataSerializerSerializationWhitelistTest.java | 12 ++ 5 files changed, 211 insertions(+), 114 deletions(-) diff --git a/geode-core/src/main/java/org/apache/geode/internal/EmptyInputStreamFilter.java b/geode-core/src/main/java/org/apache/geode/internal/EmptyInputStreamFilter.java new file mode 100644 index 0000000..82369a0 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/EmptyInputStreamFilter.java @@ -0,0 +1,24 @@ +/* + * 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.geode.internal; + +import java.io.ObjectInputStream; + +public class EmptyInputStreamFilter implements InputStreamFilter { + @Override + public void setFilterOn(ObjectInputStream ois) { + // Do nothing, this is the case where we don't filter. + } +} diff --git a/geode-core/src/main/java/org/apache/geode/internal/InputStreamFilter.java b/geode-core/src/main/java/org/apache/geode/internal/InputStreamFilter.java new file mode 100644 index 0000000..19d4102 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/InputStreamFilter.java @@ -0,0 +1,21 @@ +/* + * 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.geode.internal; + +import java.io.ObjectInputStream; + +public interface InputStreamFilter { + void setFilterOn(ObjectInputStream ois); +} 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 71a802a..969ece4 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 @@ -14,7 +14,60 @@ */ package org.apache.geode.internal; +import java.io.BufferedReader; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.EOFException; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.NotSerializableException; +import java.io.ObjectInput; +import java.io.ObjectInputStream; +import java.io.ObjectOutput; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamClass; +import java.io.OutputStream; +import java.io.Serializable; +import java.io.UTFDataFormatException; +import java.lang.ref.WeakReference; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; +import java.lang.reflect.Proxy; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.net.InetAddress; +import java.net.URL; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; +import java.util.Set; +import java.util.Stack; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.UUID; +import java.util.Vector; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeUnit; + import org.apache.commons.lang.StringUtils; +import org.apache.logging.log4j.Logger; + import org.apache.geode.CancelException; import org.apache.geode.CanonicalInstantiator; import org.apache.geode.DataSerializable; @@ -24,7 +77,6 @@ import org.apache.geode.GemFireIOException; import org.apache.geode.GemFireRethrowable; import org.apache.geode.Instantiator; import org.apache.geode.InternalGemFireError; -import org.apache.geode.InternalGemFireException; import org.apache.geode.SerializationException; import org.apache.geode.SystemFailure; import org.apache.geode.ToDataException; @@ -70,59 +122,6 @@ import org.apache.geode.pdx.internal.PdxReaderImpl; import org.apache.geode.pdx.internal.PdxType; import org.apache.geode.pdx.internal.PdxWriterImpl; import org.apache.geode.pdx.internal.TypeRegistry; -import org.apache.logging.log4j.Logger; -import sun.misc.ObjectInputFilter; - -import java.io.BufferedReader; -import java.io.DataInput; -import java.io.DataOutput; -import java.io.EOFException; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.NotSerializableException; -import java.io.ObjectInput; -import java.io.ObjectInputStream; -import java.io.ObjectOutput; -import java.io.ObjectOutputStream; -import java.io.ObjectStreamClass; -import java.io.OutputStream; -import java.io.Serializable; -import java.io.UTFDataFormatException; -import java.lang.ref.WeakReference; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Modifier; -import java.lang.reflect.Proxy; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.net.InetAddress; -import java.net.URL; -import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Hashtable; -import java.util.IdentityHashMap; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Properties; -import java.util.Set; -import java.util.Stack; -import java.util.TreeMap; -import java.util.TreeSet; -import java.util.UUID; -import java.util.Vector; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.TimeUnit; /** * Contains static methods for data serializing instances of internal GemFire classes. It also @@ -151,13 +150,12 @@ public abstract class InternalDataSerializer extends DataSerializer implements D + ";"; - private static ObjectInputFilter defaultSerializationFilter = - ObjectInputFilter.Config.createFilter("**"); + private static InputStreamFilter defaultSerializationFilter = new EmptyInputStreamFilter(); /** * A deserialization filter for ObjectInputStreams */ - private static ObjectInputFilter serializationFilter = defaultSerializationFilter; + private static InputStreamFilter serializationFilter = defaultSerializationFilter; private static final String serializationVersionTxt = System.getProperty(DistributionConfig.GEMFIRE_PREFIX + "serializationVersion"); @@ -226,8 +224,9 @@ public abstract class InternalDataSerializer extends DataSerializer implements D 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(SANCTIONED_SERIALIZABLES_DEPENDENCIES_PATTERN - + distributionConfig.getSerializableObjectFilter() + ";!*", services); + serializationFilter = + new ObjectInputStreamFilterWrapper(SANCTIONED_SERIALIZABLES_DEPENDENCIES_PATTERN + + distributionConfig.getSerializableObjectFilter() + ";!*", services); } else { clearSerializationFilter(); } @@ -237,59 +236,11 @@ public abstract class InternalDataSerializer extends DataSerializer implements D serializationFilter = defaultSerializationFilter; } - private static void createSerializationFilter(String serializationFilterSpec, - Collection<DistributedSystemService> services) { - - Set<String> sanctionedClasses = new HashSet<>(500); - for (DistributedSystemService service : services) { - try { - sanctionedClasses.addAll(service.getSerializationWhitelist()); - } catch (IOException e) { - e.printStackTrace(); - } - } - try { - URL sanctionedSerializables = ClassPathLoader.getLatest() - .getResource(InternalDataSerializer.class, "sanctionedSerializables.txt"); - Collection<String> coreClassNames = loadClassNames(sanctionedSerializables); - sanctionedClasses.addAll(coreClassNames); - } catch (IOException e) { - throw new InternalGemFireException( - "unable to read sanctionedSerializables.txt to form a serialization white-list", e); - } - - logger.debug("setting a serialization filter containing {}", serializationFilterSpec); - - final ObjectInputFilter userFilter = - ObjectInputFilter.Config.createFilter(serializationFilterSpec); - serializationFilter = filterInfo -> { - if (filterInfo.serialClass() == null) { - return userFilter.checkInput(filterInfo); - } - - String className = filterInfo.serialClass().getName(); - if (filterInfo.serialClass().isArray()) { - className = filterInfo.serialClass().getComponentType().getName(); - } - if (sanctionedClasses.contains(className)) { - return ObjectInputFilter.Status.ALLOWED; - // return ObjectInputFilter.Status.UNDECIDED; - } else { - ObjectInputFilter.Status status = userFilter.checkInput(filterInfo); - if (status == ObjectInputFilter.Status.REJECTED) { - logger.warn("Serialization filter is rejecting class {}", className); - } - return status; - } - }; - - // global filter - if we enable this it will affect all ObjectInputStreams - // ObjectInputFilter.Config.setSerialFilter(serializationFilter); - } /** - * Loads the class names from sanctionedSerializables.txt, a file that is also maintained for - * backward-compatibility testing with AnalyzeSerializablesJUnitTest + * {@link DistributedSystemService}s that need to whitelist Serializable objects can use this to + * read them from a file and then return them via + * {@link DistributedSystemService#getSerializationWhitelist} */ public static Collection<String> loadClassNames(URL sanctionedSerializables) throws IOException { Collection<String> result = new ArrayList(1000); @@ -2966,10 +2917,7 @@ public abstract class InternalDataSerializer extends DataSerializer implements D } ObjectInput ois = new DSObjectInputStream(stream); - if (serializationFilter != null) { - ObjectInputFilter.Config.setObjectInputFilter((ObjectInputStream) ois, - serializationFilter); - } + serializationFilter.setFilterOn((ObjectInputStream) ois); if (stream instanceof VersionedDataStream) { Version v = ((VersionedDataStream) stream).getVersion(); if (v != null && v != Version.CURRENT) { diff --git a/geode-core/src/main/java/org/apache/geode/internal/ObjectInputStreamFilterWrapper.java b/geode-core/src/main/java/org/apache/geode/internal/ObjectInputStreamFilterWrapper.java new file mode 100644 index 0000000..841d052 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/ObjectInputStreamFilterWrapper.java @@ -0,0 +1,92 @@ +/* + * 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.geode.internal; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.net.URL; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import org.apache.logging.log4j.Logger; + +import org.apache.geode.InternalGemFireException; +import org.apache.geode.distributed.internal.DistributedSystemService; +import org.apache.geode.internal.logging.LogService; + +import sun.misc.ObjectInputFilter; + + +public class ObjectInputStreamFilterWrapper implements InputStreamFilter { + private static final Logger logger = LogService.getLogger(); + private final ObjectInputFilter serializationFilter; + + public ObjectInputStreamFilterWrapper(String serializationFilterSpec, + Collection<DistributedSystemService> services) { + + Set<String> sanctionedClasses = new HashSet<>(500); + for (DistributedSystemService service : services) { + try { + sanctionedClasses.addAll(service.getSerializationWhitelist()); + } catch (IOException e) { + e.printStackTrace(); + } + } + try { + URL sanctionedSerializables = ClassPathLoader.getLatest() + .getResource(InternalDataSerializer.class, "sanctionedSerializables.txt"); + Collection<String> coreClassNames = + InternalDataSerializer.loadClassNames(sanctionedSerializables); + sanctionedClasses.addAll(coreClassNames); + } catch (IOException e) { + throw new InternalGemFireException( + "unable to read sanctionedSerializables.txt to form a serialization white-list", e); + } + + logger.debug("setting a serialization filter containing {}", serializationFilterSpec); + + final ObjectInputFilter userFilter = + ObjectInputFilter.Config.createFilter(serializationFilterSpec); + serializationFilter = filterInfo -> { + if (filterInfo.serialClass() == null) { + return userFilter.checkInput(filterInfo); + } + + String className = filterInfo.serialClass().getName(); + if (filterInfo.serialClass().isArray()) { + className = filterInfo.serialClass().getComponentType().getName(); + } + if (sanctionedClasses.contains(className)) { + return ObjectInputFilter.Status.ALLOWED; + // return ObjectInputFilter.Status.UNDECIDED; + } else { + ObjectInputFilter.Status status = userFilter.checkInput(filterInfo); + if (status == ObjectInputFilter.Status.REJECTED) { + logger.warn("Serialization filter is rejecting class {}", className); + } + return status; + } + }; + + // global filter - if we enable this it will affect all ObjectInputStreams + // ObjectInputFilter.Config.setSerialFilter(serializationFilter); + } + + @Override + public void setFilterOn(ObjectInputStream objectInputStream) { + ObjectInputFilter.Config.setObjectInputFilter(objectInputStream, serializationFilter); + } +} 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 index 1064e2f..73690d9 100644 --- a/geode-core/src/test/java/org/apache/geode/internal/InternalDataSerializerSerializationWhitelistTest.java +++ b/geode-core/src/test/java/org/apache/geode/internal/InternalDataSerializerSerializationWhitelistTest.java @@ -12,6 +12,7 @@ import java.util.ArrayList; import java.util.Properties; import org.junit.AfterClass; +import org.junit.Assume; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -43,11 +44,22 @@ public class InternalDataSerializerSerializationWhitelistTest { @Before public void setUp() { + Assume.assumeTrue("ObjectInputFilter is present in this JVM (post- 8.111)", + hasObjectInputFilter()); outputStream = new HeapDataOutputStream(Version.CURRENT); testSerializable = new TestSerializable(); properties = new Properties(); } + private boolean hasObjectInputFilter() { + try { + Class.forName("sun.misc.ObjectInputFilter"); + return true; + } catch (ClassNotFoundException e) { + return false; + } + } + @AfterClass public static void clearDataSerializerFilter() { InternalDataSerializer.initialize(new DistributionConfigImpl(new Properties()), -- To stop receiving notification emails like this one, please contact "commits@geode.apache.org" <commits@geode.apache.org>.