You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by kl...@apache.org on 2022/03/29 19:29:32 UTC
[geode] 05/06: GEODE-9758: Add internal serial filter API (#7217)
This is an automated email from the ASF dual-hosted git repository.
klund pushed a commit to branch support/1.14
in repository https://gitbox.apache.org/repos/asf/geode.git
commit 92e0e89c982ef4ed53e0a7be0194aea45adb8726
Author: Kirk Lund <kl...@apache.org>
AuthorDate: Tue Jan 18 11:01:25 2022 -0800
GEODE-9758: Add internal serial filter API (#7217)
GEODE-9758: Add internal serial filter API #7217
Expand ObjectInputStreamFilterWrapper to be an internal API which
supports all of Geode's uses of Java's ObjectInputFilter.
Introduce a new system property, geode.enableGlobalSerialFilter, to
enable a process-wide filter with all serializable Geode classes on the
classpath and the value of serializable-object-filter accept-listed.
To enable the process-wide filter with GFSH start commands, add:
* --J=-Dgeode.enableGlobalSerialFilter=true
Functional Capabilities
The internal API lives in geode-serialization and works on OpenJDK
based JREs providing a facade for Java's ObjectInputFilter in Java 8
and Java 9 or greater using reflection. The API provides the following
capabilities:
* creating an ObjectInputFilter
* setting an ObjectInputFilter on an ObjectInputStream
* getting an ObjectInputFilter from a ObjectInputStream
* setting a process-wide ObjectInputFilter
* getting a process-wide ObjectInputFilter
Design Notes
The API defines the following primary interface types:
* factory interfaces for creating instances of types within the API
* filter interfaces to split out single ops from Java's
ObjectInputFilter
* configuration interfaces for handling system properties, logging,
and config validation
The concrete classes in the API receive parameters injected via a
constructor for any collaborators that are not specified by the
interfaces. This is intentional even when the instance is only used
once before de-referencing it. All collaborators that are defined in
the interface are passed in as parameters to the implementing
method; all others are passed in via the constructor and stored as
fields.
(cherry picked from commit 7978abf34707d11da45cff0b7cb7445f18d21438)
---
...artLocatorGlobalSerialFilterAcceptanceTest.java | 138 ++++++++
...StartLocatorJmxSerialFilterAcceptanceTest.java} | 58 ++--
...tartServerGlobalSerialFilterAcceptanceTest.java | 150 +++++++++
.../StartServerJmxSerialFilterAcceptanceTest.java} | 55 ++--
geode-core/build.gradle | 2 +-
...ValidateSerializableObjectsDistributedTest.java | 320 +++++++++++++++++++
.../geode/distributed/LocatorIntegrationTest.java | 180 ++++++-----
...catorLauncherJmxManagerLocalRegressionTest.java | 22 +-
...cherGlobalSerialFilterBlankIntegrationTest.java | 55 ++++
...herGlobalSerialFilterExistsIntegrationTest.java | 55 ++++
...rLauncherGlobalSerialFilterIntegrationTest.java | 52 +++
...alSerialFilterPropertyBlankIntegrationTest.java | 54 ++++
...alSerialFilterPropertyEmptyIntegrationTest.java | 54 ++++
...atorLauncherJmxSerialFilterIntegrationTest.java | 84 +++++
...mxSerialFilterPropertyBlankIntegrationTest.java | 88 ++++++
...mxSerialFilterPropertyEmptyIntegrationTest.java | 88 ++++++
...xSerialFilterPropertyExistsIntegrationTest.java | 90 ++++++
.../filter/LocatorLauncherWithJmxManager.java | 82 +++++
.../filter/SerialFilterAssertions.java | 64 ++++
...cherGlobalSerialFilterBlankIntegrationTest.java | 55 ++++
...herGlobalSerialFilterExistsIntegrationTest.java | 55 ++++
...rLauncherGlobalSerialFilterIntegrationTest.java | 51 +++
...alSerialFilterPropertyBlankIntegrationTest.java | 53 ++++
...alSerialFilterPropertyEmptyIntegrationTest.java | 53 ++++
...rverLauncherJmxSerialFilterIntegrationTest.java | 87 +++++
...mxSerialFilterPropertyBlankIntegrationTest.java | 88 ++++++
...mxSerialFilterPropertyEmptyIntegrationTest.java | 88 ++++++
...xSerialFilterPropertyExistsIntegrationTest.java | 90 ++++++
.../filter/ServerLauncherWithJmxManager.java | 77 +++++
...erConfiguresJmxSerialFilterIntegrationTest.java | 204 ------------
.../internal/ManagementAgentIntegrationTest.java | 6 +-
...erConfiguresJmxSerialFilterIntegrationTest.java | 201 ------------
.../apache/geode/distributed/LocatorLauncher.java | 12 +
.../apache/geode/distributed/ServerLauncher.java | 11 +
.../distributed/internal/DistributionConfig.java | 4 +-
.../DistributedSerializableObjectConfig.java | 51 +++
.../geode/internal/InternalDataSerializer.java | 41 ++-
.../internal/ObjectInputStreamFilterWrapper.java | 233 --------------
.../internal/JmxRmiOpenTypesSerialFilter.java | 148 ---------
.../geode/management/internal/ManagementAgent.java | 10 +-
.../internal/ManagementAgentFactory.java | 3 +-
.../internal/SystemManagementService.java | 9 +-
.../internal/DistributionConfigJUnitTest.java | 8 +
.../DistributedSerializableObjectConfigTest.java | 62 ++++
...lDataSerializerSerializationAcceptlistTest.java | 144 ++++++---
.../InternalDataSerializerShiroAcceptListTest.java | 34 +-
.../internal/JmxRmiOpenTypesSerialFilterTest.java | 351 ---------------------
geode-core/src/test/resources/expected-pom.xml | 10 +-
geode-http-service/build.gradle | 1 +
.../codeAnalysis/AnalyzeSerializablesTestBase.java | 6 +-
...nputFilterApiSetFilterBlankIntegrationTest.java | 63 ++++
...jectInputFilterApiSetFilterIntegrationTest.java | 60 ++++
...InputFilterApiSetFilterNullIntegrationTest.java | 61 ++++
...edSerializablesService.java => ApiPackage.java} | 28 +-
.../serialization/filter/FilterConfiguration.java | 12 +-
.../serialization/filter/FilterPattern.java | 13 +-
.../serialization/filter/GlobalSerialFilter.java | 12 +-
.../filter/GlobalSerialFilterConfiguration.java | 144 +++++++++
...=> GlobalSerialFilterConfigurationFactory.java} | 24 +-
...Service.java => GlobalSerialFilterFactory.java} | 21 +-
.../Java9ReflectiveObjectInputFilterApi.java | 64 ++++
.../filter/JmxSerialFilterConfiguration.java | 72 +++++
.../JmxSerialFilterConfigurationFactory.java | 13 +-
.../filter/NullObjectInputFilter.java | 10 +-
.../serialization/filter/ObjectInputFilter.java | 15 +-
.../serialization/filter/ObjectInputFilterApi.java | 85 +++++
.../filter/ObjectInputFilterApiFactory.java | 9 +-
.../filter/ObjectInputFilterFactory.java | 12 +-
.../filter/ObjectInputFilterUtils.java | 61 ++++
.../filter/OpenMBeanFilterPattern.java | 68 ++++
.../filter/ReflectiveFacadeGlobalSerialFilter.java | 71 +++++
...ReflectiveFacadeGlobalSerialFilterFactory.java} | 29 +-
.../filter/ReflectiveFacadeObjectInputFilter.java | 78 +++++
.../ReflectiveFacadeObjectInputFilterFactory.java | 61 ++++
.../filter/ReflectiveObjectInputFilterApi.java | 269 ++++++++++++++++
.../ReflectiveObjectInputFilterApiFactory.java | 45 +++
.../filter/SanctionedSerializables.java | 13 +-
.../SanctionedSerializablesFilterPattern.java | 111 +++++++
.../filter/SanctionedSerializablesService.java | 6 +
...sService.java => SerializableObjectConfig.java} | 22 +-
...ertyGlobalSerialFilterConfigurationFactory.java | 52 +++
...ropertyJmxSerialFilterConfigurationFactory.java | 55 ++++
...anctioned-geode-serialization-serializables.txt | 1 +
.../SerializationDependenciesTest.java | 2 +-
.../serialization/filter/ApiPackageTest.java | 61 ++++
.../GlobalSerialFilterConfigurationTest.java | 76 +++++
.../JmxSerialFilterConfigurationFactoryTest.java | 65 ++++
.../filter/JmxSerialFilterConfigurationTest.java | 155 +++++++++
.../filter/NullObjectInputFilterTest.java} | 24 +-
.../filter/ObjectInputFilterUtilsTest.java | 94 ++++++
.../filter/OpenMBeanFilterPatternTest.java | 142 +++++++++
...lectiveFacadeGlobalSerialFilterFactoryTest.java | 71 +++++
.../ReflectiveFacadeGlobalSerialFilterTest.java | 104 ++++++
...flectiveFacadeObjectInputFilterFactoryTest.java | 84 +++++
.../ReflectiveFacadeObjectInputFilterTest.java | 142 +++++++++
.../ReflectiveObjectInputFilterApiFactoryTest.java | 60 ++++
.../filter/ReflectiveObjectInputFilterApiTest.java | 223 +++++++++++++
.../SanctionedSerializablesFilterPatternTest.java | 206 ++++++++++++
.../filter/SerializableObjectConfigTest.java | 46 +++
...GlobalSerialFilterConfigurationFactoryTest.java | 75 +++++
...rtyJmxSerialFilterConfigurationFactoryTest.java | 90 ++++++
101 files changed, 5841 insertions(+), 1476 deletions(-)
diff --git a/geode-assembly/src/acceptanceTest/java/org/apache/geode/serialization/filter/StartLocatorGlobalSerialFilterAcceptanceTest.java b/geode-assembly/src/acceptanceTest/java/org/apache/geode/serialization/filter/StartLocatorGlobalSerialFilterAcceptanceTest.java
new file mode 100644
index 0000000..e4cc254
--- /dev/null
+++ b/geode-assembly/src/acceptanceTest/java/org/apache/geode/serialization/filter/StartLocatorGlobalSerialFilterAcceptanceTest.java
@@ -0,0 +1,138 @@
+/*
+ * 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.serialization.filter;
+
+import static org.apache.geode.internal.AvailablePortHelper.getRandomAvailableTCPPorts;
+import static org.apache.geode.test.assertj.LogFileAssert.assertThat;
+import static org.apache.geode.test.awaitility.GeodeAwaitility.await;
+
+import java.nio.file.Path;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.apache.geode.test.junit.rules.RequiresGeodeHome;
+import org.apache.geode.test.junit.rules.gfsh.GfshRule;
+
+public class StartLocatorGlobalSerialFilterAcceptanceTest {
+
+ @Rule
+ public RequiresGeodeHome requiresGeodeHome = new RequiresGeodeHome();
+ @Rule
+ public GfshRule gfshRule = new GfshRule();
+
+ private Path locatorFolder;
+ private int locatorPort;
+ private int locatorJmxPort;
+ private Path locatorLogFile;
+
+ @Before
+ public void setUpFiles() {
+ locatorFolder = gfshRule.getTemporaryFolder().getRoot().toPath().toAbsolutePath();
+ locatorLogFile = locatorFolder.resolve("locator.log");
+ }
+
+ @Before
+ public void setUpPorts() {
+ int[] ports = getRandomAvailableTCPPorts(2);
+ locatorPort = ports[0];
+ locatorJmxPort = ports[1];
+ }
+
+ @Test
+ public void startDoesNotConfigureGlobalSerialFilter_byDefault() {
+ String startLocatorCommand = String.join(" ",
+ "start locator",
+ "--name=locator",
+ "--dir=" + locatorFolder,
+ "--port=" + locatorPort,
+ "--J=-Dgemfire.jmx-manager-port=" + locatorJmxPort);
+
+ gfshRule.execute(startLocatorCommand);
+
+ await().untilAsserted(() -> {
+ assertThat(locatorLogFile.toFile())
+ .as(locatorLogFile.toFile().getAbsolutePath())
+ .exists()
+ .doesNotContain("Global serial filter is now configured.")
+ .doesNotContain("jdk.serialFilter");
+ });
+ }
+
+ @Test
+ public void startDoesNotConfigureGlobalSerialFilter_whenJdkSerialFilterIsNotBlank() {
+ String startLocatorCommand = String.join(" ",
+ "start locator",
+ "--name=locator",
+ "--dir=" + locatorFolder,
+ "--port=" + locatorPort,
+ "--J=-Dgemfire.jmx-manager-port=" + locatorJmxPort,
+ "--J=-Djdk.serialFilter=*");
+
+ gfshRule.execute(startLocatorCommand);
+
+ await().untilAsserted(() -> {
+ assertThat(locatorLogFile.toFile())
+ .as(locatorLogFile.toFile().getAbsolutePath())
+ .exists()
+ .doesNotContain("Global serial filter is now configured.")
+ .contains("jdk.serialFilter");
+ });
+ }
+
+ @Test
+ public void startConfiguresGlobalSerialFilter_whenEnableGlobalSerialFilterIsTrue() {
+ String startLocatorCommand = String.join(" ",
+ "start locator",
+ "--name=locator",
+ "--dir=" + locatorFolder,
+ "--port=" + locatorPort,
+ "--J=-Dgemfire.jmx-manager-port=" + locatorJmxPort,
+ "--J=-Dgeode.enableGlobalSerialFilter=true");
+
+ gfshRule.execute(startLocatorCommand);
+
+ await().untilAsserted(() -> {
+ assertThat(locatorLogFile.toFile())
+ .as(locatorLogFile.toFile().getAbsolutePath())
+ .exists()
+ .contains("Global serial filter is now configured.")
+ .doesNotContain("jdk.serialFilter");
+ });
+ }
+
+ @Test
+ public void startDoesNotConfigureGlobalSerialFilter_whenEnableGlobalSerialFilterIsTrue_andJdkSerialFilterIsNotBlank() {
+ String startLocatorCommand = String.join(" ",
+ "start locator",
+ "--name=locator",
+ "--dir=" + locatorFolder,
+ "--port=" + locatorPort,
+ "--J=-Dgemfire.jmx-manager-port=" + locatorJmxPort,
+ "--J=-Dgeode.enableGlobalSerialFilter=true",
+ "--J=-Djdk.serialFilter=*");
+
+ gfshRule.execute(startLocatorCommand);
+
+ await().untilAsserted(() -> {
+ assertThat(locatorLogFile.toFile())
+ .as(locatorLogFile.toFile().getAbsolutePath())
+ .exists()
+ .doesNotContain("Global serial filter is now configured.")
+ .contains("jdk.serialFilter");
+ });
+ }
+}
diff --git a/geode-assembly/src/acceptanceTest/java/org/apache/geode/management/LocatorManagerConfiguresJmxSerialFilterAcceptanceTest.java b/geode-assembly/src/acceptanceTest/java/org/apache/geode/serialization/filter/StartLocatorJmxSerialFilterAcceptanceTest.java
similarity index 66%
rename from geode-assembly/src/acceptanceTest/java/org/apache/geode/management/LocatorManagerConfiguresJmxSerialFilterAcceptanceTest.java
rename to geode-assembly/src/acceptanceTest/java/org/apache/geode/serialization/filter/StartLocatorJmxSerialFilterAcceptanceTest.java
index de0b8c8..f6d50c2 100644
--- a/geode-assembly/src/acceptanceTest/java/org/apache/geode/management/LocatorManagerConfiguresJmxSerialFilterAcceptanceTest.java
+++ b/geode-assembly/src/acceptanceTest/java/org/apache/geode/serialization/filter/StartLocatorJmxSerialFilterAcceptanceTest.java
@@ -12,65 +12,61 @@
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
-package org.apache.geode.management;
+package org.apache.geode.serialization.filter;
+import static org.apache.commons.lang3.JavaVersion.JAVA_1_8;
+import static org.apache.commons.lang3.JavaVersion.JAVA_9;
import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtMost;
import static org.apache.geode.internal.AvailablePortHelper.getRandomAvailableTCPPorts;
-import static org.apache.geode.management.internal.JmxRmiOpenTypesSerialFilter.PROPERTY_NAME;
+import static org.apache.geode.test.assertj.LogFileAssert.assertThat;
import static org.apache.geode.test.awaitility.GeodeAwaitility.await;
import static org.assertj.core.api.Assumptions.assumeThat;
import java.nio.file.Path;
-import org.apache.commons.lang3.JavaVersion;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.apache.geode.test.assertj.LogFileAssert;
import org.apache.geode.test.junit.rules.RequiresGeodeHome;
import org.apache.geode.test.junit.rules.gfsh.GfshRule;
-public class LocatorManagerConfiguresJmxSerialFilterAcceptanceTest {
+public class StartLocatorJmxSerialFilterAcceptanceTest {
- private static final String NAME = "the-locator";
-
- private Path workingDir;
- private int locatorPort;
- private int jmxPort;
- private Path locatorLogFile;
+ private static final String PROPERTY_NAME = "jmx.remote.rmi.server.serial.filter.pattern";
@Rule
public RequiresGeodeHome requiresGeodeHome = new RequiresGeodeHome();
@Rule
public GfshRule gfshRule = new GfshRule();
- @Before
- public void setUpOutputFiles() {
- TemporaryFolder temporaryFolder = gfshRule.getTemporaryFolder();
+ private Path locatorFolder;
+ private int locatorPort;
+ private int jmxPort;
+ private Path locatorLogFile;
- workingDir = temporaryFolder.getRoot().toPath().toAbsolutePath();
- locatorLogFile = workingDir.resolve(NAME + ".log");
+ @Before
+ public void setUpFiles() {
+ locatorFolder = gfshRule.getTemporaryFolder().getRoot().toPath().toAbsolutePath();
+ locatorLogFile = locatorFolder.resolve("locator.log");
}
@Before
- public void setUpRandomPorts() {
+ public void setUpPorts() {
int[] ports = getRandomAvailableTCPPorts(2);
-
locatorPort = ports[0];
jmxPort = ports[1];
}
@Test
- public void startingLocatorWithJmxManager_configuresSerialFilter_atLeastJava9() {
- assumeThat(isJavaVersionAtLeast(JavaVersion.JAVA_9)).isTrue();
+ public void startWithJmxManagerConfiguresJmxSerialFilter_onJava9orGreater() {
+ assumeThat(isJavaVersionAtLeast(JAVA_9)).isTrue();
String startLocatorCommand = String.join(" ",
"start locator",
- "--name=" + NAME,
- "--dir=" + workingDir,
+ "--name=locator",
+ "--dir=" + locatorFolder,
"--port=" + locatorPort,
"--J=-Dgemfire.enable-cluster-configuration=false",
"--J=-Dgemfire.http-service-port=0",
@@ -81,21 +77,21 @@ public class LocatorManagerConfiguresJmxSerialFilterAcceptanceTest {
gfshRule.execute(startLocatorCommand);
await().untilAsserted(() -> {
- LogFileAssert.assertThat(locatorLogFile.toFile())
+ assertThat(locatorLogFile.toFile())
.as(locatorLogFile.toFile().getAbsolutePath())
.exists()
- .contains("System property " + PROPERTY_NAME + " is now configured with");
+ .contains("System property '" + PROPERTY_NAME + "' is now configured with");
});
}
@Test
- public void startingLocatorWithJmxManager_configuresSerialFilter_atMostJava8() {
- assumeThat(isJavaVersionAtMost(JavaVersion.JAVA_1_8)).isTrue();
+ public void startWithJmxManagerDoesNotConfigureJmxSerialFilter_onJava8() {
+ assumeThat(isJavaVersionAtMost(JAVA_1_8)).isTrue();
String startLocatorCommand = String.join(" ",
"start locator",
- "--name=" + NAME,
- "--dir=" + workingDir,
+ "--name=locator",
+ "--dir=" + locatorFolder,
"--port=" + locatorPort,
"--J=-Dgemfire.enable-cluster-configuration=false",
"--J=-Dgemfire.http-service-port=0",
@@ -106,10 +102,10 @@ public class LocatorManagerConfiguresJmxSerialFilterAcceptanceTest {
gfshRule.execute(startLocatorCommand);
await().untilAsserted(() -> {
- LogFileAssert.assertThat(locatorLogFile.toFile())
+ assertThat(locatorLogFile.toFile())
.as(locatorLogFile.toFile().getAbsolutePath())
.exists()
- .doesNotContain("System property " + PROPERTY_NAME + " is now configured with");
+ .doesNotContain("System property '" + PROPERTY_NAME + "' is now configured with");
});
}
}
diff --git a/geode-assembly/src/acceptanceTest/java/org/apache/geode/serialization/filter/StartServerGlobalSerialFilterAcceptanceTest.java b/geode-assembly/src/acceptanceTest/java/org/apache/geode/serialization/filter/StartServerGlobalSerialFilterAcceptanceTest.java
new file mode 100644
index 0000000..06bd7e2
--- /dev/null
+++ b/geode-assembly/src/acceptanceTest/java/org/apache/geode/serialization/filter/StartServerGlobalSerialFilterAcceptanceTest.java
@@ -0,0 +1,150 @@
+/*
+ * 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.serialization.filter;
+
+import static org.apache.geode.internal.AvailablePortHelper.getRandomAvailableTCPPort;
+import static org.apache.geode.test.awaitility.GeodeAwaitility.await;
+
+import java.io.File;
+import java.nio.file.Path;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.apache.geode.test.assertj.LogFileAssert;
+import org.apache.geode.test.junit.rules.RequiresGeodeHome;
+import org.apache.geode.test.junit.rules.gfsh.GfshRule;
+
+public class StartServerGlobalSerialFilterAcceptanceTest {
+
+ @Rule
+ public RequiresGeodeHome requiresGeodeHome = new RequiresGeodeHome();
+ @Rule
+ public GfshRule gfshRule = new GfshRule();
+
+ private File serverFolder;
+ private int jmxPort;
+
+ @Before
+ public void setServerFolder() {
+ serverFolder = gfshRule.getTemporaryFolder().getRoot();
+ }
+
+ @Before
+ public void setJmxPort() {
+ jmxPort = getRandomAvailableTCPPort();
+ }
+
+ @Test
+ public void startDoesNotConfigureGlobalSerialFilter_byDefault() {
+ String startServerCommand = String.join(" ",
+ "start server",
+ "--name=server",
+ "--dir=" + serverFolder.getAbsolutePath(),
+ "--disable-default-server",
+ "--J=-Dgemfire.enable-cluster-configuration=false",
+ "--J=-Dgemfire.http-service-port=0",
+ "--J=-Dgemfire.jmx-manager=true",
+ "--J=-Dgemfire.jmx-manager-port=" + jmxPort,
+ "--J=-Dgemfire.jmx-manager-start=true");
+
+ gfshRule.execute(startServerCommand);
+
+ Path serverLogFile = serverFolder.toPath().resolve("server.log");
+ await().untilAsserted(() -> {
+ LogFileAssert.assertThat(serverLogFile.toFile()).exists()
+ .doesNotContain("Global serial filter is now configured.")
+ .doesNotContain("jdk.serialFilter");
+ });
+ }
+
+ @Test
+ public void startDoesNotConfigureGlobalSerialFilter_whenJdkSerialFilterIsNotBlank() {
+ String startServerCommand = String.join(" ",
+ "start server",
+ "--name=server",
+ "--dir=" + serverFolder.getAbsolutePath(),
+ "--disable-default-server",
+ "--J=-Dgemfire.enable-cluster-configuration=false",
+ "--J=-Dgemfire.http-service-port=0",
+ "--J=-Dgemfire.jmx-manager=true",
+ "--J=-Dgemfire.jmx-manager-port=" + jmxPort,
+ "--J=-Dgemfire.jmx-manager-start=true",
+ "--J=-Djdk.serialFilter=*");
+
+ gfshRule.execute(startServerCommand);
+
+ Path serverLogFile = serverFolder.toPath().resolve("server.log");
+ await().untilAsserted(() -> {
+ LogFileAssert.assertThat(serverLogFile.toFile()).exists()
+ .doesNotContain("Global serial filter is now configured.")
+ .contains("jdk.serialFilter");
+ });
+ }
+
+ /**
+ * ServerLauncher is not currently wired up with EnabledGlobalSerialFilterConfigurationFactory
+ * like LocatorLauncher is.
+ */
+ @Test
+ public void startConfiguresGlobalSerialFilter_whenEnableGlobalSerialFilterIsTrue() {
+ String startServerCommand = String.join(" ",
+ "start server",
+ "--name=server",
+ "--dir=" + serverFolder.getAbsolutePath(),
+ "--disable-default-server",
+ "--J=-Dgemfire.enable-cluster-configuration=false",
+ "--J=-Dgemfire.http-service-port=0",
+ "--J=-Dgemfire.jmx-manager=true",
+ "--J=-Dgemfire.jmx-manager-port=" + jmxPort,
+ "--J=-Dgemfire.jmx-manager-start=true",
+ "--J=-Dgeode.enableGlobalSerialFilter=true");
+
+ gfshRule.execute(startServerCommand);
+
+ Path serverLogFile = serverFolder.toPath().resolve("server.log");
+ await().untilAsserted(() -> {
+ LogFileAssert.assertThat(serverLogFile.toFile()).exists()
+ .contains("Global serial filter is now configured.")
+ .doesNotContain("jdk.serialFilter");
+ });
+ }
+
+ @Test
+ public void startDoesNotConfigureGlobalSerialFilter_whenEnableGlobalSerialFilterIsTrue_andJdkSerialFilterIsNotBlank() {
+ String startServerCommand = String.join(" ",
+ "start server",
+ "--name=server",
+ "--dir=" + serverFolder.getAbsolutePath(),
+ "--disable-default-server",
+ "--J=-Dgemfire.enable-cluster-configuration=false",
+ "--J=-Dgemfire.http-service-port=0",
+ "--J=-Dgemfire.jmx-manager=true",
+ "--J=-Dgemfire.jmx-manager-port=" + jmxPort,
+ "--J=-Dgemfire.jmx-manager-start=true",
+ "--J=-Dgeode.enableGlobalSerialFilter=true",
+ "--J=-Djdk.serialFilter=*");
+
+ gfshRule.execute(startServerCommand);
+
+ Path serverLogFile = serverFolder.toPath().resolve("server.log");
+ await().untilAsserted(() -> {
+ LogFileAssert.assertThat(serverLogFile.toFile()).exists()
+ .doesNotContain("Global serial filter is now configured.")
+ .contains("jdk.serialFilter");
+ });
+ }
+}
diff --git a/geode-assembly/src/acceptanceTest/java/org/apache/geode/management/ServerManagerConfiguresJmxSerialFilterAcceptanceTest.java b/geode-assembly/src/acceptanceTest/java/org/apache/geode/serialization/filter/StartServerJmxSerialFilterAcceptanceTest.java
similarity index 66%
rename from geode-assembly/src/acceptanceTest/java/org/apache/geode/management/ServerManagerConfiguresJmxSerialFilterAcceptanceTest.java
rename to geode-assembly/src/acceptanceTest/java/org/apache/geode/serialization/filter/StartServerJmxSerialFilterAcceptanceTest.java
index 7754dec..bf03b22 100644
--- a/geode-assembly/src/acceptanceTest/java/org/apache/geode/management/ServerManagerConfiguresJmxSerialFilterAcceptanceTest.java
+++ b/geode-assembly/src/acceptanceTest/java/org/apache/geode/serialization/filter/StartServerJmxSerialFilterAcceptanceTest.java
@@ -12,61 +12,58 @@
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
-package org.apache.geode.management;
+package org.apache.geode.serialization.filter;
+import static org.apache.commons.lang3.JavaVersion.JAVA_1_8;
+import static org.apache.commons.lang3.JavaVersion.JAVA_9;
import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtMost;
import static org.apache.geode.internal.AvailablePortHelper.getRandomAvailableTCPPort;
-import static org.apache.geode.management.internal.JmxRmiOpenTypesSerialFilter.PROPERTY_NAME;
+import static org.apache.geode.test.assertj.LogFileAssert.assertThat;
import static org.apache.geode.test.awaitility.GeodeAwaitility.await;
import static org.assertj.core.api.Assumptions.assumeThat;
import java.nio.file.Path;
-import org.apache.commons.lang3.JavaVersion;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.apache.geode.test.assertj.LogFileAssert;
import org.apache.geode.test.junit.rules.RequiresGeodeHome;
import org.apache.geode.test.junit.rules.gfsh.GfshRule;
-public class ServerManagerConfiguresJmxSerialFilterAcceptanceTest {
+public class StartServerJmxSerialFilterAcceptanceTest {
- private static final String NAME = "the-server";
-
- private Path workingDir;
- private int jmxPort;
- private Path serverLogFile;
+ private static final String PROPERTY_NAME = "jmx.remote.rmi.server.serial.filter.pattern";
@Rule
public RequiresGeodeHome requiresGeodeHome = new RequiresGeodeHome();
@Rule
public GfshRule gfshRule = new GfshRule();
- @Before
- public void setUpOutputFiles() {
- TemporaryFolder temporaryFolder = gfshRule.getTemporaryFolder();
+ private Path serverFolder;
+ private int jmxPort;
+ private Path serverLogFile;
- workingDir = temporaryFolder.getRoot().toPath().toAbsolutePath();
- serverLogFile = workingDir.resolve(NAME + ".log");
+ @Before
+ public void setUpFiles() {
+ serverFolder = gfshRule.getTemporaryFolder().getRoot().toPath().toAbsolutePath();
+ serverLogFile = serverFolder.resolve("server.log");
}
@Before
- public void setUpRandomPorts() {
+ public void setUpPorts() {
jmxPort = getRandomAvailableTCPPort();
}
@Test
- public void startingServerWithJmxManager_configuresSerialFilter_atLeastJava9() {
- assumeThat(isJavaVersionAtLeast(JavaVersion.JAVA_9)).isTrue();
+ public void startWithJmxManagerConfiguresJmxSerialFilter_onJava9orGreater() {
+ assumeThat(isJavaVersionAtLeast(JAVA_9)).isTrue();
String startServerCommand = String.join(" ",
"start server",
- "--name=" + NAME,
- "--dir=" + workingDir,
+ "--name=server",
+ "--dir=" + serverFolder,
"--disable-default-server",
"--J=-Dgemfire.enable-cluster-configuration=false",
"--J=-Dgemfire.http-service-port=0",
@@ -77,21 +74,21 @@ public class ServerManagerConfiguresJmxSerialFilterAcceptanceTest {
gfshRule.execute(startServerCommand);
await().untilAsserted(() -> {
- LogFileAssert.assertThat(serverLogFile.toFile())
+ assertThat(serverLogFile.toFile())
.as(serverLogFile.toFile().getAbsolutePath())
.exists()
- .contains("System property " + PROPERTY_NAME + " is now configured with");
+ .contains("System property '" + PROPERTY_NAME + "' is now configured with");
});
}
@Test
- public void startingServerWithJmxManager_configuresSerialFilter_atMostJava8() {
- assumeThat(isJavaVersionAtMost(JavaVersion.JAVA_1_8)).isTrue();
+ public void startWithJmxManagerDoesNotConfigureJmxSerialFilter_onJava8() {
+ assumeThat(isJavaVersionAtMost(JAVA_1_8)).isTrue();
String startServerCommand = String.join(" ",
"start server",
- "--name=" + NAME,
- "--dir=" + workingDir,
+ "--name=server",
+ "--dir=" + serverFolder,
"--disable-default-server",
"--J=-Dgemfire.enable-cluster-configuration=false",
"--J=-Dgemfire.http-service-port=0",
@@ -102,10 +99,10 @@ public class ServerManagerConfiguresJmxSerialFilterAcceptanceTest {
gfshRule.execute(startServerCommand);
await().untilAsserted(() -> {
- LogFileAssert.assertThat(serverLogFile.toFile())
+ assertThat(serverLogFile.toFile())
.as(serverLogFile.toFile().getAbsolutePath())
.exists()
- .doesNotContain("System property " + PROPERTY_NAME + " is now configured with");
+ .doesNotContain("System property '" + PROPERTY_NAME + "' is now configured with");
});
}
}
diff --git a/geode-core/build.gradle b/geode-core/build.gradle
index b129c55..51ee9be 100755
--- a/geode-core/build.gradle
+++ b/geode-core/build.gradle
@@ -315,7 +315,7 @@ dependencies {
implementation(project(':geode-logging'))
implementation(project(':geode-membership'))
implementation(project(':geode-unsafe'))
- implementation(project(':geode-serialization'))
+ api(project(':geode-serialization'))
implementation(project(':geode-tcp-server'))
//geode-management currently has pieces of the public API
diff --git a/geode-core/src/distributedTest/java/org/apache/geode/cache/ValidateSerializableObjectsDistributedTest.java b/geode-core/src/distributedTest/java/org/apache/geode/cache/ValidateSerializableObjectsDistributedTest.java
new file mode 100644
index 0000000..27d60d3
--- /dev/null
+++ b/geode-core/src/distributedTest/java/org/apache/geode/cache/ValidateSerializableObjectsDistributedTest.java
@@ -0,0 +1,320 @@
+/*
+ * 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.cache;
+
+import static java.util.Arrays.asList;
+import static org.apache.geode.cache.RegionShortcut.REPLICATE;
+import static org.apache.geode.distributed.ConfigurationProperties.ENABLE_CLUSTER_CONFIGURATION;
+import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS;
+import static org.apache.geode.distributed.ConfigurationProperties.VALIDATE_SERIALIZABLE_OBJECTS;
+import static org.apache.geode.test.dunit.IgnoredException.addIgnoredException;
+import static org.apache.geode.test.dunit.VM.getVM;
+import static org.apache.geode.test.dunit.rules.DistributedRule.getLocatorPort;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.catchThrowable;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InvalidClassException;
+import java.io.NotSerializableException;
+import java.io.Serializable;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.apache.geode.InternalGemFireException;
+import org.apache.geode.SerializationException;
+import org.apache.geode.cache.util.CacheListenerAdapter;
+import org.apache.geode.distributed.ServerLauncher;
+import org.apache.geode.test.dunit.VM;
+import org.apache.geode.test.dunit.rules.DistributedReference;
+import org.apache.geode.test.dunit.rules.DistributedRule;
+import org.apache.geode.test.junit.rules.serializable.SerializableTemporaryFolder;
+
+@SuppressWarnings("serial")
+public class ValidateSerializableObjectsDistributedTest implements Serializable {
+
+ private VM server1;
+ private VM server2;
+
+ private File server1Dir;
+ private File server2Dir;
+ private int locatorPort;
+
+ @Rule
+ public DistributedRule distributedRule = new DistributedRule();
+ @Rule
+ public DistributedReference<ServerLauncher> server = new DistributedReference<>();
+ @Rule
+ public SerializableTemporaryFolder temporaryFolder = new SerializableTemporaryFolder();
+
+ @Before
+ public void setUp() throws IOException {
+ server1 = getVM(0);
+ server2 = getVM(1);
+
+ server1Dir = temporaryFolder.newFolder("server1");
+ server2Dir = temporaryFolder.newFolder("server2");
+
+ locatorPort = getLocatorPort();
+
+ server1.invoke(() -> {
+ server.set(startServer("server1", server1Dir));
+ });
+ server2.invoke(() -> {
+ server.set(startServer("server2", server2Dir));
+ });
+
+ asList(server1, server2).forEach(vm -> vm.invoke(() -> {
+ server.get().getCache()
+ .createRegionFactory(REPLICATE)
+ .addCacheListener(new CacheListenerAdapter<Object, Object>() {
+ @Override
+ public void afterCreate(EntryEvent<Object, Object> event) {
+ // cache listener afterCreate causes all creates to deserialize the value which causes
+ // the tests to pass if serialization filter is configured
+ assertThat(event.getNewValue()).isNotNull();
+ }
+ })
+ .create("region");
+ }));
+ }
+
+ @Test
+ public void stringIsAllowed() {
+ server1.invoke(() -> {
+ Region<Object, Object> region = server.get().getCache().getRegion("region");
+
+ Object key = "key";
+ Object value = "value";
+
+ // puts entry locally and propagates to server2
+ region.put(key, value);
+
+ // entry exists in server1
+ assertThat(region.containsKey(key)).isTrue();
+ assertThat(region.get(key)).isSameAs(value);
+ });
+
+ server2.invoke(() -> {
+ Region<Object, Object> region = server.get().getCache().getRegion("region");
+
+ Object key = "key";
+ Object value = "value";
+
+ // entry exists in server2
+ assertThat(region.containsKey(key)).isTrue();
+ assertThat(region.get(key)).isEqualTo(value);
+ });
+ }
+
+ @Test
+ public void primitiveIsAllowed() {
+ server1.invoke(() -> {
+ Region<Object, Object> region = server.get().getCache().getRegion("region");
+
+ Object key = 1;
+ Object value = 1;
+
+ // puts entry locally and propagates to server2
+ region.put(key, value);
+
+ // entry exists in server1
+ assertThat(region.containsKey(key)).isTrue();
+ assertThat(region.get(key)).isSameAs(value);
+ });
+
+ server2.invoke(() -> {
+ Region<Object, Object> region = server.get().getCache().getRegion("region");
+
+ Object key = 1;
+ Object value = 1;
+
+ // entry exists in server2
+ assertThat(region.containsKey(key)).isTrue();
+ assertThat(region.get(key)).isEqualTo(value);
+ });
+ }
+
+ @Test
+ public void nonSerializableThrowsNotSerializableException() {
+ server1.invoke(() -> {
+ Region<Object, Object> region = server.get().getCache().getRegion("region");
+
+ Object key = new Object();
+ Object value = new Object();
+
+ // put stores entry locally and then tries to propagate to server2
+ Throwable thrown = catchThrowable(() -> {
+ region.put(key, value);
+ });
+
+ // key and value fail to serialize non-serializable objects in server1
+ assertThat(thrown).hasCauseExactlyInstanceOf(NotSerializableException.class);
+
+ // entry exists in server1 despite serialization failure
+ assertThat(region.containsKey(key)).isTrue();
+ assertThat(region.get(key)).isSameAs(value);
+ });
+
+ server2.invoke(() -> {
+ Region<Object, Object> region = server.get().getCache().getRegion("region");
+
+ Object key = new Object();
+
+ // entry does NOT exist in server2 at all
+ assertThat(region.containsKey(key)).isFalse();
+ assertThat(region.get(key)).isNull();
+ });
+ }
+
+ @Test
+ public void nonAllowedValueFailsToDeserializeInOtherServer() {
+ addIgnoredException(InvalidClassException.class);
+ addIgnoredException(SerializationException.class);
+
+ server1.invoke(() -> {
+ Region<Object, Object> region = server.get().getCache().getRegion("region");
+
+ Object key = "key";
+ Object value = new SerializableClass();
+
+ // put stores entry locally and sends serialized key/value to server2
+ region.put(key, value);
+
+ // entry exists in server1
+ assertThat(region.get(key)).isInstanceOf(SerializableClass.class);
+ });
+
+ server2.invoke(() -> {
+ Region<Object, Object> region = server.get().getCache().getRegion("region");
+
+ Object key = "key";
+
+ // key exists in server2
+ assertThat(region.containsKey(key)).isTrue();
+
+ // get tries to fetch value from server1 if it's missing in server2
+ Throwable thrown = catchThrowable(() -> {
+ region.get(key);
+ });
+
+ // value fails to deserialize in server2
+ assertThat(thrown)
+ .isInstanceOf(SerializationException.class)
+ .hasCauseInstanceOf(InvalidClassException.class);
+ });
+ }
+
+ @Test
+ public void nonAllowedKeyFailsToDeserializeInOtherServer() {
+ addIgnoredException(InvalidClassException.class);
+ addIgnoredException(IOException.class);
+
+ server1.invoke(() -> {
+ Region<Object, Object> region = server.get().getCache().getRegion("region");
+
+ Object key = new SerializableClass();
+ Object value = "value";
+
+ // put stores entry locally and ails to serialize for propagation to server2
+ Throwable thrown = catchThrowable(() -> {
+ region.put(key, value);
+ });
+
+ // put fails to create entry locally because key is not serializable
+ assertThat(thrown)
+ .isInstanceOf(InternalGemFireException.class)
+ .hasCauseInstanceOf(IOException.class)
+ .hasRootCauseInstanceOf(InvalidClassException.class);
+
+ // entry exists in server1
+ assertThat(region.containsKey(key)).isTrue();
+ assertThat(region.get(key)).isEqualTo(value);
+ });
+
+ server2.invoke(() -> {
+ Region<Object, Object> region = server.get().getCache().getRegion("region");
+
+ Object key = new Object();
+
+ // entry does NOT exist in server2
+ assertThat(region.containsKey(key)).isFalse();
+ assertThat(region.get(key)).isNull();
+ });
+ }
+
+ @Test
+ public void nonAllowedKeyAndValueThrowsInsteadOfPutting() {
+ addIgnoredException(InvalidClassException.class);
+ addIgnoredException(IOException.class);
+
+ server1.invoke(() -> {
+ Region<Object, Object> region = server.get().getCache().getRegion("region");
+
+ Object key = new SerializableClass();
+ Object value = new SerializableClass();
+
+ // put stores entry locally tries sending to server/key to server2
+ Throwable thrown = catchThrowable(() -> {
+ region.put(key, value);
+ });
+
+ // value fails to propagate to server2
+ assertThat(thrown)
+ .isInstanceOf(InternalGemFireException.class)
+ .hasCauseInstanceOf(IOException.class)
+ .hasRootCauseInstanceOf(InvalidClassException.class);
+ });
+
+ server2.invoke(() -> {
+ Region<Object, Object> region = server.get().getCache().getRegion("region");
+
+ Object key = new SerializableClass();
+
+ // entry does NOT exist in server2
+ assertThat(region.containsKey(key)).isFalse();
+ assertThat(region.get(key)).isNull();
+ });
+ }
+
+ private ServerLauncher startServer(String serverName, File serverDir) {
+ ServerLauncher serverLauncher = new ServerLauncher.Builder()
+ .setDisableDefaultServer(true)
+ .setDeletePidFileOnStop(true)
+ .setMemberName(serverName)
+ .setWorkingDirectory(serverDir.getAbsolutePath())
+ .setServerPort(0)
+ .set(ENABLE_CLUSTER_CONFIGURATION, "false")
+ .set(LOCATORS, "localHost[" + locatorPort + "]")
+ .set(VALIDATE_SERIALIZABLE_OBJECTS, "true")
+ .build();
+
+ serverLauncher.start();
+
+ return serverLauncher;
+ }
+
+ /**
+ * Simple Java serializable class that is not accept listed using serializable-object-filter.
+ * Deserialization of instances of this type will be rejected when validate-serializable-objects
+ * is enabled.
+ */
+ public static class SerializableClass implements Serializable {
+ }
+}
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/distributed/LocatorIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/distributed/LocatorIntegrationTest.java
index 329197e..92212a8 100644
--- a/geode-core/src/integrationTest/java/org/apache/geode/distributed/LocatorIntegrationTest.java
+++ b/geode-core/src/integrationTest/java/org/apache/geode/distributed/LocatorIntegrationTest.java
@@ -15,84 +15,56 @@
package org.apache.geode.distributed;
import static org.apache.geode.distributed.ConfigurationProperties.ENABLE_CLUSTER_CONFIGURATION;
-import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_HTTP_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
-import static org.apache.geode.distributed.ConfigurationProperties.LOCATOR_WAIT_TIME;
import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
import static org.apache.geode.internal.AvailablePortHelper.getRandomAvailableTCPPort;
-import static org.apache.geode.util.internal.GeodeGlossary.GEMFIRE_PREFIX;
+import static org.apache.geode.internal.security.SecurableCommunicationChannel.LOCATOR;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
import java.io.File;
import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collection;
import java.util.List;
import java.util.Properties;
-import java.util.function.IntSupplier;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
-import org.junit.contrib.java.lang.system.RestoreSystemProperties;
import org.junit.experimental.categories.Category;
import org.junit.rules.TemporaryFolder;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-import org.junit.runners.Parameterized.UseParametersRunnerFactory;
import org.apache.geode.distributed.internal.InternalLocator;
-import org.apache.geode.distributed.internal.ServerLocation;
import org.apache.geode.distributed.internal.tcpserver.HostAndPort;
import org.apache.geode.distributed.internal.tcpserver.TcpClient;
import org.apache.geode.distributed.internal.tcpserver.TcpSocketFactory;
-import org.apache.geode.internal.AvailablePortHelper;
import org.apache.geode.internal.InternalDataSerializer;
-import org.apache.geode.internal.cache.GemFireCacheImpl;
+import org.apache.geode.internal.cache.InternalCache;
import org.apache.geode.internal.net.SocketCreatorFactory;
-import org.apache.geode.internal.security.SecurableCommunicationChannel;
import org.apache.geode.logging.internal.OSProcess;
+import org.apache.geode.management.ManagementService;
import org.apache.geode.management.internal.JmxManagerAdvisor.JmxManagerProfile;
+import org.apache.geode.management.internal.SystemManagementService;
import org.apache.geode.management.internal.configuration.messages.SharedConfigurationStatusRequest;
import org.apache.geode.test.junit.categories.MembershipTest;
-import org.apache.geode.test.junit.runners.CategoryWithParameterizedRunnerFactory;
-@Category({MembershipTest.class})
-@RunWith(Parameterized.class)
-@UseParametersRunnerFactory(CategoryWithParameterizedRunnerFactory.class)
+@Category(MembershipTest.class)
public class LocatorIntegrationTest {
private Locator locator;
- private File tmpFile;
+ private File logFile;
private int port;
- @Parameters
- public static Collection<Object> data() {
- return Arrays.asList(new Object[] {
- (IntSupplier) () -> 0,
- (IntSupplier) AvailablePortHelper::getRandomAvailableTCPPort});
- }
-
- @Parameter
- public IntSupplier portSupplier;
-
- @Rule
- public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
-
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Before
public void setUp() throws IOException {
- tmpFile = File.createTempFile("locator", ".log");
- port = portSupplier.getAsInt();
- deleteLocatorViewFile(port);
+ logFile = temporaryFolder.newFile("locator.log");
}
@After
@@ -100,21 +72,22 @@ public class LocatorIntegrationTest {
if (locator != null) {
locator.stop();
}
- assertThat(Locator.hasLocator()).isFalse();
+ deleteLocatorViewFile(port);
}
/**
* Fix: locator creates "locator0view.dat" file when started with port 0
*/
@Test
- public void testThatLocatorDoesNotCreateFileWithZeroPort() throws Exception {
+ public void doesNotCreateZeroPortViewFileForEphemeralPort() throws Exception {
deleteLocatorViewFile(0);
Properties configProperties = new Properties();
- configProperties.setProperty(MCAST_PORT, "0");
configProperties.setProperty(ENABLE_CLUSTER_CONFIGURATION, "false");
- configProperties.setProperty(LOCATOR_WAIT_TIME, "1"); // seconds
+ configProperties.setProperty(HTTP_SERVICE_PORT, "0");
+ configProperties.setProperty(JMX_MANAGER, "false");
configProperties.setProperty(LOG_FILE, "");
+ configProperties.setProperty(MCAST_PORT, "0");
locator = Locator.startLocatorAndDS(port, null, configProperties);
@@ -123,75 +96,121 @@ public class LocatorIntegrationTest {
assertThat(viewFile).doesNotExist();
}
+ @Test
+ public void locatorStartsOnSpecifiedPort() throws IOException {
+ Properties configProperties = new Properties();
+ configProperties.setProperty(ENABLE_CLUSTER_CONFIGURATION, "false");
+ configProperties.setProperty(HTTP_SERVICE_PORT, "0");
+ configProperties.setProperty(JMX_MANAGER, "false");
+ configProperties.setProperty(LOG_FILE, "");
+ configProperties.setProperty(MCAST_PORT, "0");
+
+ port = getRandomAvailableTCPPort();
+ locator = Locator.startLocatorAndDS(port, null, configProperties);
+
+ port = locator.getPort();
+ assertThat(port).isEqualTo(port);
+ }
+
+ @Test
+ public void locatorStartsOnEphemeralPort() throws IOException {
+ Properties configProperties = new Properties();
+ configProperties.setProperty(ENABLE_CLUSTER_CONFIGURATION, "false");
+ configProperties.setProperty(HTTP_SERVICE_PORT, "0");
+ configProperties.setProperty(JMX_MANAGER, "false");
+ configProperties.setProperty(LOG_FILE, "");
+ configProperties.setProperty(MCAST_PORT, "0");
+
+ locator = Locator.startLocatorAndDS(0, null, configProperties);
+
+ port = locator.getPort();
+ assertThat(port).isNotZero();
+ }
+
/**
* Fix: if jmx-manager-start is true in a locator then gfsh connect will fail
*/
@Test
- public void testGfshConnectShouldSucceedIfJmxManagerStartIsTrueInLocator() throws Exception {
+ public void gfshConnectsIfJmxManagerStartIsTrue() throws Exception {
int jmxPort = getRandomAvailableTCPPort();
Properties configProperties = new Properties();
- configProperties.setProperty(MCAST_PORT, "0");
- configProperties.setProperty(JMX_MANAGER_PORT, "" + jmxPort);
- configProperties.setProperty(JMX_MANAGER_START, "true");
- configProperties.setProperty(JMX_MANAGER_HTTP_PORT, "0");
configProperties.setProperty(ENABLE_CLUSTER_CONFIGURATION, "false");
+ configProperties.setProperty(HTTP_SERVICE_PORT, "0");
+ configProperties.setProperty(JMX_MANAGER_PORT, String.valueOf(jmxPort));
+ configProperties.setProperty(JMX_MANAGER_START, "true");
configProperties.setProperty(LOG_FILE, "");
-
- // not needed
- System.setProperty(GEMFIRE_PREFIX + "disableManagement", "false");
+ configProperties.setProperty(MCAST_PORT, "0");
locator = Locator.startLocatorAndDS(port, null, configProperties);
- List<JmxManagerProfile> alreadyManaging =
- GemFireCacheImpl.getInstance().getJmxManagerAdvisor().adviseAlreadyManaging();
+ InternalLocator internalLocator = (InternalLocator) locator;
+ InternalCache cache = internalLocator.getCache();
+ List<JmxManagerProfile> alreadyManaging = cache.getJmxManagerAdvisor().adviseAlreadyManaging();
assertThat(alreadyManaging).hasSize(1);
- assertThat(alreadyManaging.get(0).getDistributedMember())
- .isEqualTo(GemFireCacheImpl.getInstance().getMyId());
+ assertThat(alreadyManaging.get(0).getDistributedMember()).isEqualTo(cache.getMyId());
}
@Test
- public void testHandlersAreWaitedOn() throws Exception {
+ public void hasHandlerForSharedConfigurationStatusRequest() throws Exception {
Properties configProperties = new Properties();
- configProperties.setProperty(MCAST_PORT, "0");
configProperties.setProperty(ENABLE_CLUSTER_CONFIGURATION, "false");
- configProperties.setProperty(LOCATOR_WAIT_TIME, "1"); // seconds
+ configProperties.setProperty(HTTP_SERVICE_PORT, "0");
+ configProperties.setProperty(JMX_MANAGER, "false");
configProperties.setProperty(LOG_FILE, "");
+ configProperties.setProperty(MCAST_PORT, "0");
locator = Locator.startLocatorAndDS(port, null, configProperties);
InternalLocator internalLocator = (InternalLocator) locator;
// the locator should always install a SharedConfigurationStatusRequest handler
- assertThat(internalLocator.hasHandlerForClass(SharedConfigurationStatusRequest.class)).isTrue();
+ boolean hasHandler = internalLocator.hasHandlerForClass(SharedConfigurationStatusRequest.class);
+ assertThat(hasHandler).isTrue();
+ }
+
+ @Test
+ public void infoRequestIncludesActualPortWhenSpecifiedPortIsZero() throws Exception {
+ locator = Locator.startLocator(0, logFile);
+ port = locator.getPort();
+ TcpClient client = new TcpClient(
+ SocketCreatorFactory.getSocketCreatorForComponent(LOCATOR),
+ InternalDataSerializer.getDSFIDSerializer().getObjectSerializer(),
+ InternalDataSerializer.getDSFIDSerializer().getObjectDeserializer(),
+ TcpSocketFactory.DEFAULT);
+
+ String[] info = client.getInfo(new HostAndPort("localhost", port));
+
+ assertThat(info).isNotNull();
+ assertThat(info.length).isGreaterThanOrEqualTo(1);
}
@Test
- public void testBasicInfo() throws Exception {
- locator = Locator.startLocator(port, tmpFile);
- int boundPort = port == 0 ? locator.getPort() : port;
- TcpClient client = new TcpClient(SocketCreatorFactory
- .getSocketCreatorForComponent(SecurableCommunicationChannel.LOCATOR),
+ public void infoRequestIncludesActualPortWhenSpecifiedIsNonZero() throws Exception {
+ locator = Locator.startLocator(getRandomAvailableTCPPort(), logFile);
+ port = locator.getPort();
+ TcpClient client = new TcpClient(
+ SocketCreatorFactory.getSocketCreatorForComponent(LOCATOR),
InternalDataSerializer.getDSFIDSerializer().getObjectSerializer(),
InternalDataSerializer.getDSFIDSerializer().getObjectDeserializer(),
TcpSocketFactory.DEFAULT);
- String[] info = client.getInfo(new HostAndPort("localhost", boundPort));
+
+ String[] info = client.getInfo(new HostAndPort("localhost", port));
assertThat(info).isNotNull();
assertThat(info.length).isGreaterThanOrEqualTo(1);
}
@Test
- public void testNoThreadLeftBehind() throws Exception {
+ public void threadsAreCleanedUpWhenStartFails() throws Exception {
Properties configProperties = new Properties();
+ configProperties.setProperty(LOG_FILE, "");
configProperties.setProperty(MCAST_PORT, "0");
- configProperties.setProperty(JMX_MANAGER_START, "false");
- configProperties.setProperty(ENABLE_CLUSTER_CONFIGURATION, "false");
int threadCount = Thread.activeCount();
Throwable thrown = catchThrowable(
- () -> locator = Locator.startLocatorAndDS(-2, new File(""), configProperties));
+ () -> locator = Locator.startLocatorAndDS(-2, null, configProperties));
assertThat(thrown).isInstanceOf(IllegalArgumentException.class);
@@ -206,22 +225,31 @@ public class LocatorIntegrationTest {
assertThat(threadCount)
.as("Expected " + threadCount + " threads or fewer but found " + Thread.activeCount()
+ ". Check log file for a thread dump.")
+ .withThreadDumpOnError()
.isGreaterThanOrEqualTo(Thread.activeCount());
}
/**
- * Make sure two ServerLocation objects on different hosts but with the same port are not equal
- *
- * <p>
- * Fix: LoadBalancing directs all traffic to a single cache server if all servers are started on
- * the same port
+ * Validates that Locator.startLocatorAndDS does not start a JMX Manager by default. Only the
+ * LocatorLauncher starts one by default.
*/
@Test
- public void testServerLocationOnDifferentHostsShouldNotTestEqual() {
- ServerLocation serverLocation1 = new ServerLocation("host1", 777);
- ServerLocation serverLocation2 = new ServerLocation("host2", 777);
+ public void doesNotStartJmxManagerByDefault() throws Exception {
+ Properties configProperties = new Properties();
+ configProperties.setProperty(ENABLE_CLUSTER_CONFIGURATION, "false");
+ configProperties.setProperty(HTTP_SERVICE_PORT, "0");
+ configProperties.setProperty(LOG_FILE, "");
+ configProperties.setProperty(MCAST_PORT, "0");
+
+ locator = Locator.startLocatorAndDS(port, null, configProperties);
+
+ InternalLocator internalLocator = (InternalLocator) locator;
+ InternalCache cache = internalLocator.getCache();
+ SystemManagementService managementService =
+ (SystemManagementService) ManagementService.getManagementService(cache);
- assertThat(serverLocation1).isNotEqualTo(serverLocation2);
+ boolean isManager = managementService.isManager();
+ assertThat(isManager).isFalse();
}
private void deleteLocatorViewFile(int portNumber) {
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/distributed/LocatorLauncherJmxManagerLocalRegressionTest.java b/geode-core/src/integrationTest/java/org/apache/geode/distributed/LocatorLauncherJmxManagerLocalRegressionTest.java
index d304b91..430d8b1 100644
--- a/geode-core/src/integrationTest/java/org/apache/geode/distributed/LocatorLauncherJmxManagerLocalRegressionTest.java
+++ b/geode-core/src/integrationTest/java/org/apache/geode/distributed/LocatorLauncherJmxManagerLocalRegressionTest.java
@@ -35,7 +35,7 @@ import org.apache.geode.internal.process.ProcessType;
* Regression tests for stopping a JMX Manager process launched with {@link LocatorLauncher}.
*
* <p>
- * Confirms fix for <bold>Locator not stopping correctly if jmx-manager-port=0</bold>
+ * Confirms fix for <strong>Locator not stopping correctly if jmx-manager-port=0</strong>
*
* <p>
* Refactored from LocatorLauncherAssemblyIntegrationTest which used to be in geode-assembly.
@@ -104,6 +104,26 @@ public class LocatorLauncherJmxManagerLocalRegressionTest
assertThatThreadsStopped();
}
+ @Test
+ public void startsLocatorWithJmxManager() {
+ startLocator(newBuilder()
+ .setDeletePidFileOnStop(true)
+ .setMemberName(getUniqueName())
+ .setPort(defaultLocatorPort)
+ .setRedirectOutput(false)
+ .setWorkingDirectory(getWorkingDirectoryPath())
+ .set(ENABLE_CLUSTER_CONFIGURATION, "false")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_START, "true")
+ .set(JMX_MANAGER_PORT, String.valueOf(jmxManagerPort))
+ .set(LOG_LEVEL, "config"));
+
+ stopLocator();
+
+ assertDeletionOf(getPidFile());
+ assertThatThreadsStopped();
+ }
+
private void assertThatThreadsStopped() {
await()
.atMost(AWAIT_MILLIS, MILLISECONDS)
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherGlobalSerialFilterBlankIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherGlobalSerialFilterBlankIntegrationTest.java
new file mode 100644
index 0000000..0b352c4
--- /dev/null
+++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherGlobalSerialFilterBlankIntegrationTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.serialization.filter;
+
+import static java.lang.String.valueOf;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
+import static org.apache.geode.internal.serialization.filter.SerialFilterAssertions.assertThatSerialFilterIsSameAs;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.junit.Test;
+
+import org.apache.geode.distributed.LocatorLauncher;
+
+public class LocatorLauncherGlobalSerialFilterBlankIntegrationTest
+ extends LocatorLauncherWithJmxManager {
+
+ @Test
+ public void startDoesNotConfigureGlobalSerialFilter_whenFilterIsBlank()
+ throws InvocationTargetException, IllegalAccessException {
+ Object existingGlobalSerialFilter = OBJECT_INPUT_FILTER_API.createFilter(" ");
+ OBJECT_INPUT_FILTER_API.setSerialFilter(existingGlobalSerialFilter);
+
+ locator.set(new LocatorLauncher.Builder()
+ .setMemberName(NAME)
+ .setPort(locatorPort)
+ .setWorkingDirectory(valueOf(workingDirectory))
+ .set(HTTP_SERVICE_PORT, "0")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_PORT, valueOf(jmxPort))
+ .set(JMX_MANAGER_START, "true")
+ .set(LOG_FILE, valueOf(logFile))
+ .build())
+ .get()
+ .start();
+
+ assertThatSerialFilterIsSameAs(existingGlobalSerialFilter);
+ }
+}
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherGlobalSerialFilterExistsIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherGlobalSerialFilterExistsIntegrationTest.java
new file mode 100644
index 0000000..c948f59
--- /dev/null
+++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherGlobalSerialFilterExistsIntegrationTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.serialization.filter;
+
+import static java.lang.String.valueOf;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
+import static org.apache.geode.internal.serialization.filter.SerialFilterAssertions.assertThatSerialFilterIsSameAs;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.junit.Test;
+
+import org.apache.geode.distributed.LocatorLauncher;
+
+public class LocatorLauncherGlobalSerialFilterExistsIntegrationTest
+ extends LocatorLauncherWithJmxManager {
+
+ @Test
+ public void startDoesNotConfigureGlobalSerialFilter_whenFilterExists()
+ throws InvocationTargetException, IllegalAccessException {
+ Object existingGlobalSerialFilter = OBJECT_INPUT_FILTER_API.createFilter("!*");
+ OBJECT_INPUT_FILTER_API.setSerialFilter(existingGlobalSerialFilter);
+
+ locator.set(new LocatorLauncher.Builder()
+ .setMemberName(NAME)
+ .setPort(locatorPort)
+ .setWorkingDirectory(valueOf(workingDirectory))
+ .set(HTTP_SERVICE_PORT, "0")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_PORT, valueOf(jmxPort))
+ .set(JMX_MANAGER_START, "true")
+ .set(LOG_FILE, valueOf(logFile))
+ .build())
+ .get()
+ .start();
+
+ assertThatSerialFilterIsSameAs(existingGlobalSerialFilter);
+ }
+}
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherGlobalSerialFilterIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherGlobalSerialFilterIntegrationTest.java
new file mode 100644
index 0000000..8be64f3
--- /dev/null
+++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherGlobalSerialFilterIntegrationTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.serialization.filter;
+
+import static java.lang.String.valueOf;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
+import static org.apache.geode.internal.serialization.filter.SerialFilterAssertions.assertThatSerialFilterIsNull;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.junit.Test;
+
+import org.apache.geode.distributed.LocatorLauncher;
+
+public class LocatorLauncherGlobalSerialFilterIntegrationTest
+ extends LocatorLauncherWithJmxManager {
+
+ @Test
+ public void startDoesNotConfigureGlobalSerialFilter_whenFilterDoesNotExist()
+ throws InvocationTargetException, IllegalAccessException {
+ locator.set(new LocatorLauncher.Builder()
+ .setMemberName(NAME)
+ .setPort(locatorPort)
+ .setWorkingDirectory(valueOf(workingDirectory))
+ .set(HTTP_SERVICE_PORT, "0")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_PORT, valueOf(jmxPort))
+ .set(JMX_MANAGER_START, "true")
+ .set(LOG_FILE, valueOf(logFile))
+ .build())
+ .get()
+ .start();
+
+ assertThatSerialFilterIsNull();
+ }
+}
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherGlobalSerialFilterPropertyBlankIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherGlobalSerialFilterPropertyBlankIntegrationTest.java
new file mode 100644
index 0000000..ea021f4
--- /dev/null
+++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherGlobalSerialFilterPropertyBlankIntegrationTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.serialization.filter;
+
+import static java.lang.String.valueOf;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
+import static org.apache.geode.internal.serialization.filter.SerialFilterAssertions.assertThatSerialFilterIsNull;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.junit.Test;
+
+import org.apache.geode.distributed.LocatorLauncher;
+
+public class LocatorLauncherGlobalSerialFilterPropertyBlankIntegrationTest
+ extends LocatorLauncherWithJmxManager {
+
+ @Test
+ public void startDoesNotConfigureGlobalSerialFilter_whenPropertyIsBlank()
+ throws InvocationTargetException, IllegalAccessException {
+ System.setProperty(JDK_PROPERTY, " ");
+
+ locator.set(new LocatorLauncher.Builder()
+ .setMemberName(NAME)
+ .setPort(locatorPort)
+ .setWorkingDirectory(valueOf(workingDirectory))
+ .set(HTTP_SERVICE_PORT, "0")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_PORT, valueOf(jmxPort))
+ .set(JMX_MANAGER_START, "true")
+ .set(LOG_FILE, valueOf(logFile))
+ .build())
+ .get()
+ .start();
+
+ assertThatSerialFilterIsNull();
+ }
+}
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherGlobalSerialFilterPropertyEmptyIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherGlobalSerialFilterPropertyEmptyIntegrationTest.java
new file mode 100644
index 0000000..52b46f6
--- /dev/null
+++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherGlobalSerialFilterPropertyEmptyIntegrationTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.serialization.filter;
+
+import static java.lang.String.valueOf;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
+import static org.apache.geode.internal.serialization.filter.SerialFilterAssertions.assertThatSerialFilterIsNull;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.junit.Test;
+
+import org.apache.geode.distributed.LocatorLauncher;
+
+public class LocatorLauncherGlobalSerialFilterPropertyEmptyIntegrationTest
+ extends LocatorLauncherWithJmxManager {
+
+ @Test
+ public void startDoesNotConfigureGlobalSerialFilter_whenPropertyIsEmpty()
+ throws InvocationTargetException, IllegalAccessException {
+ System.setProperty(JDK_PROPERTY, "");
+
+ locator.set(new LocatorLauncher.Builder()
+ .setMemberName(NAME)
+ .setPort(locatorPort)
+ .setWorkingDirectory(valueOf(workingDirectory))
+ .set(HTTP_SERVICE_PORT, "0")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_PORT, valueOf(jmxPort))
+ .set(JMX_MANAGER_START, "true")
+ .set(LOG_FILE, valueOf(logFile))
+ .build())
+ .get()
+ .start();
+
+ assertThatSerialFilterIsNull();
+ }
+}
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherJmxSerialFilterIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherJmxSerialFilterIntegrationTest.java
new file mode 100644
index 0000000..66f7137
--- /dev/null
+++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherJmxSerialFilterIntegrationTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.serialization.filter;
+
+import static java.lang.String.valueOf;
+import static org.apache.commons.lang3.JavaVersion.JAVA_1_8;
+import static org.apache.commons.lang3.JavaVersion.JAVA_9;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtMost;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assumptions.assumeThat;
+
+import org.junit.Test;
+
+import org.apache.geode.distributed.LocatorLauncher;
+
+public class LocatorLauncherJmxSerialFilterIntegrationTest
+ extends LocatorLauncherWithJmxManager {
+
+ @Test
+ public void startConfiguresJmxSerialFilter_onJava9orGreater() {
+ assumeThat(isJavaVersionAtLeast(JAVA_9)).isTrue();
+
+ locator.set(new LocatorLauncher.Builder()
+ .setMemberName(NAME)
+ .setPort(locatorPort)
+ .setWorkingDirectory(valueOf(workingDirectory))
+ .set(HTTP_SERVICE_PORT, "0")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_PORT, valueOf(jmxPort))
+ .set(JMX_MANAGER_START, "true")
+ .set(LOG_FILE, valueOf(logFile))
+ .build())
+ .get()
+ .start();
+
+ assertThat(isJmxManagerStarted())
+ .isTrue();
+ assertThat(System.getProperty(JMX_PROPERTY))
+ .as(JMX_PROPERTY)
+ .isEqualTo(openMBeanFilterPattern);
+ }
+
+ @Test
+ public void startDoesNotConfigureJmxSerialFilter_onJava8() {
+ assumeThat(isJavaVersionAtMost(JAVA_1_8)).isTrue();
+
+ locator.set(new LocatorLauncher.Builder()
+ .setMemberName(NAME)
+ .setPort(locatorPort)
+ .setWorkingDirectory(valueOf(workingDirectory))
+ .set(HTTP_SERVICE_PORT, "0")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_PORT, valueOf(jmxPort))
+ .set(JMX_MANAGER_START, "true")
+ .set(LOG_FILE, valueOf(logFile))
+ .build())
+ .get()
+ .start();
+
+ assertThat(isJmxManagerStarted())
+ .isTrue();
+ assertThat(System.getProperty(JMX_PROPERTY))
+ .as(JMX_PROPERTY)
+ .isNull();
+ }
+}
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherJmxSerialFilterPropertyBlankIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherJmxSerialFilterPropertyBlankIntegrationTest.java
new file mode 100644
index 0000000..bb6b01b
--- /dev/null
+++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherJmxSerialFilterPropertyBlankIntegrationTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.serialization.filter;
+
+import static java.lang.String.valueOf;
+import static org.apache.commons.lang3.JavaVersion.JAVA_1_8;
+import static org.apache.commons.lang3.JavaVersion.JAVA_9;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtMost;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assumptions.assumeThat;
+
+import org.junit.Test;
+
+import org.apache.geode.distributed.LocatorLauncher;
+
+public class LocatorLauncherJmxSerialFilterPropertyBlankIntegrationTest
+ extends LocatorLauncherWithJmxManager {
+
+ @Test
+ public void startConfiguresJmxSerialFilter_whenPropertyIsBlank_onJava9orGreater() {
+ assumeThat(isJavaVersionAtLeast(JAVA_9)).isTrue();
+
+ System.setProperty(JMX_PROPERTY, " ");
+
+ locator.set(new LocatorLauncher.Builder()
+ .setMemberName(NAME)
+ .setPort(locatorPort)
+ .setWorkingDirectory(valueOf(workingDirectory))
+ .set(HTTP_SERVICE_PORT, "0")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_PORT, valueOf(jmxPort))
+ .set(JMX_MANAGER_START, "true")
+ .set(LOG_FILE, valueOf(logFile))
+ .build())
+ .get()
+ .start();
+
+ assertThat(isJmxManagerStarted())
+ .isTrue();
+ assertThat(System.getProperty(JMX_PROPERTY))
+ .as(JMX_PROPERTY)
+ .isEqualTo(openMBeanFilterPattern);
+ }
+
+ @Test
+ public void startDoesNotConfigureJmxSerialFilter_whenPropertyIsBlank_onJava8() {
+ assumeThat(isJavaVersionAtMost(JAVA_1_8)).isTrue();
+
+ System.setProperty(JMX_PROPERTY, " ");
+
+ locator.set(new LocatorLauncher.Builder()
+ .setMemberName(NAME)
+ .setPort(locatorPort)
+ .setWorkingDirectory(valueOf(workingDirectory))
+ .set(HTTP_SERVICE_PORT, "0")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_PORT, valueOf(jmxPort))
+ .set(JMX_MANAGER_START, "true")
+ .set(LOG_FILE, valueOf(logFile))
+ .build())
+ .get()
+ .start();
+
+ assertThat(isJmxManagerStarted())
+ .isTrue();
+ assertThat(System.getProperty(JMX_PROPERTY))
+ .as(JMX_PROPERTY)
+ .isEqualTo(" ");
+ }
+}
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherJmxSerialFilterPropertyEmptyIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherJmxSerialFilterPropertyEmptyIntegrationTest.java
new file mode 100644
index 0000000..d924f6c
--- /dev/null
+++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherJmxSerialFilterPropertyEmptyIntegrationTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.serialization.filter;
+
+import static java.lang.String.valueOf;
+import static org.apache.commons.lang3.JavaVersion.JAVA_1_8;
+import static org.apache.commons.lang3.JavaVersion.JAVA_9;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtMost;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assumptions.assumeThat;
+
+import org.junit.Test;
+
+import org.apache.geode.distributed.LocatorLauncher;
+
+public class LocatorLauncherJmxSerialFilterPropertyEmptyIntegrationTest
+ extends LocatorLauncherWithJmxManager {
+
+ @Test
+ public void startConfiguresJmxSerialFilter_whenPropertyIsEmpty_onJava9orGreater() {
+ assumeThat(isJavaVersionAtLeast(JAVA_9)).isTrue();
+
+ System.setProperty(JMX_PROPERTY, "");
+
+ locator.set(new LocatorLauncher.Builder()
+ .setMemberName(NAME)
+ .setPort(locatorPort)
+ .setWorkingDirectory(valueOf(workingDirectory))
+ .set(HTTP_SERVICE_PORT, "0")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_PORT, valueOf(jmxPort))
+ .set(JMX_MANAGER_START, "true")
+ .set(LOG_FILE, valueOf(logFile))
+ .build())
+ .get()
+ .start();
+
+ assertThat(isJmxManagerStarted())
+ .isTrue();
+ assertThat(System.getProperty(JMX_PROPERTY))
+ .as(JMX_PROPERTY)
+ .isEqualTo(openMBeanFilterPattern);
+ }
+
+ @Test
+ public void startDoesNotConfigureJmxSerialFilter_whenPropertyIsEmpty_onJava8() {
+ assumeThat(isJavaVersionAtMost(JAVA_1_8)).isTrue();
+
+ System.setProperty(JMX_PROPERTY, "");
+
+ locator.set(new LocatorLauncher.Builder()
+ .setMemberName(NAME)
+ .setPort(locatorPort)
+ .setWorkingDirectory(valueOf(workingDirectory))
+ .set(HTTP_SERVICE_PORT, "0")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_PORT, valueOf(jmxPort))
+ .set(JMX_MANAGER_START, "true")
+ .set(LOG_FILE, valueOf(logFile))
+ .build())
+ .get()
+ .start();
+
+ assertThat(isJmxManagerStarted())
+ .isTrue();
+ assertThat(System.getProperty(JMX_PROPERTY))
+ .as(JMX_PROPERTY)
+ .isEqualTo("");
+ }
+}
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherJmxSerialFilterPropertyExistsIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherJmxSerialFilterPropertyExistsIntegrationTest.java
new file mode 100644
index 0000000..3de7ac2
--- /dev/null
+++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherJmxSerialFilterPropertyExistsIntegrationTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.serialization.filter;
+
+import static java.lang.String.valueOf;
+import static org.apache.commons.lang3.JavaVersion.JAVA_1_8;
+import static org.apache.commons.lang3.JavaVersion.JAVA_9;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtMost;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assumptions.assumeThat;
+
+import org.junit.Test;
+
+import org.apache.geode.distributed.LocatorLauncher;
+
+public class LocatorLauncherJmxSerialFilterPropertyExistsIntegrationTest
+ extends LocatorLauncherWithJmxManager {
+
+ @Test
+ public void startDoesNotConfigureJmxSerialFilter_whenPropertyExists_onJava9orGreater() {
+ assumeThat(isJavaVersionAtLeast(JAVA_9)).isTrue();
+
+ String existingJmxSerialFilter = "!*";
+ System.setProperty(JMX_PROPERTY, existingJmxSerialFilter);
+
+ locator.set(new LocatorLauncher.Builder()
+ .setMemberName(NAME)
+ .setPort(locatorPort)
+ .setWorkingDirectory(valueOf(workingDirectory))
+ .set(HTTP_SERVICE_PORT, "0")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_PORT, valueOf(jmxPort))
+ .set(JMX_MANAGER_START, "true")
+ .set(LOG_FILE, valueOf(logFile))
+ .build())
+ .get()
+ .start();
+
+ assertThat(isJmxManagerStarted())
+ .isTrue();
+ assertThat(System.getProperty(JMX_PROPERTY))
+ .as(JMX_PROPERTY)
+ .isEqualTo(existingJmxSerialFilter);
+ }
+
+ @Test
+ public void startDoesNotConfigureJmxSerialFilter_whenPropertyExists_onJava8() {
+ assumeThat(isJavaVersionAtMost(JAVA_1_8)).isTrue();
+
+ String existingJmxSerialFilter = "!*";
+ System.setProperty(JMX_PROPERTY, existingJmxSerialFilter);
+
+ locator.set(new LocatorLauncher.Builder()
+ .setMemberName(NAME)
+ .setPort(locatorPort)
+ .setWorkingDirectory(valueOf(workingDirectory))
+ .set(HTTP_SERVICE_PORT, "0")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_PORT, valueOf(jmxPort))
+ .set(JMX_MANAGER_START, "true")
+ .set(LOG_FILE, valueOf(logFile))
+ .build())
+ .get()
+ .start();
+
+ assertThat(isJmxManagerStarted())
+ .isTrue();
+ assertThat(System.getProperty(JMX_PROPERTY))
+ .as(JMX_PROPERTY)
+ .isEqualTo(existingJmxSerialFilter);
+ }
+}
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherWithJmxManager.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherWithJmxManager.java
new file mode 100644
index 0000000..8bd96f5
--- /dev/null
+++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/LocatorLauncherWithJmxManager.java
@@ -0,0 +1,82 @@
+/*
+ * 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.serialization.filter;
+
+import static org.apache.geode.internal.AvailablePortHelper.getRandomAvailableTCPPorts;
+
+import java.nio.file.Path;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.contrib.java.lang.system.RestoreSystemProperties;
+import org.junit.rules.TemporaryFolder;
+
+import org.apache.geode.distributed.LocatorLauncher;
+import org.apache.geode.distributed.internal.InternalLocator;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.management.ManagementService;
+import org.apache.geode.management.internal.SystemManagementService;
+import org.apache.geode.test.junit.rules.CloseableReference;
+
+abstract class LocatorLauncherWithJmxManager {
+
+ static final String NAME = "locator";
+ static final String JDK_PROPERTY = "jdk.serialFilter";
+ static final String JMX_PROPERTY = "jmx.remote.rmi.server.serial.filter.pattern";
+
+ static final ObjectInputFilterApi OBJECT_INPUT_FILTER_API =
+ new ReflectiveObjectInputFilterApiFactory().createObjectInputFilterApi();
+
+ Path workingDirectory;
+ int locatorPort;
+ int jmxPort;
+ Path logFile;
+ String openMBeanFilterPattern;
+
+ @Rule
+ public CloseableReference<LocatorLauncher> locator = new CloseableReference<>();
+ @Rule
+ public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
+ @Rule
+ public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+ @Before
+ public void setUpFiles() {
+ workingDirectory = temporaryFolder.getRoot().toPath().toAbsolutePath();
+ logFile = workingDirectory.resolve(NAME + ".log").toAbsolutePath();
+ }
+
+ @Before
+ public void setUpPorts() {
+ int[] ports = getRandomAvailableTCPPorts(2);
+ jmxPort = ports[0];
+ locatorPort = ports[1];
+ }
+
+ @Before
+ public void setUpFilterPattern() {
+ openMBeanFilterPattern = new OpenMBeanFilterPattern().pattern();
+ }
+
+ SystemManagementService getSystemManagementService() {
+ InternalLocator locator = (InternalLocator) this.locator.get().getLocator();
+ InternalCache cache = locator.getCache();
+ return (SystemManagementService) ManagementService.getManagementService(cache);
+ }
+
+ boolean isJmxManagerStarted() {
+ return getSystemManagementService().isManager();
+ }
+}
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/SerialFilterAssertions.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/SerialFilterAssertions.java
new file mode 100644
index 0000000..b6d552a
--- /dev/null
+++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/SerialFilterAssertions.java
@@ -0,0 +1,64 @@
+/*
+ * 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.serialization.filter;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.lang.reflect.InvocationTargetException;
+
+@SuppressWarnings({"unused", "WeakerAccess"})
+public class SerialFilterAssertions {
+
+ private static final ObjectInputFilterApi API = new ReflectiveObjectInputFilterApiFactory()
+ .createObjectInputFilterApi();
+
+ private SerialFilterAssertions() {
+ // do not instantiate
+ }
+
+ public static void assertThatSerialFilterIsNull()
+ throws InvocationTargetException, IllegalAccessException {
+ boolean exists = API.getSerialFilter() != null;
+ assertThat(exists)
+ .as("ObjectInputFilter$Config.getSerialFilter() is null")
+ .isFalse();
+ }
+
+ public static void assertThatSerialFilterIsNotNull()
+ throws InvocationTargetException, IllegalAccessException {
+ boolean exists = API.getSerialFilter() != null;
+ assertThat(exists)
+ .as("ObjectInputFilter$Config.getSerialFilter() is not null")
+ .isTrue();
+ }
+
+ public static void assertThatSerialFilterIsSameAs(Object objectInputFilter)
+ throws InvocationTargetException, IllegalAccessException {
+ Object currentFilter = API.getSerialFilter();
+ boolean sameIdentity = currentFilter == objectInputFilter;
+ assertThat(sameIdentity)
+ .as("ObjectInputFilter$Config.getSerialFilter() is same as parameter")
+ .isTrue();
+ }
+
+ public static void assertThatSerialFilterIsNotSameAs(Object objectInputFilter)
+ throws InvocationTargetException, IllegalAccessException {
+ Object currentFilter = API.getSerialFilter();
+ boolean sameIdentity = currentFilter == objectInputFilter;
+ assertThat(sameIdentity)
+ .as("ObjectInputFilter$Config.getSerialFilter() is same as parameter")
+ .isFalse();
+ }
+}
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherGlobalSerialFilterBlankIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherGlobalSerialFilterBlankIntegrationTest.java
new file mode 100644
index 0000000..5cbb8c2
--- /dev/null
+++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherGlobalSerialFilterBlankIntegrationTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.serialization.filter;
+
+import static java.lang.String.valueOf;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
+import static org.apache.geode.internal.serialization.filter.SerialFilterAssertions.assertThatSerialFilterIsSameAs;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.junit.Test;
+
+import org.apache.geode.distributed.ServerLauncher;
+
+public class ServerLauncherGlobalSerialFilterBlankIntegrationTest
+ extends ServerLauncherWithJmxManager {
+
+ @Test
+ public void startDoesNotConfigureGlobalSerialFilter_whenFilterIsBlank()
+ throws InvocationTargetException, IllegalAccessException {
+ Object existingGlobalSerialFilter = OBJECT_INPUT_FILTER_API.createFilter(" ");
+ OBJECT_INPUT_FILTER_API.setSerialFilter(existingGlobalSerialFilter);
+
+ server.set(new ServerLauncher.Builder()
+ .setMemberName(NAME)
+ .setDisableDefaultServer(true)
+ .setWorkingDirectory(valueOf(workingDirectory))
+ .set(HTTP_SERVICE_PORT, "0")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_PORT, valueOf(jmxPort))
+ .set(JMX_MANAGER_START, "true")
+ .set(LOG_FILE, valueOf(logFile))
+ .build())
+ .get()
+ .start();
+
+ assertThatSerialFilterIsSameAs(existingGlobalSerialFilter);
+ }
+}
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherGlobalSerialFilterExistsIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherGlobalSerialFilterExistsIntegrationTest.java
new file mode 100644
index 0000000..b5560c6
--- /dev/null
+++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherGlobalSerialFilterExistsIntegrationTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.serialization.filter;
+
+import static java.lang.String.valueOf;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
+import static org.apache.geode.internal.serialization.filter.SerialFilterAssertions.assertThatSerialFilterIsSameAs;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.junit.Test;
+
+import org.apache.geode.distributed.ServerLauncher;
+
+public class ServerLauncherGlobalSerialFilterExistsIntegrationTest
+ extends ServerLauncherWithJmxManager {
+
+ @Test
+ public void startDoesNotConfigureGlobalSerialFilter_whenFilterExists()
+ throws InvocationTargetException, IllegalAccessException {
+ Object existingGlobalSerialFilter = OBJECT_INPUT_FILTER_API.createFilter("!*");
+ OBJECT_INPUT_FILTER_API.setSerialFilter(existingGlobalSerialFilter);
+
+ server.set(new ServerLauncher.Builder()
+ .setMemberName(NAME)
+ .setDisableDefaultServer(true)
+ .setWorkingDirectory(valueOf(workingDirectory))
+ .set(HTTP_SERVICE_PORT, "0")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_PORT, valueOf(jmxPort))
+ .set(JMX_MANAGER_START, "true")
+ .set(LOG_FILE, valueOf(logFile))
+ .build())
+ .get()
+ .start();
+
+ assertThatSerialFilterIsSameAs(existingGlobalSerialFilter);
+ }
+}
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherGlobalSerialFilterIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherGlobalSerialFilterIntegrationTest.java
new file mode 100644
index 0000000..7c90152
--- /dev/null
+++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherGlobalSerialFilterIntegrationTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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.serialization.filter;
+
+import static java.lang.String.valueOf;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Test;
+
+import org.apache.geode.distributed.ServerLauncher;
+
+public class ServerLauncherGlobalSerialFilterIntegrationTest
+ extends ServerLauncherWithJmxManager {
+
+ @Test
+ public void startDoesNotConfigureGlobalSerialFilter() {
+ server.set(new ServerLauncher.Builder()
+ .setMemberName(NAME)
+ .setDisableDefaultServer(true)
+ .setWorkingDirectory(valueOf(workingDirectory))
+ .set(HTTP_SERVICE_PORT, "0")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_PORT, valueOf(jmxPort))
+ .set(JMX_MANAGER_START, "true")
+ .set(LOG_FILE, valueOf(logFile))
+ .build())
+ .get()
+ .start();
+
+ assertThat(System.getProperty(JDK_PROPERTY))
+ .as(JDK_PROPERTY)
+ .isNull();
+ }
+}
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherGlobalSerialFilterPropertyBlankIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherGlobalSerialFilterPropertyBlankIntegrationTest.java
new file mode 100644
index 0000000..6fb95df
--- /dev/null
+++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherGlobalSerialFilterPropertyBlankIntegrationTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.serialization.filter;
+
+import static java.lang.String.valueOf;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Test;
+
+import org.apache.geode.distributed.ServerLauncher;
+
+public class ServerLauncherGlobalSerialFilterPropertyBlankIntegrationTest
+ extends ServerLauncherWithJmxManager {
+
+ @Test
+ public void startDoesNotConfigureGlobalSerialFilter_whenPropertyIsBlank() {
+ System.setProperty(JDK_PROPERTY, " ");
+
+ server.set(new ServerLauncher.Builder()
+ .setMemberName(NAME)
+ .setDisableDefaultServer(true)
+ .setWorkingDirectory(valueOf(workingDirectory))
+ .set(HTTP_SERVICE_PORT, "0")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_PORT, valueOf(jmxPort))
+ .set(JMX_MANAGER_START, "true")
+ .set(LOG_FILE, valueOf(logFile))
+ .build())
+ .get()
+ .start();
+
+ assertThat(System.getProperty(JDK_PROPERTY))
+ .as(JDK_PROPERTY)
+ .isEqualTo(" ");
+ }
+}
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherGlobalSerialFilterPropertyEmptyIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherGlobalSerialFilterPropertyEmptyIntegrationTest.java
new file mode 100644
index 0000000..e34d400
--- /dev/null
+++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherGlobalSerialFilterPropertyEmptyIntegrationTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.serialization.filter;
+
+import static java.lang.String.valueOf;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Test;
+
+import org.apache.geode.distributed.ServerLauncher;
+
+public class ServerLauncherGlobalSerialFilterPropertyEmptyIntegrationTest
+ extends ServerLauncherWithJmxManager {
+
+ @Test
+ public void startDoesNotConfigureGlobalSerialFilter_whenPropertyIsEmpty() {
+ System.setProperty(JDK_PROPERTY, "");
+
+ server.set(new ServerLauncher.Builder()
+ .setMemberName(NAME)
+ .setDisableDefaultServer(true)
+ .setWorkingDirectory(valueOf(workingDirectory))
+ .set(HTTP_SERVICE_PORT, "0")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_PORT, valueOf(jmxPort))
+ .set(JMX_MANAGER_START, "true")
+ .set(LOG_FILE, valueOf(logFile))
+ .build())
+ .get()
+ .start();
+
+ assertThat(System.getProperty(JDK_PROPERTY))
+ .as(JDK_PROPERTY)
+ .isEmpty();
+ }
+}
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherJmxSerialFilterIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherJmxSerialFilterIntegrationTest.java
new file mode 100644
index 0000000..cf4c851
--- /dev/null
+++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherJmxSerialFilterIntegrationTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.serialization.filter;
+
+import static java.lang.String.valueOf;
+import static org.apache.commons.lang3.JavaVersion.JAVA_1_8;
+import static org.apache.commons.lang3.JavaVersion.JAVA_9;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtMost;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assumptions.assumeThat;
+
+import org.junit.Test;
+
+import org.apache.geode.distributed.ServerLauncher;
+
+public class ServerLauncherJmxSerialFilterIntegrationTest
+ extends ServerLauncherWithJmxManager {
+
+ @Test
+ public void startConfiguresJmxSerialFilter_onJava9orGreater() {
+ assumeThat(isJavaVersionAtLeast(JAVA_9)).isTrue();
+
+ server.set(new ServerLauncher.Builder()
+ .setDisableDefaultServer(true)
+ .setMemberName(NAME)
+ .setWorkingDirectory(valueOf(workingDirectory))
+ .set(HTTP_SERVICE_PORT, "0")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_PORT, valueOf(jmxPort))
+ .set(JMX_MANAGER_START, "true")
+ .set(LOG_FILE, valueOf(logFile))
+ .build())
+ .get()
+ .start();
+
+ assertThat(isJmxManagerStarted())
+ .isTrue();
+ assertThat(System.getProperty(JMX_PROPERTY))
+ .as(JMX_PROPERTY)
+ .isEqualTo(openMBeanFilterPattern);
+ }
+
+ /**
+ * The system property for the JmxSerialFilter was not added until Java 9.
+ */
+ @Test
+ public void startDoesNotConfigureJmxSerialFilter_onJava8() {
+ assumeThat(isJavaVersionAtMost(JAVA_1_8)).isTrue();
+
+ server.set(new ServerLauncher.Builder()
+ .setDisableDefaultServer(true)
+ .setMemberName(NAME)
+ .setWorkingDirectory(valueOf(workingDirectory))
+ .set(HTTP_SERVICE_PORT, "0")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_PORT, valueOf(jmxPort))
+ .set(JMX_MANAGER_START, "true")
+ .set(LOG_FILE, valueOf(logFile))
+ .build())
+ .get()
+ .start();
+
+ assertThat(isJmxManagerStarted())
+ .isTrue();
+ assertThat(System.getProperty(JMX_PROPERTY))
+ .as(JMX_PROPERTY)
+ .isNull();
+ }
+}
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherJmxSerialFilterPropertyBlankIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherJmxSerialFilterPropertyBlankIntegrationTest.java
new file mode 100644
index 0000000..26aa5ed
--- /dev/null
+++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherJmxSerialFilterPropertyBlankIntegrationTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.serialization.filter;
+
+import static java.lang.String.valueOf;
+import static org.apache.commons.lang3.JavaVersion.JAVA_1_8;
+import static org.apache.commons.lang3.JavaVersion.JAVA_9;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtMost;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assumptions.assumeThat;
+
+import org.junit.Test;
+
+import org.apache.geode.distributed.ServerLauncher;
+
+public class ServerLauncherJmxSerialFilterPropertyBlankIntegrationTest
+ extends ServerLauncherWithJmxManager {
+
+ @Test
+ public void startConfiguresJmxSerialFilter_whenPropertyIsBlank_onJava9orGreater() {
+ assumeThat(isJavaVersionAtLeast(JAVA_9)).isTrue();
+
+ System.setProperty(JMX_PROPERTY, " ");
+
+ server.set(new ServerLauncher.Builder()
+ .setDisableDefaultServer(true)
+ .setMemberName(NAME)
+ .setWorkingDirectory(valueOf(workingDirectory))
+ .set(HTTP_SERVICE_PORT, "0")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_PORT, valueOf(jmxPort))
+ .set(JMX_MANAGER_START, "true")
+ .set(LOG_FILE, valueOf(logFile))
+ .build())
+ .get()
+ .start();
+
+ assertThat(isJmxManagerStarted())
+ .isTrue();
+ assertThat(System.getProperty(JMX_PROPERTY))
+ .as(JMX_PROPERTY)
+ .isEqualTo(openMBeanFilterPattern);
+ }
+
+ @Test
+ public void startDoesNotConfigureJmxSerialFilter_whenPropertyIsBlank_onJava8() {
+ assumeThat(isJavaVersionAtMost(JAVA_1_8)).isTrue();
+
+ System.setProperty(JMX_PROPERTY, " ");
+
+ server.set(new ServerLauncher.Builder()
+ .setDisableDefaultServer(true)
+ .setMemberName(NAME)
+ .setWorkingDirectory(valueOf(workingDirectory))
+ .set(HTTP_SERVICE_PORT, "0")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_PORT, valueOf(jmxPort))
+ .set(JMX_MANAGER_START, "true")
+ .set(LOG_FILE, valueOf(logFile))
+ .build())
+ .get()
+ .start();
+
+ assertThat(isJmxManagerStarted())
+ .isTrue();
+ assertThat(System.getProperty(JMX_PROPERTY))
+ .as(JMX_PROPERTY)
+ .isEqualTo(" ");
+ }
+}
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherJmxSerialFilterPropertyEmptyIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherJmxSerialFilterPropertyEmptyIntegrationTest.java
new file mode 100644
index 0000000..68232a2
--- /dev/null
+++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherJmxSerialFilterPropertyEmptyIntegrationTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.serialization.filter;
+
+import static java.lang.String.valueOf;
+import static org.apache.commons.lang3.JavaVersion.JAVA_1_8;
+import static org.apache.commons.lang3.JavaVersion.JAVA_9;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtMost;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assumptions.assumeThat;
+
+import org.junit.Test;
+
+import org.apache.geode.distributed.ServerLauncher;
+
+public class ServerLauncherJmxSerialFilterPropertyEmptyIntegrationTest
+ extends ServerLauncherWithJmxManager {
+
+ @Test
+ public void startConfiguresJmxSerialFilter_whenPropertyIsEmpty_onJava9orGreater() {
+ assumeThat(isJavaVersionAtLeast(JAVA_9)).isTrue();
+
+ System.setProperty(JMX_PROPERTY, "");
+
+ server.set(new ServerLauncher.Builder()
+ .setDisableDefaultServer(true)
+ .setMemberName(NAME)
+ .setWorkingDirectory(valueOf(workingDirectory))
+ .set(HTTP_SERVICE_PORT, "0")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_PORT, valueOf(jmxPort))
+ .set(JMX_MANAGER_START, "true")
+ .set(LOG_FILE, valueOf(logFile))
+ .build())
+ .get()
+ .start();
+
+ assertThat(isJmxManagerStarted())
+ .isTrue();
+ assertThat(System.getProperty(JMX_PROPERTY))
+ .as(JMX_PROPERTY)
+ .isEqualTo(openMBeanFilterPattern);
+ }
+
+ @Test
+ public void startDoesNotConfigureJmxSerialFilter_whenPropertyIsEmpty_onJava8() {
+ assumeThat(isJavaVersionAtMost(JAVA_1_8)).isTrue();
+
+ System.setProperty(JMX_PROPERTY, "");
+
+ server.set(new ServerLauncher.Builder()
+ .setDisableDefaultServer(true)
+ .setMemberName(NAME)
+ .setWorkingDirectory(valueOf(workingDirectory))
+ .set(HTTP_SERVICE_PORT, "0")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_PORT, valueOf(jmxPort))
+ .set(JMX_MANAGER_START, "true")
+ .set(LOG_FILE, valueOf(logFile))
+ .build())
+ .get()
+ .start();
+
+ assertThat(isJmxManagerStarted())
+ .isTrue();
+ assertThat(System.getProperty(JMX_PROPERTY))
+ .as(JMX_PROPERTY)
+ .isEqualTo("");
+ }
+}
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherJmxSerialFilterPropertyExistsIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherJmxSerialFilterPropertyExistsIntegrationTest.java
new file mode 100644
index 0000000..05e33ac
--- /dev/null
+++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherJmxSerialFilterPropertyExistsIntegrationTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.serialization.filter;
+
+import static java.lang.String.valueOf;
+import static org.apache.commons.lang3.JavaVersion.JAVA_1_8;
+import static org.apache.commons.lang3.JavaVersion.JAVA_9;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtMost;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assumptions.assumeThat;
+
+import org.junit.Test;
+
+import org.apache.geode.distributed.ServerLauncher;
+
+public class ServerLauncherJmxSerialFilterPropertyExistsIntegrationTest
+ extends ServerLauncherWithJmxManager {
+
+ @Test
+ public void startDoesNotConfigureJmxSerialFilter_whenPropertyExists_onJava9orGreater() {
+ assumeThat(isJavaVersionAtLeast(JAVA_9)).isTrue();
+
+ String existingJmxSerialFilter = "!*";
+ System.setProperty(JMX_PROPERTY, existingJmxSerialFilter);
+
+ server.set(new ServerLauncher.Builder()
+ .setDisableDefaultServer(true)
+ .setMemberName(NAME)
+ .setWorkingDirectory(valueOf(workingDirectory))
+ .set(HTTP_SERVICE_PORT, "0")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_PORT, valueOf(jmxPort))
+ .set(JMX_MANAGER_START, "true")
+ .set(LOG_FILE, valueOf(logFile))
+ .build())
+ .get()
+ .start();
+
+ assertThat(isJmxManagerStarted())
+ .isTrue();
+ assertThat(System.getProperty(JMX_PROPERTY))
+ .as(JMX_PROPERTY)
+ .isEqualTo(existingJmxSerialFilter);
+ }
+
+ @Test
+ public void startDoesNotConfigureJmxSerialFilter_whenPropertyExists_onJava8() {
+ assumeThat(isJavaVersionAtMost(JAVA_1_8)).isTrue();
+
+ String existingJmxSerialFilter = "!*";
+ System.setProperty(JMX_PROPERTY, existingJmxSerialFilter);
+
+ server.set(new ServerLauncher.Builder()
+ .setDisableDefaultServer(true)
+ .setMemberName(NAME)
+ .setWorkingDirectory(valueOf(workingDirectory))
+ .set(HTTP_SERVICE_PORT, "0")
+ .set(JMX_MANAGER, "true")
+ .set(JMX_MANAGER_PORT, valueOf(jmxPort))
+ .set(JMX_MANAGER_START, "true")
+ .set(LOG_FILE, valueOf(logFile))
+ .build())
+ .get()
+ .start();
+
+ assertThat(isJmxManagerStarted())
+ .isTrue();
+ assertThat(System.getProperty(JMX_PROPERTY))
+ .as(JMX_PROPERTY)
+ .isEqualTo(existingJmxSerialFilter);
+ }
+}
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherWithJmxManager.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherWithJmxManager.java
new file mode 100644
index 0000000..eba157c
--- /dev/null
+++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ServerLauncherWithJmxManager.java
@@ -0,0 +1,77 @@
+/*
+ * 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.serialization.filter;
+
+import static org.apache.geode.internal.AvailablePortHelper.getRandomAvailableTCPPort;
+
+import java.nio.file.Path;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.contrib.java.lang.system.RestoreSystemProperties;
+import org.junit.rules.TemporaryFolder;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.distributed.ServerLauncher;
+import org.apache.geode.management.ManagementService;
+import org.apache.geode.management.internal.SystemManagementService;
+import org.apache.geode.test.junit.rules.CloseableReference;
+
+abstract class ServerLauncherWithJmxManager {
+
+ static final String NAME = "server";
+ static final String JDK_PROPERTY = "jdk.serialFilter";
+ static final String JMX_PROPERTY = "jmx.remote.rmi.server.serial.filter.pattern";
+
+ static final ObjectInputFilterApi OBJECT_INPUT_FILTER_API =
+ new ReflectiveObjectInputFilterApiFactory().createObjectInputFilterApi();
+
+ Path workingDirectory;
+ int jmxPort;
+ Path logFile;
+ String openMBeanFilterPattern;
+
+ @Rule
+ public CloseableReference<ServerLauncher> server = new CloseableReference<>();
+ @Rule
+ public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
+ @Rule
+ public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+ @Before
+ public void setUpFiles() {
+ workingDirectory = temporaryFolder.getRoot().toPath().toAbsolutePath();
+ logFile = workingDirectory.resolve(NAME + ".log").toAbsolutePath();
+ }
+
+ @Before
+ public void setUpPorts() {
+ jmxPort = getRandomAvailableTCPPort();
+ }
+
+ @Before
+ public void setUpFilterPattern() {
+ openMBeanFilterPattern = new OpenMBeanFilterPattern().pattern();
+ }
+
+ SystemManagementService getSystemManagementService() {
+ Cache cache = server.get().getCache();
+ return (SystemManagementService) ManagementService.getManagementService(cache);
+ }
+
+ boolean isJmxManagerStarted() {
+ return getSystemManagementService().isManager();
+ }
+}
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/management/internal/LocatorManagerConfiguresJmxSerialFilterIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/management/internal/LocatorManagerConfiguresJmxSerialFilterIntegrationTest.java
deleted file mode 100644
index 47f196f..0000000
--- a/geode-core/src/integrationTest/java/org/apache/geode/management/internal/LocatorManagerConfiguresJmxSerialFilterIntegrationTest.java
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * 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.management.internal;
-
-import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
-import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtMost;
-import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
-import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
-import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
-import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
-import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
-import static org.apache.geode.internal.AvailablePortHelper.getRandomAvailableTCPPorts;
-import static org.apache.geode.management.internal.JmxRmiOpenTypesSerialFilter.PROPERTY_NAME;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assumptions.assumeThat;
-
-import java.io.File;
-
-import org.apache.commons.lang3.JavaVersion;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-
-import org.apache.geode.distributed.LocatorLauncher;
-import org.apache.geode.test.junit.rules.CloseableReference;
-
-public class LocatorManagerConfiguresJmxSerialFilterIntegrationTest {
-
- private static final String NAME = "locator";
-
- private File workingDirectory;
- private int locatorPort;
- private int jmxPort;
- private String expectedSerialFilter;
-
- @Rule
- public CloseableReference<LocatorLauncher> locator = new CloseableReference<>();
- @Rule
- public TemporaryFolder temporaryFolder = new TemporaryFolder();
-
- @Before
- public void setUp() throws Exception {
- workingDirectory = temporaryFolder.newFolder(NAME);
- int[] ports = getRandomAvailableTCPPorts(2);
- locatorPort = ports[0];
- jmxPort = ports[1];
- expectedSerialFilter = new JmxRmiOpenTypesSerialFilter().createSerialFilterPattern();
- }
-
- @After
- public void tearDown() {
- System.clearProperty(PROPERTY_NAME);
- }
-
- @Test
- public void startingLocatorWithJmxManager_configuresSerialFilter_atLeastJava9() {
- assumeThat(isJavaVersionAtLeast(JavaVersion.JAVA_9)).isTrue();
-
- locator.set(new LocatorLauncher.Builder()
- .setMemberName(NAME)
- .setPort(locatorPort)
- .setWorkingDirectory(workingDirectory.getAbsolutePath())
- .set(HTTP_SERVICE_PORT, "0")
- .set(JMX_MANAGER, "true")
- .set(JMX_MANAGER_PORT, String.valueOf(jmxPort))
- .set(JMX_MANAGER_START, "true")
- .set(LOG_FILE, new File(workingDirectory, NAME + ".log").getAbsolutePath())
- .build())
- .get()
- .start();
-
- String serialFilter = System.getProperty(PROPERTY_NAME);
- assertThat(serialFilter).isEqualTo(expectedSerialFilter);
- }
-
- @Test
- public void startingLocatorWithJmxManager_changesEmptySerialFilter_atLeastJava9() {
- assumeThat(isJavaVersionAtLeast(JavaVersion.JAVA_9)).isTrue();
-
- System.setProperty(PROPERTY_NAME, "");
-
- locator.set(new LocatorLauncher.Builder()
- .setMemberName(NAME)
- .setPort(locatorPort)
- .setWorkingDirectory(workingDirectory.getAbsolutePath())
- .set(HTTP_SERVICE_PORT, "0")
- .set(JMX_MANAGER, "true")
- .set(JMX_MANAGER_PORT, String.valueOf(jmxPort))
- .set(JMX_MANAGER_START, "true")
- .set(LOG_FILE, new File(workingDirectory, NAME + ".log").getAbsolutePath())
- .build())
- .get()
- .start();
-
- String serialFilter = System.getProperty(PROPERTY_NAME);
- assertThat(serialFilter).isEqualTo(expectedSerialFilter);
- }
-
- @Test
- public void startingLocatorWithJmxManager_skipsNonEmptySerialFilter_atLeastJava9() {
- assumeThat(isJavaVersionAtLeast(JavaVersion.JAVA_9)).isTrue();
-
- String existingSerialFilter = "!*";
- System.setProperty(PROPERTY_NAME, existingSerialFilter);
-
- locator.set(new LocatorLauncher.Builder()
- .setMemberName(NAME)
- .setPort(locatorPort)
- .setWorkingDirectory(workingDirectory.getAbsolutePath())
- .set(HTTP_SERVICE_PORT, "0")
- .set(JMX_MANAGER, "true")
- .set(JMX_MANAGER_PORT, String.valueOf(jmxPort))
- .set(JMX_MANAGER_START, "true")
- .set(LOG_FILE, new File(workingDirectory, NAME + ".log").getAbsolutePath())
- .build())
- .get()
- .start();
-
- String serialFilter = System.getProperty(PROPERTY_NAME);
- assertThat(serialFilter).isEqualTo(existingSerialFilter);
- }
-
- @Test
- public void startingLocatorWithJmxManager_skipsSerialFilter_atMostJava8() {
- assumeThat(isJavaVersionAtMost(JavaVersion.JAVA_1_8)).isTrue();
-
- locator.set(new LocatorLauncher.Builder()
- .setMemberName(NAME)
- .setPort(locatorPort)
- .setWorkingDirectory(workingDirectory.getAbsolutePath())
- .set(HTTP_SERVICE_PORT, "0")
- .set(JMX_MANAGER, "true")
- .set(JMX_MANAGER_PORT, String.valueOf(jmxPort))
- .set(JMX_MANAGER_START, "true")
- .set(LOG_FILE, new File(workingDirectory, NAME + ".log").getAbsolutePath())
- .build())
- .get()
- .start();
-
- String serialFilter = System.getProperty(PROPERTY_NAME);
- assertThat(serialFilter).isNull();
- }
-
- @Test
- public void startingLocatorWithJmxManager_skipsEmptySerialFilter_atMostJava8() {
- assumeThat(isJavaVersionAtMost(JavaVersion.JAVA_1_8)).isTrue();
-
- System.setProperty(PROPERTY_NAME, "");
-
- locator.set(new LocatorLauncher.Builder()
- .setMemberName(NAME)
- .setPort(locatorPort)
- .setWorkingDirectory(workingDirectory.getAbsolutePath())
- .set(HTTP_SERVICE_PORT, "0")
- .set(JMX_MANAGER, "true")
- .set(JMX_MANAGER_PORT, String.valueOf(jmxPort))
- .set(JMX_MANAGER_START, "true")
- .set(LOG_FILE, new File(workingDirectory, NAME + ".log").getAbsolutePath())
- .build())
- .get()
- .start();
-
- String serialFilter = System.getProperty(PROPERTY_NAME);
- assertThat(serialFilter).isEqualTo("");
- }
-
- @Test
- public void startingLocatorWithJmxManager_skipsNonEmptySerialFilter_atMostJava8() {
- assumeThat(isJavaVersionAtMost(JavaVersion.JAVA_1_8)).isTrue();
-
- String existingSerialFilter = "!*";
- System.setProperty(PROPERTY_NAME, existingSerialFilter);
-
- locator.set(new LocatorLauncher.Builder()
- .setMemberName(NAME)
- .setPort(locatorPort)
- .setWorkingDirectory(workingDirectory.getAbsolutePath())
- .set(HTTP_SERVICE_PORT, "0")
- .set(JMX_MANAGER, "true")
- .set(JMX_MANAGER_PORT, String.valueOf(jmxPort))
- .set(JMX_MANAGER_START, "true")
- .set(LOG_FILE, new File(workingDirectory, NAME + ".log").getAbsolutePath())
- .build())
- .get()
- .start();
-
- String serialFilter = System.getProperty(PROPERTY_NAME);
- assertThat(serialFilter).isEqualTo(existingSerialFilter);
- }
-}
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/management/internal/ManagementAgentIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/management/internal/ManagementAgentIntegrationTest.java
index 15815a5..257454d9 100644
--- a/geode-core/src/integrationTest/java/org/apache/geode/management/internal/ManagementAgentIntegrationTest.java
+++ b/geode-core/src/integrationTest/java/org/apache/geode/management/internal/ManagementAgentIntegrationTest.java
@@ -35,10 +35,10 @@ import org.junit.rules.TemporaryFolder;
import org.apache.geode.distributed.internal.DistributionConfig;
import org.apache.geode.internal.cache.InternalCache;
import org.apache.geode.internal.security.SecurityService;
+import org.apache.geode.internal.serialization.filter.FilterConfiguration;
public class ManagementAgentIntegrationTest {
- // private ManagementAgent managementAgent = spy(ManagementAgent.class);
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@@ -46,14 +46,14 @@ public class ManagementAgentIntegrationTest {
public void testSetMBeanServer() throws IOException {
DistributionConfig distributionConfig = mock(DistributionConfig.class);
InternalCache internalCache = mock(InternalCache.class);
- JmxRmiSerialFilter serialFilter = mock(JmxRmiSerialFilter.class);
+ FilterConfiguration filterConfiguration = mock(FilterConfiguration.class);
SecurityService securityService = mock(SecurityService.class);
when(internalCache.getSecurityService()).thenReturn(securityService);
when(securityService.isIntegratedSecurity()).thenReturn(false);
File tempFile = temporaryFolder.newFile("testFile");
when(distributionConfig.getJmxManagerAccessFile()).thenReturn(tempFile.getCanonicalPath());
ManagementAgent managementAgent =
- new ManagementAgent(distributionConfig, internalCache, serialFilter);
+ new ManagementAgent(distributionConfig, internalCache, filterConfiguration);
MBeanServer mBeanServer = mock(MBeanServer.class);
JMXConnectorServer jmxConnectorServerWithMBeanServer = new JMXConnectorServer(mBeanServer) {
@Override
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/management/internal/ServerManagerConfiguresJmxSerialFilterIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/management/internal/ServerManagerConfiguresJmxSerialFilterIntegrationTest.java
deleted file mode 100644
index f77438e..0000000
--- a/geode-core/src/integrationTest/java/org/apache/geode/management/internal/ServerManagerConfiguresJmxSerialFilterIntegrationTest.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * 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.management.internal;
-
-import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
-import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtMost;
-import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
-import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
-import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
-import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
-import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
-import static org.apache.geode.internal.AvailablePortHelper.getRandomAvailableTCPPort;
-import static org.apache.geode.management.internal.JmxRmiOpenTypesSerialFilter.PROPERTY_NAME;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assumptions.assumeThat;
-
-import java.io.File;
-
-import org.apache.commons.lang3.JavaVersion;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-
-import org.apache.geode.distributed.ServerLauncher;
-import org.apache.geode.test.junit.rules.CloseableReference;
-
-public class ServerManagerConfiguresJmxSerialFilterIntegrationTest {
-
- private static final String NAME = "server";
-
- private File workingDirectory;
- private int jmxPort;
- private String expectedSerialFilter;
-
- @Rule
- public CloseableReference<ServerLauncher> server = new CloseableReference<>();
- @Rule
- public TemporaryFolder temporaryFolder = new TemporaryFolder();
-
- @Before
- public void setUp() throws Exception {
- workingDirectory = temporaryFolder.newFolder(NAME);
- jmxPort = getRandomAvailableTCPPort();
- expectedSerialFilter = new JmxRmiOpenTypesSerialFilter().createSerialFilterPattern();
- }
-
- @After
- public void tearDown() {
- System.clearProperty(PROPERTY_NAME);
- }
-
- @Test
- public void startingServerWithJmxManager_configuresSerialFilter_atLeastJava9() {
- assumeThat(isJavaVersionAtLeast(JavaVersion.JAVA_9)).isTrue();
-
- server.set(new ServerLauncher.Builder()
- .setMemberName(NAME)
- .setDisableDefaultServer(true)
- .setWorkingDirectory(workingDirectory.getAbsolutePath())
- .set(HTTP_SERVICE_PORT, "0")
- .set(JMX_MANAGER, "true")
- .set(JMX_MANAGER_PORT, String.valueOf(jmxPort))
- .set(JMX_MANAGER_START, "true")
- .set(LOG_FILE, new File(workingDirectory, NAME + ".log").getAbsolutePath())
- .build())
- .get()
- .start();
-
- String serialFilter = System.getProperty(PROPERTY_NAME);
- assertThat(serialFilter).isEqualTo(expectedSerialFilter);
- }
-
- @Test
- public void startingServerWithJmxManager_changesEmptySerialFilter_atLeastJava9() {
- assumeThat(isJavaVersionAtLeast(JavaVersion.JAVA_9)).isTrue();
-
- System.setProperty(PROPERTY_NAME, "");
-
- server.set(new ServerLauncher.Builder()
- .setMemberName(NAME)
- .setDisableDefaultServer(true)
- .setWorkingDirectory(workingDirectory.getAbsolutePath())
- .set(HTTP_SERVICE_PORT, "0")
- .set(JMX_MANAGER, "true")
- .set(JMX_MANAGER_PORT, String.valueOf(jmxPort))
- .set(JMX_MANAGER_START, "true")
- .set(LOG_FILE, new File(workingDirectory, NAME + ".log").getAbsolutePath())
- .build())
- .get()
- .start();
-
- String serialFilter = System.getProperty(PROPERTY_NAME);
- assertThat(serialFilter).isEqualTo(expectedSerialFilter);
- }
-
- @Test
- public void startingServerWithJmxManager_skipsNonEmptySerialFilter_atLeastJava9() {
- assumeThat(isJavaVersionAtLeast(JavaVersion.JAVA_9)).isTrue();
-
- String existingSerialFilter = "!*";
- System.setProperty(PROPERTY_NAME, existingSerialFilter);
-
- server.set(new ServerLauncher.Builder()
- .setMemberName(NAME)
- .setDisableDefaultServer(true)
- .setWorkingDirectory(workingDirectory.getAbsolutePath())
- .set(HTTP_SERVICE_PORT, "0")
- .set(JMX_MANAGER, "true")
- .set(JMX_MANAGER_PORT, String.valueOf(jmxPort))
- .set(JMX_MANAGER_START, "true")
- .set(LOG_FILE, new File(workingDirectory, NAME + ".log").getAbsolutePath())
- .build())
- .get()
- .start();
-
- String serialFilter = System.getProperty(PROPERTY_NAME);
- assertThat(serialFilter).isEqualTo(existingSerialFilter);
- }
-
- @Test
- public void startingServerWithJmxManager_skipsSerialFilter_atMostJava8() {
- assumeThat(isJavaVersionAtMost(JavaVersion.JAVA_1_8)).isTrue();
-
- server.set(new ServerLauncher.Builder()
- .setMemberName(NAME)
- .setDisableDefaultServer(true)
- .setWorkingDirectory(workingDirectory.getAbsolutePath())
- .set(HTTP_SERVICE_PORT, "0")
- .set(JMX_MANAGER, "true")
- .set(JMX_MANAGER_PORT, String.valueOf(jmxPort))
- .set(JMX_MANAGER_START, "true")
- .set(LOG_FILE, new File(workingDirectory, NAME + ".log").getAbsolutePath())
- .build())
- .get()
- .start();
-
- String serialFilter = System.getProperty(PROPERTY_NAME);
- assertThat(serialFilter).isNull();
- }
-
- @Test
- public void startingServerWithJmxManager_skipsEmptySerialFilter_atMostJava8() {
- assumeThat(isJavaVersionAtMost(JavaVersion.JAVA_1_8)).isTrue();
-
- System.setProperty(PROPERTY_NAME, "");
-
- server.set(new ServerLauncher.Builder()
- .setMemberName(NAME)
- .setDisableDefaultServer(true)
- .setWorkingDirectory(workingDirectory.getAbsolutePath())
- .set(HTTP_SERVICE_PORT, "0")
- .set(JMX_MANAGER, "true")
- .set(JMX_MANAGER_PORT, String.valueOf(jmxPort))
- .set(JMX_MANAGER_START, "true")
- .set(LOG_FILE, new File(workingDirectory, NAME + ".log").getAbsolutePath())
- .build())
- .get()
- .start();
-
- String serialFilter = System.getProperty(PROPERTY_NAME);
- assertThat(serialFilter).isEqualTo("");
- }
-
- @Test
- public void startingServerWithJmxManager_skipsNonEmptySerialFilter_atMostJava8() {
- assumeThat(isJavaVersionAtMost(JavaVersion.JAVA_1_8)).isTrue();
-
- String existingSerialFilter = "!*";
- System.setProperty(PROPERTY_NAME, existingSerialFilter);
-
- server.set(new ServerLauncher.Builder()
- .setMemberName(NAME)
- .setDisableDefaultServer(true)
- .setWorkingDirectory(workingDirectory.getAbsolutePath())
- .set(HTTP_SERVICE_PORT, "0")
- .set(JMX_MANAGER, "true")
- .set(JMX_MANAGER_PORT, String.valueOf(jmxPort))
- .set(JMX_MANAGER_START, "true")
- .set(LOG_FILE, new File(workingDirectory, NAME + ".log").getAbsolutePath())
- .build())
- .get()
- .start();
-
- String serialFilter = System.getProperty(PROPERTY_NAME);
- assertThat(serialFilter).isEqualTo(existingSerialFilter);
- }
-}
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/LocatorLauncher.java b/geode-core/src/main/java/org/apache/geode/distributed/LocatorLauncher.java
index 0cd015e..fa9f7cc 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/LocatorLauncher.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/LocatorLauncher.java
@@ -64,6 +64,7 @@ import org.apache.geode.distributed.internal.tcpserver.HostAndPort;
import org.apache.geode.distributed.internal.tcpserver.TcpClient;
import org.apache.geode.distributed.internal.tcpserver.TcpSocketCreator;
import org.apache.geode.distributed.internal.tcpserver.TcpSocketFactory;
+import org.apache.geode.internal.DistributedSerializableObjectConfig;
import org.apache.geode.internal.DistributionLocator;
import org.apache.geode.internal.GemFireVersion;
import org.apache.geode.internal.InternalDataSerializer;
@@ -87,6 +88,7 @@ import org.apache.geode.internal.process.ProcessType;
import org.apache.geode.internal.process.ProcessUtils;
import org.apache.geode.internal.process.UnableToControlProcessException;
import org.apache.geode.internal.security.SecurableCommunicationChannel;
+import org.apache.geode.internal.serialization.filter.SystemPropertyGlobalSerialFilterConfigurationFactory;
import org.apache.geode.lang.AttachAPINotFoundException;
import org.apache.geode.logging.internal.log4j.api.LogService;
import org.apache.geode.management.internal.util.HostUtils;
@@ -702,6 +704,11 @@ public class LocatorLauncher extends AbstractLauncher<String> {
if (isStartable()) {
INSTANCE.compareAndSet(null, this);
+ boolean serializationFilterConfigured =
+ new SystemPropertyGlobalSerialFilterConfigurationFactory()
+ .create(new DistributedSerializableObjectConfig(getDistributedSystemProperties()))
+ .configure();
+
try {
this.process =
new FileControllableProcess(this.controlHandler, new File(getWorkingDirectory()),
@@ -716,6 +723,11 @@ public class LocatorLauncher extends AbstractLauncher<String> {
this.locator = InternalLocator.startLocator(getPort(), getLogFile(), null, null,
getBindAddress(), true, getDistributedSystemProperties(), getHostnameForClients(),
Paths.get(workingDirectory));
+
+ if (serializationFilterConfigured) {
+ log.info("Global serial filter is now configured.");
+ }
+
} finally {
ProcessLauncherContext.remove();
}
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/ServerLauncher.java b/geode-core/src/main/java/org/apache/geode/distributed/ServerLauncher.java
index f10b053..d1b6c97 100755
--- a/geode-core/src/main/java/org/apache/geode/distributed/ServerLauncher.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/ServerLauncher.java
@@ -71,6 +71,7 @@ import org.apache.geode.cache.partition.PartitionRegionHelper;
import org.apache.geode.cache.server.CacheServer;
import org.apache.geode.distributed.internal.DefaultServerLauncherCacheProvider;
import org.apache.geode.distributed.internal.InternalDistributedSystem;
+import org.apache.geode.internal.DistributedSerializableObjectConfig;
import org.apache.geode.internal.GemFireVersion;
import org.apache.geode.internal.cache.AbstractCacheServer;
import org.apache.geode.internal.cache.CacheConfig;
@@ -94,6 +95,7 @@ import org.apache.geode.internal.process.ProcessControllerParameters;
import org.apache.geode.internal.process.ProcessLauncherContext;
import org.apache.geode.internal.process.ProcessType;
import org.apache.geode.internal.process.UnableToControlProcessException;
+import org.apache.geode.internal.serialization.filter.SystemPropertyGlobalSerialFilterConfigurationFactory;
import org.apache.geode.lang.AttachAPINotFoundException;
import org.apache.geode.logging.internal.executors.LoggingThread;
import org.apache.geode.logging.internal.log4j.api.LogService;
@@ -787,6 +789,11 @@ public class ServerLauncher extends AbstractLauncher<String> {
if (isStartable()) {
INSTANCE.compareAndSet(null, this);
+ boolean serializationFilterConfigured =
+ new SystemPropertyGlobalSerialFilterConfigurationFactory()
+ .create(new DistributedSerializableObjectConfig(getDistributedSystemProperties()))
+ .configure();
+
try {
process = getControllableProcess();
@@ -806,6 +813,10 @@ public class ServerLauncher extends AbstractLauncher<String> {
final Properties gemfireProperties = getDistributedSystemProperties(getProperties());
cache = createCache(gemfireProperties);
+ if (serializationFilterConfigured) {
+ log.info("Global serial filter is now configured.");
+ }
+
// Set the resource manager options
if (criticalHeapPercentage != null) {
cache.getResourceManager().setCriticalHeapPercentage(getCriticalHeapPercentage());
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 6f6f523..027a536 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
@@ -211,6 +211,7 @@ import org.apache.geode.internal.Config;
import org.apache.geode.internal.ConfigSource;
import org.apache.geode.internal.logging.LogWriterImpl;
import org.apache.geode.internal.security.SecurableCommunicationChannel;
+import org.apache.geode.internal.serialization.filter.SerializableObjectConfig;
import org.apache.geode.internal.statistics.StatisticsConfig;
import org.apache.geode.internal.tcp.Connection;
import org.apache.geode.logging.internal.spi.LogConfig;
@@ -227,7 +228,8 @@ import org.apache.geode.util.internal.GeodeGlossary;
* @see Config
* @since GemFire 2.1
*/
-public interface DistributionConfig extends Config, LogConfig, StatisticsConfig {
+public interface DistributionConfig
+ extends Config, LogConfig, StatisticsConfig, SerializableObjectConfig {
/**
* The static String definition of the prefix used to defined ssl-* properties
diff --git a/geode-core/src/main/java/org/apache/geode/internal/DistributedSerializableObjectConfig.java b/geode-core/src/main/java/org/apache/geode/internal/DistributedSerializableObjectConfig.java
new file mode 100644
index 0000000..1a9aec0
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/DistributedSerializableObjectConfig.java
@@ -0,0 +1,51 @@
+/*
+ * 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 static java.util.Objects.requireNonNull;
+import static org.apache.geode.distributed.ConfigurationProperties.SERIALIZABLE_OBJECT_FILTER;
+import static org.apache.geode.distributed.ConfigurationProperties.VALIDATE_SERIALIZABLE_OBJECTS;
+
+import java.util.Properties;
+
+import org.apache.geode.internal.serialization.filter.SerializableObjectConfig;
+
+/**
+ * Simple implementation of {@code SerializableObjectConfig} for use when an instance of
+ * {@code DistributionConfig} is not available.
+ */
+public class DistributedSerializableObjectConfig implements SerializableObjectConfig {
+
+ private final Properties config;
+
+ public DistributedSerializableObjectConfig(Properties config) {
+ this.config = requireNonNull(config);
+ }
+
+ @Override
+ public boolean getValidateSerializableObjects() {
+ return "true".equalsIgnoreCase(config.getProperty(VALIDATE_SERIALIZABLE_OBJECTS));
+ }
+
+ @Override
+ public void setValidateSerializableObjects(boolean value) {
+ config.setProperty(VALIDATE_SERIALIZABLE_OBJECTS, Boolean.valueOf(value).toString());
+ }
+
+ @Override
+ public String getSerializableObjectFilter() {
+ return config.getProperty(SERIALIZABLE_OBJECT_FILTER);
+ }
+}
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 9c5018a..064044f 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,6 +14,7 @@
*/
package org.apache.geode.internal;
+import static org.apache.geode.internal.serialization.filter.SanctionedSerializables.loadSanctionedClassNames;
import static org.apache.geode.internal.serialization.filter.SanctionedSerializables.loadSanctionedSerializablesServices;
import java.io.DataInput;
@@ -73,7 +74,6 @@ import org.apache.geode.CancelException;
import org.apache.geode.CanonicalInstantiator;
import org.apache.geode.DataSerializable;
import org.apache.geode.DataSerializer;
-import org.apache.geode.GemFireConfigException;
import org.apache.geode.GemFireIOException;
import org.apache.geode.GemFireRethrowable;
import org.apache.geode.Instantiator;
@@ -88,7 +88,6 @@ import org.apache.geode.cache.CacheClosedException;
import org.apache.geode.cache.execute.Function;
import org.apache.geode.distributed.internal.ClusterDistributionManager;
import org.apache.geode.distributed.internal.DMStats;
-import org.apache.geode.distributed.internal.DistributionConfig;
import org.apache.geode.distributed.internal.InternalDistributedSystem;
import org.apache.geode.distributed.internal.LonerDistributionManager;
import org.apache.geode.distributed.internal.SerialDistributionMessage;
@@ -103,7 +102,6 @@ import org.apache.geode.internal.cache.tier.sockets.ClientDataSerializerMessage;
import org.apache.geode.internal.cache.tier.sockets.ClientProxyMembershipID;
import org.apache.geode.internal.cache.tier.sockets.OldClientSupportService;
import org.apache.geode.internal.cache.tier.sockets.Part;
-import org.apache.geode.internal.lang.utils.ClassUtils;
import org.apache.geode.internal.logging.log4j.LogMarker;
import org.apache.geode.internal.serialization.BasicSerializable;
import org.apache.geode.internal.serialization.DSCODE;
@@ -119,7 +117,12 @@ import org.apache.geode.internal.serialization.SerializationContext;
import org.apache.geode.internal.serialization.SerializationVersions;
import org.apache.geode.internal.serialization.StaticSerialization;
import org.apache.geode.internal.serialization.VersionedDataStream;
+import org.apache.geode.internal.serialization.filter.NullObjectInputFilter;
+import org.apache.geode.internal.serialization.filter.ObjectInputFilter;
+import org.apache.geode.internal.serialization.filter.ObjectInputFilterFactory;
+import org.apache.geode.internal.serialization.filter.ReflectiveFacadeObjectInputFilterFactory;
import org.apache.geode.internal.serialization.filter.SanctionedSerializablesService;
+import org.apache.geode.internal.serialization.filter.SerializableObjectConfig;
import org.apache.geode.internal.util.concurrent.CopyOnWriteHashMap;
import org.apache.geode.logging.internal.log4j.api.LogService;
import org.apache.geode.pdx.NonPortableClassException;
@@ -283,12 +286,12 @@ public abstract class InternalDataSerializer extends DataSerializer {
"org.apache.geode.cache.query.internal.cq.ServerCQImpl";
@Immutable
- private static final InputStreamFilter defaultSerializationFilter = new EmptyInputStreamFilter();
+ private static final ObjectInputFilter defaultSerializationFilter = new NullObjectInputFilter();
/**
* A deserialization filter for ObjectInputStreams
*/
@MakeNotStatic
- private static InputStreamFilter serializationFilter = defaultSerializationFilter;
+ private static ObjectInputFilter serializationFilter = defaultSerializationFilter;
/**
* support for old GemFire clients and WAN sites - needed to enable moving from GemFire to Geode
*/
@@ -397,35 +400,29 @@ public abstract class InternalDataSerializer extends DataSerializer {
* Initializes the optional serialization "accept list" if the user has requested it in the
* DistributionConfig
*
- * @param distributionConfig the DistributedSystem configuration
+ * @param config the DistributedSystem configuration
*/
- public static void initializeSerializationFilter(DistributionConfig distributionConfig) {
- initializeSerializationFilter(distributionConfig, loadSanctionedSerializablesServices());
+ public static void initializeSerializationFilter(SerializableObjectConfig config) {
+ initializeSerializationFilter(config, loadSanctionedSerializablesServices());
}
/**
* Initializes the optional serialization "accept list" if the user has requested it in the
* DistributionConfig
*
- * @param distributionConfig the DistributedSystem configuration
+ * @param config the DistributedSystem configuration
* @param services SanctionedSerializablesService that might have classes to acceptlist
*/
@VisibleForTesting
- public static void initializeSerializationFilter(DistributionConfig distributionConfig,
+ public static void initializeSerializationFilter(SerializableObjectConfig config,
Collection<SanctionedSerializablesService> services) {
logger.info("initializing InternalDataSerializer with {} services", services.size());
- if (distributionConfig.getValidateSerializableObjects()) {
- if (!ClassUtils.isClassAvailable("sun.misc.ObjectInputFilter")
- && !ClassUtils.isClassAvailable("java.io.ObjectInputFilter")) {
- throw new GemFireConfigException(
- "A serialization filter has been specified but this version of Java does not support serialization filters - ObjectInputFilter is not available");
- }
- serializationFilter =
- new ObjectInputStreamFilterWrapper(SANCTIONED_SERIALIZABLES_DEPENDENCIES_PATTERN
- + distributionConfig.getSerializableObjectFilter() + ";!*", services);
- } else {
- clearSerializationFilter();
- }
+
+ ObjectInputFilterFactory objectInputFilterFactory =
+ new ReflectiveFacadeObjectInputFilterFactory();
+
+ serializationFilter =
+ objectInputFilterFactory.create(config, loadSanctionedClassNames(services));
}
@VisibleForTesting
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
deleted file mode 100644
index 25d5e35..0000000
--- a/geode-core/src/main/java/org/apache/geode/internal/ObjectInputStreamFilterWrapper.java
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * 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.InvalidClassException;
-import java.io.ObjectInputStream;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-
-import org.apache.logging.log4j.Logger;
-
-import org.apache.geode.GemFireConfigException;
-import org.apache.geode.InternalGemFireError;
-import org.apache.geode.InternalGemFireException;
-import org.apache.geode.internal.serialization.filter.SanctionedSerializablesService;
-import org.apache.geode.logging.internal.log4j.api.LogService;
-
-
-/**
- * ObjectInputStreamFilterWrapper isolates InternalDataSerializer from the JDK's
- * ObjectInputFilter class, which is absent in builds of java8 prior to 121 and
- * is sun.misc.ObjectInputFilter in later builds but is java.io.ObjectInputFilter
- * in java9.
- * <p>
- * This class uses reflection and dynamic proxies to find the class and create a
- * serialization filter. Once java8 is retired and no longer supported by Geode the
- * use of reflection should be removed ObjectInputFilter can be directly used by
- * InternalDataSerializer.
- */
-public class ObjectInputStreamFilterWrapper implements InputStreamFilter {
- private static final Logger logger = LogService.getLogger();
-
- private boolean usingJava8;
- private Object serializationFilter;
-
- private Class configClass; // ObjectInputFilter$Config
- private Method setObjectInputFilterMethod; // method on ObjectInputFilter$Config or
- // ObjectInputStream
- private Method createFilterMethod; // method on ObjectInputFilter$Config
-
- private Class filterClass; // ObjectInputFilter
- private Object ALLOWED; // field on ObjectInputFilter
- private Object REJECTED; // field on ObjectInputFilter
- private Method checkInputMethod; // method on ObjectInputFilter
-
- private Class filterInfoClass; // ObjectInputFilter$FilterInfo
- private Method serialClassMethod; // method on ObjectInputFilter$FilterInfo
-
- public ObjectInputStreamFilterWrapper(String serializationFilterSpec,
- Collection<SanctionedSerializablesService> services) {
-
- Set<String> sanctionedClasses = new HashSet<>(500);
- for (SanctionedSerializablesService service : services) {
- try {
- Collection<String> classNames = service.getSerializationAcceptlist();
- logger.info("loaded {} sanctioned serializables from {}", classNames.size(),
- service.getClass().getSimpleName());
- sanctionedClasses.addAll(classNames);
- } catch (IOException e) {
- throw new InternalGemFireException("error initializing serialization filter for " + service,
- e);
- }
- }
-
- logger.info("setting a serialization filter containing {}", serializationFilterSpec);
-
- // try java8 - this will not throw an exception if ObjectInputFilter can't be found
- if (createJava8Filter(serializationFilterSpec, sanctionedClasses)) {
- return;
- }
-
- // try java9 - this throws an exception if it fails to create the filter
- createJava9Filter(serializationFilterSpec, sanctionedClasses);
- }
-
- @Override
- public void setFilterOn(ObjectInputStream objectInputStream) {
- try {
- if (usingJava8) {
- setObjectInputFilterMethod.invoke(configClass, objectInputStream, serializationFilter);
- } else {
- setObjectInputFilterMethod.invoke(objectInputStream, serializationFilter);
- }
- } catch (IllegalAccessException | InvocationTargetException e) {
- throw new InternalGemFireError("Unable to filter serialization", e);
- }
- }
-
- /**
- * java8 has sun.misc.ObjectInputFilter and uses ObjectInputFilter$Config.setObjectInputFilter()
- */
- private boolean createJava8Filter(String serializationFilterSpec,
- Collection<String> sanctionedClasses) {
- ClassPathLoader classPathLoader = ClassPathLoader.getLatest();
- try {
-
- filterInfoClass = classPathLoader.forName("sun.misc.ObjectInputFilter$FilterInfo");
- serialClassMethod = filterInfoClass.getDeclaredMethod("serialClass");
-
- filterClass = classPathLoader.forName("sun.misc.ObjectInputFilter");
- checkInputMethod = filterClass.getDeclaredMethod("checkInput", filterInfoClass);
-
- Class statusClass = classPathLoader.forName("sun.misc.ObjectInputFilter$Status");
- ALLOWED = statusClass.getEnumConstants()[1];
- REJECTED = statusClass.getEnumConstants()[2];
- if (!ALLOWED.toString().equals("ALLOWED") || !REJECTED.toString().equals("REJECTED")) {
- throw new GemFireConfigException(
- "ObjectInputFilter$Status enumeration in this JDK is not as expected");
- }
-
- configClass = classPathLoader.forName("sun.misc.ObjectInputFilter$Config");
- setObjectInputFilterMethod = configClass.getDeclaredMethod("setObjectInputFilter",
- ObjectInputStream.class, filterClass);
- createFilterMethod = configClass.getDeclaredMethod("createFilter", String.class);
-
- serializationFilter = createSerializationFilter(serializationFilterSpec, sanctionedClasses);
- usingJava8 = true;
-
- } catch (ClassNotFoundException | InvocationTargetException | IllegalAccessException
- | NoSuchMethodException e) {
- if (filterInfoClass != null) {
- throw new GemFireConfigException(
- "A serialization filter has been specified but Geode was unable to configure a filter",
- e);
- }
- return false;
- }
-
- return true;
- }
-
- /** java9 has java.io.ObjectInputFilter and uses ObjectInputStream.setObjectInputFilter() */
- private void createJava9Filter(String serializationFilterSpec,
- Collection<String> sanctionedClasses) {
- try {
- ClassPathLoader classPathLoader = ClassPathLoader.getLatest();
-
- filterInfoClass = classPathLoader.forName("java.io.ObjectInputFilter$FilterInfo");
- serialClassMethod = filterInfoClass.getDeclaredMethod("serialClass");
-
-
- filterClass = classPathLoader.forName("java.io.ObjectInputFilter");
- checkInputMethod = filterClass.getDeclaredMethod("checkInput", filterInfoClass);
-
- Class statusClass = classPathLoader.forName("java.io.ObjectInputFilter$Status");
- ALLOWED = statusClass.getEnumConstants()[1];
- REJECTED = statusClass.getEnumConstants()[2];
- if (!ALLOWED.toString().equals("ALLOWED") || !REJECTED.toString().equals("REJECTED")) {
- throw new GemFireConfigException(
- "ObjectInputFilter$Status enumeration in this JDK is not as expected");
- }
-
- configClass = classPathLoader.forName("java.io.ObjectInputFilter$Config");
- setObjectInputFilterMethod =
- ObjectInputStream.class.getDeclaredMethod("setObjectInputFilter", filterClass);
- createFilterMethod = configClass.getDeclaredMethod("createFilter", String.class);
-
- serializationFilter = createSerializationFilter(serializationFilterSpec, sanctionedClasses);
-
- } catch (ClassNotFoundException | InvocationTargetException | IllegalAccessException
- | NoSuchMethodException e) {
- throw new GemFireConfigException(
- "A serialization filter has been specified but Geode was unable to configure a filter",
- e);
- }
- }
-
-
- private Object createSerializationFilter(String serializationFilterSpec,
- Collection<String> sanctionedClasses)
- throws InvocationTargetException, IllegalAccessException {
-
- /*
- * create a user filter with the serialization acceptlist/denylist. This will be wrapped
- * by a filter that accept-lists sanctioned classes
- */
- Object userFilter = createFilterMethod.invoke(null, serializationFilterSpec);
-
- InvocationHandler handler = (proxy, method, args) -> {
- switch (method.getName()) {
- case "checkInput":
- Object filterInfo = args[0];
- Class<?> serialClass = (Class<?>) serialClassMethod.invoke(filterInfo);
- if (serialClass == null) { // no class to check, so nothing to accept-list
- return checkInputMethod.invoke(userFilter, filterInfo);
- }
- String className = serialClass.getName();
- if (serialClass.isArray()) {
- className = serialClass.getComponentType().getName();
- }
- if (sanctionedClasses.contains(className)) {
- return ALLOWED;
- }
- Object status = checkInputMethod.invoke(userFilter, filterInfo);
- if (status == REJECTED) {
- logger.fatal("Serialization filter is rejecting class {}", className,
- new InvalidClassException(className));
- }
- return status;
- case "toString":
- return userFilter.toString();
- default:
- throw new UnsupportedOperationException(
- "ObjectInputFilter." + method.getName() + " is not implemented");
- }
- };
-
- ClassPathLoader classPathLoader = ClassPathLoader.getLatest();
- return Proxy.newProxyInstance(classPathLoader.asClassLoader(), new Class[] {filterClass},
- handler);
-
- }
-
-
-}
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/JmxRmiOpenTypesSerialFilter.java b/geode-core/src/main/java/org/apache/geode/management/internal/JmxRmiOpenTypesSerialFilter.java
deleted file mode 100644
index 803bc03..0000000
--- a/geode-core/src/main/java/org/apache/geode/management/internal/JmxRmiOpenTypesSerialFilter.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * 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.management.internal;
-
-import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.rmi.MarshalledObject;
-import java.util.function.Consumer;
-import java.util.function.Supplier;
-
-import javax.management.ObjectName;
-import javax.management.openmbean.ArrayType;
-import javax.management.openmbean.CompositeData;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.OpenType;
-import javax.management.openmbean.SimpleType;
-import javax.management.openmbean.TabularData;
-import javax.management.openmbean.TabularType;
-
-import org.apache.commons.lang3.JavaVersion;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.logging.log4j.Logger;
-
-import org.apache.geode.annotations.VisibleForTesting;
-import org.apache.geode.logging.internal.log4j.api.LogService;
-
-/**
- * Configure the “jmx.remote.rmi.server.serial.filter.pattern” system property if Java version is
- * greater than Java 8. The serial pattern will be configured to accept only standard JMX
- * open-types. If the system property already has a non-null value, then leave it as is.
- */
-public class JmxRmiOpenTypesSerialFilter implements JmxRmiSerialFilter {
-
- private static final Logger logger = LogService.getLogger();
-
- @VisibleForTesting
- public static final String PROPERTY_NAME = "jmx.remote.rmi.server.serial.filter.pattern";
-
- private final Consumer<String> infoLogger;
- private final Supplier<Boolean> supportsSerialFilter;
-
- JmxRmiOpenTypesSerialFilter() {
- this(logger::info, () -> isJavaVersionAtLeast(JavaVersion.JAVA_9));
- }
-
- @VisibleForTesting
- JmxRmiOpenTypesSerialFilter(Consumer<String> infoLogger, Supplier<Boolean> supportsSerialFilter) {
- this.infoLogger = infoLogger;
- this.supportsSerialFilter = supportsSerialFilter;
- }
-
- @Override
- public void configureSerialFilter() {
- if (supportsDedicatedSerialFilter()) {
- setPropertyValueUnlessExists(createSerialFilterPattern());
- }
- }
-
- @VisibleForTesting
- boolean supportsDedicatedSerialFilter() {
- return supportsSerialFilter.get();
- }
-
- /**
- * Sets the value of the system property {@code jmx.remote.rmi.server.serial.filter.pattern}
- * unless it exists with a value that is not null or empty ("").
- */
- @VisibleForTesting
- void setPropertyValueUnlessExists(String value) {
- String existingValue = System.getProperty(PROPERTY_NAME);
- if (StringUtils.isNotEmpty(existingValue)) {
- infoLogger.accept("System property " + PROPERTY_NAME + " is already configured.");
- return;
- }
-
- System.setProperty(PROPERTY_NAME, value);
- infoLogger.accept("System property " + PROPERTY_NAME + " is now configured with '"
- + value + "'.");
- }
-
- /**
- * Returns a serial filter pattern that accepts all open MBean data types and rejects everything
- * not included in the pattern.
- */
- @VisibleForTesting
- String createSerialFilterPattern() {
- // note: java.util.* may also be needed
- return new StringBuilder()
- // accept all open MBean data types
- .append(Boolean.class.getName())
- .append(';')
- .append(Byte.class.getName())
- .append(';')
- .append(Character.class.getName())
- .append(';')
- .append(Short.class.getName())
- .append(';')
- .append(Integer.class.getName())
- .append(';')
- .append(Long.class.getName())
- .append(';')
- .append(Float.class.getName())
- .append(';')
- .append(Double.class.getName())
- .append(';')
- .append(String.class.getName())
- .append(';')
- .append(BigInteger.class.getName())
- .append(';')
- .append(BigDecimal.class.getName())
- .append(';')
- .append(ObjectName.class.getName())
- .append(';')
- .append(OpenType.class.getName())
- .append(';')
- .append(CompositeData.class.getName())
- .append(';')
- .append(TabularData.class.getName())
- .append(';')
- .append(SimpleType.class.getName())
- .append(';')
- .append(CompositeType.class.getName())
- .append(';')
- .append(TabularType.class.getName())
- .append(';')
- .append(ArrayType.class.getName())
- .append(';')
- .append(MarshalledObject.class.getName())
- .append(';')
- // reject all other classes
- .append("!*")
- .toString();
- }
-}
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/ManagementAgent.java b/geode-core/src/main/java/org/apache/geode/management/internal/ManagementAgent.java
index 5648ceb..22d50bd 100755
--- a/geode-core/src/main/java/org/apache/geode/management/internal/ManagementAgent.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/ManagementAgent.java
@@ -65,6 +65,7 @@ import org.apache.geode.internal.net.SocketCreatorFactory;
import org.apache.geode.internal.security.SecurableCommunicationChannel;
import org.apache.geode.internal.security.SecurityService;
import org.apache.geode.internal.security.shiro.JMXShiroAuthenticator;
+import org.apache.geode.internal.serialization.filter.FilterConfiguration;
import org.apache.geode.internal.tcp.TCPConduit;
import org.apache.geode.logging.internal.log4j.api.LogService;
import org.apache.geode.management.ManagementException;
@@ -109,7 +110,7 @@ public class ManagementAgent {
private int port;
private RemoteStreamExporter remoteStreamExporter = null;
- private final JmxRmiSerialFilter serialFilter;
+ private final FilterConfiguration filterConfiguration;
/**
* This system property is set to true when the embedded HTTP server is started so that the
@@ -122,20 +123,19 @@ public class ManagementAgent {
private static final String PULSE_USESSL_LOCATOR = "pulse.useSSL.locator";
public ManagementAgent(DistributionConfig config, InternalCache cache,
- JmxRmiSerialFilter serialFilter) {
+ FilterConfiguration filterConfiguration) {
this.config = config;
this.cache = cache;
this.securityService = cache.getSecurityService();
- this.serialFilter = serialFilter;
+ this.filterConfiguration = filterConfiguration;
}
public synchronized boolean isRunning() {
return this.running;
}
-
public synchronized void startAgent() {
- serialFilter.configureSerialFilter();
+ filterConfiguration.configure();
loadWebApplications();
if (!this.running && this.config.getJmxManagerPort() != 0) {
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/ManagementAgentFactory.java b/geode-core/src/main/java/org/apache/geode/management/internal/ManagementAgentFactory.java
index bff205e..31c3652 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/ManagementAgentFactory.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/ManagementAgentFactory.java
@@ -16,10 +16,11 @@ package org.apache.geode.management.internal;
import org.apache.geode.distributed.internal.DistributionConfig;
import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.internal.serialization.filter.FilterConfiguration;
@FunctionalInterface
interface ManagementAgentFactory {
ManagementAgent create(DistributionConfig config, InternalCache cache,
- JmxRmiSerialFilter serialFilter);
+ FilterConfiguration filterConfiguration);
}
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/SystemManagementService.java b/geode-core/src/main/java/org/apache/geode/management/internal/SystemManagementService.java
index 76f47c5..7d117fa 100755
--- a/geode-core/src/main/java/org/apache/geode/management/internal/SystemManagementService.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/SystemManagementService.java
@@ -45,6 +45,8 @@ import org.apache.geode.distributed.internal.ResourceEvent;
import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
import org.apache.geode.internal.cache.InternalCache;
import org.apache.geode.internal.cache.InternalCacheForClientAccess;
+import org.apache.geode.internal.serialization.filter.FilterConfiguration;
+import org.apache.geode.internal.serialization.filter.SystemPropertyJmxSerialFilterConfigurationFactory;
import org.apache.geode.internal.statistics.StatisticsClock;
import org.apache.geode.logging.internal.executors.LoggingExecutors;
import org.apache.geode.logging.internal.log4j.api.LogService;
@@ -178,9 +180,12 @@ public class SystemManagementService extends BaseManagementService {
repo = new ManagementResourceRepo();
notificationHub = notificationHubFactory.apply(repo);
+
if (system.getConfig().getJmxManager()) {
- agent = managementAgentFactory.create(system.getConfig(), cache,
- new JmxRmiOpenTypesSerialFilter());
+ FilterConfiguration filterConfiguration =
+ new SystemPropertyJmxSerialFilterConfigurationFactory().create();
+
+ agent = managementAgentFactory.create(system.getConfig(), cache, filterConfiguration);
} else {
agent = null;
}
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 f204a47..b33ee4a 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
@@ -63,6 +63,7 @@ import org.junit.experimental.categories.Category;
import org.apache.geode.UnmodifiableException;
import org.apache.geode.internal.ConfigSource;
+import org.apache.geode.internal.serialization.filter.SerializableObjectConfig;
import org.apache.geode.security.TestPostProcessor;
import org.apache.geode.security.TestSecurityManager;
import org.apache.geode.test.junit.categories.MembershipTest;
@@ -494,4 +495,11 @@ public class DistributionConfigJUnitTest {
DistributionConfig config = new DistributionConfigImpl(props);
assertThat(config.getSecurityAuthTokenEnabledComponents()).containsExactly("MANAGEMENT");
}
+
+ @Test
+ public void isASerializableObjectConfig() {
+ DistributionConfig config = new DistributionConfigImpl(new Properties());
+
+ assertThat(config).isInstanceOf(SerializableObjectConfig.class);
+ }
}
diff --git a/geode-core/src/test/java/org/apache/geode/internal/DistributedSerializableObjectConfigTest.java b/geode-core/src/test/java/org/apache/geode/internal/DistributedSerializableObjectConfigTest.java
new file mode 100644
index 0000000..d528904
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/DistributedSerializableObjectConfigTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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 static org.apache.geode.distributed.ConfigurationProperties.SERIALIZABLE_OBJECT_FILTER;
+import static org.apache.geode.distributed.ConfigurationProperties.VALIDATE_SERIALIZABLE_OBJECTS;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import java.util.Properties;
+
+import org.junit.Test;
+
+import org.apache.geode.internal.serialization.filter.SerializableObjectConfig;
+
+public class DistributedSerializableObjectConfigTest {
+
+ @Test
+ public void getValidateSerializableObjects_returnsTrue_whenPropertyIsTrue() {
+ Properties properties = spy(new Properties());
+ SerializableObjectConfig config = new DistributedSerializableObjectConfig(properties);
+ when(properties.getProperty(VALIDATE_SERIALIZABLE_OBJECTS)).thenReturn("true");
+
+ boolean result = config.getValidateSerializableObjects();
+
+ assertThat(result).isTrue();
+ }
+
+ @Test
+ public void setValidateSerializableObjects_setsPropertyValue() {
+ Properties properties = spy(new Properties());
+ SerializableObjectConfig config = new DistributedSerializableObjectConfig(properties);
+
+ config.setValidateSerializableObjects(true);
+
+ assertThat(properties.getProperty(VALIDATE_SERIALIZABLE_OBJECTS)).isEqualTo("true");
+ }
+
+ @Test
+ public void getSerializableObjectFilter_returnsPropertyValue() {
+ Properties properties = spy(new Properties());
+ SerializableObjectConfig config = new DistributedSerializableObjectConfig(properties);
+ when(properties.getProperty(SERIALIZABLE_OBJECT_FILTER)).thenReturn("!*");
+
+ String result = config.getSerializableObjectFilter();
+
+ assertThat(result).isEqualTo("!*");
+ }
+}
diff --git a/geode-core/src/test/java/org/apache/geode/internal/InternalDataSerializerSerializationAcceptlistTest.java b/geode-core/src/test/java/org/apache/geode/internal/InternalDataSerializerSerializationAcceptlistTest.java
index edbb395..f186df9 100644
--- a/geode-core/src/test/java/org/apache/geode/internal/InternalDataSerializerSerializationAcceptlistTest.java
+++ b/geode-core/src/test/java/org/apache/geode/internal/InternalDataSerializerSerializationAcceptlistTest.java
@@ -17,14 +17,15 @@ package org.apache.geode.internal;
import static java.util.Collections.emptySet;
import static org.apache.geode.distributed.internal.DistributionConfig.SERIALIZABLE_OBJECT_FILTER_NAME;
import static org.apache.geode.distributed.internal.DistributionConfig.VALIDATE_SERIALIZABLE_OBJECTS_NAME;
-import static org.apache.geode.internal.lang.utils.ClassUtils.isClassAvailable;
+import static org.apache.geode.internal.InternalDataSerializer.initializeSerializationFilter;
+import static org.apache.geode.internal.serialization.filter.ObjectInputFilterUtils.supportsObjectInputFilter;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
-import static org.junit.Assume.assumeTrue;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.InvalidClassException;
import java.io.Serializable;
import java.util.Properties;
@@ -36,9 +37,9 @@ 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.internal.serialization.KnownVersion;
+import org.apache.geode.internal.serialization.filter.SerializableObjectConfig;
import org.apache.geode.test.junit.categories.SerializationTest;
@Category(SerializationTest.class)
@@ -50,9 +51,9 @@ public class InternalDataSerializerSerializationAcceptlistTest {
@BeforeClass
public static void hasObjectInputFilter() {
- assumeTrue("ObjectInputFilter is present in this JVM",
- isClassAvailable("sun.misc.ObjectInputFilter") ||
- isClassAvailable("java.io.ObjectInputFilter"));
+ assertThat(supportsObjectInputFilter())
+ .as("java.io.ObjectInputFilter or sun.misc.ObjectInputFilter is available")
+ .isTrue();
}
@Before
@@ -69,23 +70,37 @@ public class InternalDataSerializerSerializationAcceptlistTest {
@Test
public void distributionConfigDefaults() {
- DistributionConfig distributionConfig = new DistributionConfigImpl(new Properties());
+ SerializableObjectConfig config = new DistributionConfigImpl(new Properties());
- assertThat(distributionConfig.getValidateSerializableObjects()).isFalse();
- assertThat(distributionConfig.getSerializableObjectFilter()).isEqualTo("!*");
+ assertThat(config.getValidateSerializableObjects()).isFalse();
+ assertThat(config.getSerializableObjectFilter()).isEqualTo("!*");
}
@Test
- public void canSerializeWhenFilterIsDisabled() throws Exception {
- trySerializingTestObject(new Properties());
+ public void canSerializeWhenFilterIsDisabled() throws ClassNotFoundException, IOException {
+ initializeSerializationFilter(emptyConfig(), emptySet());
+ DataSerializer.writeObject(testSerializable, outputStream);
+
+ Object deserializedObject;
+ try (InputStream in = new ByteArrayInputStream(outputStream.toByteArray());
+ DataInputStream dataInputStream = new DataInputStream(in)) {
+ deserializedObject = DataSerializer.readObject(dataInputStream);
+ }
+
+ assertThat(deserializedObject).isInstanceOf(testSerializable.getClass());
}
@Test
- public void notAcceptlistedWithFilterCannotSerialize() {
+ public void notAcceptlistedWithFilterCannotSerialize() throws IOException {
properties.setProperty(VALIDATE_SERIALIZABLE_OBJECTS_NAME, "true");
+ initializeSerializationFilter(config(properties), emptySet());
+ DataSerializer.writeObject(testSerializable, outputStream);
Throwable thrown = catchThrowable(() -> {
- trySerializingTestObject(properties);
+ try (InputStream in = new ByteArrayInputStream(outputStream.toByteArray());
+ DataInputStream dataInputStream = new DataInputStream(in)) {
+ DataSerializer.readObject(dataInputStream);
+ }
});
assertThat(thrown).isInstanceOf(InvalidClassException.class);
@@ -95,51 +110,100 @@ public class InternalDataSerializerSerializationAcceptlistTest {
public void acceptlistedWithFilterCanSerialize() throws Exception {
properties.setProperty(VALIDATE_SERIALIZABLE_OBJECTS_NAME, "true");
properties.setProperty(SERIALIZABLE_OBJECT_FILTER_NAME, TestSerializable.class.getName());
+ initializeSerializationFilter(config(properties), emptySet());
+ DataSerializer.writeObject(testSerializable, outputStream);
+
+ Object deserializedObject;
+ try (InputStream in = new ByteArrayInputStream(outputStream.toByteArray());
+ DataInputStream dataInputStream = new DataInputStream(in)) {
+ deserializedObject = DataSerializer.readObject(dataInputStream);
+ }
- trySerializingTestObject(properties);
+ assertThat(deserializedObject).isInstanceOf(testSerializable.getClass());
}
@Test
- public void acceptlistedWithNonMatchingFilterCannotSerialize() {
+ public void acceptlistedWithNonMatchingFilterCannotSerialize() throws IOException {
+ properties.setProperty(VALIDATE_SERIALIZABLE_OBJECTS_NAME, "true");
+ properties.setProperty(SERIALIZABLE_OBJECT_FILTER_NAME, "RabidMonkeyTurnip");
+ initializeSerializationFilter(config(properties), emptySet());
+ DataSerializer.writeObject(testSerializable, outputStream);
+
Throwable thrown = catchThrowable(() -> {
- trySerializingWithFilter("RabidMonkeyTurnip");
+ try (InputStream in = new ByteArrayInputStream(outputStream.toByteArray());
+ DataInputStream dataInputStream = new DataInputStream(in)) {
+ DataSerializer.readObject(dataInputStream);
+ }
});
assertThat(thrown).isInstanceOf(InvalidClassException.class);
}
@Test
- public void acceptlistedWithPartialMatchingFilterCannotSerialize() {
+ public void acceptlistedWithPartialMatchingFilterCannotSerialize() throws IOException {
+ // Not fully qualified class name
+ properties.setProperty(VALIDATE_SERIALIZABLE_OBJECTS_NAME, "true");
+ properties.setProperty(SERIALIZABLE_OBJECT_FILTER_NAME, "TestSerializable");
+ initializeSerializationFilter(config(properties), emptySet());
+ DataSerializer.writeObject(testSerializable, outputStream);
+
Throwable thrown = catchThrowable(() -> {
- trySerializingWithFilter("TestSerializable"); // Not fully qualified class name
+ try (InputStream in = new ByteArrayInputStream(outputStream.toByteArray());
+ DataInputStream dataInputStream = new DataInputStream(in)) {
+ DataSerializer.readObject(dataInputStream);
+ }
});
assertThat(thrown).isInstanceOf(InvalidClassException.class);
}
@Test
- public void acceptlistedWithEmptyFilterCannotSerialize() {
+ public void acceptlistedWithEmptyFilterCannotSerialize() throws IOException {
+ properties.setProperty(VALIDATE_SERIALIZABLE_OBJECTS_NAME, "true");
+ properties.setProperty(SERIALIZABLE_OBJECT_FILTER_NAME, "");
+ initializeSerializationFilter(config(properties), emptySet());
+ DataSerializer.writeObject(testSerializable, outputStream);
+
Throwable thrown = catchThrowable(() -> {
- trySerializingWithFilter("");
+ try (InputStream in = new ByteArrayInputStream(outputStream.toByteArray());
+ DataInputStream dataInputStream = new DataInputStream(in)) {
+ DataSerializer.readObject(dataInputStream);
+ }
});
assertThat(thrown).isInstanceOf(InvalidClassException.class);
}
@Test
- public void acceptlistedWithIncorrectPathFilterCannotSerialize() {
+ public void acceptlistedWithIncorrectPathFilterCannotSerialize() throws IOException {
+ properties.setProperty(VALIDATE_SERIALIZABLE_OBJECTS_NAME, "true");
+ properties.setProperty(SERIALIZABLE_OBJECT_FILTER_NAME,
+ "org.apache.commons.InternalDataSerializerSerializationAcceptlistTest$TestSerializable");
+ initializeSerializationFilter(config(properties), emptySet());
+ DataSerializer.writeObject(testSerializable, outputStream);
+
Throwable thrown = catchThrowable(() -> {
- trySerializingWithFilter(
- "org.apache.commons.InternalDataSerializerSerializationAcceptlistTest$TestSerializable");
+ try (InputStream in = new ByteArrayInputStream(outputStream.toByteArray());
+ DataInputStream dataInputStream = new DataInputStream(in)) {
+ DataSerializer.readObject(dataInputStream);
+ }
});
assertThat(thrown).isInstanceOf(InvalidClassException.class);
}
@Test
- public void acceptlistedWithWildcardPathFilterCannotSerialize() {
+ public void acceptlistedWithWildcardPathFilterCannotSerialize() throws IOException {
+ properties.setProperty(VALIDATE_SERIALIZABLE_OBJECTS_NAME, "true");
+ properties.setProperty(SERIALIZABLE_OBJECT_FILTER_NAME, "org.apache.*");
+ initializeSerializationFilter(config(properties), emptySet());
+ DataSerializer.writeObject(testSerializable, outputStream);
+
Throwable thrown = catchThrowable(() -> {
- trySerializingWithFilter("org.apache.*");
+ try (InputStream in = new ByteArrayInputStream(outputStream.toByteArray());
+ DataInputStream dataInputStream = new DataInputStream(in)) {
+ DataSerializer.readObject(dataInputStream);
+ }
});
assertThat(thrown).isInstanceOf(InvalidClassException.class);
@@ -147,26 +211,26 @@ public class InternalDataSerializerSerializationAcceptlistTest {
@Test
public void acceptlistedWithWildcardSubpathFilterCanSerialize() throws Exception {
- trySerializingWithFilter("org.apache.**");
- }
-
- private void trySerializingWithFilter(String filter) throws Exception {
properties.setProperty(VALIDATE_SERIALIZABLE_OBJECTS_NAME, "true");
- properties.setProperty(SERIALIZABLE_OBJECT_FILTER_NAME, filter);
+ properties.setProperty(SERIALIZABLE_OBJECT_FILTER_NAME, "org.apache.**");
+ initializeSerializationFilter(config(properties), emptySet());
+ DataSerializer.writeObject(testSerializable, outputStream);
- trySerializingTestObject(properties);
- }
+ Object deserializedObject;
+ try (InputStream in = new ByteArrayInputStream(outputStream.toByteArray());
+ DataInputStream dataInputStream = new DataInputStream(in)) {
+ deserializedObject = DataSerializer.readObject(dataInputStream);
+ }
- private void trySerializingTestObject(Properties properties)
- throws IOException, ClassNotFoundException {
- DistributionConfig distributionConfig = new DistributionConfigImpl(properties);
- InternalDataSerializer.initializeSerializationFilter(distributionConfig, emptySet());
+ assertThat(deserializedObject).isInstanceOf(testSerializable.getClass());
+ }
- DataSerializer.writeObject(testSerializable, outputStream);
+ private static SerializableObjectConfig emptyConfig() {
+ return config(new Properties());
+ }
- // if this throws, we're good!
- DataSerializer
- .readObject(new DataInputStream(new ByteArrayInputStream(outputStream.toByteArray())));
+ private static SerializableObjectConfig config(Properties properties) {
+ return new DistributedSerializableObjectConfig(properties);
}
@SuppressWarnings("serial")
diff --git a/geode-core/src/test/java/org/apache/geode/internal/InternalDataSerializerShiroAcceptListTest.java b/geode-core/src/test/java/org/apache/geode/internal/InternalDataSerializerShiroAcceptListTest.java
index 59b7062..64f3415 100644
--- a/geode-core/src/test/java/org/apache/geode/internal/InternalDataSerializerShiroAcceptListTest.java
+++ b/geode-core/src/test/java/org/apache/geode/internal/InternalDataSerializerShiroAcceptListTest.java
@@ -16,9 +16,9 @@ package org.apache.geode.internal;
import static java.util.Collections.emptySet;
import static org.apache.geode.distributed.internal.DistributionConfig.VALIDATE_SERIALIZABLE_OBJECTS_NAME;
-import static org.apache.geode.internal.lang.utils.ClassUtils.isClassAvailable;
import static org.apache.geode.internal.serialization.KnownVersion.CURRENT;
-import static org.junit.Assume.assumeTrue;
+import static org.apache.geode.internal.serialization.filter.ObjectInputFilterUtils.supportsObjectInputFilter;
+import static org.assertj.core.api.Assertions.assertThat;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
@@ -44,8 +44,7 @@ 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.internal.serialization.filter.SerializableObjectConfig;
import org.apache.geode.test.junit.categories.SecurityTest;
import org.apache.geode.test.junit.categories.SerializationTest;
@@ -54,9 +53,9 @@ public class InternalDataSerializerShiroAcceptListTest {
@BeforeClass
public static void hasObjectInputFilter() {
- assumeTrue("ObjectInputFilter is present in this JVM",
- isClassAvailable("sun.misc.ObjectInputFilter") ||
- isClassAvailable("java.io.ObjectInputFilter"));
+ assertThat(supportsObjectInputFilter())
+ .as("java.io.ObjectInputFilter or sun.misc.ObjectInputFilter is available")
+ .isTrue();
}
@After
@@ -138,17 +137,9 @@ public class InternalDataSerializerShiroAcceptListTest {
propertiesWithoutFilter());
}
- private static Properties propertiesWithoutFilter() {
- Properties properties = new Properties();
- properties.setProperty(VALIDATE_SERIALIZABLE_OBJECTS_NAME, "true");
-
- return properties;
- }
-
private static void trySerializingObject(Object object, Properties properties)
throws IOException, ClassNotFoundException {
- DistributionConfig distributionConfig = new DistributionConfigImpl(properties);
- InternalDataSerializer.initializeSerializationFilter(distributionConfig, emptySet());
+ InternalDataSerializer.initializeSerializationFilter(config(properties), emptySet());
HeapDataOutputStream outputStream = new HeapDataOutputStream(CURRENT);
DataSerializer.writeObject(object, outputStream);
@@ -158,4 +149,15 @@ public class InternalDataSerializerShiroAcceptListTest {
DataSerializer.readObject(dis);
}
}
+
+ private static SerializableObjectConfig config(Properties properties) {
+ return new DistributedSerializableObjectConfig(properties);
+ }
+
+ private static Properties propertiesWithoutFilter() {
+ Properties properties = new Properties();
+ properties.setProperty(VALIDATE_SERIALIZABLE_OBJECTS_NAME, "true");
+
+ return properties;
+ }
}
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/JmxRmiOpenTypesSerialFilterTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/JmxRmiOpenTypesSerialFilterTest.java
deleted file mode 100644
index c8f8ea9..0000000
--- a/geode-core/src/test/java/org/apache/geode/management/internal/JmxRmiOpenTypesSerialFilterTest.java
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * 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.management.internal;
-
-import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
-import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtMost;
-import static org.apache.geode.util.internal.UncheckedUtils.uncheckedCast;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assumptions.assumeThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.rmi.MarshalledObject;
-import java.util.function.Consumer;
-
-import javax.management.ObjectName;
-import javax.management.openmbean.ArrayType;
-import javax.management.openmbean.CompositeData;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.SimpleType;
-import javax.management.openmbean.TabularData;
-import javax.management.openmbean.TabularType;
-
-import org.apache.commons.lang3.JavaVersion;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.contrib.java.lang.system.RestoreSystemProperties;
-
-public class JmxRmiOpenTypesSerialFilterTest {
-
- private Consumer<String> infoLogger;
-
- @Rule
- public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
-
- @Before
- public void setUp() {
- infoLogger = uncheckedCast(mock(Consumer.class));
- }
-
- @Test
- public void propertyValueIsNullByDefault() {
- String propertyValue = System.getProperty(JmxRmiOpenTypesSerialFilter.PROPERTY_NAME);
-
- assertThat(propertyValue).isNull();
- }
-
- @Test
- public void supportsDedicatedSerialFilter_returnsTrue_atLeastJava9() {
- assumeThat(isJavaVersionAtLeast(JavaVersion.JAVA_9)).isTrue();
-
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter = new JmxRmiOpenTypesSerialFilter();
-
- boolean result = jmxRmiOpenTypesSerialFilter.supportsDedicatedSerialFilter();
-
- assertThat(result).isTrue();
- }
-
- @Test
- public void supportsDedicatedSerialFilter_returnsFalse_atMostJava8() {
- assumeThat(isJavaVersionAtMost(JavaVersion.JAVA_1_8)).isTrue();
-
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter = new JmxRmiOpenTypesSerialFilter();
-
- boolean result = jmxRmiOpenTypesSerialFilter.supportsDedicatedSerialFilter();
-
- assertThat(result).isFalse();
- }
-
- @Test
- public void setPropertyValue_setsValue_ifExistingValueIsNull() {
- String value = "value-of-property";
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter = new JmxRmiOpenTypesSerialFilter();
-
- jmxRmiOpenTypesSerialFilter.setPropertyValueUnlessExists(value);
-
- String propertyValue = System.getProperty(JmxRmiOpenTypesSerialFilter.PROPERTY_NAME);
- assertThat(propertyValue).isEqualTo(value);
- }
-
- @Test
- public void setPropertyValue_setsValue_ifExistingValueIsEmpty() {
- System.setProperty(JmxRmiOpenTypesSerialFilter.PROPERTY_NAME, "");
- String value = "value-of-property";
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter = new JmxRmiOpenTypesSerialFilter();
-
- jmxRmiOpenTypesSerialFilter.setPropertyValueUnlessExists(value);
-
- String propertyValue = System.getProperty(JmxRmiOpenTypesSerialFilter.PROPERTY_NAME);
- assertThat(propertyValue).isEqualTo(value);
- }
-
- @Test
- public void setPropertyValue_logsMessage_ifExistingValueIsEmpty() {
- System.setProperty(JmxRmiOpenTypesSerialFilter.PROPERTY_NAME, "");
- String value = "value-of-property";
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter =
- new JmxRmiOpenTypesSerialFilter(infoLogger, () -> true);
-
- jmxRmiOpenTypesSerialFilter.setPropertyValueUnlessExists(value);
-
- String expectedLogMessage = "System property " + JmxRmiOpenTypesSerialFilter.PROPERTY_NAME +
- " is now configured with '" + value + "'.";
- verify(infoLogger).accept(expectedLogMessage);
- }
-
- @Test
- public void setPropertyValue_leavesExistingValue_ifExistingValueIsNotEmpty() {
- String existingValue = "existing-value-of-property";
- System.setProperty(JmxRmiOpenTypesSerialFilter.PROPERTY_NAME, existingValue);
- String value = "value-of-property";
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter = new JmxRmiOpenTypesSerialFilter();
-
- jmxRmiOpenTypesSerialFilter.setPropertyValueUnlessExists(value);
-
- String propertyValue = System.getProperty(JmxRmiOpenTypesSerialFilter.PROPERTY_NAME);
- assertThat(propertyValue).isEqualTo(existingValue);
- }
-
- @Test
- public void setPropertyValue_logsMessage_ifExistingValueIsNotEmpty() {
- String existingValue = "existing-value-of-property";
- System.setProperty(JmxRmiOpenTypesSerialFilter.PROPERTY_NAME, existingValue);
- String value = "value-of-property";
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter =
- new JmxRmiOpenTypesSerialFilter(infoLogger, () -> true);
-
- jmxRmiOpenTypesSerialFilter.setPropertyValueUnlessExists(value);
-
- String expectedLogMessage = "System property " + JmxRmiOpenTypesSerialFilter.PROPERTY_NAME +
- " is already configured.";
- verify(infoLogger).accept(expectedLogMessage);
- }
-
- @Test
- public void createSerialFilterPattern_includesBoolean() {
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter = new JmxRmiOpenTypesSerialFilter();
-
- String result = jmxRmiOpenTypesSerialFilter.createSerialFilterPattern();
-
- assertThat(result).contains(Boolean.class.getName());
- }
-
- @Test
- public void createSerialFilterPattern_includesByte() {
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter = new JmxRmiOpenTypesSerialFilter();
-
- String result = jmxRmiOpenTypesSerialFilter.createSerialFilterPattern();
-
- assertThat(result).contains(Byte.class.getName());
- }
-
- @Test
- public void createSerialFilterPattern_includesCharacter() {
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter = new JmxRmiOpenTypesSerialFilter();
-
- String result = jmxRmiOpenTypesSerialFilter.createSerialFilterPattern();
-
- assertThat(result).contains(Character.class.getName());
- }
-
- @Test
- public void createSerialFilterPattern_includesShort() {
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter = new JmxRmiOpenTypesSerialFilter();
-
- String result = jmxRmiOpenTypesSerialFilter.createSerialFilterPattern();
-
- assertThat(result).contains(Short.class.getName());
- }
-
- @Test
- public void createSerialFilterPattern_includesInteger() {
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter = new JmxRmiOpenTypesSerialFilter();
-
- String result = jmxRmiOpenTypesSerialFilter.createSerialFilterPattern();
-
- assertThat(result).contains(Integer.class.getName());
- }
-
- @Test
- public void createSerialFilterPattern_includesLong() {
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter = new JmxRmiOpenTypesSerialFilter();
-
- String result = jmxRmiOpenTypesSerialFilter.createSerialFilterPattern();
-
- assertThat(result).contains(Long.class.getName());
- }
-
- @Test
- public void createSerialFilterPattern_includesFloat() {
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter = new JmxRmiOpenTypesSerialFilter();
-
- String result = jmxRmiOpenTypesSerialFilter.createSerialFilterPattern();
-
- assertThat(result).contains(Float.class.getName());
- }
-
- @Test
- public void createSerialFilterPattern_includesDouble() {
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter = new JmxRmiOpenTypesSerialFilter();
-
- String result = jmxRmiOpenTypesSerialFilter.createSerialFilterPattern();
-
- assertThat(result).contains(Double.class.getName());
- }
-
- @Test
- public void createSerialFilterPattern_includesString() {
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter = new JmxRmiOpenTypesSerialFilter();
-
- String result = jmxRmiOpenTypesSerialFilter.createSerialFilterPattern();
-
- assertThat(result).contains(String.class.getName());
- }
-
- @Test
- public void createSerialFilterPattern_includesBigInteger() {
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter = new JmxRmiOpenTypesSerialFilter();
-
- String result = jmxRmiOpenTypesSerialFilter.createSerialFilterPattern();
-
- assertThat(result).contains(BigInteger.class.getName());
- }
-
- @Test
- public void createSerialFilterPattern_includesBigDecimal() {
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter = new JmxRmiOpenTypesSerialFilter();
-
- String result = jmxRmiOpenTypesSerialFilter.createSerialFilterPattern();
-
- assertThat(result).contains(BigDecimal.class.getName());
- }
-
- @Test
- public void createSerialFilterPattern_includesObjectName() {
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter = new JmxRmiOpenTypesSerialFilter();
-
- String result = jmxRmiOpenTypesSerialFilter.createSerialFilterPattern();
-
- assertThat(result).contains(ObjectName.class.getName());
- }
-
- @Test
- public void createSerialFilterPattern_includesCompositeData() {
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter = new JmxRmiOpenTypesSerialFilter();
-
- String result = jmxRmiOpenTypesSerialFilter.createSerialFilterPattern();
-
- assertThat(result).contains(CompositeData.class.getName());
- }
-
- @Test
- public void createSerialFilterPattern_includesTabularData() {
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter = new JmxRmiOpenTypesSerialFilter();
-
- String result = jmxRmiOpenTypesSerialFilter.createSerialFilterPattern();
-
- assertThat(result).contains(TabularData.class.getName());
- }
-
- @Test
- public void createSerialFilterPattern_includesSimpleType() {
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter = new JmxRmiOpenTypesSerialFilter();
-
- String result = jmxRmiOpenTypesSerialFilter.createSerialFilterPattern();
-
- assertThat(result).contains(SimpleType.class.getName());
- }
-
- @Test
- public void createSerialFilterPattern_includesCompositeType() {
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter = new JmxRmiOpenTypesSerialFilter();
-
- String result = jmxRmiOpenTypesSerialFilter.createSerialFilterPattern();
-
- assertThat(result).contains(CompositeType.class.getName());
- }
-
- @Test
- public void createSerialFilterPattern_includesTabularType() {
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter = new JmxRmiOpenTypesSerialFilter();
-
- String result = jmxRmiOpenTypesSerialFilter.createSerialFilterPattern();
-
- assertThat(result).contains(TabularType.class.getName());
- }
-
- @Test
- public void createSerialFilterPattern_includesArrayType() {
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter = new JmxRmiOpenTypesSerialFilter();
-
- String result = jmxRmiOpenTypesSerialFilter.createSerialFilterPattern();
-
- assertThat(result).contains(ArrayType.class.getName());
- }
-
- @Test
- public void createSerialFilterPattern_includesMarshalledObject() {
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter = new JmxRmiOpenTypesSerialFilter();
-
- String result = jmxRmiOpenTypesSerialFilter.createSerialFilterPattern();
-
- assertThat(result).contains(MarshalledObject.class.getName());
- }
-
- @Test
- public void createSerialFilterPattern_rejectsAllOtherTypes() {
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter = new JmxRmiOpenTypesSerialFilter();
-
- String result = jmxRmiOpenTypesSerialFilter.createSerialFilterPattern();
-
- assertThat(result).endsWith("!*");
- }
-
- @Test
- public void configureSerialFilterIfEmpty_setsPropertyValue_atLeastJava9() {
- JmxRmiOpenTypesSerialFilter jmxRmiOpenTypesSerialFilter =
- new JmxRmiOpenTypesSerialFilter(infoLogger, () -> true);
-
- jmxRmiOpenTypesSerialFilter.configureSerialFilter();
-
- String propertyValue = System.getProperty(JmxRmiOpenTypesSerialFilter.PROPERTY_NAME);
- assertThat(propertyValue).isNotEmpty();
- }
-
- @Test
- public void configureSerialFilterIfEmpty_setsPropertyValue_atMostJava8() {
- JmxRmiSerialFilter jmxRmiOpenTypesSerialFilter =
- new JmxRmiOpenTypesSerialFilter(infoLogger, () -> false);
-
- jmxRmiOpenTypesSerialFilter.configureSerialFilter();
-
- String propertyValue = System.getProperty(JmxRmiOpenTypesSerialFilter.PROPERTY_NAME);
- assertThat(propertyValue).isNull();
- }
-}
diff --git a/geode-core/src/test/resources/expected-pom.xml b/geode-core/src/test/resources/expected-pom.xml
index c131a25..480c2c0 100644
--- a/geode-core/src/test/resources/expected-pom.xml
+++ b/geode-core/src/test/resources/expected-pom.xml
@@ -78,6 +78,11 @@
</dependency>
<dependency>
<groupId>org.apache.geode</groupId>
+ <artifactId>geode-serialization</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.geode</groupId>
<artifactId>geode-management</artifactId>
<scope>compile</scope>
</dependency>
@@ -229,11 +234,6 @@
</dependency>
<dependency>
<groupId>org.apache.geode</groupId>
- <artifactId>geode-serialization</artifactId>
- <scope>runtime</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.geode</groupId>
<artifactId>geode-tcp-server</artifactId>
<scope>runtime</scope>
</dependency>
diff --git a/geode-http-service/build.gradle b/geode-http-service/build.gradle
index c9e0580..5af9232 100755
--- a/geode-http-service/build.gradle
+++ b/geode-http-service/build.gradle
@@ -33,6 +33,7 @@ dependencies {
compileOnly(project(':geode-common')) {
exclude module: 'junit'
}
+ compileOnly(project(':geode-serialization'))
testImplementation(project(':geode-core'))
testImplementation(project(':geode-common'))
diff --git a/geode-junit/src/main/java/org/apache/geode/codeAnalysis/AnalyzeSerializablesTestBase.java b/geode-junit/src/main/java/org/apache/geode/codeAnalysis/AnalyzeSerializablesTestBase.java
index 2d5dd3a..c9d6d57 100644
--- a/geode-junit/src/main/java/org/apache/geode/codeAnalysis/AnalyzeSerializablesTestBase.java
+++ b/geode-junit/src/main/java/org/apache/geode/codeAnalysis/AnalyzeSerializablesTestBase.java
@@ -16,6 +16,7 @@ package org.apache.geode.codeAnalysis;
import static org.apache.geode.distributed.ConfigurationProperties.SERIALIZABLE_OBJECT_FILTER;
import static org.apache.geode.distributed.ConfigurationProperties.VALIDATE_SERIALIZABLE_OBJECTS;
+import static org.apache.geode.internal.InternalDataSerializer.initializeSerializationFilter;
import static org.assertj.core.api.Assertions.fail;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -52,8 +53,7 @@ import org.apache.geode.DataSerializable;
import org.apache.geode.DataSerializer;
import org.apache.geode.codeAnalysis.decode.CompiledClass;
import org.apache.geode.codeAnalysis.decode.CompiledField;
-import org.apache.geode.distributed.internal.DistributionConfigImpl;
-import org.apache.geode.internal.InternalDataSerializer;
+import org.apache.geode.internal.DistributedSerializableObjectConfig;
import org.apache.geode.internal.serialization.BufferDataOutputStream;
import org.apache.geode.internal.serialization.DataSerializableFixedID;
import org.apache.geode.internal.serialization.KnownVersion;
@@ -333,7 +333,7 @@ public abstract class AnalyzeSerializablesTestBase
properties.setProperty(VALIDATE_SERIALIZABLE_OBJECTS, "true");
properties.setProperty(SERIALIZABLE_OBJECT_FILTER, "!*");
- InternalDataSerializer.initializeSerializationFilter(new DistributionConfigImpl(properties));
+ initializeSerializationFilter(new DistributedSerializableObjectConfig(properties));
}
@Override
diff --git a/geode-serialization/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiSetFilterBlankIntegrationTest.java b/geode-serialization/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiSetFilterBlankIntegrationTest.java
new file mode 100644
index 0000000..6155c8b
--- /dev/null
+++ b/geode-serialization/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiSetFilterBlankIntegrationTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.serialization.filter;
+
+import static org.apache.commons.lang3.JavaVersion.JAVA_1_8;
+import static org.apache.commons.lang3.JavaVersion.JAVA_9;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtMost;
+import static org.apache.geode.internal.serialization.filter.ApiPackage.JAVA_IO;
+import static org.apache.geode.internal.serialization.filter.ApiPackage.SUN_MISC;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * This test calls the real setSerialFilter which can only be set once within a JVM, so it's in an
+ * integration test which forks a new JVM for the test class.
+ */
+public class ReflectiveObjectInputFilterApiSetFilterBlankIntegrationTest {
+
+ private ApiPackage apiPackage;
+
+ @Before
+ public void setUp() {
+ if (isJavaVersionAtLeast(JAVA_1_8) && isJavaVersionAtMost(JAVA_1_8)) {
+ apiPackage = SUN_MISC;
+ }
+
+ if (isJavaVersionAtLeast(JAVA_9)) {
+ apiPackage = JAVA_IO;
+ }
+
+ }
+
+ @Test
+ public void setsFilterGivenBlankPattern()
+ throws ClassNotFoundException, IllegalAccessException, InvocationTargetException,
+ NoSuchMethodException {
+ ObjectInputFilterApi api = new ReflectiveObjectInputFilterApi(apiPackage);
+ Object filter = api.createFilter(" ");
+
+ api.setSerialFilter(filter);
+
+ assertThat(api.getSerialFilter())
+ .as("ObjectInputFilter$Config.getSerialFilter()")
+ .isSameAs(filter);
+ }
+}
diff --git a/geode-serialization/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiSetFilterIntegrationTest.java b/geode-serialization/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiSetFilterIntegrationTest.java
new file mode 100644
index 0000000..619673b
--- /dev/null
+++ b/geode-serialization/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiSetFilterIntegrationTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.serialization.filter;
+
+import static org.apache.commons.lang3.JavaVersion.JAVA_1_8;
+import static org.apache.commons.lang3.JavaVersion.JAVA_9;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtMost;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * This test calls the real setSerialFilter which can only be set once within a JVM, so it's in an
+ * integration test which forks a new JVM for the test class.
+ */
+public class ReflectiveObjectInputFilterApiSetFilterIntegrationTest {
+
+ private ApiPackage apiPackage;
+
+ @Before
+ public void setUp() {
+ if (isJavaVersionAtLeast(JAVA_1_8) && isJavaVersionAtMost(JAVA_1_8)) {
+ apiPackage = ApiPackage.SUN_MISC;
+ }
+
+ if (isJavaVersionAtLeast(JAVA_9)) {
+ apiPackage = ApiPackage.JAVA_IO;
+ }
+ }
+
+ @Test
+ public void setsFilterGivenValidPattern()
+ throws ClassNotFoundException, IllegalAccessException, InvocationTargetException,
+ NoSuchMethodException {
+ ObjectInputFilterApi api = new ReflectiveObjectInputFilterApi(apiPackage);
+ Object filter = api.createFilter("!*");
+
+ api.setSerialFilter(filter);
+
+ assertThat(api.getSerialFilter())
+ .as("ObjectInputFilter$Config.getSerialFilter()")
+ .isSameAs(filter);
+ }
+}
diff --git a/geode-serialization/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiSetFilterNullIntegrationTest.java b/geode-serialization/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiSetFilterNullIntegrationTest.java
new file mode 100644
index 0000000..9b13b73
--- /dev/null
+++ b/geode-serialization/src/integrationTest/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiSetFilterNullIntegrationTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.serialization.filter;
+
+import static org.apache.commons.lang3.JavaVersion.JAVA_1_8;
+import static org.apache.commons.lang3.JavaVersion.JAVA_9;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtMost;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.catchThrowable;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * This test calls the real setSerialFilter which can only be set once within a JVM, so it's in an
+ * integration test which forks a new JVM for the test class.
+ */
+public class ReflectiveObjectInputFilterApiSetFilterNullIntegrationTest {
+
+ private ApiPackage apiPackage;
+
+ @Before
+ public void setUp() {
+ if (isJavaVersionAtLeast(JAVA_1_8) && isJavaVersionAtMost(JAVA_1_8)) {
+ apiPackage = ApiPackage.SUN_MISC;
+ }
+
+ if (isJavaVersionAtLeast(JAVA_9)) {
+ apiPackage = ApiPackage.JAVA_IO;
+ }
+ }
+
+ @Test
+ public void throwsNullPointerExceptionGivenNull()
+ throws ClassNotFoundException, NoSuchMethodException {
+ ObjectInputFilterApi api = new ReflectiveObjectInputFilterApi(apiPackage);
+
+ Throwable thrown = catchThrowable(() -> {
+ api.setSerialFilter(null);
+ });
+
+ assertThat(thrown)
+ .isInstanceOf(InvocationTargetException.class)
+ .hasCauseInstanceOf(NullPointerException.class);
+ }
+}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesService.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ApiPackage.java
similarity index 63%
copy from geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesService.java
copy to geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ApiPackage.java
index 1d139ce..549911e 100644
--- a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesService.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ApiPackage.java
@@ -14,20 +14,28 @@
*/
package org.apache.geode.internal.serialization.filter;
-import java.io.IOException;
-import java.net.URL;
-import java.util.Collection;
+import static java.util.Objects.requireNonNull;
-@FunctionalInterface
-public interface SanctionedSerializablesService {
+/**
+ * The Java package containing {@code ObjectInputFilter}. On Java 8, it's {@code sun.misc}. On
+ * Java 9 or greater, it's {@code java.io}.
+ */
+enum ApiPackage {
+
+ JAVA_IO("java.io."),
+ SUN_MISC("sun.misc.");
- URL getSanctionedSerializablesURL();
+ private final String prefix;
+
+ ApiPackage(String prefix) {
+ this.prefix = prefix;
+ }
- default Class<?> getInterface() {
- return getClass();
+ String getPrefix() {
+ return prefix;
}
- default Collection<String> getSerializationAcceptlist() throws IOException {
- return SanctionedSerializables.loadClassNames(getSanctionedSerializablesURL());
+ String qualify(String className) {
+ return prefix + requireNonNull(className, "className is required");
}
}
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/JmxRmiSerialFilter.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/FilterConfiguration.java
similarity index 75%
copy from geode-core/src/main/java/org/apache/geode/management/internal/JmxRmiSerialFilter.java
copy to geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/FilterConfiguration.java
index 4a187e0..9a51a28 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/JmxRmiSerialFilter.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/FilterConfiguration.java
@@ -12,10 +12,16 @@
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
-package org.apache.geode.management.internal;
+package org.apache.geode.internal.serialization.filter;
+/**
+ * Defines operation to configure a serialization filter.
+ */
@FunctionalInterface
-public interface JmxRmiSerialFilter {
+public interface FilterConfiguration {
- void configureSerialFilter();
+ /**
+ * Returns true if serialization filter was successfully configured.
+ */
+ boolean configure();
}
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/JmxRmiSerialFilter.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/FilterPattern.java
similarity index 69%
copy from geode-core/src/main/java/org/apache/geode/management/internal/JmxRmiSerialFilter.java
copy to geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/FilterPattern.java
index 4a187e0..79135b5 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/JmxRmiSerialFilter.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/FilterPattern.java
@@ -12,10 +12,17 @@
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
-package org.apache.geode.management.internal;
+package org.apache.geode.internal.serialization.filter;
+/**
+ * Defines operation to generate a serialization filter pattern. The syntax is defined in the
+ * javadocs of the JREs {@code (sun.misc. or java.io.)ObjectInputFilter$Config#createFilter}
+ */
@FunctionalInterface
-public interface JmxRmiSerialFilter {
+public interface FilterPattern {
- void configureSerialFilter();
+ /**
+ * Returns the serialization filter pattern.
+ */
+ String pattern();
}
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/JmxRmiSerialFilter.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilter.java
similarity index 74%
copy from geode-core/src/main/java/org/apache/geode/management/internal/JmxRmiSerialFilter.java
copy to geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilter.java
index 4a187e0..87c19bd 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/JmxRmiSerialFilter.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilter.java
@@ -12,10 +12,16 @@
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
-package org.apache.geode.management.internal;
+package org.apache.geode.internal.serialization.filter;
+/**
+ * Defines operation to set this serialization filter as the JVMs process-wide filter.
+ */
@FunctionalInterface
-public interface JmxRmiSerialFilter {
+interface GlobalSerialFilter {
- void configureSerialFilter();
+ /**
+ * Sets this serialization filter as the process-wide filter.
+ */
+ void setFilter();
}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilterConfiguration.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilterConfiguration.java
new file mode 100644
index 0000000..7d312ac
--- /dev/null
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilterConfiguration.java
@@ -0,0 +1,144 @@
+/*
+ * 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.serialization.filter;
+
+import static java.util.Objects.nonNull;
+import static org.apache.commons.lang3.exception.ExceptionUtils.getRootCause;
+import static org.apache.geode.internal.serialization.filter.SanctionedSerializables.loadSanctionedClassNames;
+import static org.apache.geode.internal.serialization.filter.SanctionedSerializables.loadSanctionedSerializablesServices;
+
+import java.util.Set;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+import org.apache.logging.log4j.Logger;
+
+import org.apache.geode.logging.internal.log4j.api.LogService;
+
+/**
+ * Implementation of {@code FilterConfiguration} that delegates to an {@code ObjectInputFilterApi}.
+ */
+class GlobalSerialFilterConfiguration implements FilterConfiguration {
+
+ private static final Logger LOGGER = LogService.getLogger();
+
+ private final SerializableObjectConfig serializableObjectConfig;
+ private final FilterPatternFactory filterPatternFactory;
+ private final Supplier<Set<String>> sanctionedClassesSupplier;
+ private final Consumer<String> logger;
+ private final GlobalSerialFilterFactory globalSerialFilterFactory;
+
+ /**
+ * Constructs instance with collaborators.
+ */
+ GlobalSerialFilterConfiguration(SerializableObjectConfig serializableObjectConfig) {
+ this(serializableObjectConfig,
+ new DefaultFilterPatternFactory(),
+ () -> loadSanctionedClassNames(loadSanctionedSerializablesServices()),
+ LOGGER::info,
+ (pattern, sanctionedClasses) -> new ReflectiveFacadeGlobalSerialFilterFactory()
+ .create(pattern, sanctionedClasses));
+ }
+
+ GlobalSerialFilterConfiguration(SerializableObjectConfig serializableObjectConfig,
+ Consumer<String> logger, GlobalSerialFilterFactory globalSerialFilterFactory) {
+ this(serializableObjectConfig,
+ new DefaultFilterPatternFactory(),
+ () -> loadSanctionedClassNames(loadSanctionedSerializablesServices()),
+ logger,
+ globalSerialFilterFactory);
+ }
+
+ private GlobalSerialFilterConfiguration(
+ SerializableObjectConfig serializableObjectConfig,
+ FilterPatternFactory filterPatternFactory,
+ Supplier<Set<String>> sanctionedClassesSupplier,
+ Consumer<String> logger,
+ GlobalSerialFilterFactory globalSerialFilterFactory) {
+ this.serializableObjectConfig = serializableObjectConfig;
+ this.filterPatternFactory = filterPatternFactory;
+ this.sanctionedClassesSupplier = sanctionedClassesSupplier;
+ this.logger = logger;
+ this.globalSerialFilterFactory = globalSerialFilterFactory;
+ }
+
+ @Override
+ public boolean configure() {
+ try {
+ // enable validate-serializable-objects
+ serializableObjectConfig.setValidateSerializableObjects(true);
+
+ // create a GlobalSerialFilter
+ String pattern = filterPatternFactory
+ .create(serializableObjectConfig.getSerializableObjectFilterIfEnabled());
+ Set<String> sanctionedClasses = sanctionedClassesSupplier.get();
+ GlobalSerialFilter globalSerialFilter =
+ globalSerialFilterFactory.create(pattern, sanctionedClasses);
+
+ // invoke setFilter on GlobalSerialFilter to set the process-wide filter
+ globalSerialFilter.setFilter();
+
+ // log statement that filter is now configured
+ logger.accept("Global serial filter is now configured.");
+ return true;
+
+ } catch (UnsupportedOperationException e) {
+ if (hasRootCauseWithMessage(e, IllegalStateException.class,
+ "Serial filter can only be set once")) {
+
+ // log statement that filter was already configured
+ logger.accept("Global serial filter is already configured.");
+ }
+ return false;
+ }
+ }
+
+ private static boolean hasRootCauseWithMessage(Throwable throwable,
+ Class<? extends Throwable> causeClass, String message) {
+ Throwable rootCause = getRootCause(throwable);
+ return isInstanceOf(rootCause, causeClass) && hasMessage(rootCause, message);
+ }
+
+ private static boolean isInstanceOf(Throwable throwable, Class<? extends Throwable> causeClass) {
+ return nonNull(throwable) && throwable.getClass().equals(causeClass);
+ }
+
+ private static boolean hasMessage(Throwable throwable, String message) {
+ return nonNull(throwable) && throwable.getMessage().equalsIgnoreCase(message);
+ }
+
+ /**
+ * Creates filter pattern string including the specified optional
+ * {@code serializable-object-filter}.
+ */
+ @FunctionalInterface
+ interface FilterPatternFactory {
+
+ String create(String optionalSerializableObjectFilter);
+ }
+
+ /**
+ * Default implementation of {@code FilterPatternFactory}.
+ */
+ static class DefaultFilterPatternFactory implements FilterPatternFactory {
+
+ @Override
+ public String create(String optionalSerializableObjectFilter) {
+ return new SanctionedSerializablesFilterPattern()
+ .append(optionalSerializableObjectFilter)
+ .pattern();
+ }
+ }
+}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesService.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilterConfigurationFactory.java
similarity index 68%
copy from geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesService.java
copy to geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilterConfigurationFactory.java
index 1d139ce..6a85bfd 100644
--- a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesService.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilterConfigurationFactory.java
@@ -14,20 +14,16 @@
*/
package org.apache.geode.internal.serialization.filter;
-import java.io.IOException;
-import java.net.URL;
-import java.util.Collection;
-
+/**
+ * Defines the factory for creating a {@code FilterConfiguration} to configure a
+ * {@code GlobalSerialFilter}.
+ */
@FunctionalInterface
-public interface SanctionedSerializablesService {
-
- URL getSanctionedSerializablesURL();
-
- default Class<?> getInterface() {
- return getClass();
- }
+interface GlobalSerialFilterConfigurationFactory {
- default Collection<String> getSerializationAcceptlist() throws IOException {
- return SanctionedSerializables.loadClassNames(getSanctionedSerializablesURL());
- }
+ /**
+ * Creates a {@code FilterConfiguration} to configure a {@code GlobalSerialFilter} using the
+ * specified {@code SerializableObjectConfig}.
+ */
+ FilterConfiguration create(SerializableObjectConfig serializableObjectConfig);
}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesService.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilterFactory.java
similarity index 70%
copy from geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesService.java
copy to geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilterFactory.java
index 1d139ce..6745831 100644
--- a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesService.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilterFactory.java
@@ -14,20 +14,17 @@
*/
package org.apache.geode.internal.serialization.filter;
-import java.io.IOException;
-import java.net.URL;
import java.util.Collection;
+/**
+ * Defines the factory for creating a {@code GlobalSerialFilter}.
+ */
@FunctionalInterface
-public interface SanctionedSerializablesService {
-
- URL getSanctionedSerializablesURL();
-
- default Class<?> getInterface() {
- return getClass();
- }
+interface GlobalSerialFilterFactory {
- default Collection<String> getSerializationAcceptlist() throws IOException {
- return SanctionedSerializables.loadClassNames(getSanctionedSerializablesURL());
- }
+ /**
+ * Creates a {@code GlobalSerialFilter} using the specified filter pattern and collection of
+ * sanctioned classes. The pattern is generated by {@code FilterPattern}.
+ */
+ GlobalSerialFilter create(String pattern, Collection<String> sanctionedClasses);
}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/Java9ReflectiveObjectInputFilterApi.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/Java9ReflectiveObjectInputFilterApi.java
new file mode 100644
index 0000000..53e3652
--- /dev/null
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/Java9ReflectiveObjectInputFilterApi.java
@@ -0,0 +1,64 @@
+/*
+ * 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.serialization.filter;
+
+import java.io.ObjectInputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Java 9 or greater needs to override some API paths in {@code ReflectiveObjectInputFilterApi}.
+ */
+class Java9ReflectiveObjectInputFilterApi extends ReflectiveObjectInputFilterApi {
+
+ private final Class<?> ObjectInputStream;
+ private final Method ObjectInputStream_setObjectInputFilter;
+ private final Method ObjectInputStream_getObjectInputFilter;
+
+ /**
+ * Constructs instance for the specified {@code ApiPackage}.
+ */
+ Java9ReflectiveObjectInputFilterApi(ApiPackage apiPackage)
+ throws ClassNotFoundException, NoSuchMethodException {
+ super(apiPackage);
+ ObjectInputStream = ObjectInputStream();
+ ObjectInputStream_setObjectInputFilter = ObjectInputStream_setObjectInputFilter();
+ ObjectInputStream_getObjectInputFilter = ObjectInputStream_getObjectInputFilter();
+ }
+
+ private Class<?> ObjectInputStream() throws ClassNotFoundException {
+ return Class.forName(apiPackage.qualify("ObjectInputStream"));
+ }
+
+ private Method ObjectInputStream_setObjectInputFilter() throws NoSuchMethodException {
+ return ObjectInputStream.getDeclaredMethod("setObjectInputFilter", ObjectInputFilter);
+ }
+
+ private Method ObjectInputStream_getObjectInputFilter() throws NoSuchMethodException {
+ return ObjectInputStream.getDeclaredMethod("getObjectInputFilter");
+ }
+
+ @Override
+ public Object getObjectInputFilter(ObjectInputStream inputStream)
+ throws InvocationTargetException, IllegalAccessException {
+ return ObjectInputStream_getObjectInputFilter.invoke(inputStream);
+ }
+
+ @Override
+ public void setObjectInputFilter(ObjectInputStream inputStream, Object objectInputFilter)
+ throws InvocationTargetException, IllegalAccessException {
+ ObjectInputStream_setObjectInputFilter.invoke(inputStream, objectInputFilter);
+ }
+}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/JmxSerialFilterConfiguration.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/JmxSerialFilterConfiguration.java
new file mode 100644
index 0000000..21b0908
--- /dev/null
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/JmxSerialFilterConfiguration.java
@@ -0,0 +1,72 @@
+/*
+ * 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.serialization.filter;
+
+import static org.apache.commons.lang3.StringUtils.isBlank;
+
+import java.util.function.Consumer;
+
+import org.apache.logging.log4j.Logger;
+
+import org.apache.geode.annotations.VisibleForTesting;
+import org.apache.geode.logging.internal.log4j.api.LogService;
+
+/**
+ * Implementation of {@code FilterConfiguration} for configuring the JVMs JMX serialization filter.
+ *
+ * <p>
+ * Configure the “jmx.remote.rmi.server.serial.filter.pattern” system property if Java version is
+ * Java 9 or greater. The serial pattern will be configured to accept only standard JMX open-types.
+ * If the system property already has a non-null value, then leave it as is.
+ *
+ * <p>
+ * Configure the {@code jdk.serialFilter} system property if Java version is Java 8. The serial
+ * pattern will be configured to accept only geode sanctioned serializables and standard JMX
+ * open-types. If the system property already has a non-null value, then leave it as is.
+ */
+class JmxSerialFilterConfiguration implements FilterConfiguration {
+
+ private static final Logger LOGGER = LogService.getLogger();
+
+ private final String key;
+ private final String value;
+ private final Consumer<String> logger;
+
+ /**
+ * Constructs instance for the specified system property and filter pattern.
+ */
+ JmxSerialFilterConfiguration(String property, String pattern) {
+ this(property, pattern, LOGGER::info);
+ }
+
+ @VisibleForTesting
+ JmxSerialFilterConfiguration(String property, String pattern, Consumer<String> logger) {
+ key = property;
+ value = pattern;
+ this.logger = logger;
+ }
+
+ @Override
+ public boolean configure() {
+ if (isBlank(System.getProperty(key))) {
+ System.setProperty(key, value);
+ logger.accept("System property '" + key + "' is now configured with '" + value + "'.");
+ return true;
+ }
+
+ logger.accept("System property '" + key + "' is already configured.");
+ return false;
+ }
+}
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/JmxRmiSerialFilter.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/JmxSerialFilterConfigurationFactory.java
similarity index 70%
copy from geode-core/src/main/java/org/apache/geode/management/internal/JmxRmiSerialFilter.java
copy to geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/JmxSerialFilterConfigurationFactory.java
index 4a187e0..8062e0d 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/JmxRmiSerialFilter.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/JmxSerialFilterConfigurationFactory.java
@@ -12,10 +12,17 @@
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
-package org.apache.geode.management.internal;
+package org.apache.geode.internal.serialization.filter;
+/**
+ * Defines the factory for creating a {@code FilterConfiguration} to configure a
+ * {@code JmxSerialFilter}.
+ */
@FunctionalInterface
-public interface JmxRmiSerialFilter {
+interface JmxSerialFilterConfigurationFactory {
- void configureSerialFilter();
+ /**
+ * Creates a {@code FilterConfiguration} to configure a {@code JmxSerialFilter}.
+ */
+ FilterConfiguration create();
}
diff --git a/geode-core/src/main/java/org/apache/geode/internal/EmptyInputStreamFilter.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/NullObjectInputFilter.java
similarity index 77%
rename from geode-core/src/main/java/org/apache/geode/internal/EmptyInputStreamFilter.java
rename to geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/NullObjectInputFilter.java
index 82369a0..e25c073 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/EmptyInputStreamFilter.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/NullObjectInputFilter.java
@@ -12,13 +12,17 @@
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
-package org.apache.geode.internal;
+package org.apache.geode.internal.serialization.filter;
import java.io.ObjectInputStream;
-public class EmptyInputStreamFilter implements InputStreamFilter {
+/**
+ * Implementation of {@code ObjectInputFilter} that does nothing.
+ */
+public class NullObjectInputFilter implements ObjectInputFilter {
+
@Override
- public void setFilterOn(ObjectInputStream ois) {
+ public void setFilterOn(ObjectInputStream objectInputStream) {
// 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-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ObjectInputFilter.java
similarity index 69%
copy from geode-core/src/main/java/org/apache/geode/internal/InputStreamFilter.java
copy to geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ObjectInputFilter.java
index 43b43e6..091f8f6 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/InputStreamFilter.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ObjectInputFilter.java
@@ -12,13 +12,18 @@
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
-package org.apache.geode.internal;
+package org.apache.geode.internal.serialization.filter;
import java.io.ObjectInputStream;
-public interface InputStreamFilter {
-
- /** establish a serialization filter on the given stream */
- void setFilterOn(ObjectInputStream ois);
+/**
+ * Defines operation to set this serialization filter on an {@code ObjectInputStream}.
+ */
+@FunctionalInterface
+public interface ObjectInputFilter {
+ /**
+ * Sets this serialization filter on the specified {@code ObjectInputStream}.
+ */
+ void setFilterOn(ObjectInputStream objectInputStream);
}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ObjectInputFilterApi.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ObjectInputFilterApi.java
new file mode 100644
index 0000000..976c748
--- /dev/null
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ObjectInputFilterApi.java
@@ -0,0 +1,85 @@
+/*
+ * 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.serialization.filter;
+
+import java.io.ObjectInputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+
+/**
+ * Adapter interface that defines a layer of indirection for JDK's {@code ObjectInputFilter} class.
+ *
+ * <p>
+ * {@code ObjectInputFilter} is absent in builds of Java 8 prior to 121. It is present in later
+ * builds of Java 8 as {@code sun.misc.ObjectInputFilter} and underwent changes in Java 9 including
+ * being moved to {@code java.io.ObjectInputFilter}.
+ */
+interface ObjectInputFilterApi {
+
+ /**
+ * Get the filter for classes being deserialized on the ObjectInputStream.
+ *
+ * <p>
+ * Invokes {@code getObjectInputFilter} on {@code ObjectInputFilter$Config}.
+ */
+ Object getObjectInputFilter(ObjectInputStream inputStream)
+ throws InvocationTargetException, IllegalAccessException;
+
+ /**
+ * Set the process-wide filter if it has not already been configured or set.
+ *
+ * <p>
+ * Invokes {@code setObjectInputFilter} on {@code ObjectInputFilter$Config}
+ */
+ void setObjectInputFilter(ObjectInputStream inputStream, Object objectInputFilter)
+ throws InvocationTargetException, IllegalAccessException;
+
+ /**
+ * Returns the process-wide serialization filter or null if not configured.
+ *
+ * <p>
+ * Invokes {@code getSerialFilter} on {@code ObjectInputFilter$Config}
+ */
+ Object getSerialFilter()
+ throws InvocationTargetException, IllegalAccessException;
+
+ /**
+ * Set the process-wide filter if it has not already been configured or set.
+ *
+ * <p>
+ * Invokes {@code setSerialFilter} on {@code ObjectInputFilter$Config}
+ */
+ void setSerialFilter(Object objectInputFilter)
+ throws InvocationTargetException, IllegalAccessException;
+
+ /**
+ * Returns an ObjectInputFilter from a string of patterns. The syntax is defined in the javadocs
+ * of the JREs {@code (sun.misc. or java.io.)ObjectInputFilter$Config}.
+ *
+ * <p>
+ * Invokes {@code createFilter} on {@code ObjectInputFilter$Config}.
+ */
+ Object createFilter(String pattern)
+ throws InvocationTargetException, IllegalAccessException;
+
+ /**
+ * Returns a Java Proxy with InvocationHandler to allow Geode to inject custom behavior before
+ * invoking the methods on the JREs {@code (sun.misc. or java.io.)ObjectInputFilter$Config}.
+ */
+ Object createObjectInputFilterProxy(String pattern, Collection<String> sanctionedClasses)
+ throws InvocationTargetException, IllegalAccessException;
+
+ Class<?> getObjectInputFilterClass();
+}
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/JmxRmiSerialFilter.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ObjectInputFilterApiFactory.java
similarity index 78%
rename from geode-core/src/main/java/org/apache/geode/management/internal/JmxRmiSerialFilter.java
rename to geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ObjectInputFilterApiFactory.java
index 4a187e0..11957dd 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/JmxRmiSerialFilter.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ObjectInputFilterApiFactory.java
@@ -12,10 +12,13 @@
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
-package org.apache.geode.management.internal;
+package org.apache.geode.internal.serialization.filter;
+/**
+ * Creates an instance of {@code ObjectInputFilterApi}.
+ */
@FunctionalInterface
-public interface JmxRmiSerialFilter {
+public interface ObjectInputFilterApiFactory {
- void configureSerialFilter();
+ ObjectInputFilterApi createObjectInputFilterApi();
}
diff --git a/geode-core/src/main/java/org/apache/geode/internal/InputStreamFilter.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ObjectInputFilterFactory.java
similarity index 75%
rename from geode-core/src/main/java/org/apache/geode/internal/InputStreamFilter.java
rename to geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ObjectInputFilterFactory.java
index 43b43e6..c5fe4bf 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/InputStreamFilter.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ObjectInputFilterFactory.java
@@ -12,13 +12,13 @@
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
-package org.apache.geode.internal;
+package org.apache.geode.internal.serialization.filter;
-import java.io.ObjectInputStream;
+import java.util.Set;
-public interface InputStreamFilter {
-
- /** establish a serialization filter on the given stream */
- void setFilterOn(ObjectInputStream ois);
+@FunctionalInterface
+public interface ObjectInputFilterFactory {
+ ObjectInputFilter create(SerializableObjectConfig serializableObjectConfig,
+ Set<String> sanctionedClasses);
}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ObjectInputFilterUtils.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ObjectInputFilterUtils.java
new file mode 100644
index 0000000..6a44f49
--- /dev/null
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ObjectInputFilterUtils.java
@@ -0,0 +1,61 @@
+/*
+ * 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.serialization.filter;
+
+import java.util.function.Function;
+
+import org.apache.geode.annotations.VisibleForTesting;
+import org.apache.geode.internal.lang.utils.ClassUtils;
+
+/**
+ * Utility methods for {@code ObjectInputFilter}.
+ */
+public class ObjectInputFilterUtils {
+
+ private static final String UNSUPPORTED_MESSAGE = "ObjectInputFilter is not available.";
+
+ /**
+ * Returns true if this JVM supports {@code ObjectInputFilter}.
+ */
+ public static boolean supportsObjectInputFilter() {
+ return supportsObjectInputFilter(ClassUtils::isClassAvailable);
+ }
+
+ static void throwUnsupportedOperationException() {
+ throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE, null);
+ }
+
+ static void throwUnsupportedOperationException(Throwable cause) {
+ throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE, cause);
+ }
+
+ static void throwUnsupportedOperationException(String message) {
+ throw new UnsupportedOperationException(message, null);
+ }
+
+ static void throwUnsupportedOperationException(String message, Throwable cause) {
+ throw new UnsupportedOperationException(message, cause);
+ }
+
+ @VisibleForTesting
+ static boolean supportsObjectInputFilter(Function<String, Boolean> isClassAvailable) {
+ return isClassAvailable.apply("sun.misc.ObjectInputFilter") ||
+ isClassAvailable.apply("java.io.ObjectInputFilter");
+ }
+
+ private ObjectInputFilterUtils() {
+ // do not instantiate
+ }
+}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/OpenMBeanFilterPattern.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/OpenMBeanFilterPattern.java
new file mode 100644
index 0000000..14aa037
--- /dev/null
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/OpenMBeanFilterPattern.java
@@ -0,0 +1,68 @@
+/*
+ * 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.serialization.filter;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.rmi.MarshalledObject;
+import java.util.StringJoiner;
+
+import javax.management.ObjectName;
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.TabularType;
+
+/**
+ * Defines a serial filter pattern that accepts all open MBean data types and rejects everything
+ * not included in the pattern.
+ */
+public class OpenMBeanFilterPattern implements FilterPattern {
+
+ @Override
+ public String pattern() {
+ // note: java.util.* may also be needed
+ return new StringJoiner(";")
+
+ // accept all open MBean data types
+ .add(Boolean.class.getName())
+ .add(Byte.class.getName())
+ .add(Character.class.getName())
+ .add(Short.class.getName())
+ .add(Integer.class.getName())
+ .add(Long.class.getName())
+ .add(Float.class.getName())
+ .add(Double.class.getName())
+ .add(String.class.getName())
+ .add(BigInteger.class.getName())
+ .add(BigDecimal.class.getName())
+ .add(ObjectName.class.getName())
+ .add(OpenType.class.getName())
+ .add(CompositeData.class.getName())
+ .add(TabularData.class.getName())
+ .add(SimpleType.class.getName())
+ .add(CompositeType.class.getName())
+ .add(TabularType.class.getName())
+ .add(ArrayType.class.getName())
+ .add(MarshalledObject.class.getName())
+
+ // reject all others
+ .add("!*")
+ .toString();
+ }
+}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilter.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilter.java
new file mode 100644
index 0000000..4a1152d
--- /dev/null
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilter.java
@@ -0,0 +1,71 @@
+/*
+ * 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.serialization.filter;
+
+import static java.util.Collections.unmodifiableCollection;
+import static org.apache.geode.internal.serialization.filter.ObjectInputFilterUtils.throwUnsupportedOperationException;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+
+/**
+ * Implementation of {@code GlobalSerialFilter} that delegates to {@code ObjectInputFilterApi} to
+ * maintain independence from the JRE version.
+ */
+class ReflectiveFacadeGlobalSerialFilter implements GlobalSerialFilter {
+
+ private final ObjectInputFilterApi api;
+ private final String pattern;
+ private final Collection<String> sanctionedClasses;
+
+ /**
+ * Constructs instance with the specified collaborators.
+ */
+ ReflectiveFacadeGlobalSerialFilter(ObjectInputFilterApi api, String pattern,
+ Collection<String> sanctionedClasses) {
+ this.api = api;
+ this.pattern = pattern;
+ this.sanctionedClasses = unmodifiableCollection(sanctionedClasses);
+ }
+
+ /**
+ * Invokes interface-defined operation to set this as the process-wide filter.
+ */
+ @Override
+ public void setFilter() {
+ try {
+ // create the ObjectInputFilter to set as the global serial filter
+ Object objectInputFilter = api.createObjectInputFilterProxy(pattern, sanctionedClasses);
+
+ // set the global serial filter
+ api.setSerialFilter(objectInputFilter);
+
+ } catch (IllegalAccessException | InvocationTargetException e) {
+ throwUnsupportedOperationException(
+ "Geode was unable to configure a global serialization filter",
+ e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder(getClass().getSimpleName())
+ .append('{')
+ .append("api=").append(api)
+ .append(", pattern='").append(pattern).append('\'')
+ .append('}')
+ .toString();
+ }
+}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesService.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilterFactory.java
similarity index 50%
copy from geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesService.java
copy to geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilterFactory.java
index 1d139ce..022c766 100644
--- a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesService.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilterFactory.java
@@ -14,20 +14,31 @@
*/
package org.apache.geode.internal.serialization.filter;
-import java.io.IOException;
-import java.net.URL;
+import static java.util.Objects.requireNonNull;
+
import java.util.Collection;
-@FunctionalInterface
-public interface SanctionedSerializablesService {
+import org.apache.geode.annotations.VisibleForTesting;
+
+/**
+ * Creates an instance of {@code GlobalSerialFilter} that delegates to {@code ObjectInputFilterApi}
+ * to maintain independence from the JRE version.
+ */
+class ReflectiveFacadeGlobalSerialFilterFactory implements GlobalSerialFilterFactory {
- URL getSanctionedSerializablesURL();
+ private final ObjectInputFilterApi api;
+
+ ReflectiveFacadeGlobalSerialFilterFactory() {
+ this(new ReflectiveObjectInputFilterApiFactory().createObjectInputFilterApi());
+ }
- default Class<?> getInterface() {
- return getClass();
+ @VisibleForTesting
+ ReflectiveFacadeGlobalSerialFilterFactory(ObjectInputFilterApi api) {
+ this.api = requireNonNull(api, "ObjectInputFilterApi is required");
}
- default Collection<String> getSerializationAcceptlist() throws IOException {
- return SanctionedSerializables.loadClassNames(getSanctionedSerializablesURL());
+ @Override
+ public GlobalSerialFilter create(String pattern, Collection<String> sanctionedClasses) {
+ return new ReflectiveFacadeGlobalSerialFilter(api, pattern, sanctionedClasses);
}
}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeObjectInputFilter.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeObjectInputFilter.java
new file mode 100644
index 0000000..08bae44
--- /dev/null
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeObjectInputFilter.java
@@ -0,0 +1,78 @@
+/*
+ * 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.serialization.filter;
+
+import static java.util.Collections.unmodifiableCollection;
+import static org.apache.geode.internal.serialization.filter.ObjectInputFilterUtils.throwUnsupportedOperationException;
+
+import java.io.ObjectInputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+
+/**
+ * Implementation of {@code ObjectInputFilter} that delegates to {@code ObjectInputFilterApi} to
+ * maintain independence from the JRE version.
+ */
+class ReflectiveFacadeObjectInputFilter implements ObjectInputFilter {
+
+ private final ObjectInputFilterApi api;
+ private final String pattern;
+ private final Collection<String> sanctionedClasses;
+
+ /**
+ * Constructs instance with the specified collaborators.
+ */
+ ReflectiveFacadeObjectInputFilter(ObjectInputFilterApi api, String pattern,
+ Collection<String> sanctionedClasses) {
+ this.pattern = pattern;
+ this.sanctionedClasses = unmodifiableCollection(sanctionedClasses);
+ this.api = api;
+ }
+
+ /**
+ * Invokes interface-defined operation to set this serialization filter on the specified target
+ * {@code ObjectInputStream}.
+ */
+ @Override
+ public void setFilterOn(ObjectInputStream objectInputStream) {
+ try {
+ // create the ObjectInputFilter to set as the global serial filter
+ Object objectInputFilter = api.createObjectInputFilterProxy(pattern, sanctionedClasses);
+
+ // set the global serial filter
+ api.setObjectInputFilter(objectInputStream, objectInputFilter);
+
+ } catch (IllegalAccessException | InvocationTargetException e) {
+ throwUnsupportedOperationException(
+ "Geode was unable to configure a serialization filter on input stream '"
+ + objectInputStream.hashCode() + "'",
+ e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder(getClass().getSimpleName())
+ .append('{')
+ .append("api=").append(api)
+ .append(", pattern='").append(pattern).append('\'')
+ .append('}')
+ .toString();
+ }
+
+ ObjectInputFilterApi getObjectInputFilterApi() {
+ return api;
+ }
+}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeObjectInputFilterFactory.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeObjectInputFilterFactory.java
new file mode 100644
index 0000000..a38416c
--- /dev/null
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeObjectInputFilterFactory.java
@@ -0,0 +1,61 @@
+/*
+ * 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.serialization.filter;
+
+import static java.util.Objects.requireNonNull;
+import static org.apache.geode.internal.serialization.filter.ObjectInputFilterUtils.supportsObjectInputFilter;
+import static org.apache.geode.internal.serialization.filter.ObjectInputFilterUtils.throwUnsupportedOperationException;
+
+import java.util.Set;
+
+/**
+ * Creates an instance of {@code ObjectInputFilter} that delegates to {@code ObjectInputFilterApi}
+ * to maintain independence from the JRE version.
+ */
+public class ReflectiveFacadeObjectInputFilterFactory implements ObjectInputFilterFactory {
+
+ private static final String UNSUPPORTED_MESSAGE =
+ "A serialization filter has been specified but this version of Java does not support serialization filters - ObjectInputFilter is not available";
+
+ private final ObjectInputFilterApi api;
+
+ public ReflectiveFacadeObjectInputFilterFactory() {
+ this(new ReflectiveObjectInputFilterApiFactory().createObjectInputFilterApi());
+ }
+
+ private ReflectiveFacadeObjectInputFilterFactory(ObjectInputFilterApi api) {
+ this.api = requireNonNull(api, "ObjectInputFilterApi is required");
+ }
+
+ @Override
+ public ObjectInputFilter create(SerializableObjectConfig config, Set<String> sanctionedClasses) {
+ if (config.getValidateSerializableObjects()) {
+ requireObjectInputFilter();
+
+ String pattern = new SanctionedSerializablesFilterPattern()
+ .append(config.getSerializableObjectFilter())
+ .pattern();
+
+ return new ReflectiveFacadeObjectInputFilter(api, pattern, sanctionedClasses);
+ }
+ return new NullObjectInputFilter();
+ }
+
+ public static void requireObjectInputFilter() {
+ if (!supportsObjectInputFilter()) {
+ throwUnsupportedOperationException(UNSUPPORTED_MESSAGE);
+ }
+ }
+}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApi.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApi.java
new file mode 100644
index 0000000..10c3aad
--- /dev/null
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApi.java
@@ -0,0 +1,269 @@
+/*
+ * 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.serialization.filter;
+
+import java.io.InvalidClassException;
+import java.io.ObjectInputStream;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Collection;
+
+import org.apache.logging.log4j.Logger;
+
+import org.apache.geode.annotations.VisibleForTesting;
+import org.apache.geode.logging.internal.log4j.api.LogService;
+
+/**
+ * Implementation of {@code ObjectInputFilterApi} that uses reflection and a dynamic proxy to wrap
+ * the JREs ObjectInputFilter API in both Java 8 and Java 9 or greater.
+ */
+public class ReflectiveObjectInputFilterApi implements ObjectInputFilterApi {
+
+ private static final Logger logger = LogService.getLogger();
+
+ protected final ApiPackage apiPackage;
+
+ // api.package.ObjectInputFilter
+ protected final Class<?> ObjectInputFilter;
+ private final Method ObjectInputFilter_checkInput;
+ private final Object ObjectInputFilter_Status_ALLOWED;
+ private final Object ObjectInputFilter_Status_REJECTED;
+
+ // api.package.ObjectInputFilter$Config
+ private final Class<?> ObjectInputFilter_Config;
+ private final Method ObjectInputFilter_Config_createFilter;
+ private final Method ObjectInputFilter_Config_getObjectInputFilter;
+ private final Method ObjectInputFilter_Config_setObjectInputFilter;
+ private final Method ObjectInputFilter_Config_getSerialFilter;
+ private final Method ObjectInputFilter_Config_setSerialFilter;
+
+ // api.package.ObjectInputFilter$FilterInfo
+ private final Class<?> ObjectInputFilter_FilterInfo;
+ private final Method ObjectInputFilter_FilterInfo_serialClass;
+
+ /**
+ * Use reflection to look up the classes and methods for the API.
+ */
+ public ReflectiveObjectInputFilterApi(ApiPackage apiPackage)
+ throws ClassNotFoundException, NoSuchMethodException {
+ this.apiPackage = apiPackage;
+
+ ObjectInputFilter = ObjectInputFilter();
+ ObjectInputFilter_Config = ObjectInputFilter_Config();
+ ObjectInputFilter_FilterInfo = ObjectInputFilter_FilterInfo();
+ Class<?> ObjectInputFilter_Status = ObjectInputFilter_Status();
+ ObjectInputFilter_Status_ALLOWED = ObjectInputFilter_Status.getEnumConstants()[1];
+ ObjectInputFilter_Status_REJECTED = ObjectInputFilter_Status.getEnumConstants()[2];
+
+ // Status enum includes UNDECIDED, ALLOWED, and REJECTED
+ if (!ObjectInputFilter_Status_ALLOWED.toString().equals("ALLOWED")
+ || !ObjectInputFilter_Status_REJECTED.toString().equals("REJECTED")) {
+ throw new UnsupportedOperationException(
+ "ObjectInputFilter$Status enumeration in this JDK is not as expected");
+ }
+
+ ObjectInputFilter_checkInput = ObjectInputFilter_checkInput();
+
+ ObjectInputFilter_Config_createFilter = ObjectInputFilter_Config_createFilter();
+ if (apiPackage == ApiPackage.SUN_MISC) {
+ ObjectInputFilter_Config_getObjectInputFilter =
+ ObjectInputFilter_Config_getObjectInputFilter();
+ ObjectInputFilter_Config_setObjectInputFilter =
+ ObjectInputFilter_Config_setObjectInputFilter();
+ } else {
+ ObjectInputFilter_Config_getObjectInputFilter = null;
+ ObjectInputFilter_Config_setObjectInputFilter = null;
+ }
+ ObjectInputFilter_Config_getSerialFilter = ObjectInputFilter_Config_getSerialFilter();
+ ObjectInputFilter_Config_setSerialFilter = ObjectInputFilter_Config_setSerialFilter();
+
+ ObjectInputFilter_FilterInfo_serialClass = ObjectInputFilter_FilterInfo_serialClass();
+ }
+
+ @Override
+ public Object getObjectInputFilter(ObjectInputStream inputStream)
+ throws InvocationTargetException, IllegalAccessException {
+ return ObjectInputFilter_Config_getObjectInputFilter.invoke(ObjectInputFilter_Config,
+ inputStream);
+ }
+
+ @Override
+ public void setObjectInputFilter(ObjectInputStream inputStream, Object objectInputFilter)
+ throws InvocationTargetException, IllegalAccessException {
+ ObjectInputFilter_Config_setObjectInputFilter.invoke(ObjectInputFilter_Config, inputStream,
+ objectInputFilter);
+ }
+
+ @Override
+ public Object getSerialFilter()
+ throws InvocationTargetException, IllegalAccessException {
+ return ObjectInputFilter_Config_getSerialFilter.invoke(ObjectInputFilter_Config);
+ }
+
+ @Override
+ public void setSerialFilter(Object objectInputFilter)
+ throws InvocationTargetException, IllegalAccessException {
+ ObjectInputFilter_Config_setSerialFilter.invoke(ObjectInputFilter_Config, objectInputFilter);
+ }
+
+ @Override
+ public Object createFilter(String pattern)
+ throws InvocationTargetException, IllegalAccessException {
+ return ObjectInputFilter_Config_createFilter.invoke(null, pattern);
+ }
+
+ @Override
+ public Object createObjectInputFilterProxy(String pattern, Collection<String> sanctionedClasses)
+ throws InvocationTargetException, IllegalAccessException {
+ Object objectInputFilter =
+ ObjectInputFilter_Config_createFilter.invoke(ObjectInputFilter_Config, pattern);
+
+ /*
+ * Members first connect to each other with sockets that are restricted to the Geode sanctioned
+ * serializables which sets the Filter on that stream (an ObjectInputStream can only set a
+ * Filter once in its lifetime). Geode then loads up its ConfigurationProperties and needs
+ * to widen the Filter to include the User's sanctioned serializables if they provided any
+ * (serializable-object-filter).
+ *
+ * Wrap the Filter in a dynamic Proxy to provide an InvocationHandler in order to decorate
+ * before-calls to checkInput (checks the class against the filter). This allows us to
+ * effectively override the call to widen the filter to include the User's addition to the set
+ * of sanctioned serializables.
+ */
+ InvocationHandler invocationHandler = (proxy, method, args) -> {
+ if (!"checkInput".equals(method.getName())) {
+ throw new UnsupportedOperationException(
+ "ObjectInputFilter." + method.getName() + " is not implemented");
+ }
+
+ // fetch the class of the serialized instance
+ Object objectInputFilter_filterInfo = args[0];
+ Class<?> serialClass =
+ (Class<?>) ObjectInputFilter_FilterInfo_serialClass.invoke(objectInputFilter_filterInfo);
+ if (serialClass == null) { // no class to check, so nothing to accept-list
+ return ObjectInputFilter_checkInput.invoke(objectInputFilter, objectInputFilter_filterInfo);
+ }
+
+ // check sanctionedClasses to determine if the name of the class is ALLOWED
+ String serialClassName = serialClass.getName();
+ if (serialClass.isArray()) {
+ serialClassName = serialClass.getComponentType().getName();
+ }
+ if (sanctionedClasses.contains(serialClassName)) {
+ return ObjectInputFilter_Status_ALLOWED;
+ }
+
+ // check the filter to determine if the class is ALLOWED
+ Object objectInputFilter_Status =
+ ObjectInputFilter_checkInput.invoke(objectInputFilter, objectInputFilter_filterInfo);
+ if (objectInputFilter_Status == ObjectInputFilter_Status_REJECTED) {
+ logger.fatal("Serialization filter is rejecting class {}", serialClassName,
+ new InvalidClassException(serialClassName));
+ }
+ return objectInputFilter_Status;
+ };
+
+ // wrap the filter within a proxy to inject the above invocation handler
+ return Proxy.newProxyInstance(
+ ObjectInputFilter.getClassLoader(),
+ new Class[] {ObjectInputFilter},
+ invocationHandler);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("ReflectiveObjectInputFilterApi{");
+ sb.append("apiPackage='").append(apiPackage).append('\'');
+ sb.append('}');
+ return sb.toString();
+ }
+
+ @Override
+ public Class<?> getObjectInputFilterClass() {
+ return ObjectInputFilter;
+ }
+
+ @VisibleForTesting
+ public ApiPackage getApiPackage() {
+ return apiPackage;
+ }
+
+ /** {@code public interface ObjectInputFilter} */
+ private Class<?> ObjectInputFilter() throws ClassNotFoundException {
+ return Class.forName(apiPackage.qualify("ObjectInputFilter"));
+ }
+
+ /** {@code public Status checkInput(FilterInfo filterInfo)} */
+ private Method ObjectInputFilter_checkInput()
+ throws NoSuchMethodException {
+ return ObjectInputFilter
+ .getDeclaredMethod("checkInput", ObjectInputFilter_FilterInfo);
+ }
+
+ /** {@code public enum Status} */
+ private Class<?> ObjectInputFilter_Status() throws ClassNotFoundException {
+ return Class.forName(apiPackage.qualify("ObjectInputFilter$Status"));
+ }
+
+ /** {@code public final class Config} */
+ private Class<?> ObjectInputFilter_Config() throws ClassNotFoundException {
+ return Class.forName(apiPackage.qualify("ObjectInputFilter$Config"));
+ }
+
+ /** {@code public static ObjectInputFilter createFilter(String pattern)} */
+ private Method ObjectInputFilter_Config_createFilter()
+ throws NoSuchMethodException {
+ return ObjectInputFilter_Config.getDeclaredMethod("createFilter", String.class);
+ }
+
+ /** {@code public static ObjectInputFilter getSerialFilter()} */
+ private Method ObjectInputFilter_Config_getObjectInputFilter()
+ throws NoSuchMethodException {
+ return ObjectInputFilter_Config.getDeclaredMethod("getObjectInputFilter",
+ ObjectInputStream.class);
+ }
+
+ /** {@code public static setSerialFilter(ObjectInputFilter filter)} */
+ private Method ObjectInputFilter_Config_setObjectInputFilter()
+ throws NoSuchMethodException {
+ return ObjectInputFilter_Config.getDeclaredMethod("setObjectInputFilter",
+ ObjectInputStream.class, ObjectInputFilter);
+ }
+
+ /** {@code public static ObjectInputFilter getSerialFilter()} */
+ private Method ObjectInputFilter_Config_getSerialFilter()
+ throws NoSuchMethodException {
+ return ObjectInputFilter_Config.getDeclaredMethod("getSerialFilter");
+ }
+
+ /** {@code public static setSerialFilter(ObjectInputFilter filter)} */
+ private Method ObjectInputFilter_Config_setSerialFilter()
+ throws NoSuchMethodException {
+ return ObjectInputFilter_Config.getDeclaredMethod("setSerialFilter", ObjectInputFilter);
+ }
+
+ /** {@code public interface FilterInfo} */
+ private Class<?> ObjectInputFilter_FilterInfo() throws ClassNotFoundException {
+ return Class.forName(apiPackage.qualify("ObjectInputFilter$FilterInfo"));
+ }
+
+ /** {@code public Class<?> serialClass()} */
+ private Method ObjectInputFilter_FilterInfo_serialClass()
+ throws NoSuchMethodException {
+ return ObjectInputFilter_FilterInfo.getDeclaredMethod("serialClass");
+ }
+}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiFactory.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiFactory.java
new file mode 100644
index 0000000..d50c15d
--- /dev/null
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiFactory.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.geode.internal.serialization.filter;
+
+import static org.apache.commons.lang3.JavaVersion.JAVA_1_8;
+import static org.apache.commons.lang3.JavaVersion.JAVA_9;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
+import static org.apache.geode.internal.serialization.filter.ApiPackage.JAVA_IO;
+import static org.apache.geode.internal.serialization.filter.ApiPackage.SUN_MISC;
+import static org.apache.geode.internal.serialization.filter.ObjectInputFilterUtils.throwUnsupportedOperationException;
+
+/**
+ * Implementation of {@code ObjectInputFilterApiFactory} that creates a reflection based
+ * {@code ObjectInputFilterApi}.
+ */
+public class ReflectiveObjectInputFilterApiFactory implements ObjectInputFilterApiFactory {
+
+ @Override
+ public ObjectInputFilterApi createObjectInputFilterApi() {
+ try {
+ if (isJavaVersionAtLeast(JAVA_9)) {
+ return new Java9ReflectiveObjectInputFilterApi(JAVA_IO);
+ }
+ if (isJavaVersionAtLeast(JAVA_1_8)) {
+ return new ReflectiveObjectInputFilterApi(SUN_MISC);
+ }
+ } catch (ClassNotFoundException | NoSuchMethodException e) {
+ throwUnsupportedOperationException(e);
+ }
+ throwUnsupportedOperationException();
+ return null; // unreachable
+ }
+}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializables.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializables.java
index a493c58..6c68010 100644
--- a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializables.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializables.java
@@ -32,14 +32,13 @@ import org.apache.logging.log4j.Logger;
import org.apache.geode.logging.internal.log4j.api.LogService;
+/**
+ * Loads {@code SanctionedSerializablesService}s and sanctioned class data.
+ */
public class SanctionedSerializables {
private static final Logger logger = LogService.getLogger();
- private SanctionedSerializables() {
- // do not instantiate
- }
-
/**
* Loads all SanctionedSerializablesServices on the classpath.
*/
@@ -57,7 +56,7 @@ public class SanctionedSerializables {
* Loads class names of sanctioned serializables from a resource. Caller will add these to the
* serialization filter acceptlist.
*/
- public static Collection<String> loadClassNames(URL sanctionedSerializables) throws IOException {
+ static Collection<String> loadClassNames(URL sanctionedSerializables) throws IOException {
if (sanctionedSerializables == null) {
return emptyList();
}
@@ -93,4 +92,8 @@ public class SanctionedSerializables {
}
return sanctionedClasses;
}
+
+ private SanctionedSerializables() {
+ // do not instantiate
+ }
}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesFilterPattern.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesFilterPattern.java
new file mode 100644
index 0000000..b40ef0e
--- /dev/null
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesFilterPattern.java
@@ -0,0 +1,111 @@
+/*
+ * 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.serialization.filter;
+
+import java.util.StringJoiner;
+
+/**
+ * This list contains classes that Geode's classes subclass, such as antlr AST classes which are
+ * used by our Object Query Language. It also contains certain classes that are DataSerializable
+ * but end up being serialized as part of other serializable objects. VersionedObjectList, for
+ * instance, is serialized as part of a partial putAll exception object.
+ *
+ * <p>
+ * Do not java-serialize objects that Geode does not have complete control over. This leaves us
+ * open to security attacks such as Gadget Chains and compromises the ability to do a rolling
+ * upgrade from one version of Geode to the next.
+ *
+ * <p>
+ * In general, you shouldn't use java serialization, and you should implement
+ * DataSerializableFixedID for internal Geode objects. This gives you better control over
+ * backward-compatibility.
+ *
+ * <p>
+ * Do not add to this list unless absolutely necessary. Instead, put your classes either in the
+ * sanctionedSerializables file for your module or in its excludedClasses file. Run
+ * AnalyzeSerializables to generate the content for the file.
+ */
+public class SanctionedSerializablesFilterPattern implements FilterPattern {
+
+ private final StringJoiner stringJoiner = dependenciesPattern();
+
+ @Override
+ public String pattern() {
+ return new StringJoiner(";")
+ .merge(stringJoiner)
+
+ // reject all others
+ .add("!*")
+
+ .toString();
+ }
+
+ /**
+ * Used to append the user specified serializable-object-filter
+ */
+ public SanctionedSerializablesFilterPattern append(CharSequence chars) {
+ stringJoiner.add(chars);
+ return this;
+ }
+
+ private static StringJoiner dependenciesPattern() {
+ return new StringJoiner(";")
+
+ // accept all open MBean data types
+ .add("java.**")
+ .add("javax.management.**")
+
+ // used for some old enums
+ .add("javax.print.attribute.EnumSyntax")
+
+ // query AST objects
+ .add("antlr.**")
+
+ // old Admin API
+ .add("org.apache.commons.modeler.AttributeInfo")
+ .add("org.apache.commons.modeler.FeatureInfo")
+ .add("org.apache.commons.modeler.ManagedBean")
+ .add("org.apache.geode.distributed.internal.DistributionConfigSnapshot")
+ .add("org.apache.geode.distributed.internal.RuntimeDistributionConfigImpl")
+ .add("org.apache.geode.distributed.internal.DistributionConfigImpl")
+
+ // WindowedExportFunction, RegionSnapshotService
+ .add("org.apache.geode.distributed.internal.membership.InternalDistributedMember")
+
+ // putAll
+ .add("org.apache.geode.internal.cache.persistence.PersistentMemberID")
+ .add("org.apache.geode.internal.cache.persistence.DiskStoreID")
+ .add("org.apache.geode.internal.cache.tier.sockets.VersionedObjectList")
+
+ // security services
+ .add("org.apache.shiro.**")
+
+ // export logs
+ .add("org.apache.logging.log4j.Level")
+ .add("org.apache.logging.log4j.spi.StandardLevel")
+
+ // jar deployment
+ .add("com.sun.proxy.$Proxy*")
+ .add("com.healthmarketscience.rmiio.RemoteInputStream")
+ .add("javax.rmi.ssl.SslRMIClientSocketFactory")
+ .add("javax.net.ssl.SSLHandshakeException")
+ .add("javax.net.ssl.SSLException")
+ .add("sun.security.validator.ValidatorException")
+ .add("sun.security.provider.certpath.SunCertPathBuilderException")
+
+ // geode-modules
+ .add("org.apache.geode.modules.util.SessionCustomExpiry");
+ }
+}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesService.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesService.java
index 1d139ce..9306934 100644
--- a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesService.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesService.java
@@ -18,9 +18,15 @@ import java.io.IOException;
import java.net.URL;
import java.util.Collection;
+/**
+ * Service interface to define a module's sanctioned serializables.
+ */
@FunctionalInterface
public interface SanctionedSerializablesService {
+ /**
+ * Returns a URL for loading a module's collection of sanctioned serializables.
+ */
URL getSanctionedSerializablesURL();
default Class<?> getInterface() {
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesService.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SerializableObjectConfig.java
similarity index 67%
copy from geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesService.java
copy to geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SerializableObjectConfig.java
index 1d139ce..40ab638 100644
--- a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesService.java
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SerializableObjectConfig.java
@@ -14,20 +14,18 @@
*/
package org.apache.geode.internal.serialization.filter;
-import java.io.IOException;
-import java.net.URL;
-import java.util.Collection;
+/**
+ * Defines the configuration properties used by serialization filter in Geode.
+ */
+public interface SerializableObjectConfig {
-@FunctionalInterface
-public interface SanctionedSerializablesService {
+ default String getSerializableObjectFilterIfEnabled() {
+ return getValidateSerializableObjects() ? getSerializableObjectFilter() : null;
+ }
- URL getSanctionedSerializablesURL();
+ boolean getValidateSerializableObjects();
- default Class<?> getInterface() {
- return getClass();
- }
+ void setValidateSerializableObjects(boolean value);
- default Collection<String> getSerializationAcceptlist() throws IOException {
- return SanctionedSerializables.loadClassNames(getSanctionedSerializablesURL());
- }
+ String getSerializableObjectFilter();
}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SystemPropertyGlobalSerialFilterConfigurationFactory.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SystemPropertyGlobalSerialFilterConfigurationFactory.java
new file mode 100644
index 0000000..4c592d3
--- /dev/null
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SystemPropertyGlobalSerialFilterConfigurationFactory.java
@@ -0,0 +1,52 @@
+/*
+ * 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.serialization.filter;
+
+import static org.apache.commons.lang3.StringUtils.isBlank;
+
+import org.apache.geode.internal.lang.SystemProperty;
+
+/**
+ * Creates an instance of {@code GlobalSerialFilterConfiguration} that is enabled only if certain
+ * conditions are met. The system property {@code jdk.serialFilter} must be blank, and the system
+ * property {@code geode.enableGlobalSerialFilter} must be set to true.
+ */
+public class SystemPropertyGlobalSerialFilterConfigurationFactory
+ implements GlobalSerialFilterConfigurationFactory {
+
+ private final boolean enabled;
+
+ public SystemPropertyGlobalSerialFilterConfigurationFactory() {
+ // enable GlobalSerialFilter only under these conditions:
+ // (1) jdk.serialFilter must be blank
+ // (2) geode.enableGlobalSerialFilter must be set "true"
+ this(isBlank(System.getProperty("jdk.serialFilter")) &&
+ SystemProperty
+ .getProductBooleanProperty("enableGlobalSerialFilter")
+ .orElse(false));
+ }
+
+ private SystemPropertyGlobalSerialFilterConfigurationFactory(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ @Override
+ public FilterConfiguration create(SerializableObjectConfig serializableObjectConfig) {
+ if (enabled) {
+ return new GlobalSerialFilterConfiguration(serializableObjectConfig);
+ }
+ return () -> false;
+ }
+}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SystemPropertyJmxSerialFilterConfigurationFactory.java b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SystemPropertyJmxSerialFilterConfigurationFactory.java
new file mode 100644
index 0000000..6f9fbd7
--- /dev/null
+++ b/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SystemPropertyJmxSerialFilterConfigurationFactory.java
@@ -0,0 +1,55 @@
+/*
+ * 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.serialization.filter;
+
+import static org.apache.commons.lang3.JavaVersion.JAVA_9;
+import static org.apache.commons.lang3.StringUtils.isBlank;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
+
+import org.apache.geode.annotations.VisibleForTesting;
+
+/**
+ * Creates an instance of {@code JmxSerialFilterConfiguration} that is enabled only if certain
+ * conditions are met. The system property {@code jmx.remote.rmi.server.serial.filter.pattern} must
+ * be blank, and the JRE must be Java 9 or greater.
+ */
+public class SystemPropertyJmxSerialFilterConfigurationFactory
+ implements JmxSerialFilterConfigurationFactory {
+
+ private static final String PROPERTY_NAME = "jmx.remote.rmi.server.serial.filter.pattern";
+
+ private final boolean enabled;
+ private final String pattern;
+
+ public SystemPropertyJmxSerialFilterConfigurationFactory() {
+ // JmxSerialFilter requires Java 9 or greater
+ this(isJavaVersionAtLeast(JAVA_9) && isBlank(System.getProperty(PROPERTY_NAME)),
+ new OpenMBeanFilterPattern().pattern());
+ }
+
+ @VisibleForTesting
+ SystemPropertyJmxSerialFilterConfigurationFactory(boolean enabled, String pattern) {
+ this.enabled = enabled;
+ this.pattern = pattern;
+ }
+
+ @Override
+ public FilterConfiguration create() {
+ if (enabled) {
+ return new JmxSerialFilterConfiguration(PROPERTY_NAME, pattern);
+ }
+ return () -> false;
+ }
+}
diff --git a/geode-serialization/src/main/resources/org/apache/geode/internal/serialization/sanctioned-geode-serialization-serializables.txt b/geode-serialization/src/main/resources/org/apache/geode/internal/serialization/sanctioned-geode-serialization-serializables.txt
index 4e9c598..3133970 100644
--- a/geode-serialization/src/main/resources/org/apache/geode/internal/serialization/sanctioned-geode-serialization-serializables.txt
+++ b/geode-serialization/src/main/resources/org/apache/geode/internal/serialization/sanctioned-geode-serialization-serializables.txt
@@ -1,3 +1,4 @@
org/apache/geode/internal/serialization/DSCODE,false,value:byte
org/apache/geode/internal/serialization/DSFIDNotFoundException,true,130596009484324655,dsfid:int,versionOrdinal:short
org/apache/geode/internal/serialization/UnsupportedSerializationVersionException,true,3572445857994216007
+org/apache/geode/internal/serialization/filter/ApiPackage,false,prefix:java/lang/String
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/SerializationDependenciesTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/SerializationDependenciesTest.java
index 3806564..4dfb4c5 100644
--- a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/SerializationDependenciesTest.java
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/SerializationDependenciesTest.java
@@ -43,7 +43,7 @@ public class SerializationDependenciesTest {
resideInAPackage("org.apache.geode.internal.serialization..")
.or(not(resideInAPackage("org.apache.geode..")))
.or(resideInAPackage("org.apache.geode.annotations.."))
- .or(resideInAPackage("org.apache.geode.internal.lang.utils.."))
+ .or(resideInAPackage("org.apache.geode.internal.lang.."))
.or(resideInAPackage("org.apache.geode.logging.internal.log4j.api.."))
.or(resideInAPackage("org.apache.geode.test..")));
}
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ApiPackageTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ApiPackageTest.java
new file mode 100644
index 0000000..19c159b
--- /dev/null
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ApiPackageTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.serialization.filter;
+
+import static org.apache.geode.internal.serialization.filter.ApiPackage.JAVA_IO;
+import static org.apache.geode.internal.serialization.filter.ApiPackage.SUN_MISC;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.catchThrowable;
+
+import org.junit.Test;
+
+public class ApiPackageTest {
+
+ @Test
+ public void JAVA_IO_prefix() {
+ assertThat(JAVA_IO.getPrefix()).isEqualTo("java.io.");
+ }
+
+ @Test
+ public void SUN_MISC_prefix() {
+ assertThat(SUN_MISC.getPrefix()).isEqualTo("sun.misc.");
+ }
+
+ @Test
+ public void qualifyEmptyStringEqualsPrefix() {
+ assertThat(JAVA_IO.qualify("")).isEqualTo(JAVA_IO.getPrefix());
+ }
+
+ @Test
+ public void qualifyNullStringThrowsNullPointerException() {
+ Throwable thrown = catchThrowable(() -> {
+ JAVA_IO.qualify(null);
+ });
+
+ assertThat(thrown)
+ .isInstanceOf(NullPointerException.class)
+ .hasMessage("className is required");
+ }
+
+ @Test
+ public void qualifyReturnsPrefixedClassName() {
+ ApiPackage apiPackage = JAVA_IO;
+ String className = "className";
+
+ String qualifiedClassName = apiPackage.qualify(className);
+
+ assertThat(qualifiedClassName).isEqualTo(apiPackage.getPrefix() + className);
+ }
+}
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilterConfigurationTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilterConfigurationTest.java
new file mode 100644
index 0000000..e31126b
--- /dev/null
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/GlobalSerialFilterConfigurationTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.serialization.filter;
+
+import static org.apache.geode.util.internal.UncheckedUtils.uncheckedCast;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+
+import java.util.function.Consumer;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class GlobalSerialFilterConfigurationTest {
+
+ private SerializableObjectConfig config;
+ private GlobalSerialFilter globalSerialFilter;
+ private Consumer<String> logger;
+
+ @Before
+ public void setUp() {
+ config = mock(SerializableObjectConfig.class);
+ globalSerialFilter = mock(GlobalSerialFilter.class);
+ logger = uncheckedCast(mock(Consumer.class));
+ }
+
+ @Test
+ public void configureLogs_whenUnsupportedOperationExceptionIsThrown_withCause() {
+ doThrow(new UnsupportedOperationException(
+ new IllegalStateException("Serial filter can only be set once")))
+ .when(globalSerialFilter).setFilter();
+ FilterConfiguration filterConfiguration = new GlobalSerialFilterConfiguration(
+ config, logger, (pattern, sanctionedClasses) -> globalSerialFilter);
+
+ filterConfiguration.configure();
+
+ verify(logger).accept("Global serial filter is already configured.");
+ }
+
+ @Test
+ public void configureDoesNotLog_whenUnsupportedOperationExceptionIsThrown_withoutCause() {
+ doThrow(new UnsupportedOperationException("testing with no root cause"))
+ .when(globalSerialFilter).setFilter();
+ FilterConfiguration filterConfiguration = new GlobalSerialFilterConfiguration(
+ config, logger, (pattern, sanctionedClasses) -> globalSerialFilter);
+
+ filterConfiguration.configure();
+
+ verifyNoInteractions(logger);
+ }
+
+ @Test
+ public void configureSetsValidateSerializableObjects() {
+ SerializableObjectConfig serializableObjectConfig = mock(SerializableObjectConfig.class);
+ FilterConfiguration filterConfiguration =
+ new GlobalSerialFilterConfiguration(serializableObjectConfig);
+
+ filterConfiguration.configure();
+
+ verify(serializableObjectConfig).setValidateSerializableObjects(true);
+ }
+}
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/JmxSerialFilterConfigurationFactoryTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/JmxSerialFilterConfigurationFactoryTest.java
new file mode 100644
index 0000000..e7e72f6
--- /dev/null
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/JmxSerialFilterConfigurationFactoryTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.serialization.filter;
+
+import static org.apache.commons.lang3.JavaVersion.JAVA_1_8;
+import static org.apache.commons.lang3.JavaVersion.JAVA_9;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtMost;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assumptions.assumeThat;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.contrib.java.lang.system.RestoreSystemProperties;
+
+public class JmxSerialFilterConfigurationFactoryTest {
+
+ @Rule
+ public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
+
+ @Test
+ public void createsConditionalJmxSerialFilterConfiguration_onJava9orGreater() {
+ assumeThat(isJavaVersionAtLeast(JAVA_9)).isTrue();
+ JmxSerialFilterConfigurationFactory factory =
+ new SystemPropertyJmxSerialFilterConfigurationFactory();
+
+ FilterConfiguration filterConfiguration = factory.create();
+
+ assertThat(filterConfiguration).isInstanceOf(JmxSerialFilterConfiguration.class);
+ }
+
+ @Test
+ public void createsNoOp_onJava8() {
+ assumeThat(isJavaVersionAtMost(JAVA_1_8)).isTrue();
+ JmxSerialFilterConfigurationFactory factory =
+ new SystemPropertyJmxSerialFilterConfigurationFactory();
+
+ FilterConfiguration filterConfiguration = factory.create();
+
+ assertThat(filterConfiguration).isNotInstanceOf(JmxSerialFilterConfiguration.class);
+ }
+
+ @Test
+ public void createsNoOp_whenJmxSerialFilter_isSet() {
+ System.setProperty("jmx.remote.rmi.server.serial.filter.pattern", "*");
+ JmxSerialFilterConfigurationFactory factory =
+ new SystemPropertyJmxSerialFilterConfigurationFactory();
+
+ FilterConfiguration filterConfiguration = factory.create();
+
+ assertThat(filterConfiguration).isNotInstanceOf(JmxSerialFilterConfiguration.class);
+ }
+}
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/JmxSerialFilterConfigurationTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/JmxSerialFilterConfigurationTest.java
new file mode 100644
index 0000000..ad05630
--- /dev/null
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/JmxSerialFilterConfigurationTest.java
@@ -0,0 +1,155 @@
+/*
+ * 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.serialization.filter;
+
+import static org.apache.geode.util.internal.UncheckedUtils.uncheckedCast;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import java.util.function.Consumer;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.contrib.java.lang.system.RestoreSystemProperties;
+
+public class JmxSerialFilterConfigurationTest {
+
+ private static final String SYSTEM_PROPERTY = "system.property.name";
+
+ private String pattern;
+ private Consumer<String> loggerConsumer;
+
+ @Rule
+ public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
+
+ @Before
+ public void setUp() {
+ pattern = "the-filter-pattern";
+ loggerConsumer = uncheckedCast(mock(Consumer.class));
+ }
+
+ @Test
+ public void propertyValue_isNullByDefault() {
+ assertThat(System.getProperty(SYSTEM_PROPERTY))
+ .as(SYSTEM_PROPERTY)
+ .isNull();
+ }
+
+ @Test
+ public void setsPropertyValue() {
+ FilterConfiguration filterConfiguration =
+ new JmxSerialFilterConfiguration(SYSTEM_PROPERTY, pattern);
+
+ filterConfiguration.configure();
+
+ assertThat(System.getProperty(SYSTEM_PROPERTY))
+ .as(SYSTEM_PROPERTY)
+ .isNotEmpty();
+ }
+
+ @Test
+ public void setsPropertyValue_ifExistingValueIsNull() {
+ System.clearProperty(SYSTEM_PROPERTY);
+ FilterConfiguration filterConfiguration =
+ new JmxSerialFilterConfiguration(SYSTEM_PROPERTY, pattern);
+
+ filterConfiguration.configure();
+
+ assertThat(System.getProperty(SYSTEM_PROPERTY))
+ .as(SYSTEM_PROPERTY)
+ .isEqualTo(pattern);
+ }
+
+ @Test
+ public void setsPropertyValue_ifExistingValueIsEmpty() {
+ System.setProperty(SYSTEM_PROPERTY, "");
+ FilterConfiguration filterConfiguration =
+ new JmxSerialFilterConfiguration(SYSTEM_PROPERTY, pattern);
+
+ filterConfiguration.configure();
+
+ assertThat(System.getProperty(SYSTEM_PROPERTY))
+ .as(SYSTEM_PROPERTY)
+ .isEqualTo(pattern);
+ }
+
+ @Test
+ public void setsPropertyValue_ifExistingValueIsBlank() {
+ System.setProperty(SYSTEM_PROPERTY, " ");
+ FilterConfiguration filterConfiguration =
+ new JmxSerialFilterConfiguration(SYSTEM_PROPERTY, pattern);
+
+ filterConfiguration.configure();
+
+ assertThat(System.getProperty(SYSTEM_PROPERTY))
+ .as(SYSTEM_PROPERTY)
+ .isEqualTo(pattern);
+ }
+
+ @Test
+ public void logsNowConfigured_ifExistingValueIsEmpty() {
+ System.setProperty(SYSTEM_PROPERTY, "");
+ FilterConfiguration filterConfiguration =
+ new JmxSerialFilterConfiguration(SYSTEM_PROPERTY, pattern, loggerConsumer);
+
+ filterConfiguration.configure();
+
+ verify(loggerConsumer)
+ .accept("System property '" + SYSTEM_PROPERTY + "' is now configured with '" +
+ pattern + "'.");
+ }
+
+ @Test
+ public void logsNowConfigured_ifExistingValueIsBlank() {
+ System.setProperty(SYSTEM_PROPERTY, " ");
+ FilterConfiguration filterConfiguration =
+ new JmxSerialFilterConfiguration(SYSTEM_PROPERTY, pattern, loggerConsumer);
+
+ filterConfiguration.configure();
+
+ verify(loggerConsumer)
+ .accept("System property '" + SYSTEM_PROPERTY + "' is now configured with '" +
+ pattern + "'.");
+ }
+
+ @Test
+ public void doesNotSetPropertyValue_ifExistingValueIsNotEmpty() {
+ String existingValue = "existing-value-of-property";
+ System.setProperty(SYSTEM_PROPERTY, existingValue);
+ FilterConfiguration filterConfiguration =
+ new JmxSerialFilterConfiguration(SYSTEM_PROPERTY, pattern);
+
+ filterConfiguration.configure();
+
+ assertThat(System.getProperty(SYSTEM_PROPERTY))
+ .as(SYSTEM_PROPERTY)
+ .isEqualTo(existingValue);
+ }
+
+ @Test
+ public void logsAlreadyConfiguredMessage_ifExistingPropertyValueIsNotEmpty() {
+ String existingValue = "existing-value-of-property";
+ System.setProperty(SYSTEM_PROPERTY, existingValue);
+ FilterConfiguration filterConfiguration =
+ new JmxSerialFilterConfiguration(SYSTEM_PROPERTY, pattern, loggerConsumer);
+
+ filterConfiguration.configure();
+
+ verify(loggerConsumer)
+ .accept("System property '" + SYSTEM_PROPERTY + "' is already configured.");
+ }
+}
diff --git a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesService.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/NullObjectInputFilterTest.java
similarity index 65%
copy from geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesService.java
copy to geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/NullObjectInputFilterTest.java
index 1d139ce..2ab18a9 100644
--- a/geode-serialization/src/main/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesService.java
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/NullObjectInputFilterTest.java
@@ -14,20 +14,22 @@
*/
package org.apache.geode.internal.serialization.filter;
-import java.io.IOException;
-import java.net.URL;
-import java.util.Collection;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verifyNoInteractions;
-@FunctionalInterface
-public interface SanctionedSerializablesService {
+import java.io.ObjectInputStream;
- URL getSanctionedSerializablesURL();
+import org.junit.Test;
- default Class<?> getInterface() {
- return getClass();
- }
+public class NullObjectInputFilterTest {
+
+ @Test
+ public void doesNothing() {
+ ObjectInputStream objectInputStream = mock(ObjectInputStream.class);
+ ObjectInputFilter filter = new NullObjectInputFilter();
+
+ filter.setFilterOn(objectInputStream);
- default Collection<String> getSerializationAcceptlist() throws IOException {
- return SanctionedSerializables.loadClassNames(getSanctionedSerializablesURL());
+ verifyNoInteractions(objectInputStream);
}
}
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ObjectInputFilterUtilsTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ObjectInputFilterUtilsTest.java
new file mode 100644
index 0000000..fc0d480
--- /dev/null
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ObjectInputFilterUtilsTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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.serialization.filter;
+
+import static org.apache.commons.lang3.JavaVersion.JAVA_1_8;
+import static org.apache.commons.lang3.JavaVersion.JAVA_9;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtMost;
+import static org.apache.geode.internal.serialization.filter.ObjectInputFilterUtils.supportsObjectInputFilter;
+import static org.apache.geode.util.internal.UncheckedUtils.uncheckedCast;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assumptions.assumeThat;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.function.Function;
+
+import org.junit.Test;
+
+public class ObjectInputFilterUtilsTest {
+
+ @Test
+ public void supportsObjectInputFilter_delegatesToClassUtils() {
+ Function<String, Boolean> isClassAvailable = uncheckedCast(mock(Function.class));
+ when(isClassAvailable.apply(anyString())).thenReturn(true);
+
+ supportsObjectInputFilter(isClassAvailable);
+
+ verify(isClassAvailable).apply(anyString());
+ }
+
+ @Test
+ public void supportsObjectInputFilter_checksSunMisc() {
+ Function<String, Boolean> isClassAvailable = uncheckedCast(mock(Function.class));
+ when(isClassAvailable.apply(anyString())).thenReturn(false);
+
+ supportsObjectInputFilter(isClassAvailable);
+
+ verify(isClassAvailable).apply("sun.misc.ObjectInputFilter");
+ }
+
+ @Test
+ public void supportsObjectInputFilter_checksJavaIo() {
+ Function<String, Boolean> isClassAvailable = uncheckedCast(mock(Function.class));
+ when(isClassAvailable.apply(anyString())).thenReturn(false);
+
+ supportsObjectInputFilter(isClassAvailable);
+
+ verify(isClassAvailable).apply("java.io.ObjectInputFilter");
+ }
+
+ @Test
+ public void supportsObjectInputFilter_checksSunMiscAndJavaIo() {
+ Function<String, Boolean> isClassAvailable = uncheckedCast(mock(Function.class));
+ when(isClassAvailable.apply(anyString())).thenReturn(false);
+
+ supportsObjectInputFilter(isClassAvailable);
+
+ verify(isClassAvailable).apply("sun.misc.ObjectInputFilter");
+ verify(isClassAvailable).apply("java.io.ObjectInputFilter");
+ }
+
+ @Test
+ public void supportsObjectInputFilter_returnsTrue_onJava8() {
+ assumeThat(isJavaVersionAtMost(JAVA_1_8)).isTrue();
+
+ boolean result = supportsObjectInputFilter();
+
+ assertThat(result).isTrue();
+ }
+
+ @Test
+ public void supportsObjectInputFilter_returnsTrue_onJava9orGreater() {
+ assumeThat(isJavaVersionAtLeast(JAVA_9)).isTrue();
+
+ boolean result = supportsObjectInputFilter();
+
+ assertThat(result).isTrue();
+ }
+}
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/OpenMBeanFilterPatternTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/OpenMBeanFilterPatternTest.java
new file mode 100644
index 0000000..bfb8809
--- /dev/null
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/OpenMBeanFilterPatternTest.java
@@ -0,0 +1,142 @@
+/*
+ * 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.serialization.filter;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.rmi.MarshalledObject;
+
+import javax.management.ObjectName;
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.SimpleType;
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.TabularType;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class OpenMBeanFilterPatternTest {
+
+ private String defaultPattern;
+
+ @Before
+ public void setUp() {
+ defaultPattern = new OpenMBeanFilterPattern().pattern();
+ }
+
+ @Test
+ public void includesBoolean() {
+ assertThat(defaultPattern).contains(Boolean.class.getName());
+ }
+
+ @Test
+ public void includesByte() {
+ assertThat(defaultPattern).contains(Byte.class.getName());
+ }
+
+ @Test
+ public void includesCharacter() {
+ assertThat(defaultPattern).contains(Character.class.getName());
+ }
+
+ @Test
+ public void includesShort() {
+ assertThat(defaultPattern).contains(Short.class.getName());
+ }
+
+ @Test
+ public void includesInteger() {
+ assertThat(defaultPattern).contains(Integer.class.getName());
+ }
+
+ @Test
+ public void includesLong() {
+ assertThat(defaultPattern).contains(Long.class.getName());
+ }
+
+ @Test
+ public void includesFloat() {
+ assertThat(defaultPattern).contains(Float.class.getName());
+ }
+
+ @Test
+ public void includesDouble() {
+ assertThat(defaultPattern).contains(Double.class.getName());
+ }
+
+ @Test
+ public void includesString() {
+ assertThat(defaultPattern).contains(String.class.getName());
+ }
+
+ @Test
+ public void includesBigInteger() {
+ assertThat(defaultPattern).contains(BigInteger.class.getName());
+ }
+
+ @Test
+ public void includesBigDecimal() {
+ assertThat(defaultPattern).contains(BigDecimal.class.getName());
+ }
+
+ @Test
+ public void includesObjectName() {
+ assertThat(defaultPattern).contains(ObjectName.class.getName());
+ }
+
+ @Test
+ public void includesCompositeData() {
+ assertThat(defaultPattern).contains(CompositeData.class.getName());
+ }
+
+ @Test
+ public void includesTabularData() {
+ assertThat(defaultPattern).contains(TabularData.class.getName());
+ }
+
+ @Test
+ public void includesSimpleType() {
+ assertThat(defaultPattern).contains(SimpleType.class.getName());
+ }
+
+ @Test
+ public void includesCompositeType() {
+ assertThat(defaultPattern).contains(CompositeType.class.getName());
+ }
+
+ @Test
+ public void includesTabularType() {
+ assertThat(defaultPattern).contains(TabularType.class.getName());
+ }
+
+ @Test
+ public void includesArrayType() {
+ assertThat(defaultPattern).contains(ArrayType.class.getName());
+ }
+
+ @Test
+ public void includesMarshalledObject() {
+ assertThat(defaultPattern).contains(MarshalledObject.class.getName());
+ }
+
+ @Test
+ public void rejectsAllOtherTypes() {
+ assertThat(defaultPattern).endsWith(";!*");
+ }
+}
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilterFactoryTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilterFactoryTest.java
new file mode 100644
index 0000000..34c83c4
--- /dev/null
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilterFactoryTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.serialization.filter;
+
+import static java.util.Collections.emptySet;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.junit.Test;
+
+public class ReflectiveFacadeGlobalSerialFilterFactoryTest {
+
+ @Test
+ public void constructsDelegatingGlobalSerialFilter() {
+ ObjectInputFilterApi api = mock(ObjectInputFilterApi.class);
+ GlobalSerialFilterFactory factory = new ReflectiveFacadeGlobalSerialFilterFactory(api);
+
+ GlobalSerialFilter filter = factory.create("pattern", emptySet());
+
+ assertThat(filter).isInstanceOf(ReflectiveFacadeGlobalSerialFilter.class);
+ }
+
+ @Test
+ public void delegatesToObjectInputFilterApiToCreateObjectInputFilter()
+ throws InvocationTargetException, IllegalAccessException {
+ ObjectInputFilterApi api = mock(ObjectInputFilterApi.class);
+ GlobalSerialFilterFactory factory = new ReflectiveFacadeGlobalSerialFilterFactory(api);
+ GlobalSerialFilter filter = factory.create("pattern", emptySet());
+ Object objectInputFilter = mock(Object.class);
+
+ when(api.createObjectInputFilterProxy(any(), any()))
+ .thenReturn(objectInputFilter);
+
+ filter.setFilter();
+
+ verify(api).createObjectInputFilterProxy(any(), any());
+ }
+
+ @Test
+ public void delegatesToObjectInputFilterApiToSetSerialFilter()
+ throws InvocationTargetException, IllegalAccessException {
+ ObjectInputFilterApi api = mock(ObjectInputFilterApi.class);
+ GlobalSerialFilterFactory factory = new ReflectiveFacadeGlobalSerialFilterFactory(api);
+ GlobalSerialFilter filter = factory.create("pattern", emptySet());
+ Object objectInputFilter = mock(Object.class);
+
+ when(api.createObjectInputFilterProxy(any(), any()))
+ .thenReturn(objectInputFilter);
+
+ filter.setFilter();
+
+ verify(api).setSerialFilter(objectInputFilter);
+ }
+}
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilterTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilterTest.java
new file mode 100644
index 0000000..5966d1b
--- /dev/null
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeGlobalSerialFilterTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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.serialization.filter;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.singleton;
+import static org.apache.geode.util.internal.UncheckedUtils.uncheckedCast;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.catchThrowable;
+import static org.mockito.ArgumentCaptor.forClass;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+public class ReflectiveFacadeGlobalSerialFilterTest {
+
+ private ObjectInputFilterApi api;
+
+ @Before
+ public void setUp() {
+ api = mock(ObjectInputFilterApi.class);
+ }
+
+ @Test
+ public void createsObjectInputFilterProxy()
+ throws InvocationTargetException, IllegalAccessException {
+ String pattern = "the-pattern";
+ Collection<String> sanctionedClasses = asList("class-name-one", "class-name-two");
+ GlobalSerialFilter globalSerialFilter =
+ new ReflectiveFacadeGlobalSerialFilter(api, pattern, sanctionedClasses);
+
+ globalSerialFilter.setFilter();
+
+ ArgumentCaptor<Collection<String>> captor = uncheckedCast(forClass(Collection.class));
+ verify(api).createObjectInputFilterProxy(eq(pattern), captor.capture());
+ assertThat(captor.getValue()).containsExactlyElementsOf(sanctionedClasses);
+ }
+
+ @Test
+ public void setsSerialFilter() throws InvocationTargetException, IllegalAccessException {
+ GlobalSerialFilter globalSerialFilter =
+ new ReflectiveFacadeGlobalSerialFilter(api, "the-pattern", singleton("class-name"));
+
+ globalSerialFilter.setFilter();
+
+ verify(api).setSerialFilter(any());
+ }
+
+ @Test
+ public void propagatesIllegalAccessExceptionInUnsupportedOperationException()
+ throws InvocationTargetException, IllegalAccessException {
+ IllegalAccessException exception = new IllegalAccessException("testing");
+ doThrow(exception).when(api).setSerialFilter(any());
+ GlobalSerialFilter globalSerialFilter =
+ new ReflectiveFacadeGlobalSerialFilter(api, "the-pattern", singleton("class-name"));
+
+ Throwable thrown = catchThrowable(() -> {
+ globalSerialFilter.setFilter();
+ });
+
+ assertThat(thrown)
+ .isInstanceOf(UnsupportedOperationException.class)
+ .hasRootCause(exception);
+ }
+
+ @Test
+ public void propagatesInvocationTargetExceptionInUnsupportedOperationException()
+ throws InvocationTargetException, IllegalAccessException {
+ InvocationTargetException exception =
+ new InvocationTargetException(new Exception("testing"), "testing");
+ doThrow(exception).when(api).setSerialFilter(any());
+ GlobalSerialFilter globalSerialFilter =
+ new ReflectiveFacadeGlobalSerialFilter(api, "the-pattern", singleton("class-name"));
+
+ Throwable thrown = catchThrowable(() -> {
+ globalSerialFilter.setFilter();
+ });
+
+ assertThat(thrown)
+ .isInstanceOf(UnsupportedOperationException.class)
+ .hasCause(exception);
+ }
+}
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeObjectInputFilterFactoryTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeObjectInputFilterFactoryTest.java
new file mode 100644
index 0000000..e35b5bd
--- /dev/null
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeObjectInputFilterFactoryTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.serialization.filter;
+
+import static java.util.Collections.emptySet;
+import static org.apache.commons.lang3.JavaVersion.JAVA_1_8;
+import static org.apache.commons.lang3.JavaVersion.JAVA_9;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtMost;
+import static org.apache.geode.internal.serialization.filter.ApiPackage.JAVA_IO;
+import static org.apache.geode.internal.serialization.filter.ApiPackage.SUN_MISC;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assumptions.assumeThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Set;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class ReflectiveFacadeObjectInputFilterFactoryTest {
+
+ private static final Set<String> SANCTIONED_CLASSES = emptySet();
+
+ private SerializableObjectConfig config;
+
+ @Before
+ public void setUp() {
+ config = mock(SerializableObjectConfig.class);
+ when(config.getValidateSerializableObjects()).thenReturn(true);
+ }
+
+ @Test
+ public void createsJava9InputStreamFilter_onJava9orGreater() {
+ assumeThat(isJavaVersionAtLeast(JAVA_9)).isTrue();
+
+ // arrange
+ ObjectInputFilterFactory factory = new ReflectiveFacadeObjectInputFilterFactory();
+
+ // act
+ ObjectInputFilter objectInputFilter = factory.create(config, SANCTIONED_CLASSES);
+
+ // assert
+ assertThat(getApiPackage(getObjectInputFilterApi(objectInputFilter))).isEqualTo(JAVA_IO);
+ }
+
+ @Test
+ public void createsJava8InputStreamFilter_onJava8() {
+ assumeThat(isJavaVersionAtMost(JAVA_1_8)).isTrue();
+
+ // arrange
+ ObjectInputFilterFactory factory = new ReflectiveFacadeObjectInputFilterFactory();
+
+ // act
+ ObjectInputFilter objectInputFilter = factory.create(config, SANCTIONED_CLASSES);
+
+ // assert
+ assertThat(getApiPackage(getObjectInputFilterApi(objectInputFilter))).isEqualTo(SUN_MISC);
+ }
+
+ private static ObjectInputFilterApi getObjectInputFilterApi(ObjectInputFilter result) {
+ ReflectiveFacadeObjectInputFilter impl = (ReflectiveFacadeObjectInputFilter) result;
+ ObjectInputFilterApi objectInputFilterApi = impl.getObjectInputFilterApi();
+ assertThat(objectInputFilterApi).isInstanceOf(ReflectiveObjectInputFilterApi.class);
+ return objectInputFilterApi;
+ }
+
+ private static ApiPackage getApiPackage(ObjectInputFilterApi reflectionObjectInputFilterApi) {
+ return ((ReflectiveObjectInputFilterApi) reflectionObjectInputFilterApi).getApiPackage();
+ }
+}
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeObjectInputFilterTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeObjectInputFilterTest.java
new file mode 100644
index 0000000..cca697f
--- /dev/null
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveFacadeObjectInputFilterTest.java
@@ -0,0 +1,142 @@
+/*
+ * 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.serialization.filter;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptySet;
+import static java.util.Collections.singleton;
+import static org.apache.geode.util.internal.UncheckedUtils.uncheckedCast;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.catchThrowable;
+import static org.mockito.ArgumentCaptor.forClass;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.same;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.ObjectInputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+public class ReflectiveFacadeObjectInputFilterTest {
+
+ private ObjectInputFilterApi api;
+ private ObjectInputStream objectInputStream;
+
+ @Before
+ public void setUp() {
+ api = mock(ObjectInputFilterApi.class);
+ objectInputStream = mock(ObjectInputStream.class);
+ }
+
+ @Test
+ public void createsObjectInputFilterProxy()
+ throws InvocationTargetException, IllegalAccessException {
+ String pattern = "the-pattern";
+ Collection<String> sanctionedClasses = asList("class-name-one", "class-name-two");
+ ObjectInputFilter objectInputFilter =
+ new ReflectiveFacadeObjectInputFilter(api, pattern, sanctionedClasses);
+
+ objectInputFilter.setFilterOn(objectInputStream);
+
+ ArgumentCaptor<Collection<String>> captor = uncheckedCast(forClass(Collection.class));
+ verify(api).createObjectInputFilterProxy(eq(pattern), captor.capture());
+ assertThat(captor.getValue()).containsExactlyElementsOf(sanctionedClasses);
+ }
+
+ @Test
+ public void setsSerialFilter() throws InvocationTargetException, IllegalAccessException {
+ ObjectInputFilter objectInputFilter =
+ new ReflectiveFacadeObjectInputFilter(api, "the-pattern", singleton("class-name"));
+
+ objectInputFilter.setFilterOn(objectInputStream);
+
+ verify(api).setObjectInputFilter(same(objectInputStream), any());
+ }
+
+ @Test
+ public void propagatesIllegalAccessExceptionInUnsupportedOperationException()
+ throws InvocationTargetException, IllegalAccessException {
+ IllegalAccessException exception = new IllegalAccessException("testing");
+ doThrow(exception).when(api).setObjectInputFilter(same(objectInputStream), any());
+ ObjectInputFilter objectInputFilter =
+ new ReflectiveFacadeObjectInputFilter(api, "the-pattern", singleton("class-name"));
+
+ Throwable thrown = catchThrowable(() -> {
+ objectInputFilter.setFilterOn(objectInputStream);
+ });
+
+ assertThat(thrown)
+ .isInstanceOf(UnsupportedOperationException.class)
+ .hasRootCause(exception);
+ }
+
+ @Test
+ public void propagatesInvocationTargetExceptionInUnsupportedOperationException()
+ throws InvocationTargetException, IllegalAccessException {
+ InvocationTargetException exception =
+ new InvocationTargetException(new Exception("testing"), "testing");
+ doThrow(exception).when(api).setObjectInputFilter(same(objectInputStream), any());
+ ObjectInputFilter objectInputFilter =
+ new ReflectiveFacadeObjectInputFilter(api, "the-pattern", singleton("class-name"));
+
+ Throwable thrown = catchThrowable(() -> {
+ objectInputFilter.setFilterOn(objectInputStream);
+ });
+
+ assertThat(thrown)
+ .isInstanceOf(UnsupportedOperationException.class)
+ .hasCause(exception);
+ }
+
+ @Test
+ public void delegatesToObjectInputFilterApiToCreateObjectInputFilter()
+ throws InvocationTargetException, IllegalAccessException {
+ ObjectInputFilterApi api = mock(ObjectInputFilterApi.class);
+ ObjectInputFilter filter = new ReflectiveFacadeObjectInputFilter(api, "pattern", emptySet());
+ Object objectInputFilter = mock(Object.class);
+ ObjectInputStream objectInputStream = mock(ObjectInputStream.class);
+
+ when(api.createObjectInputFilterProxy(any(), any()))
+ .thenReturn(objectInputFilter);
+
+ filter.setFilterOn(objectInputStream);
+
+ verify(api).createObjectInputFilterProxy(any(), any());
+ }
+
+ @Test
+ public void delegatesToObjectInputFilterApiToSetFilterOnObjectInputStream()
+ throws InvocationTargetException, IllegalAccessException {
+ ObjectInputFilterApi api = mock(ObjectInputFilterApi.class);
+ ObjectInputFilter filter = new ReflectiveFacadeObjectInputFilter(api, "pattern", emptySet());
+ Object objectInputFilter = mock(Object.class);
+ ObjectInputStream objectInputStream = mock(ObjectInputStream.class);
+
+ when(api.createObjectInputFilterProxy(any(), any()))
+ .thenReturn(objectInputFilter);
+
+ filter.setFilterOn(objectInputStream);
+
+ verify(api).setObjectInputFilter(objectInputStream, objectInputFilter);
+ }
+}
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiFactoryTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiFactoryTest.java
new file mode 100644
index 0000000..b3ac61f
--- /dev/null
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiFactoryTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.serialization.filter;
+
+import static org.apache.commons.lang3.JavaVersion.JAVA_1_8;
+import static org.apache.commons.lang3.JavaVersion.JAVA_9;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtMost;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assumptions.assumeThat;
+
+import org.junit.Test;
+
+public class ReflectiveObjectInputFilterApiFactoryTest {
+
+ @Test
+ public void createsInstanceOfReflectionObjectInputFilterApi() {
+ ObjectInputFilterApiFactory factory = new ReflectiveObjectInputFilterApiFactory();
+
+ ObjectInputFilterApi api = factory.createObjectInputFilterApi();
+
+ assertThat(api).isInstanceOf(ReflectiveObjectInputFilterApi.class);
+ }
+
+ @Test
+ public void usesJavaIO_inJava9() {
+ assumeThat(isJavaVersionAtLeast(JAVA_9)).isTrue();
+
+ ObjectInputFilterApiFactory factory = new ReflectiveObjectInputFilterApiFactory();
+
+ ReflectiveObjectInputFilterApi api =
+ (ReflectiveObjectInputFilterApi) factory.createObjectInputFilterApi();
+
+ assertThat(api.getApiPackage()).isEqualTo(ApiPackage.JAVA_IO);
+ }
+
+ @Test
+ public void usesSunMisc_inJava8() {
+ assumeThat(isJavaVersionAtMost(JAVA_1_8)).isTrue();
+
+ ObjectInputFilterApiFactory factory = new ReflectiveObjectInputFilterApiFactory();
+
+ ReflectiveObjectInputFilterApi api =
+ (ReflectiveObjectInputFilterApi) factory.createObjectInputFilterApi();
+
+ assertThat(api.getApiPackage()).isEqualTo(ApiPackage.SUN_MISC);
+ }
+}
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiTest.java
new file mode 100644
index 0000000..8cf1f8c
--- /dev/null
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/ReflectiveObjectInputFilterApiTest.java
@@ -0,0 +1,223 @@
+/*
+ * 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.serialization.filter;
+
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singleton;
+import static java.util.Objects.hash;
+import static java.util.Objects.requireNonNull;
+import static org.apache.commons.lang3.JavaVersion.JAVA_1_8;
+import static org.apache.commons.lang3.JavaVersion.JAVA_9;
+import static org.apache.commons.lang3.SerializationUtils.serialize;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.catchThrowable;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InvalidClassException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.lang.reflect.InvocationTargetException;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class ReflectiveObjectInputFilterApiTest {
+
+ private ObjectInputFilterApi api;
+
+ @Before
+ public void setUp() throws ClassNotFoundException, NoSuchMethodException {
+ if (isJavaVersionAtLeast(JAVA_9)) {
+ api = new Java9ReflectiveObjectInputFilterApi(ApiPackage.JAVA_IO);
+ } else if (isJavaVersionAtLeast(JAVA_1_8)) {
+ api = new ReflectiveObjectInputFilterApi(ApiPackage.SUN_MISC);
+ }
+ }
+
+ @Test
+ public void createFilterGivenValidPatternReturnsNewFilter()
+ throws IllegalAccessException, InvocationTargetException {
+
+ Object filter = api.createFilter("!*");
+
+ assertThat(filter)
+ .as("ObjectInputFilter$Config.createFilter(\"!*\")")
+ .isNotNull()
+ .isInstanceOf(api.getObjectInputFilterClass());
+ }
+
+ @Test
+ public void createFilterGivenEmptyPatternReturnsNull()
+ throws IllegalAccessException, InvocationTargetException {
+
+ Object filter = api.createFilter("");
+
+ assertThat(filter)
+ .as("ObjectInputFilter$Config.createFilter(\"\")")
+ .isNull();
+ }
+
+ @Test
+ public void createFilterGivenBlankPatternReturnsNewFilter()
+ throws IllegalAccessException, InvocationTargetException {
+
+ Object filter = api.createFilter(" ");
+
+ assertThat(filter)
+ .as("ObjectInputFilter$Config.createFilter(\" \")")
+ .isNotNull()
+ .isInstanceOf(api.getObjectInputFilterClass());
+ }
+
+ @Test
+ public void getSerialFilterReturnsNullWhenFilterDoesNotExist()
+ throws IllegalAccessException, InvocationTargetException {
+
+ Object filter = api.getSerialFilter();
+
+ assertThat(filter)
+ .as("ObjectInputFilter$Config.getSerialFilter()")
+ .isNull();
+ }
+
+ @Test
+ public void getObjectInputFilterReturnsNullWhenFilterDoesNotExist()
+ throws IllegalAccessException, InvocationTargetException, IOException {
+ Serializable object = "hello";
+ ObjectInputStream inputStream = new ObjectInputStream(byteArrayInputStream(object));
+
+ Object filter = api.getObjectInputFilter(inputStream);
+
+ assertThat(filter).isNull();
+ }
+
+ @Test
+ public void getObjectInputFilterReturnsExistingFilter()
+ throws IllegalAccessException, InvocationTargetException, IOException {
+ Object existingFilter = api.createFilter("*");
+ Serializable object = "hello";
+ ObjectInputStream inputStream = new ObjectInputStream(byteArrayInputStream(object));
+ api.setObjectInputFilter(inputStream, existingFilter);
+
+ Object filter = api.getObjectInputFilter(inputStream);
+
+ assertThat(filter).isSameAs(existingFilter);
+ }
+
+ @Test
+ public void setObjectInputFilterGivenAcceptFilterReadsObject()
+ throws ClassNotFoundException, IllegalAccessException, InvocationTargetException,
+ IOException {
+ Serializable object = new SerializableClass("hello");
+ Object filter = api.createFilter(object.getClass().getName() + ";!*");
+
+ try (ObjectInputStream inputStream = new ObjectInputStream(byteArrayInputStream(object))) {
+ api.setObjectInputFilter(inputStream, filter);
+
+ assertThat(inputStream.readObject()).isEqualTo(object);
+ }
+ }
+
+ @Test
+ public void setObjectInputFilterGivenDenyFilterThrowsInvalidClassException()
+ throws IllegalAccessException, InvocationTargetException, IOException {
+ Serializable object = new SerializableClass("hello");
+ Object filter = api.createFilter("!" + object.getClass().getName());
+
+ try (ObjectInputStream inputStream = new ObjectInputStream(byteArrayInputStream(object))) {
+ api.setObjectInputFilter(inputStream, filter);
+
+ Throwable thrown = catchThrowable(() -> {
+ assertThat(inputStream.readObject()).isEqualTo(object);
+ });
+
+ assertThat(thrown).isInstanceOf(InvalidClassException.class);
+ }
+ }
+
+ @Test
+ public void createObjectInputFilterProxyGivenAcceptFilterReadsObject()
+ throws ClassNotFoundException, IllegalAccessException, InvocationTargetException,
+ IOException {
+ Serializable object = new SerializableClass("hello");
+ String className = object.getClass().getName();
+ Object filter = api.createObjectInputFilterProxy(className + ";!*", singleton(className));
+
+ try (ObjectInputStream inputStream = new ObjectInputStream(byteArrayInputStream(object))) {
+ api.setObjectInputFilter(inputStream, filter);
+
+ assertThat(inputStream.readObject()).isEqualTo(object);
+ }
+ }
+
+ @Test
+ public void createObjectInputFilterProxyGivenRejectFilterThrowsInvalidClassException()
+ throws IllegalAccessException, InvocationTargetException, IOException {
+ Serializable object = new SerializableClass("hello");
+ String className = object.getClass().getName();
+ Object filter = api.createObjectInputFilterProxy("!" + className + ";*", emptyList());
+
+ try (ObjectInputStream inputStream = new ObjectInputStream(byteArrayInputStream(object))) {
+ api.setObjectInputFilter(inputStream, filter);
+
+ Throwable thrown = catchThrowable(() -> {
+ assertThat(inputStream.readObject()).isEqualTo(object);
+ });
+
+ assertThat(thrown).isInstanceOf(InvalidClassException.class);
+ }
+ }
+
+ private static ByteArrayInputStream byteArrayInputStream(Serializable object) {
+ return new ByteArrayInputStream(serialize(object));
+ }
+
+ private static class SerializableClass implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private final String value;
+
+ private SerializableClass(String value) {
+ this.value = requireNonNull(value);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ SerializableClass that = (SerializableClass) o;
+ return value.equals(that.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return hash(value);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("SerializableClass{");
+ sb.append("value='").append(value).append('\'');
+ sb.append('}');
+ return sb.toString();
+ }
+ }
+}
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesFilterPatternTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesFilterPatternTest.java
new file mode 100644
index 0000000..177e2c9
--- /dev/null
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/SanctionedSerializablesFilterPatternTest.java
@@ -0,0 +1,206 @@
+/*
+ * 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.serialization.filter;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.StringJoiner;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class SanctionedSerializablesFilterPatternTest {
+
+ private String defaultPattern;
+
+ @Before
+ public void setUp() {
+ defaultPattern = new SanctionedSerializablesFilterPattern().pattern();
+ }
+
+ @Test
+ public void includesJavaWithSubpackages() {
+ assertThat(defaultPattern).contains("java.**");
+ }
+
+ @Test
+ public void includesJavaxManagementWithSubpackages() {
+ assertThat(defaultPattern).contains("javax.management.**");
+ }
+
+ @Test
+ public void includesEnumSyntax() {
+ assertThat(defaultPattern).contains("javax.print.attribute.EnumSyntax");
+ }
+
+ @Test
+ public void includesAntlrWithSubpackages() {
+ assertThat(defaultPattern).contains("antlr.**");
+ }
+
+ @Test
+ public void includesCommonsModelerAttributeInfo() {
+ assertThat(defaultPattern).contains("org.apache.commons.modeler.AttributeInfo");
+ }
+
+ @Test
+ public void includesCommonsModelerFeatureInfo() {
+ assertThat(defaultPattern).contains("org.apache.commons.modeler.FeatureInfo");
+ }
+
+ @Test
+ public void includesCommonsModelerManagedBean() {
+ assertThat(defaultPattern).contains("org.apache.commons.modeler.ManagedBean");
+ }
+
+ @Test
+ public void includesDistributionConfigSnapshot() {
+ assertThat(defaultPattern)
+ .contains("org.apache.geode.distributed.internal.DistributionConfigSnapshot");
+ }
+
+ @Test
+ public void includesRuntimeDistributionConfigImpl() {
+ assertThat(defaultPattern)
+ .contains("org.apache.geode.distributed.internal.RuntimeDistributionConfigImpl");
+ }
+
+ @Test
+ public void includesDistributionConfigImpl() {
+ assertThat(defaultPattern)
+ .contains("org.apache.geode.distributed.internal.DistributionConfigImpl");
+ }
+
+ @Test
+ public void includesInternalDistributedMember() {
+ assertThat(defaultPattern)
+ .contains("org.apache.geode.distributed.internal.membership.InternalDistributedMember");
+ }
+
+ @Test
+ public void includesPersistentMemberID() {
+ assertThat(defaultPattern)
+ .contains("org.apache.geode.internal.cache.persistence.PersistentMemberID");
+ }
+
+ @Test
+ public void includesDiskStoreID() {
+ assertThat(defaultPattern).contains("org.apache.geode.internal.cache.persistence.DiskStoreID");
+ }
+
+ @Test
+ public void includesVersionedObjectList() {
+ assertThat(defaultPattern)
+ .contains("org.apache.geode.internal.cache.tier.sockets.VersionedObjectList");
+ }
+
+ @Test
+ public void includesShiroPackage() {
+ assertThat(defaultPattern).contains("org.apache.shiro.**");
+ }
+
+ @Test
+ public void includesLog4jLevel() {
+ assertThat(defaultPattern).contains("org.apache.logging.log4j.Level");
+ }
+
+ @Test
+ public void includesLog4jStandardLevel() {
+ assertThat(defaultPattern).contains("org.apache.logging.log4j.spi.StandardLevel");
+ }
+
+ @Test
+ public void includesSunProxy() {
+ assertThat(defaultPattern).contains("com.sun.proxy.$Proxy*");
+ }
+
+ @Test
+ public void includesRmiioRemoteInputStream() {
+ assertThat(defaultPattern).contains("com.healthmarketscience.rmiio.RemoteInputStream");
+ }
+
+ @Test
+ public void includesSslRMIClientSocketFactory() {
+ assertThat(defaultPattern).contains("javax.rmi.ssl.SslRMIClientSocketFactory");
+ }
+
+ @Test
+ public void includesSSLHandshakeException() {
+ assertThat(defaultPattern).contains("javax.net.ssl.SSLHandshakeException");
+ }
+
+ @Test
+ public void includesSSLException() {
+ assertThat(defaultPattern).contains("javax.net.ssl.SSLException");
+ }
+
+ @Test
+ public void includesSunValidatorException() {
+ assertThat(defaultPattern).contains("sun.security.validator.ValidatorException");
+ }
+
+ @Test
+ public void includesSunSunCertPathBuilderException() {
+ assertThat(defaultPattern)
+ .contains("sun.security.provider.certpath.SunCertPathBuilderException");
+ }
+
+ @Test
+ public void includesSessionCustomExpiry() {
+ assertThat(defaultPattern).contains("org.apache.geode.modules.util.SessionCustomExpiry");
+ }
+
+ @Test
+ public void rejectsAllOtherTypes() {
+ assertThat(defaultPattern).endsWith(";!*");
+ }
+
+ @Test
+ public void appendsToPattern() {
+ String extraToAppend = "extra";
+ String pattern = new SanctionedSerializablesFilterPattern()
+ .append(extraToAppend)
+ .pattern();
+
+ assertThat(pattern).contains(extraToAppend);
+ }
+
+ @Test
+ public void appendsJustBeforeRejectPattern() {
+ String extraToAppend = "extra";
+ String pattern = new SanctionedSerializablesFilterPattern()
+ .append(extraToAppend)
+ .pattern();
+
+ String expectedEnd = new StringJoiner(";")
+ .add(extraToAppend)
+ .add("!*")
+ .toString();
+
+ assertThat(pattern).endsWith(expectedEnd);
+ }
+
+ @Test
+ public void patternReturnsSameValueMultipleTimes() {
+ FilterPattern sanctionedSerializablesFilterPattern =
+ new SanctionedSerializablesFilterPattern();
+ String expectedPattern = sanctionedSerializablesFilterPattern
+ .pattern();
+
+ assertThat(sanctionedSerializablesFilterPattern.pattern()).isEqualTo(expectedPattern);
+ assertThat(sanctionedSerializablesFilterPattern.pattern()).isEqualTo(expectedPattern);
+ assertThat(sanctionedSerializablesFilterPattern.pattern()).isEqualTo(expectedPattern);
+ }
+}
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/SerializableObjectConfigTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/SerializableObjectConfigTest.java
new file mode 100644
index 0000000..22fbded
--- /dev/null
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/SerializableObjectConfigTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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.serialization.filter;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import org.junit.Test;
+
+public class SerializableObjectConfigTest {
+
+ @Test
+ public void getSerializableObjectFilterIfEnabled_returnsFilter_ifValidateIsTrue() {
+ SerializableObjectConfig config = spy(SerializableObjectConfig.class);
+ when(config.getSerializableObjectFilter()).thenReturn("filter-string");
+ when(config.getValidateSerializableObjects()).thenReturn(true);
+
+ String result = config.getSerializableObjectFilterIfEnabled();
+
+ assertThat(result).isEqualTo("filter-string");
+ }
+
+ @Test
+ public void getSerializableObjectFilterIfEnabled_returnsNull_ifValidateIsFalse() {
+ SerializableObjectConfig config = spy(SerializableObjectConfig.class);
+ when(config.getSerializableObjectFilter()).thenReturn("filter-string");
+ when(config.getValidateSerializableObjects()).thenReturn(false);
+
+ String result = config.getSerializableObjectFilterIfEnabled();
+
+ assertThat(result).isNull();
+ }
+}
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/SystemPropertyGlobalSerialFilterConfigurationFactoryTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/SystemPropertyGlobalSerialFilterConfigurationFactoryTest.java
new file mode 100644
index 0000000..45070a6
--- /dev/null
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/SystemPropertyGlobalSerialFilterConfigurationFactoryTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.serialization.filter;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.contrib.java.lang.system.RestoreSystemProperties;
+
+public class SystemPropertyGlobalSerialFilterConfigurationFactoryTest {
+
+ @Rule
+ public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
+
+ @Test
+ public void createsConditionalGlobalSerialFilterConfiguration_whenEnableGlobalSerialFilter_isSet() {
+ System.setProperty("geode.enableGlobalSerialFilter", "true");
+ GlobalSerialFilterConfigurationFactory factory =
+ new SystemPropertyGlobalSerialFilterConfigurationFactory();
+
+ FilterConfiguration filterConfiguration = factory.create(mock(SerializableObjectConfig.class));
+
+ assertThat(filterConfiguration).isInstanceOf(GlobalSerialFilterConfiguration.class);
+ }
+
+ @Test
+ public void createsNoOp_whenEnableGlobalSerialFilter_isNotSet() {
+ GlobalSerialFilterConfigurationFactory factory =
+ new SystemPropertyGlobalSerialFilterConfigurationFactory();
+
+ FilterConfiguration filterConfiguration = factory.create(mock(SerializableObjectConfig.class));
+
+ assertThat(filterConfiguration)
+ .isNotInstanceOf(GlobalSerialFilterConfiguration.class);
+ }
+
+ @Test
+ public void createsNoOp_whenJdkSerialFilter_isSet() {
+ System.setProperty("jdk.serialFilter", "*");
+ GlobalSerialFilterConfigurationFactory factory =
+ new SystemPropertyGlobalSerialFilterConfigurationFactory();
+
+ FilterConfiguration filterConfiguration = factory.create(mock(SerializableObjectConfig.class));
+
+ assertThat(filterConfiguration)
+ .isNotInstanceOf(GlobalSerialFilterConfiguration.class);
+ }
+
+ @Test
+ public void createsNoOp_whenJdkSerialFilter_andEnableGlobalSerialFilter_areBothSet() {
+ System.setProperty("jdk.serialFilter", "*");
+ System.setProperty("geode.enableGlobalSerialFilter", "true");
+ GlobalSerialFilterConfigurationFactory factory =
+ new SystemPropertyGlobalSerialFilterConfigurationFactory();
+
+ FilterConfiguration filterConfiguration = factory.create(mock(SerializableObjectConfig.class));
+
+ assertThat(filterConfiguration)
+ .isNotInstanceOf(GlobalSerialFilterConfiguration.class);
+ }
+}
diff --git a/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/SystemPropertyJmxSerialFilterConfigurationFactoryTest.java b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/SystemPropertyJmxSerialFilterConfigurationFactoryTest.java
new file mode 100644
index 0000000..d95ef9c
--- /dev/null
+++ b/geode-serialization/src/test/java/org/apache/geode/internal/serialization/filter/SystemPropertyJmxSerialFilterConfigurationFactoryTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.serialization.filter;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Map;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.contrib.java.lang.system.RestoreSystemProperties;
+
+public class SystemPropertyJmxSerialFilterConfigurationFactoryTest {
+
+ private static final String PROPERTY_NAME = "jmx.remote.rmi.server.serial.filter.pattern";
+ private static final String PATTERN = "*";
+
+ @Rule
+ public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
+
+ @Test
+ public void jmxSerialFilterProperty_isBlankByDefault() {
+ assertThat(System.getProperty(PROPERTY_NAME)).isBlank();
+ }
+
+ @Test
+ public void returnsNewJmxSerialFilterConfiguration_whenFilteringIsEnabled() {
+ JmxSerialFilterConfigurationFactory factory =
+ new SystemPropertyJmxSerialFilterConfigurationFactory(true, PATTERN);
+
+ FilterConfiguration filterConfiguration = factory.create();
+
+ assertThat(filterConfiguration).isInstanceOf(JmxSerialFilterConfiguration.class);
+ }
+
+ @Test
+ public void returnsEnabledConfiguration_whenFilteringIsEnabled() {
+ JmxSerialFilterConfigurationFactory factory =
+ new SystemPropertyJmxSerialFilterConfigurationFactory(true, PATTERN);
+
+ FilterConfiguration filterConfiguration = factory.create();
+
+ assertThat(filterConfiguration.configure()).isTrue();
+ }
+
+ @Test
+ public void returnsDisabledConfiguration_whenFilteringIsDisabled() {
+ JmxSerialFilterConfigurationFactory factory =
+ new SystemPropertyJmxSerialFilterConfigurationFactory(false, PATTERN);
+
+ FilterConfiguration filterConfiguration = factory.create();
+
+ assertThat(filterConfiguration.configure()).isFalse();
+ }
+
+ @Test
+ public void enabledConfiguration_setsJmxSerialFilterProperty() {
+ JmxSerialFilterConfigurationFactory factory =
+ new SystemPropertyJmxSerialFilterConfigurationFactory(true, PATTERN);
+ FilterConfiguration filterConfiguration = factory.create();
+
+ filterConfiguration.configure();
+
+ assertThat(System.getProperty(PROPERTY_NAME)).isEqualTo(PATTERN);
+ }
+
+ @Test
+ public void disabledConfiguration_doesNotSetAnySystemProperties() {
+ Map<?, ?> propertiesBefore = System.getProperties();
+ JmxSerialFilterConfigurationFactory factory =
+ new SystemPropertyJmxSerialFilterConfigurationFactory(true, PATTERN);
+ FilterConfiguration filterConfiguration = factory.create();
+
+ filterConfiguration.configure();
+
+ assertThat(System.getProperties()).containsExactlyEntriesOf(propertiesBefore);
+ }
+}