diff --git a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/HazelcastDefaultComponent.java b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/HazelcastDefaultComponent.java index e2f777010d575..2a5d133cfe255 100644 --- a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/HazelcastDefaultComponent.java +++ b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/HazelcastDefaultComponent.java @@ -163,6 +163,7 @@ protected HazelcastInstance getOrCreateHzInstance(CamelContext context, Map + * If the supplied {@link Config} already declares a {@link JavaSerializationFilterConfig} (e.g. provided by the user + * via a reference or XML/YAML configuration), it is left untouched. + */ +public final class HazelcastSerializationFilterHelper { + + static final String[] DEFAULT_WHITELIST_PREFIXES = { "java.", "javax.", "org.apache.camel." }; + static final String[] DEFAULT_BLACKLIST_PREFIXES = { "java.net." }; + + private HazelcastSerializationFilterHelper() { + } + + /** + * Applies the default {@link JavaSerializationFilterConfig} on the {@link SerializationConfig} of the given + * {@link Config} when one is not already set. Has no effect when {@code config} is {@code null} or the user has + * already configured a {@link JavaSerializationFilterConfig}. + */ + public static void applyDefault(Config config) { + if (config == null) { + return; + } + SerializationConfig serializationConfig = config.getSerializationConfig(); + if (serializationConfig == null) { + return; + } + if (serializationConfig.getJavaSerializationFilterConfig() != null) { + return; + } + JavaSerializationFilterConfig filter = new JavaSerializationFilterConfig(); + filter.setWhitelist(new ClassFilter().addPrefixes(DEFAULT_WHITELIST_PREFIXES)); + filter.setBlacklist(new ClassFilter().addPrefixes(DEFAULT_BLACKLIST_PREFIXES)); + serializationConfig.setJavaSerializationFilterConfig(filter); + } +} diff --git a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/HazelcastUtil.java b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/HazelcastUtil.java index 1e6574aed8ce8..cf2dffe446939 100644 --- a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/HazelcastUtil.java +++ b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/HazelcastUtil.java @@ -35,6 +35,7 @@ public static HazelcastInstance newInstance() { cfg.setProperty( "hazelcast.logging.type", System.getProperty("hazelcast.logging.type", "slf4j")); + HazelcastSerializationFilterHelper.applyDefault(cfg); return newInstance(cfg); } diff --git a/components/camel-hazelcast/src/main/java/org/apache/camel/processor/aggregate/hazelcast/HazelcastAggregationRepository.java b/components/camel-hazelcast/src/main/java/org/apache/camel/processor/aggregate/hazelcast/HazelcastAggregationRepository.java index 544b01a9bdcaf..6aa84aaf75cf7 100644 --- a/components/camel-hazelcast/src/main/java/org/apache/camel/processor/aggregate/hazelcast/HazelcastAggregationRepository.java +++ b/components/camel-hazelcast/src/main/java/org/apache/camel/processor/aggregate/hazelcast/HazelcastAggregationRepository.java @@ -32,6 +32,7 @@ import org.apache.camel.CamelContext; import org.apache.camel.Exchange; import org.apache.camel.RuntimeCamelException; +import org.apache.camel.component.hazelcast.HazelcastSerializationFilterHelper; import org.apache.camel.spi.Configurer; import org.apache.camel.spi.Metadata; import org.apache.camel.spi.OptimisticLockingAggregationRepository; @@ -451,6 +452,7 @@ protected void doStart() throws Exception { useLocalHzInstance = true; Config cfg = new XmlConfigBuilder().build(); cfg.setProperty("hazelcast.version.check.enabled", "false"); + HazelcastSerializationFilterHelper.applyDefault(cfg); hazelcastInstance = Hazelcast.newHazelcastInstance(cfg); } else { ObjectHelper.notNull(hazelcastInstance, "hazelcastInstance"); diff --git a/components/camel-hazelcast/src/main/java/org/apache/camel/processor/idempotent/hazelcast/HazelcastIdempotentRepository.java b/components/camel-hazelcast/src/main/java/org/apache/camel/processor/idempotent/hazelcast/HazelcastIdempotentRepository.java index 2a08d74219f66..81dfca3ac73fc 100644 --- a/components/camel-hazelcast/src/main/java/org/apache/camel/processor/idempotent/hazelcast/HazelcastIdempotentRepository.java +++ b/components/camel-hazelcast/src/main/java/org/apache/camel/processor/idempotent/hazelcast/HazelcastIdempotentRepository.java @@ -21,6 +21,7 @@ import com.hazelcast.core.Hazelcast; import com.hazelcast.core.HazelcastInstance; import com.hazelcast.map.IMap; +import org.apache.camel.component.hazelcast.HazelcastSerializationFilterHelper; import org.apache.camel.spi.Configurer; import org.apache.camel.spi.IdempotentRepository; import org.apache.camel.spi.Metadata; @@ -59,6 +60,7 @@ protected void doStart() throws Exception { if (hazelcastInstance == null) { Config cfg = new XmlConfigBuilder().build(); cfg.setProperty("hazelcast.version.check.enabled", "false"); + HazelcastSerializationFilterHelper.applyDefault(cfg); hazelcastInstance = Hazelcast.newHazelcastInstance(cfg); useLocalHzInstance = true; } else { diff --git a/components/camel-hazelcast/src/test/java/org/apache/camel/component/hazelcast/HazelcastSerializationFilterHelperTest.java b/components/camel-hazelcast/src/test/java/org/apache/camel/component/hazelcast/HazelcastSerializationFilterHelperTest.java new file mode 100644 index 0000000000000..b85167081ce70 --- /dev/null +++ b/components/camel-hazelcast/src/test/java/org/apache/camel/component/hazelcast/HazelcastSerializationFilterHelperTest.java @@ -0,0 +1,73 @@ +/* + * 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.camel.component.hazelcast; + +import com.hazelcast.config.ClassFilter; +import com.hazelcast.config.Config; +import com.hazelcast.config.JavaSerializationFilterConfig; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class HazelcastSerializationFilterHelperTest { + + @Test + void appliesDefaultWhenNoneConfigured() { + Config config = new Config(); + assertNull(config.getSerializationConfig().getJavaSerializationFilterConfig()); + + HazelcastSerializationFilterHelper.applyDefault(config); + + JavaSerializationFilterConfig filter = config.getSerializationConfig().getJavaSerializationFilterConfig(); + assertNotNull(filter); + + ClassFilter whitelist = filter.getWhitelist(); + assertNotNull(whitelist); + assertTrue(whitelist.getPrefixes().contains("java.")); + assertTrue(whitelist.getPrefixes().contains("javax.")); + assertTrue(whitelist.getPrefixes().contains("org.apache.camel.")); + + ClassFilter blacklist = filter.getBlacklist(); + assertNotNull(blacklist); + assertTrue(blacklist.getPrefixes().contains("java.net.")); + } + + @Test + void respectsExistingUserConfiguration() { + Config config = new Config(); + JavaSerializationFilterConfig userFilter = new JavaSerializationFilterConfig(); + userFilter.setWhitelist(new ClassFilter().addPrefixes("com.example.")); + config.getSerializationConfig().setJavaSerializationFilterConfig(userFilter); + + HazelcastSerializationFilterHelper.applyDefault(config); + + JavaSerializationFilterConfig actual = config.getSerializationConfig().getJavaSerializationFilterConfig(); + assertSame(userFilter, actual); + assertEquals(1, actual.getWhitelist().getPrefixes().size()); + assertTrue(actual.getWhitelist().getPrefixes().contains("com.example.")); + } + + @Test + void handlesNullConfigGracefully() { + assertDoesNotThrow(() -> HazelcastSerializationFilterHelper.applyDefault(null)); + } +} diff --git a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc index 7a1064885054e..b684ddc2ded72 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc @@ -13,6 +13,32 @@ See the xref:camel-upgrade-recipes-tool.adoc[documentation] page for details. == Upgrading from 4.18.2 to 4.18.3 +=== camel-hazelcast + +Hazelcast instances created and managed by Camel (when no user-supplied +`Config` or `HazelcastInstance` is provided) now apply a default +`JavaSerializationFilterConfig` on the `SerializationConfig` of the +`Config` built by Camel. The default whitelists the class name prefixes +`java.`, `javax.`, `org.apache.camel.` and blacklists `java.net.`. + +This affects: + +* `camel-hazelcast` component endpoints when neither `hazelcastInstance`, +`hazelcastConfigUri`, nor a referenced `Config` is supplied +* `HazelcastAggregationRepository` and `HazelcastIdempotentRepository` +when no `hazelcastInstance` is supplied +* `HazelcastUtil#newInstance()` (no-arg) + +A user-supplied `JavaSerializationFilterConfig` (set on the +`SerializationConfig` of a `Config` provided via `hazelcastConfigUri`, a +referenced `Config` bean, or already wired into a pre-built +`HazelcastInstance`) is respected and is not overwritten. + +Applications that store classes outside the default whitelist on a +Hazelcast topic, queue, map, list, set, or in one of the repositories +above must provide their own `Config` with a +`JavaSerializationFilterConfig` configured for their class names. + === camel-jms JMS `ObjectMessage` support is now disabled by default. Java object serialization is a recurring source