diff --git a/hazelcast-client/src/main/java/com/hazelcast/client/impl/DefaultClientExtension.java b/hazelcast-client/src/main/java/com/hazelcast/client/impl/DefaultClientExtension.java index fd0cf0e6b9fb..816bc7af87c2 100644 --- a/hazelcast-client/src/main/java/com/hazelcast/client/impl/DefaultClientExtension.java +++ b/hazelcast-client/src/main/java/com/hazelcast/client/impl/DefaultClientExtension.java @@ -46,6 +46,7 @@ import com.hazelcast.nio.SocketInterceptor; import com.hazelcast.partition.strategy.DefaultPartitioningStrategy; import com.hazelcast.spi.properties.GroupProperty; +import com.hazelcast.spi.properties.HazelcastProperties; import com.hazelcast.spi.serialization.SerializationService; import com.hazelcast.util.function.Supplier; @@ -89,6 +90,7 @@ public InternalSerializationService createSerializationService(byte version) { return builder .setClassLoader(configClassLoader) .setConfig(serializationConfig) + .setProperties(new HazelcastProperties(config.getProperties())) .setManagedContext(new HazelcastClientManagedContext(client, config.getManagedContext())) .setPartitioningStrategy(partitioningStrategy) .setHazelcastInstance(hazelcastInstance) diff --git a/hazelcast-client/src/test/java/com/hazelcast/client/ClientDeserializationProtectionTest.java b/hazelcast-client/src/test/java/com/hazelcast/client/ClientDeserializationProtectionTest.java new file mode 100644 index 000000000000..ffe342253c5a --- /dev/null +++ b/hazelcast-client/src/test/java/com/hazelcast/client/ClientDeserializationProtectionTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2008-2018, Hazelcast, Inc. All Rights Reserved. + * + * Licensed 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 com.hazelcast.client; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.io.Serializable; + +import org.junit.After; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; + +import com.hazelcast.client.config.ClientConfig; +import com.hazelcast.client.test.TestAwareClientFactory; +import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.nio.serialization.HazelcastSerializationException; +import com.hazelcast.spi.properties.GroupProperty; +import com.hazelcast.test.HazelcastParallelClassRunner; +import com.hazelcast.test.annotation.ParallelTest; +import com.hazelcast.test.annotation.QuickTest; + +/** + * Tests if deserialization blacklisting works for clients + */ +@RunWith(HazelcastParallelClassRunner.class) +@Category({ QuickTest.class, ParallelTest.class }) +public class ClientDeserializationProtectionTest { + + private final TestAwareClientFactory factory = new TestAwareClientFactory(); + + @After + public void killAllHazelcastInstances() throws IOException { + factory.terminateAll(); + } + + /** + *
+ * Given: Serialization filter is configured with a blacklist on the client. + * When: Blacklisted class is deserialized. + * Then: The deserialization fails. + *+ */ + @Test + public void test() throws Exception { + HazelcastInstance hz = factory.newHazelcastInstance(null); + ClientConfig config = new ClientConfig(); + config.setProperty(GroupProperty.SERIALIZATION_FILTER_ENABLED.getName(), "true"); + config.setProperty(GroupProperty.SERIALIZATION_FILTER_BLACKLIST_CLASSES.getName(), TestDeserialized.class.getName()); + HazelcastInstance client = factory.newHazelcastClient(config); + + hz.getMap("test").put("test", new TestDeserialized()); + try { + client.getMap("test").get("test"); + fail("Deserialization should fail"); + } catch (HazelcastSerializationException s) { + assertEquals("SecurityException was expected as a cause of failed deserialization", SecurityException.class, + s.getCause().getClass()); + assertFalse("Untrusted deserialization was possible", TestDeserialized.IS_DESERIALIZED); + } + } + + public static class TestDeserialized implements Serializable { + private static final long serialVersionUID = 1L; + public static volatile boolean IS_DESERIALIZED = false; + + private void writeObject(java.io.ObjectOutputStream out) throws IOException { + } + + private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { + IS_DESERIALIZED = true; + } + } +} diff --git a/hazelcast/src/main/java/com/hazelcast/config/ClassFilter.java b/hazelcast/src/main/java/com/hazelcast/config/ClassFilter.java new file mode 100644 index 000000000000..0e7a8addd5c0 --- /dev/null +++ b/hazelcast/src/main/java/com/hazelcast/config/ClassFilter.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2008-2018, Hazelcast, Inc. All Rights Reserved. + * + * Licensed 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 com.hazelcast.config; + +import static com.hazelcast.util.Preconditions.checkNotNull; +import static java.util.Collections.unmodifiableSet; + +import java.util.Collection; +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.hazelcast.logging.ILogger; +import com.hazelcast.logging.Logger; + +/** + * Holds blacklist and whitelist configuration in java deserialization configuration. + */ +public class ClassFilter { + + private static final String PROPERTY_CLASSNAME_LIMIT = "hazelcast.serialization.filter.classname.limit"; + private static final int CLASSNAME_LIMIT = Integer.getInteger(PROPERTY_CLASSNAME_LIMIT, 10000); + private static final ILogger LOGGER = Logger.getLogger(ClassFilter.class); + + private final Set