diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/CommonScopeModelInitializer.java b/dubbo-common/src/main/java/org/apache/dubbo/common/CommonScopeModelInitializer.java index b3748db1b8..b9e5caa8bf 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/CommonScopeModelInitializer.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/CommonScopeModelInitializer.java @@ -22,6 +22,8 @@ import org.apache.dubbo.common.convert.ConverterUtil; import org.apache.dubbo.common.lang.ShutdownHookCallbacks; import org.apache.dubbo.common.status.reporter.FrameworkStatusReportService; import org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository; +import org.apache.dubbo.common.utils.DefaultSerializeClassChecker; +import org.apache.dubbo.common.utils.SerializeSecurityConfigurator; import org.apache.dubbo.common.utils.SerializeSecurityManager; import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; @@ -35,6 +37,7 @@ public class CommonScopeModelInitializer implements ScopeModelInitializer { beanFactory.registerBean(FrameworkExecutorRepository.class); beanFactory.registerBean(ConverterUtil.class); beanFactory.registerBean(SerializeSecurityManager.class); + beanFactory.registerBean(DefaultSerializeClassChecker.class); } @Override @@ -49,5 +52,6 @@ public class CommonScopeModelInitializer implements ScopeModelInitializer { public void initializeModuleModel(ModuleModel moduleModel) { ScopeBeanFactory beanFactory = moduleModel.getBeanFactory(); beanFactory.registerBean(new ConfigurationCache()); + beanFactory.registerBean(SerializeSecurityConfigurator.class); } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/beanutil/JavaBeanSerializeUtil.java b/dubbo-common/src/main/java/org/apache/dubbo/common/beanutil/JavaBeanSerializeUtil.java index 0b3da94c9a..7ad8058cab 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/beanutil/JavaBeanSerializeUtil.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/beanutil/JavaBeanSerializeUtil.java @@ -16,12 +16,6 @@ */ package org.apache.dubbo.common.beanutil; -import org.apache.dubbo.common.logger.Logger; -import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.common.utils.LogHelper; -import org.apache.dubbo.common.utils.ReflectUtils; -import org.apache.dubbo.common.utils.SerializeClassChecker; - import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Field; @@ -32,6 +26,12 @@ import java.util.HashMap; import java.util.IdentityHashMap; import java.util.Map; +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.utils.DefaultSerializeClassChecker; +import org.apache.dubbo.common.utils.LogHelper; +import org.apache.dubbo.common.utils.ReflectUtils; + public final class JavaBeanSerializeUtil { private static final Logger logger = LoggerFactory.getLogger(JavaBeanSerializeUtil.class); @@ -465,8 +465,7 @@ public final class JavaBeanSerializeUtil { if (isReferenceType(name)) { name = name.substring(1, name.length() - 1); } - SerializeClassChecker.getInstance().validateClass(name); - return Class.forName(name, false, loader); + return DefaultSerializeClassChecker.getInstance().loadClass(loader, name); } private static boolean isArray(String type) { diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/serial/SerializingExecutor.java b/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/serial/SerializingExecutor.java index 5c5327beff..5769c1296a 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/serial/SerializingExecutor.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/serial/SerializingExecutor.java @@ -16,15 +16,15 @@ package org.apache.dubbo.common.threadpool.serial; -import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; -import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.common.threadlocal.InternalThreadLocal; - import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; +import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.threadlocal.InternalThreadLocalMap; + import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_ERROR_RUN_THREAD_TASK; /** @@ -97,13 +97,13 @@ public final class SerializingExecutor implements Executor, Runnable { Runnable r; try { while ((r = runQueue.poll()) != null) { + InternalThreadLocalMap internalThreadLocalMap = InternalThreadLocalMap.getAndRemove(); try { - InternalThreadLocal.removeAll(); r.run(); } catch (RuntimeException e) { LOGGER.error(COMMON_ERROR_RUN_THREAD_TASK, "", "", "Exception while executing runnable " + r, e); } finally { - InternalThreadLocal.removeAll(); + InternalThreadLocalMap.set(internalThreadLocalMap); } } } finally { diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/AllowClassNotifyListener.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/AllowClassNotifyListener.java index 2346e0dc2c..e2f04b9e87 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/AllowClassNotifyListener.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/AllowClassNotifyListener.java @@ -22,5 +22,9 @@ public interface AllowClassNotifyListener { SerializeCheckStatus DEFAULT_STATUS = SerializeCheckStatus.WARN; - void notify(SerializeCheckStatus status, Set prefixList); + void notifyPrefix(Set allowedList, Set disAllowedList); + + void notifyCheckStatus(SerializeCheckStatus status); + + void notifyCheckSerializable(boolean checkSerializable); } diff --git a/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2AllowClassManager.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DefaultSerializeClassChecker.java similarity index 50% rename from dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2AllowClassManager.java rename to dubbo-common/src/main/java/org/apache/dubbo/common/utils/DefaultSerializeClassChecker.java index a0564d4f66..575057f33d 100644 --- a/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2AllowClassManager.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DefaultSerializeClassChecker.java @@ -14,17 +14,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.common.serialize.hessian2; +package org.apache.dubbo.common.utils; +import java.io.Serializable; import java.util.Arrays; import java.util.Set; import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.common.utils.AllowClassNotifyListener; -import org.apache.dubbo.common.utils.ConcurrentHashSet; -import org.apache.dubbo.common.utils.SerializeCheckStatus; -import org.apache.dubbo.common.utils.SerializeSecurityManager; import org.apache.dubbo.rpc.model.FrameworkModel; import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_UNTRUSTED_SERIALIZE_CLASS; @@ -33,26 +30,44 @@ import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_UNT * Inspired by Fastjson2 * see com.alibaba.fastjson2.filter.ContextAutoTypeBeforeHandler#apply(java.lang.String, java.lang.Class, long) */ -public class Hessian2AllowClassManager implements AllowClassNotifyListener { +public class DefaultSerializeClassChecker implements AllowClassNotifyListener { + private static final long MAGIC_HASH_CODE = 0xcbf29ce484222325L; private static final long MAGIC_PRIME = 0x100000001b3L; - private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(Hessian2AllowClassManager.class); + private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(DefaultSerializeClassChecker.class); private volatile SerializeCheckStatus checkStatus = AllowClassNotifyListener.DEFAULT_STATUS; private static final Set warnedClasses = new ConcurrentHashSet<>(1); + private volatile boolean checkSerializable = true; private volatile long[] allowPrefixes = new long[0]; - public Hessian2AllowClassManager(FrameworkModel frameworkModel) { + private volatile long[] disAllowPrefixes = new long[0]; + + public DefaultSerializeClassChecker(FrameworkModel frameworkModel) { SerializeSecurityManager serializeSecurityManager = frameworkModel.getBeanFactory().getOrRegisterBean(SerializeSecurityManager.class); serializeSecurityManager.registerListener(this); } @Override - public void notify(SerializeCheckStatus status, Set prefixList) { + public synchronized void notifyPrefix(Set allowedList, Set disAllowedList) { + this.allowPrefixes = loadPrefix(allowedList); + this.disAllowPrefixes = loadPrefix(disAllowedList); + } + + @Override + public synchronized void notifyCheckStatus(SerializeCheckStatus status) { this.checkStatus = status; - long[] array = new long[prefixList.size()]; + } + + @Override + public synchronized void notifyCheckSerializable(boolean checkSerializable) { + this.checkSerializable = checkSerializable; + } + + private static long[] loadPrefix(Set allowedList) { + long[] array = new long[allowedList.size()]; int index = 0; - for (String name : prefixList) { + for (String name : allowedList) { if (name == null || name.isEmpty()) { continue; } @@ -74,11 +89,33 @@ public class Hessian2AllowClassManager implements AllowClassNotifyListener { array = Arrays.copyOf(array, index); } Arrays.sort(array); - this.allowPrefixes = array; + return array; } + + /** + * Try load class + * + * @param className class name + * @throws IllegalArgumentException if class is blocked + */ public Class loadClass(ClassLoader classLoader, String className) throws ClassNotFoundException { - if (checkStatus == SerializeCheckStatus.DISABLED) { + Class aClass = loadClass0(classLoader, className); + if (checkSerializable && !aClass.isPrimitive() && !Serializable.class.isAssignableFrom(aClass)) { + String msg = "[Serialization Security] Serialized class " + className + " has not implement Serializable interface. " + + "Current mode is strict check, will disallow to deserialize it by default. "; + if (warnedClasses.add(className)) { + logger.error(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, "", "", msg); + } + + throw new IllegalArgumentException(msg); + } + + return aClass; + } + + private Class loadClass0(ClassLoader classLoader, String className) throws ClassNotFoundException { + if (checkStatus == SerializeCheckStatus.DISABLE) { return Class.forName(className, false, classLoader); } @@ -92,7 +129,7 @@ public class Hessian2AllowClassManager implements AllowClassNotifyListener { hash *= MAGIC_PRIME; if (Arrays.binarySearch(allowPrefixes, hash) >= 0) { - return Class.forName(className, false, classLoader); + return ClassUtils.forName(className, classLoader); } } @@ -105,16 +142,54 @@ public class Hessian2AllowClassManager implements AllowClassNotifyListener { } throw new IllegalArgumentException(msg); - } else { - Class clazz = Class.forName(className, false, classLoader); - if (warnedClasses.add(className)) { - logger.error(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, "", "", - "[Serialization Security] Serialized class " + clazz.getName() + " is not in allow list. " + + } + + hash = MAGIC_HASH_CODE; + for (int i = 0, typeNameLength = className.length(); i < typeNameLength; ++i) { + char ch = className.charAt(i); + if (ch == '$') { + ch = '.'; + } + hash ^= ch; + hash *= MAGIC_PRIME; + + if (Arrays.binarySearch(disAllowPrefixes, hash) >= 0) { + String msg = "[Serialization Security] Serialized class " + className + " is in disallow list. " + + "Current mode is `WARN`, will disallow to deserialize it by default. " + + "Please add it into security/serialize.allowlist or follow FAQ to configure it."; + throw new IllegalArgumentException(msg); + } + } + + hash = MAGIC_HASH_CODE; + for (int i = 0, typeNameLength = className.length(); i < typeNameLength; ++i) { + char ch = Character.toLowerCase(className.charAt(i)); + if (ch == '$') { + ch = '.'; + } + hash ^= ch; + hash *= MAGIC_PRIME; + + if (Arrays.binarySearch(disAllowPrefixes, hash) >= 0) { + String msg = "[Serialization Security] Serialized class " + className + " is in disallow list. " + + "Current mode is `WARN`, will disallow to deserialize it by default. " + + "Please add it into security/serialize.allowlist or follow FAQ to configure it."; + throw new IllegalArgumentException(msg); + } + } + + Class clazz = ClassUtils.forName(className, classLoader); + if (warnedClasses.add(className)) { + logger.error(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, "", "", + "[Serialization Security] Serialized class " + className + " is not in allow list. " + "Current mode is `WARN`, will allow to deserialize it by default. " + "Dubbo will set to `STRICT` mode by default in the future. " + "Please add it into security/serialize.allowlist or follow FAQ to configure it."); - } - return clazz; } + return clazz; + } + + public static DefaultSerializeClassChecker getInstance() { + return FrameworkModel.defaultModel().getBeanFactory().getBean(DefaultSerializeClassChecker.class); } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/PojoUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/PojoUtils.java index d2be81cf6c..016542e1dd 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/PojoUtils.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/PojoUtils.java @@ -16,11 +16,6 @@ */ package org.apache.dubbo.common.utils; -import org.apache.dubbo.common.config.ConfigurationUtils; -import org.apache.dubbo.common.constants.CommonConstants; -import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; -import org.apache.dubbo.common.logger.LoggerFactory; - import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Field; @@ -58,6 +53,11 @@ import java.util.concurrent.ConcurrentSkipListMap; import java.util.function.Consumer; import java.util.function.Supplier; +import org.apache.dubbo.common.config.ConfigurationUtils; +import org.apache.dubbo.common.constants.CommonConstants; +import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; +import org.apache.dubbo.common.logger.LoggerFactory; + import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_REFLECTIVE_OPERATION_FAILED; import static org.apache.dubbo.common.utils.ClassUtils.isAssignableFrom; @@ -410,10 +410,9 @@ public class PojoUtils { if (pojo instanceof Map && type != null) { Object className = ((Map) pojo).get("class"); if (className instanceof String) { - SerializeClassChecker.getInstance().validateClass((String) className); if (!CLASS_NOT_FOUND_CACHE.containsKey(className)) { try { - type = ClassUtils.forName((String) className); + type = DefaultSerializeClassChecker.getInstance().loadClass(ClassUtils.getClassLoader(), (String) className); } catch (ClassNotFoundException e) { CLASS_NOT_FOUND_CACHE.put((String) className, NOT_FOUND_VALUE); } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/SerializeCheckStatus.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/SerializeCheckStatus.java index 0046168312..c9f553fcee 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/SerializeCheckStatus.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/SerializeCheckStatus.java @@ -17,7 +17,28 @@ package org.apache.dubbo.common.utils; public enum SerializeCheckStatus { - DISABLED, - WARN, - STRICT, + /** + * Disable serialize check for all classes + */ + DISABLE(0), + + /** + * Only deny danger classes, warn if other classes are not in allow list + */ + WARN(1), + + /** + * Only allow classes in allow list, deny if other classes are not in allow list + */ + STRICT(2); + + private final int level; + + SerializeCheckStatus(int level) { + this.level = level; + } + + public int level() { + return level; + } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/SerializeClassChecker.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/SerializeClassChecker.java deleted file mode 100644 index ed0af8cabb..0000000000 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/SerializeClassChecker.java +++ /dev/null @@ -1,177 +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.dubbo.common.utils; - -import org.apache.dubbo.common.beanutil.JavaBeanSerializeUtil; -import org.apache.dubbo.common.constants.CommonConstants; -import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; -import org.apache.dubbo.common.logger.LoggerFactory; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Locale; -import java.util.Set; -import java.util.concurrent.atomic.AtomicLong; - -import static org.apache.dubbo.common.constants.CommonConstants.CLASS_DESERIALIZE_ALLOWED_LIST; -import static org.apache.dubbo.common.constants.CommonConstants.CLASS_DESERIALIZE_BLOCKED_LIST; -import static org.apache.dubbo.common.constants.CommonConstants.CLASS_DESERIALIZE_BLOCK_ALL; -import static org.apache.dubbo.common.constants.CommonConstants.SERIALIZE_BLOCKED_LIST_FILE_PATH; -import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_IO_EXCEPTION; -import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_UNSAFE_SERIALIZATION; - -public class SerializeClassChecker { - private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(SerializeClassChecker.class); - - private static volatile SerializeClassChecker INSTANCE = null; - - private final boolean OPEN_CHECK_CLASS; - private final boolean BLOCK_ALL_CLASS_EXCEPT_ALLOW; - private final Set CLASS_DESERIALIZE_ALLOWED_SET = new ConcurrentHashSet<>(); - private final Set CLASS_DESERIALIZE_BLOCKED_SET = new ConcurrentHashSet<>(); - - private final Object CACHE = new Object(); - private final LFUCache CLASS_ALLOW_LFU_CACHE = new LFUCache<>(); - private final LFUCache CLASS_BLOCK_LFU_CACHE = new LFUCache<>(); - - private final AtomicLong counter = new AtomicLong(0); - - private SerializeClassChecker() { - String openCheckClass = System.getProperty(CommonConstants.CLASS_DESERIALIZE_OPEN_CHECK, "true"); - OPEN_CHECK_CLASS = Boolean.parseBoolean(openCheckClass); - - String blockAllClassExceptAllow = System.getProperty(CLASS_DESERIALIZE_BLOCK_ALL, "false"); - - BLOCK_ALL_CLASS_EXCEPT_ALLOW = Boolean.parseBoolean(blockAllClassExceptAllow); - - String[] lines; - try { - ClassLoader classLoader = ClassUtils.getClassLoader(JavaBeanSerializeUtil.class); - if (classLoader != null) { - lines = IOUtils.readLines(classLoader.getResourceAsStream(SERIALIZE_BLOCKED_LIST_FILE_PATH)); - } else { - lines = IOUtils.readLines(ClassLoader.getSystemResourceAsStream(SERIALIZE_BLOCKED_LIST_FILE_PATH)); - } - for (String line : lines) { - line = line.trim(); - if (StringUtils.isEmpty(line) || line.startsWith("#")) { - continue; - } - CLASS_DESERIALIZE_BLOCKED_SET.add(line); - } - - } catch (IOException e) { - logger.error(COMMON_IO_EXCEPTION, "", "", "Failed to load blocked class list! Will ignore default blocked list.", e); - } - - String allowedClassList = System.getProperty(CLASS_DESERIALIZE_ALLOWED_LIST, "").trim().toLowerCase(Locale.ROOT); - String blockedClassList = System.getProperty(CLASS_DESERIALIZE_BLOCKED_LIST, "").trim().toLowerCase(Locale.ROOT); - - if (StringUtils.isNotEmpty(allowedClassList)) { - String[] classStrings = allowedClassList.trim().split(","); - CLASS_DESERIALIZE_ALLOWED_SET.addAll(Arrays.asList(classStrings)); - } - - if (StringUtils.isNotEmpty(blockedClassList)) { - String[] classStrings = blockedClassList.trim().split(","); - CLASS_DESERIALIZE_BLOCKED_SET.addAll(Arrays.asList(classStrings)); - } - - } - - public static SerializeClassChecker getInstance() { - if (INSTANCE == null) { - synchronized (SerializeClassChecker.class) { - if (INSTANCE == null) { - INSTANCE = new SerializeClassChecker(); - } - } - } - return INSTANCE; - } - - /** - * For ut only - */ - @Deprecated - protected static void clearInstance() { - INSTANCE = null; - } - - /** - * Check if a class is in block list, using prefix match - * - * @param name class name ( all are convert to lower case ) - * @throws IllegalArgumentException if class is blocked - */ - public void validateClass(String name) { - validateClass(name, true); - } - - public boolean validateClass(String name, boolean failOnError) { - if (!OPEN_CHECK_CLASS) { - return true; - } - - name = name.toLowerCase(Locale.ROOT); - if (CACHE == CLASS_ALLOW_LFU_CACHE.get(name)) { - return true; - } - - if (CACHE == CLASS_BLOCK_LFU_CACHE.get(name)) { - if (failOnError) { - error(name); - } - return false; - } - - for (String allowedPrefix : CLASS_DESERIALIZE_ALLOWED_SET) { - if (name.startsWith(allowedPrefix)) { - CLASS_ALLOW_LFU_CACHE.put(name, CACHE); - return true; - } - } - - for (String blockedPrefix : CLASS_DESERIALIZE_BLOCKED_SET) { - if (BLOCK_ALL_CLASS_EXCEPT_ALLOW || name.startsWith(blockedPrefix)) { - CLASS_BLOCK_LFU_CACHE.put(name, CACHE); - if (failOnError) { - error(name); - } - return false; - } - } - - CLASS_ALLOW_LFU_CACHE.put(name, CACHE); - return true; - } - - private void error(String name) { - String notice = "Trigger the safety barrier! " + - "Catch not allowed serialize class. " + - "Class name: " + name + " . " + - "This means currently maybe being attacking by others." + - "If you are sure this is a mistake, " + - "please add this class name to `" + CLASS_DESERIALIZE_ALLOWED_LIST + - "` as a system environment property."; - if (counter.incrementAndGet() % 1000 == 0 || counter.get() < 100) { - logger.error(PROTOCOL_UNSAFE_SERIALIZATION, "", "", notice); - } - throw new IllegalArgumentException(notice); - } - -} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/SerializeSecurityConfigurator.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/SerializeSecurityConfigurator.java new file mode 100644 index 0000000000..4f8206d44c --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/SerializeSecurityConfigurator.java @@ -0,0 +1,298 @@ +/* + * 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.dubbo.common.utils; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.lang.reflect.WildcardType; +import java.net.URL; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.dubbo.common.constants.CommonConstants; +import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.model.ModuleModel; +import org.apache.dubbo.rpc.model.ScopeClassLoaderListener; + +import static org.apache.dubbo.common.constants.CommonConstants.CLASS_DESERIALIZE_ALLOWED_LIST; +import static org.apache.dubbo.common.constants.CommonConstants.CLASS_DESERIALIZE_BLOCKED_LIST; +import static org.apache.dubbo.common.constants.CommonConstants.CLASS_DESERIALIZE_BLOCK_ALL; +import static org.apache.dubbo.common.constants.CommonConstants.SERIALIZE_ALLOW_LIST_FILE_PATH; +import static org.apache.dubbo.common.constants.CommonConstants.SERIALIZE_BLOCKED_LIST_FILE_PATH; +import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_IO_EXCEPTION; + +public class SerializeSecurityConfigurator implements ScopeClassLoaderListener { + private final SerializeSecurityManager serializeSecurityManager; + + private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(SerializeSecurityConfigurator.class); + + private final ModuleModel moduleModel; + + private final boolean autoTrustSerializeClass; + + private final int trustSerializeClassLevel; + + public SerializeSecurityConfigurator(ModuleModel moduleModel) { + this.moduleModel = moduleModel; + moduleModel.addClassLoaderListener(this); + + FrameworkModel frameworkModel = moduleModel.getApplicationModel().getFrameworkModel(); + serializeSecurityManager = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class); + + refreshStatus(); + refreshConfig(); + onAddClassLoader(moduleModel, Thread.currentThread().getContextClassLoader()); + + Optional applicationConfig = moduleModel.getApplicationModel().getApplicationConfigManager().getApplication(); + autoTrustSerializeClass = applicationConfig.map(ApplicationConfig::getAutoTrustSerializeClass).orElse(true); + trustSerializeClassLevel = applicationConfig.map(ApplicationConfig::getTrustSerializeClassLevel).orElse(3); + serializeSecurityManager.setCheckSerializable(applicationConfig.map(ApplicationConfig::getCheckSerializable).orElse(true)); + } + + @Override + public void onAddClassLoader(ModuleModel scopeModel, ClassLoader classLoader) { + refreshClassLoader(classLoader); + } + + @Override + public void onRemoveClassLoader(ModuleModel scopeModel, ClassLoader classLoader) { + // ignore + } + + private void refreshClassLoader(ClassLoader classLoader) { + loadAllow(classLoader); + loadBlocked(classLoader); + } + + private void refreshConfig() { + String allowedClassList = System.getProperty(CLASS_DESERIALIZE_ALLOWED_LIST, "").trim(); + String blockedClassList = System.getProperty(CLASS_DESERIALIZE_BLOCKED_LIST, "").trim(); + + if (StringUtils.isNotEmpty(allowedClassList)) { + String[] classStrings = allowedClassList.trim().split(","); + for (String className : classStrings) { + className = className.trim(); + if (StringUtils.isNotEmpty(className)) { + serializeSecurityManager.addToAlwaysAllowed(className); + } + } + } + + if (StringUtils.isNotEmpty(blockedClassList)) { + String[] classStrings = blockedClassList.trim().split(","); + for (String className : classStrings) { + className = className.trim(); + if (StringUtils.isNotEmpty(className)) { + serializeSecurityManager.addToDisAllowed(className); + } + } + } + } + + private void loadAllow(ClassLoader classLoader) { + Set urls = ClassLoaderResourceLoader.loadResources(SERIALIZE_ALLOW_LIST_FILE_PATH, classLoader); + for (URL u : urls) { + try { + logger.info("Read serialize allow list from " + u); + String[] lines = IOUtils.readLines(u.openStream()); + for (String line : lines) { + line = line.trim(); + if (StringUtils.isEmpty(line) || line.startsWith("#")) { + continue; + } + serializeSecurityManager.addToAlwaysAllowed(line); + } + } catch (IOException e) { + logger.error(COMMON_IO_EXCEPTION, "", "", "Failed to load allow class list! Will ignore allow lis from " + u, e); + } + } + } + + private void loadBlocked(ClassLoader classLoader) { + Set urls = ClassLoaderResourceLoader.loadResources(SERIALIZE_BLOCKED_LIST_FILE_PATH, classLoader); + for (URL u : urls) { + try { + logger.info("Read serialize blocked list from " + u); + String[] lines = IOUtils.readLines(u.openStream()); + for (String line : lines) { + line = line.trim(); + if (StringUtils.isEmpty(line) || line.startsWith("#")) { + continue; + } + serializeSecurityManager.addToDisAllowed(line); + } + } catch (IOException e) { + logger.error(COMMON_IO_EXCEPTION, "", "", "Failed to load blocked class list! Will ignore blocked lis from " + u, e); + } + } + } + + private void refreshStatus() { + Optional application = moduleModel.getApplicationModel().getApplicationConfigManager().getApplication(); + String statusString = application.map(ApplicationConfig::getSerializeCheckStatus).orElse(null); + SerializeCheckStatus checkStatus = null; + + if (StringUtils.isEmpty(statusString)) { + String openCheckClass = System.getProperty(CommonConstants.CLASS_DESERIALIZE_OPEN_CHECK, "true"); + if (!Boolean.parseBoolean(openCheckClass)) { + checkStatus = SerializeCheckStatus.DISABLE; + } + String blockAllClassExceptAllow = System.getProperty(CLASS_DESERIALIZE_BLOCK_ALL, "false"); + if (Boolean.parseBoolean(blockAllClassExceptAllow)) { + checkStatus = SerializeCheckStatus.STRICT; + } + } else { + checkStatus = SerializeCheckStatus.valueOf(statusString); + } + + if (checkStatus != null) { + serializeSecurityManager.setCheckStatus(checkStatus); + } + } + + public synchronized void registerInterface(Class clazz) { + if (!autoTrustSerializeClass) { + return; + } + + Set> markedClass = new HashSet<>(); + markedClass.add(clazz); + + addToAllow(clazz.getName()); + + Method[] methodsToExport = clazz.getMethods(); + + for (Method method : methodsToExport) { + Class[] parameterTypes = method.getParameterTypes(); + for (Class parameterType : parameterTypes) { + checkClass(markedClass, parameterType); + } + + Type[] genericParameterTypes = method.getGenericParameterTypes(); + for (Type genericParameterType : genericParameterTypes) { + checkType(markedClass, genericParameterType); + } + + Class returnType = method.getReturnType(); + checkClass(markedClass, returnType); + + Type genericReturnType = method.getGenericReturnType(); + checkType(markedClass, genericReturnType); + + Class[] exceptionTypes = method.getExceptionTypes(); + for (Class exceptionType : exceptionTypes) { + checkClass(markedClass, exceptionType); + } + + Type[] genericExceptionTypes = method.getGenericExceptionTypes(); + for (Type genericExceptionType : genericExceptionTypes) { + checkType(markedClass, genericExceptionType); + } + } + } + + private void checkType(Set> markedClass, Type type) { + if (type instanceof Class) { + checkClass(markedClass, (Class) type); + } else if (type instanceof ParameterizedType) { + ParameterizedType parameterizedType = (ParameterizedType) type; + checkClass(markedClass, (Class) parameterizedType.getRawType()); + for (Type actualTypeArgument : parameterizedType.getActualTypeArguments()) { + checkType(markedClass, actualTypeArgument); + } + } else if (type instanceof GenericArrayType) { + GenericArrayType genericArrayType = (GenericArrayType) type; + checkType(markedClass, genericArrayType.getGenericComponentType()); + } else if (type instanceof TypeVariable) { + TypeVariable typeVariable = (TypeVariable) type; + for (Type bound : typeVariable.getBounds()) { + checkType(markedClass, bound); + } + } else if (type instanceof WildcardType) { + WildcardType wildcardType = (WildcardType) type; + for (Type bound : wildcardType.getUpperBounds()) { + checkType(markedClass, bound); + } + for (Type bound : wildcardType.getLowerBounds()) { + checkType(markedClass, bound); + } + } + } + + private void checkClass(Set> markedClass, Class clazz) { + if (markedClass.contains(clazz)) { + return; + } + + markedClass.add(clazz); + + addToAllow(clazz.getName()); + + Class[] interfaces = clazz.getInterfaces(); + for (Class interfaceClass : interfaces) { + checkClass(markedClass, interfaceClass); + } + + Class superclass = clazz.getSuperclass(); + if (superclass != null) { + checkClass(markedClass, superclass); + } + + Field[] fields = clazz.getDeclaredFields(); + + for (Field field : fields) { + if (Modifier.isTransient(field.getModifiers())) { + continue; + } + + Class fieldClass = field.getType(); + checkClass(markedClass, fieldClass); + checkType(markedClass, field.getGenericType()); + } + } + + private void addToAllow(String className) { + // ignore jdk + if (className.startsWith("java.") || className.startsWith("javax.") || className.startsWith("com.sun.") || + className.startsWith("sun.") || className.startsWith("jdk.")) { + serializeSecurityManager.addToAllowed(className); + return; + } + + // add group package + String[] subs = className.split("\\."); + if (subs.length > trustSerializeClassLevel) { + serializeSecurityManager.addToAllowed(Arrays.stream(subs) + .limit(trustSerializeClassLevel) + .collect(Collectors.joining(".")) + "."); + } else { + serializeSecurityManager.addToAllowed(className); + } + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/SerializeSecurityManager.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/SerializeSecurityManager.java index f4ce027c91..798844eda9 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/SerializeSecurityManager.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/SerializeSecurityManager.java @@ -16,213 +16,131 @@ */ package org.apache.dubbo.common.utils; -import java.io.IOException; -import java.lang.reflect.Field; -import java.lang.reflect.GenericArrayType; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.lang.reflect.TypeVariable; -import java.lang.reflect.WildcardType; -import java.net.URL; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; +import java.util.Locale; +import java.util.Objects; import java.util.Set; -import java.util.stream.Collectors; import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.rpc.model.FrameworkModel; - -import static org.apache.dubbo.common.constants.CommonConstants.SERIALIZE_ALLOW_LIST_FILE_PATH; -import static org.apache.dubbo.common.constants.CommonConstants.SERIALIZE_CHECK_STATUS_KEY; -import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_IO_EXCEPTION; -import static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_INTERRUPTED; public class SerializeSecurityManager { - private final Set allowedPrefix = new LinkedHashSet<>(); - private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(SerializeSecurityManager.class); - private final SerializeClassChecker checker = SerializeClassChecker.getInstance(); + private final Set allowedPrefix = new ConcurrentHashSet<>(); + + private final Set alwaysAllowedPrefix = new ConcurrentHashSet<>(); + + private final Set disAllowedPrefix = new ConcurrentHashSet<>(); private final Set listeners = new ConcurrentHashSet<>(); - private volatile SerializeCheckStatus checkStatus = AllowClassNotifyListener.DEFAULT_STATUS; + private volatile SerializeCheckStatus checkStatus = null; - public SerializeSecurityManager(FrameworkModel frameworkModel) { - try { - Set classLoaders = frameworkModel.getClassLoaders(); - List urls = ClassLoaderResourceLoader.loadResources(SERIALIZE_ALLOW_LIST_FILE_PATH, classLoaders) - .values() - .stream() - .flatMap(Set::stream) - .collect(Collectors.toList()); - for (URL u : urls) { - try { - logger.info("Read serialize allow list from " + u); - String[] lines = IOUtils.readLines(u.openStream()); - for (String line : lines) { - line = line.trim(); - if (StringUtils.isEmpty(line) || line.startsWith("#")) { - continue; - } - allowedPrefix.add(line); - } - } catch (IOException e) { - logger.error(COMMON_IO_EXCEPTION, "", "", "Failed to load allow class list! Will ignore allow lis from " + u, e); - } - } + private volatile Boolean checkSerializable = null; - this.checkStatus = SerializeCheckStatus.valueOf(System.getProperty(SERIALIZE_CHECK_STATUS_KEY, AllowClassNotifyListener.DEFAULT_STATUS.name())); - logger.info("Serialize check level: " + checkStatus.name()); - } catch (InterruptedException e) { - logger.error(INTERNAL_INTERRUPTED, "", "", "Failed to load allow class list! Will ignore allow list from configuration.", e); - Thread.currentThread().interrupt(); - } - } - - public void registerInterface(Class clazz) { - Set> markedClass = new HashSet<>(); - markedClass.add(clazz); - - addToAllow(clazz.getName()); - - Method[] methodsToExport = clazz.getMethods(); - - for (Method method : methodsToExport) { - Class[] parameterTypes = method.getParameterTypes(); - for (Class parameterType : parameterTypes) { - checkClass(markedClass, parameterType); - } - - Type[] genericParameterTypes = method.getGenericParameterTypes(); - for (Type genericParameterType : genericParameterTypes) { - checkType(markedClass, genericParameterType); - } - - Class returnType = method.getReturnType(); - checkClass(markedClass, returnType); - - Type genericReturnType = method.getGenericReturnType(); - checkType(markedClass, genericReturnType); - - Class[] exceptionTypes = method.getExceptionTypes(); - for (Class exceptionType : exceptionTypes) { - checkClass(markedClass, exceptionType); - } - - Type[] genericExceptionTypes = method.getGenericExceptionTypes(); - for (Type genericExceptionType : genericExceptionTypes) { - checkType(markedClass, genericExceptionType); - } - } - } - - private void checkType(Set> markedClass, Type type) { - if (type instanceof Class) { - checkClass(markedClass, (Class) type); - } else if (type instanceof ParameterizedType) { - ParameterizedType parameterizedType = (ParameterizedType) type; - checkClass(markedClass, (Class) parameterizedType.getRawType()); - for (Type actualTypeArgument : parameterizedType.getActualTypeArguments()) { - checkType(markedClass, actualTypeArgument); - } - } else if (type instanceof GenericArrayType) { - GenericArrayType genericArrayType = (GenericArrayType) type; - checkType(markedClass, genericArrayType.getGenericComponentType()); - } else if (type instanceof TypeVariable) { - TypeVariable typeVariable = (TypeVariable) type; - for (Type bound : typeVariable.getBounds()) { - checkType(markedClass, bound); - } - } else if (type instanceof WildcardType) { - WildcardType wildcardType = (WildcardType) type; - for (Type bound : wildcardType.getUpperBounds()) { - checkType(markedClass, bound); - } - for (Type bound : wildcardType.getLowerBounds()) { - checkType(markedClass, bound); - } - } - } - - private void checkClass(Set> markedClass, Class clazz) { - if (markedClass.contains(clazz)) { - return; - } - - markedClass.add(clazz); - - addToAllow(clazz.getName()); - - Class[] interfaces = clazz.getInterfaces(); - for (Class interfaceClass : interfaces) { - checkClass(markedClass, interfaceClass); - } - - Class superclass = clazz.getSuperclass(); - if (superclass != null) { - checkClass(markedClass, superclass); - } - - Field[] fields = clazz.getDeclaredFields(); - - for (Field field : fields) { - if (Modifier.isTransient(field.getModifiers())) { - continue; - } - - Class fieldClass = field.getType(); - checkClass(markedClass, fieldClass); - checkType(markedClass, field.getGenericType()); - } - } - - protected void addToAllow(String className) { - if (!checker.validateClass(className, false)) { - return; - } - - boolean modified; - - // ignore jdk - if (className.startsWith("java.") || className.startsWith("javax.") || className.startsWith("com.sun.") || - className.startsWith("sun.") || className.startsWith("jdk.")) { - modified = allowedPrefix.add(className); - if (modified) { - notifyListeners(); - } - return; - } - - // add group package - String[] subs = className.split("\\."); - if (subs.length > 3) { - modified = allowedPrefix.add(subs[0] + "." + subs[1] + "." + subs[2]); - } else { - modified = allowedPrefix.add(className); - } + public void addToAlwaysAllowed(String className) { + boolean modified = alwaysAllowedPrefix.add(className); if (modified) { - notifyListeners(); + notifyPrefix(); + } + } + + public void addToAllowed(String className) { + if (disAllowedPrefix.stream().anyMatch(className::startsWith)) { + return; + } + + boolean modified = allowedPrefix.add(className); + + if (modified) { + notifyPrefix(); + } + } + + public void addToDisAllowed(String className) { + boolean modified = disAllowedPrefix.add(className); + modified = allowedPrefix.removeIf(allow -> allow.startsWith(className)) || modified; + + if (modified) { + notifyPrefix(); + } + + String lowerCase = className.toLowerCase(Locale.ROOT); + if (!Objects.equals(lowerCase, className)) { + addToDisAllowed(lowerCase); + } + } + + public void setCheckStatus(SerializeCheckStatus checkStatus) { + if (this.checkStatus == null) { + this.checkStatus = checkStatus; + logger.info("Serialize check level: " + checkStatus.name()); + notifyCheckStatus(); + return; + } + + // If has been set to WARN, ignore STRICT + if (this.checkStatus.level() < checkStatus.level()) { + return; + } + + this.checkStatus = checkStatus; + logger.info("Serialize check level: " + checkStatus.name()); + notifyCheckStatus(); + } + + public void setCheckSerializable(boolean checkSerializable) { + if (this.checkSerializable == null || (Boolean.TRUE.equals(this.checkSerializable) && !checkSerializable)) { + this.checkSerializable = checkSerializable; + logger.info("Serialize check serializable: " + checkSerializable); + notifyCheckSerializable(); } } public void registerListener(AllowClassNotifyListener listener) { listeners.add(listener); - listener.notify(checkStatus, allowedPrefix); + listener.notifyPrefix(getAllowedPrefix(), getDisAllowedPrefix()); + listener.notifyCheckSerializable(isCheckSerializable()); + listener.notifyCheckStatus(getCheckStatus()); } - private void notifyListeners() { + private void notifyPrefix() { for (AllowClassNotifyListener listener : listeners) { - listener.notify(checkStatus, allowedPrefix); + listener.notifyPrefix(getAllowedPrefix(), getDisAllowedPrefix()); } } + private void notifyCheckStatus() { + for (AllowClassNotifyListener listener : listeners) { + listener.notifyCheckStatus(getCheckStatus()); + } + } + + private void notifyCheckSerializable() { + for (AllowClassNotifyListener listener : listeners) { + listener.notifyCheckSerializable(isCheckSerializable()); + } + } + + protected SerializeCheckStatus getCheckStatus() { + return checkStatus == null ? AllowClassNotifyListener.DEFAULT_STATUS : checkStatus; + } + protected Set getAllowedPrefix() { - return allowedPrefix; + Set set = new ConcurrentHashSet<>(); + set.addAll(allowedPrefix); + set.addAll(alwaysAllowedPrefix); + return set; + } + + protected Set getDisAllowedPrefix() { + Set set = new ConcurrentHashSet<>(); + set.addAll(disAllowedPrefix); + return set; + } + + protected boolean isCheckSerializable() { + return checkSerializable == null || checkSerializable; } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/ApplicationConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/ApplicationConfig.java index 8a824617b8..78198f2462 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/ApplicationConfig.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/ApplicationConfig.java @@ -230,6 +230,14 @@ public class ApplicationConfig extends AbstractConfig { private Boolean enableEmptyProtection; + private String serializeCheckStatus; + + private Boolean autoTrustSerializeClass; + + private Integer trustSerializeClassLevel; + + private Boolean checkSerializable; + /** * thread pool management: default/isolation */ @@ -666,6 +674,39 @@ public class ApplicationConfig extends AbstractConfig { this.startupProbe = startupProbe; } + + public String getSerializeCheckStatus() { + return serializeCheckStatus; + } + + public void setSerializeCheckStatus(String serializeCheckStatus) { + this.serializeCheckStatus = serializeCheckStatus; + } + + public Boolean getAutoTrustSerializeClass() { + return autoTrustSerializeClass; + } + + public void setAutoTrustSerializeClass(Boolean autoTrustSerializeClass) { + this.autoTrustSerializeClass = autoTrustSerializeClass; + } + + public Integer getTrustSerializeClassLevel() { + return trustSerializeClassLevel; + } + + public void setTrustSerializeClassLevel(Integer trustSerializeClassLevel) { + this.trustSerializeClassLevel = trustSerializeClassLevel; + } + + public Boolean getCheckSerializable() { + return checkSerializable; + } + + public void setCheckSerializable(Boolean checkSerializable) { + this.checkSerializable = checkSerializable; + } + public void setExecutorManagementMode(String executorManagementMode) { this.executorManagementMode = executorManagementMode; } diff --git a/dubbo-common/src/test/java/com/service/deep1/deep2/deep3/DemoService3.java b/dubbo-common/src/test/java/com/service/deep1/deep2/deep3/DemoService3.java new file mode 100644 index 0000000000..30b8b7922e --- /dev/null +++ b/dubbo-common/src/test/java/com/service/deep1/deep2/deep3/DemoService3.java @@ -0,0 +1,20 @@ +/* + * 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 com.service.deep1.deep2.deep3; + +public interface DemoService3 { +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/beanutil/Bean.java b/dubbo-common/src/test/java/org/apache/dubbo/common/beanutil/Bean.java index 4ea53cb093..4e32514bea 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/common/beanutil/Bean.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/beanutil/Bean.java @@ -16,15 +16,16 @@ */ package org.apache.dubbo.common.beanutil; -import org.apache.dubbo.rpc.model.person.FullAddress; -import org.apache.dubbo.rpc.model.person.PersonStatus; -import org.apache.dubbo.rpc.model.person.Phone; - +import java.io.Serializable; import java.util.Collection; import java.util.Date; import java.util.Map; -public class Bean { +import org.apache.dubbo.rpc.model.person.FullAddress; +import org.apache.dubbo.rpc.model.person.PersonStatus; +import org.apache.dubbo.rpc.model.person.Phone; + +public class Bean implements Serializable { private Class type; diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/model/Person.java b/dubbo-common/src/test/java/org/apache/dubbo/common/model/Person.java index 81b42722dc..1dc2dba7c4 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/common/model/Person.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/model/Person.java @@ -16,9 +16,10 @@ */ package org.apache.dubbo.common.model; +import java.io.Serializable; import java.util.Arrays; -public class Person { +public class Person implements Serializable { byte oneByte = 123; private String name = "name1"; private int age = 11; diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/model/User.java b/dubbo-common/src/test/java/org/apache/dubbo/common/model/User.java index b322b7d6f6..3fca20d634 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/common/model/User.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/model/User.java @@ -17,12 +17,13 @@ package org.apache.dubbo.common.model; +import java.io.Serializable; import java.util.Objects; /** * this class has no nullary constructor and some field is primitive */ -public class User { +public class User implements Serializable { private int age; private String name; diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DefaultSerializeClassCheckerTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DefaultSerializeClassCheckerTest.java new file mode 100644 index 0000000000..5fd9b4850a --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DefaultSerializeClassCheckerTest.java @@ -0,0 +1,123 @@ +/* + * 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.dubbo.common.utils; + +import java.net.Socket; +import java.util.LinkedList; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import org.apache.dubbo.common.constants.CommonConstants; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class DefaultSerializeClassCheckerTest { + + @BeforeEach + void setUp() { + FrameworkModel.destroyAll(); + } + + @AfterEach + void tearDown() { + FrameworkModel.destroyAll(); + } + + @Test + void testCommon() throws ClassNotFoundException { + DefaultSerializeClassChecker defaultSerializeClassChecker = DefaultSerializeClassChecker.getInstance(); + + for (int i = 0; i < 10; i++) { + defaultSerializeClassChecker.loadClass(Thread.currentThread().getContextClassLoader(), ReentrantReadWriteLock.ReadLock.class.getName()); + defaultSerializeClassChecker.loadClass(Thread.currentThread().getContextClassLoader(), LinkedList.class.getName()); + defaultSerializeClassChecker.loadClass(Thread.currentThread().getContextClassLoader(), Integer.class.getName()); + defaultSerializeClassChecker.loadClass(Thread.currentThread().getContextClassLoader(), int.class.getName()); + } + + Assertions.assertThrows(IllegalArgumentException.class, () -> { + defaultSerializeClassChecker.loadClass(Thread.currentThread().getContextClassLoader(), Socket.class.getName()); + }); + } + + @Test + void testAddAllow() throws ClassNotFoundException { + System.setProperty(CommonConstants.CLASS_DESERIALIZE_ALLOWED_LIST, ReentrantReadWriteLock.WriteLock.class.getName() + "," + ReentrantReadWriteLock.ReadLock.class.getName()); + + DefaultSerializeClassChecker defaultSerializeClassChecker = DefaultSerializeClassChecker.getInstance(); + for (int i = 0; i < 10; i++) { + defaultSerializeClassChecker.loadClass(Thread.currentThread().getContextClassLoader(), ReentrantReadWriteLock.WriteLock.class.getName()); + defaultSerializeClassChecker.loadClass(Thread.currentThread().getContextClassLoader(), ReentrantReadWriteLock.ReadLock.class.getName()); + } + + System.clearProperty(CommonConstants.CLASS_DESERIALIZE_ALLOWED_LIST); + } + + @Test + void testAddBlock() { + System.setProperty(CommonConstants.CLASS_DESERIALIZE_BLOCKED_LIST, Runtime.class.getName() + "," + Thread.class.getName()); + + DefaultSerializeClassChecker defaultSerializeClassChecker = DefaultSerializeClassChecker.getInstance(); + for (int i = 0; i < 10; i++) { + Assertions.assertThrows(IllegalArgumentException.class, () -> { + defaultSerializeClassChecker.loadClass(Thread.currentThread().getContextClassLoader(), Runtime.class.getName()); + }); + Assertions.assertThrows(IllegalArgumentException.class, () -> { + defaultSerializeClassChecker.loadClass(Thread.currentThread().getContextClassLoader(), Thread.class.getName()); + }); + } + + System.clearProperty(CommonConstants.CLASS_DESERIALIZE_BLOCKED_LIST); + } + + @Test + void testBlockAll() throws ClassNotFoundException { + System.setProperty(CommonConstants.CLASS_DESERIALIZE_BLOCK_ALL, "true"); + System.setProperty(CommonConstants.CLASS_DESERIALIZE_ALLOWED_LIST, ReentrantReadWriteLock.WriteLock.class.getName()); + + DefaultSerializeClassChecker defaultSerializeClassChecker = DefaultSerializeClassChecker.getInstance(); + for (int i = 0; i < 10; i++) { + defaultSerializeClassChecker.loadClass(Thread.currentThread().getContextClassLoader(), ReentrantReadWriteLock.WriteLock.class.getName()); + Assertions.assertThrows(IllegalArgumentException.class, () -> { + defaultSerializeClassChecker.loadClass(Thread.currentThread().getContextClassLoader(), ReentrantReadWriteLock.ReadLock.class.getName()); + }); + } + + System.clearProperty(CommonConstants.CLASS_DESERIALIZE_BLOCK_ALL); + System.clearProperty(CommonConstants.CLASS_DESERIALIZE_ALLOWED_LIST); + } + + @Test + void testStatus() throws ClassNotFoundException { + FrameworkModel frameworkModel = FrameworkModel.defaultModel(); + SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class); + ssm.setCheckStatus(SerializeCheckStatus.STRICT); + + DefaultSerializeClassChecker defaultSerializeClassChecker = DefaultSerializeClassChecker.getInstance(); + Assertions.assertEquals(Integer.class, defaultSerializeClassChecker.loadClass(Thread.currentThread().getContextClassLoader(), Integer.class.getName())); + Assertions.assertThrows(IllegalArgumentException.class, () -> { + defaultSerializeClassChecker.loadClass(Thread.currentThread().getContextClassLoader(), ReentrantReadWriteLock.class.getName()); + }); + + ssm.setCheckStatus(SerializeCheckStatus.WARN); + Assertions.assertEquals(ReentrantReadWriteLock.class, defaultSerializeClassChecker.loadClass(Thread.currentThread().getContextClassLoader(), ReentrantReadWriteLock.class.getName())); + + ssm.setCheckStatus(SerializeCheckStatus.DISABLE); + Assertions.assertEquals(ReentrantReadWriteLock.class, defaultSerializeClassChecker.loadClass(Thread.currentThread().getContextClassLoader(), ReentrantReadWriteLock.class.getName())); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/PojoUtilsTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/PojoUtilsTest.java index 49caf104a5..9140168ecd 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/PojoUtilsTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/PojoUtilsTest.java @@ -16,20 +16,7 @@ */ package org.apache.dubbo.common.utils; -import org.apache.dubbo.common.model.Person; -import org.apache.dubbo.common.model.SerializablePerson; -import org.apache.dubbo.common.model.User; -import org.apache.dubbo.common.model.person.BigPerson; -import org.apache.dubbo.common.model.person.FullAddress; -import org.apache.dubbo.common.model.person.PersonInfo; -import org.apache.dubbo.common.model.person.PersonMap; -import org.apache.dubbo.common.model.person.PersonStatus; -import org.apache.dubbo.common.model.person.Phone; - -import com.alibaba.fastjson.JSONObject; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - +import java.io.Serializable; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.text.SimpleDateFormat; @@ -47,6 +34,20 @@ import java.util.List; import java.util.Map; import java.util.UUID; +import org.apache.dubbo.common.model.Person; +import org.apache.dubbo.common.model.SerializablePerson; +import org.apache.dubbo.common.model.User; +import org.apache.dubbo.common.model.person.BigPerson; +import org.apache.dubbo.common.model.person.FullAddress; +import org.apache.dubbo.common.model.person.PersonInfo; +import org.apache.dubbo.common.model.person.PersonMap; +import org.apache.dubbo.common.model.person.PersonStatus; +import org.apache.dubbo.common.model.person.Phone; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import com.alibaba.fastjson.JSONObject; + import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.junit.jupiter.api.Assertions.assertArrayEquals; @@ -793,7 +794,7 @@ class PojoUtilsTest { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY } - public static class BasicTestData { + public static class BasicTestData implements Serializable { public boolean a; public char b; @@ -865,7 +866,7 @@ class PojoUtilsTest { } - public static class Parent { + public static class Parent implements Serializable { public String gender; public String email; String name; @@ -910,7 +911,7 @@ class PojoUtilsTest { } } - public static class Child { + public static class Child implements Serializable { public String gender; public int age; String toy; @@ -950,7 +951,7 @@ class PojoUtilsTest { } } - public static class TestData { + public static class TestData implements Serializable { private Map children = new HashMap(); private List list = new ArrayList(); @@ -979,7 +980,7 @@ class PojoUtilsTest { } } - public static class InnerPojo { + public static class InnerPojo implements Serializable { private List list; public List getList() { @@ -991,7 +992,7 @@ class PojoUtilsTest { } } - public static class ListResult { + public static class ListResult implements Serializable { List result; public List getResult() { diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/SerializeClassCheckerTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/SerializeClassCheckerTest.java deleted file mode 100644 index 0ffd6546c3..0000000000 --- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/SerializeClassCheckerTest.java +++ /dev/null @@ -1,111 +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.dubbo.common.utils; - -import org.apache.dubbo.common.constants.CommonConstants; - -import javassist.compiler.Javac; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.net.Socket; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; - -class SerializeClassCheckerTest { - - @BeforeEach - public void setUp() { - SerializeClassChecker.clearInstance(); - } - - @AfterAll - public static void tearDown() { - SerializeClassChecker.clearInstance(); - } - - @Test - void testCommon() { - SerializeClassChecker serializeClassChecker = SerializeClassChecker.getInstance(); - - for (int i = 0; i < 10; i++) { - serializeClassChecker.validateClass(List.class.getName()); - serializeClassChecker.validateClass(LinkedList.class.getName()); - serializeClassChecker.validateClass(Integer.class.getName()); - serializeClassChecker.validateClass(int.class.getName()); - - serializeClassChecker.validateClass(List.class.getName().toUpperCase(Locale.ROOT)); - serializeClassChecker.validateClass(LinkedList.class.getName().toUpperCase(Locale.ROOT)); - serializeClassChecker.validateClass(Integer.class.getName().toUpperCase(Locale.ROOT)); - serializeClassChecker.validateClass(int.class.getName().toUpperCase(Locale.ROOT)); - } - - Assertions.assertThrows(IllegalArgumentException.class, ()-> { - serializeClassChecker.validateClass(Socket.class.getName()); - }); - } - - @Test - void testAddAllow() { - System.setProperty(CommonConstants.CLASS_DESERIALIZE_ALLOWED_LIST, Socket.class.getName() + "," + Javac.class.getName()); - - SerializeClassChecker serializeClassChecker = SerializeClassChecker.getInstance(); - for (int i = 0; i < 10; i++) { - serializeClassChecker.validateClass(Socket.class.getName()); - serializeClassChecker.validateClass(Javac.class.getName()); - } - - System.clearProperty(CommonConstants.CLASS_DESERIALIZE_ALLOWED_LIST); - } - - @Test - void testAddBlock() { - System.setProperty(CommonConstants.CLASS_DESERIALIZE_BLOCKED_LIST, LinkedList.class.getName() + "," + Integer.class.getName()); - - SerializeClassChecker serializeClassChecker = SerializeClassChecker.getInstance(); - for (int i = 0; i < 10; i++) { - Assertions.assertThrows(IllegalArgumentException.class, ()-> { - serializeClassChecker.validateClass(LinkedList.class.getName()); - }); - Assertions.assertThrows(IllegalArgumentException.class, ()-> { - serializeClassChecker.validateClass(Integer.class.getName()); - }); - } - - System.clearProperty(CommonConstants.CLASS_DESERIALIZE_BLOCKED_LIST); - } - - @Test - void testBlockAll() { - System.setProperty(CommonConstants.CLASS_DESERIALIZE_BLOCK_ALL, "true"); - System.setProperty(CommonConstants.CLASS_DESERIALIZE_ALLOWED_LIST, LinkedList.class.getName()); - - SerializeClassChecker serializeClassChecker = SerializeClassChecker.getInstance(); - for (int i = 0; i < 10; i++) { - serializeClassChecker.validateClass(LinkedList.class.getName()); - Assertions.assertThrows(IllegalArgumentException.class, ()-> { - serializeClassChecker.validateClass(Integer.class.getName()); - }); - } - - System.clearProperty(CommonConstants.CLASS_DESERIALIZE_BLOCK_ALL); - System.clearProperty(CommonConstants.CLASS_DESERIALIZE_ALLOWED_LIST); - } -} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/SerializeSecurityConfiguratorTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/SerializeSecurityConfiguratorTest.java new file mode 100644 index 0000000000..df527cc89d --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/SerializeSecurityConfiguratorTest.java @@ -0,0 +1,390 @@ +/* + * 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.dubbo.common.utils; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Vector; + +import org.apache.dubbo.common.constants.CommonConstants; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.rpc.model.ApplicationModel; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.model.ModuleModel; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import com.service.DemoService1; +import com.service.DemoService2; +import com.service.deep1.deep2.deep3.DemoService3; + +import static org.apache.dubbo.common.constants.CommonConstants.CLASS_DESERIALIZE_ALLOWED_LIST; +import static org.apache.dubbo.common.constants.CommonConstants.CLASS_DESERIALIZE_BLOCKED_LIST; + +class SerializeSecurityConfiguratorTest { + + @Test + void test() { + FrameworkModel frameworkModel = new FrameworkModel(); + ApplicationModel applicationModel = frameworkModel.newApplication(); + ModuleModel moduleModel = applicationModel.newModule(); + SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class); + + SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel); + serializeSecurityConfigurator.onAddClassLoader(moduleModel, Thread.currentThread().getContextClassLoader()); + + Assertions.assertTrue(ssm.getAllowedPrefix().contains("java.util.HashMap")); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.example.DemoInterface")); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.sun.Interface1")); + Assertions.assertTrue(ssm.getDisAllowedPrefix().contains("com.exampletest.DemoInterface")); + Assertions.assertFalse(ssm.getAllowedPrefix().contains("com.sun.Interface2")); + Assertions.assertEquals(AllowClassNotifyListener.DEFAULT_STATUS, ssm.getCheckStatus()); + + frameworkModel.destroy(); + } + + @Test + void testStatus1() { + FrameworkModel frameworkModel = new FrameworkModel(); + ApplicationModel applicationModel = frameworkModel.newApplication(); + ModuleModel moduleModel = applicationModel.newModule(); + ApplicationConfig applicationConfig = new ApplicationConfig("Test"); + applicationConfig.setSerializeCheckStatus(SerializeCheckStatus.DISABLE.name()); + applicationModel.getApplicationConfigManager().setApplication(applicationConfig); + + SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class); + + SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel); + serializeSecurityConfigurator.onAddClassLoader(moduleModel, Thread.currentThread().getContextClassLoader()); + + Assertions.assertEquals(SerializeCheckStatus.DISABLE, ssm.getCheckStatus()); + + frameworkModel.destroy(); + } + + @Test + void testStatus2() { + FrameworkModel frameworkModel = new FrameworkModel(); + ApplicationModel applicationModel = frameworkModel.newApplication(); + ModuleModel moduleModel = applicationModel.newModule(); + ApplicationConfig applicationConfig = new ApplicationConfig("Test"); + applicationConfig.setSerializeCheckStatus(SerializeCheckStatus.WARN.name()); + applicationModel.getApplicationConfigManager().setApplication(applicationConfig); + + SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class); + + SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel); + serializeSecurityConfigurator.onAddClassLoader(moduleModel, Thread.currentThread().getContextClassLoader()); + + Assertions.assertEquals(SerializeCheckStatus.WARN, ssm.getCheckStatus()); + + frameworkModel.destroy(); + } + + @Test + void testStatus3() { + FrameworkModel frameworkModel = new FrameworkModel(); + ApplicationModel applicationModel = frameworkModel.newApplication(); + ModuleModel moduleModel = applicationModel.newModule(); + ApplicationConfig applicationConfig = new ApplicationConfig("Test"); + applicationConfig.setSerializeCheckStatus(SerializeCheckStatus.STRICT.name()); + applicationModel.getApplicationConfigManager().setApplication(applicationConfig); + + SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class); + + SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel); + serializeSecurityConfigurator.onAddClassLoader(moduleModel, Thread.currentThread().getContextClassLoader()); + + Assertions.assertEquals(SerializeCheckStatus.STRICT, ssm.getCheckStatus()); + + frameworkModel.destroy(); + } + + @Test + void testStatus4() { + FrameworkModel frameworkModel = new FrameworkModel(); + ApplicationModel applicationModel = frameworkModel.newApplication(); + ModuleModel moduleModel = applicationModel.newModule(); + System.setProperty(CommonConstants.CLASS_DESERIALIZE_OPEN_CHECK, "false"); + + SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class); + + SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel); + serializeSecurityConfigurator.onAddClassLoader(moduleModel, Thread.currentThread().getContextClassLoader()); + + Assertions.assertEquals(SerializeCheckStatus.DISABLE, ssm.getCheckStatus()); + + System.clearProperty(CommonConstants.CLASS_DESERIALIZE_OPEN_CHECK); + frameworkModel.destroy(); + } + + @Test + void testStatus5() { + FrameworkModel frameworkModel = new FrameworkModel(); + ApplicationModel applicationModel = frameworkModel.newApplication(); + ModuleModel moduleModel = applicationModel.newModule(); + System.setProperty(CommonConstants.CLASS_DESERIALIZE_BLOCK_ALL, "true"); + + SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class); + + SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel); + serializeSecurityConfigurator.onAddClassLoader(moduleModel, Thread.currentThread().getContextClassLoader()); + + Assertions.assertEquals(SerializeCheckStatus.STRICT, ssm.getCheckStatus()); + + System.clearProperty(CommonConstants.CLASS_DESERIALIZE_BLOCK_ALL); + frameworkModel.destroy(); + } + + @Test + void testConfig1() { + FrameworkModel frameworkModel = new FrameworkModel(); + ApplicationModel applicationModel = frameworkModel.newApplication(); + ModuleModel moduleModel = applicationModel.newModule(); + System.setProperty(CLASS_DESERIALIZE_ALLOWED_LIST, "test.package1, test.package2, ,"); + + SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class); + + SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel); + serializeSecurityConfigurator.onAddClassLoader(moduleModel, Thread.currentThread().getContextClassLoader()); + + Assertions.assertTrue(ssm.getAllowedPrefix().contains("test.package1")); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("test.package2")); + + System.clearProperty(CommonConstants.CLASS_DESERIALIZE_ALLOWED_LIST); + frameworkModel.destroy(); + + } + + @Test + void testConfig2() { + FrameworkModel frameworkModel = new FrameworkModel(); + ApplicationModel applicationModel = frameworkModel.newApplication(); + ModuleModel moduleModel = applicationModel.newModule(); + System.setProperty(CLASS_DESERIALIZE_BLOCKED_LIST, "test.package1, test.package2, ,"); + + SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class); + + SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel); + serializeSecurityConfigurator.onAddClassLoader(moduleModel, Thread.currentThread().getContextClassLoader()); + + Assertions.assertTrue(ssm.getDisAllowedPrefix().contains("test.package1")); + Assertions.assertTrue(ssm.getDisAllowedPrefix().contains("test.package2")); + + System.clearProperty(CommonConstants.CLASS_DESERIALIZE_BLOCK_ALL); + frameworkModel.destroy(); + + } + + @Test + void testConfig3() { + FrameworkModel frameworkModel = new FrameworkModel(); + ApplicationModel applicationModel = frameworkModel.newApplication(); + ModuleModel moduleModel = applicationModel.newModule(); + System.setProperty(CLASS_DESERIALIZE_ALLOWED_LIST, "test.package1, test.package2, ,"); + System.setProperty(CLASS_DESERIALIZE_BLOCKED_LIST, "test.package1, test.package2, ,"); + + SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class); + + SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel); + serializeSecurityConfigurator.onAddClassLoader(moduleModel, Thread.currentThread().getContextClassLoader()); + + Assertions.assertTrue(ssm.getAllowedPrefix().contains("test.package1")); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("test.package2")); + + System.clearProperty(CommonConstants.CLASS_DESERIALIZE_ALLOWED_LIST); + System.clearProperty(CommonConstants.CLASS_DESERIALIZE_BLOCK_ALL); + frameworkModel.destroy(); + + } + + @Test + void testSerializable1() { + FrameworkModel frameworkModel = new FrameworkModel(); + ApplicationModel applicationModel = frameworkModel.newApplication(); + ApplicationConfig applicationConfig = new ApplicationConfig("Test"); + applicationConfig.setCheckSerializable(false); + applicationModel.getApplicationConfigManager().setApplication(applicationConfig); + ModuleModel moduleModel = applicationModel.newModule(); + + SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class); + + SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel); + serializeSecurityConfigurator.onAddClassLoader(moduleModel, Thread.currentThread().getContextClassLoader()); + + Assertions.assertFalse(ssm.isCheckSerializable()); + + frameworkModel.destroy(); + + } + + @Test + void testSerializable2() { + FrameworkModel frameworkModel = new FrameworkModel(); + ApplicationModel applicationModel = frameworkModel.newApplication(); + ModuleModel moduleModel = applicationModel.newModule(); + + SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class); + + SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel); + serializeSecurityConfigurator.onAddClassLoader(moduleModel, Thread.currentThread().getContextClassLoader()); + + Assertions.assertTrue(ssm.isCheckSerializable()); + + frameworkModel.destroy(); + + } + + @Test + void testRegister1() { + FrameworkModel frameworkModel = new FrameworkModel(); + ApplicationModel applicationModel = frameworkModel.newApplication(); + ModuleModel moduleModel = applicationModel.newModule(); + + SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class); + + SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel); + serializeSecurityConfigurator.onAddClassLoader(moduleModel, Thread.currentThread().getContextClassLoader()); + + serializeSecurityConfigurator.registerInterface(DemoService1.class); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.service.DemoService1")); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo1")); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo2")); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo3")); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo4")); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo5")); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo6")); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo7")); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo8")); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Simple")); + + Assertions.assertTrue(ssm.getAllowedPrefix().contains(List.class.getName())); + Assertions.assertTrue(ssm.getAllowedPrefix().contains(Set.class.getName())); + Assertions.assertTrue(ssm.getAllowedPrefix().contains(Map.class.getName())); + Assertions.assertTrue(ssm.getAllowedPrefix().contains(LinkedList.class.getName())); + Assertions.assertTrue(ssm.getAllowedPrefix().contains(Vector.class.getName())); + Assertions.assertTrue(ssm.getAllowedPrefix().contains(HashSet.class.getName())); + + frameworkModel.destroy(); + } + + + @Test + void testRegister2() { + FrameworkModel frameworkModel = new FrameworkModel(); + ApplicationModel applicationModel = frameworkModel.newApplication(); + ModuleModel moduleModel = applicationModel.newModule(); + + SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class); + + SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel); + serializeSecurityConfigurator.onAddClassLoader(moduleModel, Thread.currentThread().getContextClassLoader()); + + serializeSecurityConfigurator.registerInterface(DemoService2.class); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.service.DemoService2")); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo1")); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo2")); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo3")); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo4")); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo5")); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo6")); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo7")); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo8")); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Simple")); + + Assertions.assertTrue(ssm.getAllowedPrefix().contains(List.class.getName())); + Assertions.assertTrue(ssm.getAllowedPrefix().contains(Set.class.getName())); + Assertions.assertTrue(ssm.getAllowedPrefix().contains(Map.class.getName())); + Assertions.assertTrue(ssm.getAllowedPrefix().contains(LinkedList.class.getName())); + Assertions.assertTrue(ssm.getAllowedPrefix().contains(Vector.class.getName())); + Assertions.assertTrue(ssm.getAllowedPrefix().contains(HashSet.class.getName())); + + frameworkModel.destroy(); + } + + @Test + void testRegister3() { + FrameworkModel frameworkModel = new FrameworkModel(); + ApplicationModel applicationModel = frameworkModel.newApplication(); + ModuleModel moduleModel = applicationModel.newModule(); + ApplicationConfig applicationConfig = new ApplicationConfig("Test"); + applicationConfig.setAutoTrustSerializeClass(false); + applicationModel.getApplicationConfigManager().setApplication(applicationConfig); + + SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class); + + SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel); + serializeSecurityConfigurator.onAddClassLoader(moduleModel, Thread.currentThread().getContextClassLoader()); + + serializeSecurityConfigurator.registerInterface(DemoService1.class); + Assertions.assertFalse(ssm.getAllowedPrefix().contains("com.service.DemoService1")); + Assertions.assertFalse(ssm.getAllowedPrefix().contains("com.pojo.Demo1")); + Assertions.assertFalse(ssm.getAllowedPrefix().contains("com.pojo.Demo2")); + Assertions.assertFalse(ssm.getAllowedPrefix().contains("com.pojo.Demo3")); + Assertions.assertFalse(ssm.getAllowedPrefix().contains("com.pojo.Demo4")); + Assertions.assertFalse(ssm.getAllowedPrefix().contains("com.pojo.Demo5")); + Assertions.assertFalse(ssm.getAllowedPrefix().contains("com.pojo.Demo6")); + Assertions.assertFalse(ssm.getAllowedPrefix().contains("com.pojo.Demo7")); + Assertions.assertFalse(ssm.getAllowedPrefix().contains("com.pojo.Demo8")); + Assertions.assertFalse(ssm.getAllowedPrefix().contains("com.pojo.Simple")); + + frameworkModel.destroy(); + } + + @Test + void testRegister4() { + FrameworkModel frameworkModel = new FrameworkModel(); + ApplicationModel applicationModel = frameworkModel.newApplication(); + ModuleModel moduleModel = applicationModel.newModule(); + ApplicationConfig applicationConfig = new ApplicationConfig("Test"); + applicationConfig.setTrustSerializeClassLevel(4); + applicationModel.getApplicationConfigManager().setApplication(applicationConfig); + + SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class); + + SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel); + serializeSecurityConfigurator.onAddClassLoader(moduleModel, Thread.currentThread().getContextClassLoader()); + + serializeSecurityConfigurator.registerInterface(DemoService3.class); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.service.deep1.deep2.")); + + frameworkModel.destroy(); + } + + @Test + void testRegister5() { + FrameworkModel frameworkModel = new FrameworkModel(); + ApplicationModel applicationModel = frameworkModel.newApplication(); + ModuleModel moduleModel = applicationModel.newModule(); + ApplicationConfig applicationConfig = new ApplicationConfig("Test"); + applicationConfig.setTrustSerializeClassLevel(10); + applicationModel.getApplicationConfigManager().setApplication(applicationConfig); + + SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class); + + SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel); + serializeSecurityConfigurator.onAddClassLoader(moduleModel, Thread.currentThread().getContextClassLoader()); + + serializeSecurityConfigurator.registerInterface(DemoService3.class); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.service.deep1.deep2.deep3.DemoService3")); + + frameworkModel.destroy(); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/SerializeSecurityManagerTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/SerializeSecurityManagerTest.java index 69eeaf2c25..3e5a1048df 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/SerializeSecurityManagerTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/SerializeSecurityManagerTest.java @@ -16,113 +16,115 @@ */ package org.apache.dubbo.common.utils; -import org.apache.dubbo.rpc.model.FrameworkModel; - -import com.service.DemoService1; -import com.service.DemoService2; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Vector; - -public class SerializeSecurityManagerTest { +class SerializeSecurityManagerTest { @Test - public void test() { - SerializeSecurityManager ssm = new SerializeSecurityManager(FrameworkModel.defaultModel()); + void testPrefix() { + TestAllowClassNotifyListener.setCount(0); + SerializeSecurityManager ssm = new SerializeSecurityManager(); ssm.registerListener(new TestAllowClassNotifyListener()); + + ssm.addToAllowed("java.util.HashMap"); + ssm.addToAllowed("com.example.DemoInterface"); + ssm.addToAllowed("com.sun.Interface1"); + ssm.addToAllowed("com.sun.Interface2"); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("java.util.HashMap")); Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.example.DemoInterface")); Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.sun.Interface1")); - Assertions.assertFalse(ssm.getAllowedPrefix().contains("com.sun.Interface2")); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.sun.Interface2")); - Assertions.assertEquals(ssm.getAllowedPrefix(), TestAllowClassNotifyListener.getPrefixList()); + Assertions.assertEquals(ssm.getAllowedPrefix(), TestAllowClassNotifyListener.getAllowedList()); + Assertions.assertEquals(7, TestAllowClassNotifyListener.getCount()); + + ssm.addToDisAllowed("com.sun.Interface"); + Assertions.assertFalse(ssm.getAllowedPrefix().contains("com.sun.Interface1")); + Assertions.assertFalse(ssm.getAllowedPrefix().contains("com.sun.Interface2")); + Assertions.assertEquals(ssm.getDisAllowedPrefix(), TestAllowClassNotifyListener.getDisAllowedList()); + Assertions.assertEquals(9, TestAllowClassNotifyListener.getCount()); + + ssm.addToAllowed("com.sun.Interface3"); + Assertions.assertFalse(ssm.getAllowedPrefix().contains("com.sun.Interface3")); + Assertions.assertEquals(9, TestAllowClassNotifyListener.getCount()); + + ssm.addToAllowed("java.util.HashMap"); + Assertions.assertEquals(9, TestAllowClassNotifyListener.getCount()); + + ssm.addToDisAllowed("com.sun.Interface"); + Assertions.assertEquals(9, TestAllowClassNotifyListener.getCount()); + + ssm.addToAlwaysAllowed("com.sun.Interface3"); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.sun.Interface3")); + Assertions.assertEquals(10, TestAllowClassNotifyListener.getCount()); + + ssm.addToAlwaysAllowed("com.sun.Interface3"); + Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.sun.Interface3")); + Assertions.assertEquals(10, TestAllowClassNotifyListener.getCount()); } @Test - public void addToAllow() { - SerializeSecurityManager ssm = new SerializeSecurityManager(FrameworkModel.defaultModel()); + void testStatus1() { + SerializeSecurityManager ssm = new SerializeSecurityManager(); ssm.registerListener(new TestAllowClassNotifyListener()); - Assertions.assertFalse(ssm.getAllowedPrefix().contains("com.sun.Interface2")); - Assertions.assertEquals(ssm.getAllowedPrefix(), TestAllowClassNotifyListener.getPrefixList()); - ssm.addToAllow("com.sun.Interface2"); - Assertions.assertFalse(ssm.getAllowedPrefix().contains("com.sun.Interface2")); - Assertions.assertEquals(ssm.getAllowedPrefix(), TestAllowClassNotifyListener.getPrefixList()); + Assertions.assertEquals(AllowClassNotifyListener.DEFAULT_STATUS, ssm.getCheckStatus()); + Assertions.assertEquals(AllowClassNotifyListener.DEFAULT_STATUS, TestAllowClassNotifyListener.getStatus()); - ssm.addToAllow("java.util.Interface1"); - Assertions.assertTrue(ssm.getAllowedPrefix().contains("java.util.Interface1")); - Assertions.assertEquals(ssm.getAllowedPrefix(), TestAllowClassNotifyListener.getPrefixList()); + ssm.setCheckStatus(SerializeCheckStatus.STRICT); + Assertions.assertEquals(ssm.getCheckStatus(), TestAllowClassNotifyListener.getStatus()); + Assertions.assertEquals(SerializeCheckStatus.STRICT, TestAllowClassNotifyListener.getStatus()); - ssm.addToAllow("java.util.package.Interface1"); - Assertions.assertTrue(ssm.getAllowedPrefix().contains("java.util.package.Interface1")); - Assertions.assertEquals(ssm.getAllowedPrefix(), TestAllowClassNotifyListener.getPrefixList()); + ssm.setCheckStatus(SerializeCheckStatus.WARN); + Assertions.assertEquals(ssm.getCheckStatus(), TestAllowClassNotifyListener.getStatus()); + Assertions.assertEquals(SerializeCheckStatus.WARN, TestAllowClassNotifyListener.getStatus()); - ssm.addToAllow("com.example.Interface2"); - Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.example.Interface2")); - Assertions.assertEquals(ssm.getAllowedPrefix(), TestAllowClassNotifyListener.getPrefixList()); + ssm.setCheckStatus(SerializeCheckStatus.STRICT); + Assertions.assertEquals(ssm.getCheckStatus(), TestAllowClassNotifyListener.getStatus()); + Assertions.assertEquals(SerializeCheckStatus.WARN, TestAllowClassNotifyListener.getStatus()); - ssm.addToAllow("com.example.package.Interface1"); - Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.example.package")); - Assertions.assertEquals(ssm.getAllowedPrefix(), TestAllowClassNotifyListener.getPrefixList()); + ssm.setCheckStatus(SerializeCheckStatus.DISABLE); + Assertions.assertEquals(ssm.getCheckStatus(), TestAllowClassNotifyListener.getStatus()); + Assertions.assertEquals(SerializeCheckStatus.DISABLE, TestAllowClassNotifyListener.getStatus()); + + ssm.setCheckStatus(SerializeCheckStatus.STRICT); + Assertions.assertEquals(ssm.getCheckStatus(), TestAllowClassNotifyListener.getStatus()); + Assertions.assertEquals(SerializeCheckStatus.DISABLE, TestAllowClassNotifyListener.getStatus()); + + ssm.setCheckStatus(SerializeCheckStatus.WARN); + Assertions.assertEquals(ssm.getCheckStatus(), TestAllowClassNotifyListener.getStatus()); + Assertions.assertEquals(SerializeCheckStatus.DISABLE, TestAllowClassNotifyListener.getStatus()); } @Test - public void testRegister1() { - SerializeSecurityManager ssm = new SerializeSecurityManager(FrameworkModel.defaultModel()); + void testStatus2() { + SerializeSecurityManager ssm = new SerializeSecurityManager(); + + ssm.setCheckStatus(SerializeCheckStatus.STRICT); ssm.registerListener(new TestAllowClassNotifyListener()); - - ssm.registerInterface(DemoService1.class); - Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.service.DemoService1")); - Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo1")); - Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo2")); - Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo3")); - Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo4")); - Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo5")); - Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo6")); - Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo7")); - Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo8")); - Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Simple")); - - Assertions.assertTrue(ssm.getAllowedPrefix().contains(List.class.getName())); - Assertions.assertTrue(ssm.getAllowedPrefix().contains(Set.class.getName())); - Assertions.assertTrue(ssm.getAllowedPrefix().contains(Map.class.getName())); - Assertions.assertTrue(ssm.getAllowedPrefix().contains(LinkedList.class.getName())); - Assertions.assertTrue(ssm.getAllowedPrefix().contains(Vector.class.getName())); - Assertions.assertTrue(ssm.getAllowedPrefix().contains(HashSet.class.getName())); - - Assertions.assertEquals(ssm.getAllowedPrefix(), TestAllowClassNotifyListener.getPrefixList()); + Assertions.assertEquals(ssm.getCheckStatus(), TestAllowClassNotifyListener.getStatus()); + Assertions.assertEquals(SerializeCheckStatus.STRICT, TestAllowClassNotifyListener.getStatus()); } - @Test - public void testRegister2() { - SerializeSecurityManager ssm = new SerializeSecurityManager(FrameworkModel.defaultModel()); + void testSerializable() { + SerializeSecurityManager ssm = new SerializeSecurityManager(); ssm.registerListener(new TestAllowClassNotifyListener()); - ssm.registerInterface(DemoService2.class); - Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.service.DemoService2")); - Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo1")); - Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo2")); - Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo3")); - Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo4")); - Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo5")); - Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo6")); - Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo7")); - Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Demo8")); - Assertions.assertTrue(ssm.getAllowedPrefix().contains("com.pojo.Simple")); + Assertions.assertTrue(ssm.isCheckSerializable()); + Assertions.assertTrue(TestAllowClassNotifyListener.isCheckSerializable()); - Assertions.assertTrue(ssm.getAllowedPrefix().contains(List.class.getName())); - Assertions.assertTrue(ssm.getAllowedPrefix().contains(Set.class.getName())); - Assertions.assertTrue(ssm.getAllowedPrefix().contains(Map.class.getName())); - Assertions.assertTrue(ssm.getAllowedPrefix().contains(LinkedList.class.getName())); - Assertions.assertTrue(ssm.getAllowedPrefix().contains(Vector.class.getName())); - Assertions.assertTrue(ssm.getAllowedPrefix().contains(HashSet.class.getName())); + ssm.setCheckSerializable(true); + Assertions.assertTrue(ssm.isCheckSerializable()); + Assertions.assertTrue(TestAllowClassNotifyListener.isCheckSerializable()); - Assertions.assertEquals(ssm.getAllowedPrefix(), TestAllowClassNotifyListener.getPrefixList()); + ssm.setCheckSerializable(false); + Assertions.assertFalse(ssm.isCheckSerializable()); + Assertions.assertFalse(TestAllowClassNotifyListener.isCheckSerializable()); + + ssm.setCheckSerializable(true); + Assertions.assertFalse(ssm.isCheckSerializable()); + Assertions.assertFalse(TestAllowClassNotifyListener.isCheckSerializable()); } } diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/TestAllowClassNotifyListener.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/TestAllowClassNotifyListener.java index 362939cc4d..c0b2bcd3c8 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/TestAllowClassNotifyListener.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/TestAllowClassNotifyListener.java @@ -17,17 +17,58 @@ package org.apache.dubbo.common.utils; import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; public class TestAllowClassNotifyListener implements AllowClassNotifyListener { - private final static AtomicReference> prefixList = new AtomicReference<>(); + private final static AtomicReference status = new AtomicReference<>(); + private final static AtomicReference> allowedList = new AtomicReference<>(); + private final static AtomicReference> disAllowedList = new AtomicReference<>(); + private final static AtomicBoolean checkSerializable = new AtomicBoolean(); + + private final static AtomicInteger count = new AtomicInteger(0); @Override - public void notify(SerializeCheckStatus status, Set prefixList) { - TestAllowClassNotifyListener.prefixList.set(prefixList); + public void notifyPrefix(Set allowedList, Set disAllowedList) { + TestAllowClassNotifyListener.allowedList.set(allowedList); + TestAllowClassNotifyListener.disAllowedList.set(disAllowedList); + count.incrementAndGet(); } - public static Set getPrefixList() { - return prefixList.get(); + @Override + public void notifyCheckStatus(SerializeCheckStatus status) { + TestAllowClassNotifyListener.status.set(status); + count.incrementAndGet(); + } + + @Override + public void notifyCheckSerializable(boolean checkSerializable) { + TestAllowClassNotifyListener.checkSerializable.set(checkSerializable); + count.incrementAndGet(); + } + + public static SerializeCheckStatus getStatus() { + return status.get(); + } + + public static Set getAllowedList() { + return allowedList.get(); + } + + public static Set getDisAllowedList() { + return disAllowedList.get(); + } + + public static boolean isCheckSerializable() { + return checkSerializable.get(); + } + + public static int getCount() { + return count.get(); + } + + public static void setCount(int count) { + TestAllowClassNotifyListener.count.set(count); } } diff --git a/dubbo-common/src/test/resources/security/serialize.allowlist b/dubbo-common/src/test/resources/security/serialize.allowlist index 0e7c6e7208..128005c845 100644 --- a/dubbo-common/src/test/resources/security/serialize.allowlist +++ b/dubbo-common/src/test/resources/security/serialize.allowlist @@ -16,5 +16,6 @@ # limitations under the License. # # + com.example.DemoInterface com.sun.Interface1 diff --git a/dubbo-common/src/test/resources/security/serialize.blockedlist b/dubbo-common/src/test/resources/security/serialize.blockedlist new file mode 100644 index 0000000000..bb8a3b35c8 --- /dev/null +++ b/dubbo-common/src/test/resources/security/serialize.blockedlist @@ -0,0 +1,20 @@ +# +# +# 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. +# +# + +com.exampletest.DemoInterface diff --git a/dubbo-native-plugin/src/main/resources/META-INF/native-image/reflect-config.json b/dubbo-native-plugin/src/main/resources/META-INF/native-image/reflect-config.json index a171c938a0..84afa1f611 100644 --- a/dubbo-native-plugin/src/main/resources/META-INF/native-image/reflect-config.json +++ b/dubbo-native-plugin/src/main/resources/META-INF/native-image/reflect-config.json @@ -1081,9 +1081,7 @@ "methods": [ { "name": "", - "parameterTypes": [ - "org.apache.dubbo.rpc.model.FrameworkModel" - ] + "parameterTypes": [] } ] }, @@ -1105,9 +1103,7 @@ "methods": [ { "name": "", - "parameterTypes": [ - "org.apache.dubbo.rpc.model.FrameworkModel" - ] + "parameterTypes": [] } ] }, @@ -1135,9 +1131,32 @@ } ] }, + { + "name": "org.apache.dubbo.common.utils.SerializeSecurityConfigurator", + "allPublicMethods": true, + "methods": [ + { + "name": "", + "parameterTypes": [ + "org.apache.dubbo.rpc.model.ModuleModel" + ] + } + ] + }, { "name": "org.apache.dubbo.common.utils.SerializeSecurityManager", "allPublicMethods": true, + "methods": [ + { + "name": "", + "parameterTypes": [ + ] + } + ] + }, + { + "name": "org.apache.dubbo.common.utils.DefaultSerializeClassChecker", + "allPublicMethods": true, "methods": [ { "name": "", diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/QosScopeModelInitializer.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/QosScopeModelInitializer.java index 2f61507568..5dcbd6f6f4 100644 --- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/QosScopeModelInitializer.java +++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/QosScopeModelInitializer.java @@ -17,6 +17,7 @@ package org.apache.dubbo.qos; import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; +import org.apache.dubbo.qos.command.util.SerializeCheckUtils; import org.apache.dubbo.qos.server.Server; import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; @@ -28,6 +29,7 @@ public class QosScopeModelInitializer implements ScopeModelInitializer { public void initializeFrameworkModel(FrameworkModel frameworkModel) { ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory(); beanFactory.registerBean(Server.class); + beanFactory.registerBean(SerializeCheckUtils.class); } @Override diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/SerializeCheckStatus.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/SerializeCheckStatus.java new file mode 100644 index 0000000000..70b90cf11e --- /dev/null +++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/SerializeCheckStatus.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.dubbo.qos.command.impl; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +import org.apache.dubbo.common.utils.JsonUtils; +import org.apache.dubbo.qos.command.BaseCommand; +import org.apache.dubbo.qos.command.CommandContext; +import org.apache.dubbo.qos.command.annotation.Cmd; +import org.apache.dubbo.qos.command.util.SerializeCheckUtils; +import org.apache.dubbo.rpc.model.FrameworkModel; + +@Cmd(name = "serializeCheckStatus",summary = "get serialize check status") +public class SerializeCheckStatus implements BaseCommand { + + private final SerializeCheckUtils serializeCheckUtils; + + public SerializeCheckStatus(FrameworkModel frameworkModel) { + serializeCheckUtils = frameworkModel.getBeanFactory().getBean(SerializeCheckUtils.class); + } + + @Override + public String execute(CommandContext commandContext, String[] args) { + if (commandContext.isHttp()) { + Map result = new HashMap<>(); + result.put("checkStatus", serializeCheckUtils.getStatus()); + result.put("checkSerializable", serializeCheckUtils.isCheckSerializable()); + result.put("allowedPrefix", serializeCheckUtils.getAllowedList()); + result.put("disAllowedPrefix", serializeCheckUtils.getDisAllowedList()); + + return JsonUtils.getJson().toJson(result); + } else { + return "CheckStatus: " + serializeCheckUtils.getStatus() + "\n\n" + + "CheckSerializable: " + serializeCheckUtils.isCheckSerializable() + "\n\n" + + "AllowedPrefix:" + "\n" + + serializeCheckUtils.getAllowedList().stream().sorted().collect(Collectors.joining("\n")) + + "\n\n" + + "DisAllowedPrefix:" + "\n" + + serializeCheckUtils.getDisAllowedList().stream().sorted().collect(Collectors.joining("\n")) + + "\n\n"; + } + } +} diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/util/SerializeCheckUtils.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/util/SerializeCheckUtils.java new file mode 100644 index 0000000000..2442b1bc70 --- /dev/null +++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/util/SerializeCheckUtils.java @@ -0,0 +1,69 @@ +/* + * 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.dubbo.qos.command.util; + +import java.util.Collections; +import java.util.Set; + +import org.apache.dubbo.common.utils.AllowClassNotifyListener; +import org.apache.dubbo.common.utils.SerializeCheckStatus; +import org.apache.dubbo.common.utils.SerializeSecurityManager; +import org.apache.dubbo.rpc.model.FrameworkModel; + +public class SerializeCheckUtils implements AllowClassNotifyListener { + public SerializeCheckUtils(FrameworkModel frameworkModel) { + SerializeSecurityManager manager = frameworkModel.getBeanFactory().getOrRegisterBean(SerializeSecurityManager.class); + manager.registerListener(this); + } + + private volatile Set allowedList = Collections.emptySet(); + private volatile Set disAllowedList = Collections.emptySet(); + private volatile SerializeCheckStatus status = AllowClassNotifyListener.DEFAULT_STATUS; + private volatile boolean checkSerializable = true; + + @Override + public void notifyPrefix(Set allowedList, Set disAllowedList) { + this.allowedList = allowedList; + this.disAllowedList = disAllowedList; + } + + @Override + public void notifyCheckStatus(SerializeCheckStatus status) { + this.status = status; + } + + @Override + public void notifyCheckSerializable(boolean checkSerializable) { + this.checkSerializable = checkSerializable; + } + + public Set getAllowedList() { + return allowedList; + } + + public Set getDisAllowedList() { + return disAllowedList; + } + + public SerializeCheckStatus getStatus() { + return status; + } + + public boolean isCheckSerializable() { + return checkSerializable; + } +} diff --git a/dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.command.BaseCommand b/dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.command.BaseCommand index 9611af4838..43568255b6 100644 --- a/dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.command.BaseCommand +++ b/dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.command.BaseCommand @@ -32,3 +32,4 @@ getRecentRouterSnapshot=org.apache.dubbo.qos.command.impl.GetRecentRouterSnapsho loggerInfo=org.apache.dubbo.qos.command.impl.LoggerInfo switchLogger=org.apache.dubbo.qos.command.impl.SwitchLogger switchLogLevel=org.apache.dubbo.qos.command.impl.SwitchLogLevel +serializeCheckStatus=org.apache.dubbo.qos.command.impl.SerializeCheckStatus diff --git a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/SerializeCheckStatusTest.java b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/SerializeCheckStatusTest.java new file mode 100644 index 0000000000..6f32cdd239 --- /dev/null +++ b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/SerializeCheckStatusTest.java @@ -0,0 +1,66 @@ +/* + * 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.dubbo.qos.command.impl; + +import org.apache.dubbo.common.utils.SerializeSecurityManager; +import org.apache.dubbo.qos.command.CommandContext; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +class SerializeCheckStatusTest { + @Test + void testNotify() { + FrameworkModel frameworkModel = new FrameworkModel(); + + SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class); + + SerializeCheckStatus serializeCheckStatus = new SerializeCheckStatus(frameworkModel); + + CommandContext commandContext1 = Mockito.mock(CommandContext.class); + Mockito.when(commandContext1.isHttp()).thenReturn(false); + CommandContext commandContext2 = Mockito.mock(CommandContext.class); + Mockito.when(commandContext2.isHttp()).thenReturn(true); + + Assertions.assertFalse(serializeCheckStatus.execute(commandContext1, null).contains("Test1234")); + Assertions.assertFalse(serializeCheckStatus.execute(commandContext2, null).contains("Test1234")); + ssm.addToAllowed("Test1234"); + Assertions.assertTrue(serializeCheckStatus.execute(commandContext1, null).contains("Test1234")); + Assertions.assertTrue(serializeCheckStatus.execute(commandContext2, null).contains("Test1234")); + + Assertions.assertFalse(serializeCheckStatus.execute(commandContext1, null).contains("Test4321")); + Assertions.assertFalse(serializeCheckStatus.execute(commandContext2, null).contains("Test4321")); + ssm.addToDisAllowed("Test4321"); + Assertions.assertTrue(serializeCheckStatus.execute(commandContext1, null).contains("Test4321")); + Assertions.assertTrue(serializeCheckStatus.execute(commandContext2, null).contains("Test4321")); + + Assertions.assertFalse(serializeCheckStatus.execute(commandContext1, null).contains("CheckSerializable: false")); + Assertions.assertFalse(serializeCheckStatus.execute(commandContext2, null).contains("\"checkSerializable\":false")); + ssm.setCheckSerializable(false); + Assertions.assertTrue(serializeCheckStatus.execute(commandContext1, null).contains("CheckSerializable: false")); + Assertions.assertTrue(serializeCheckStatus.execute(commandContext2, null).contains("\"checkSerializable\":false")); + + Assertions.assertFalse(serializeCheckStatus.execute(commandContext1, null).contains("CheckStatus: DISABLE")); + Assertions.assertFalse(serializeCheckStatus.execute(commandContext2, null).contains("\"checkStatus\":\"DISABLE\"")); + ssm.setCheckStatus(org.apache.dubbo.common.utils.SerializeCheckStatus.DISABLE); + Assertions.assertTrue(serializeCheckStatus.execute(commandContext1, null).contains("CheckStatus: DISABLE")); + Assertions.assertTrue(serializeCheckStatus.execute(commandContext2, null).contains("\"checkStatus\":\"DISABLE\"")); + + frameworkModel.destroy(); + } +} diff --git a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/util/CommandHelperTest.java b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/util/CommandHelperTest.java index 191c65e235..abbd8312c8 100644 --- a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/util/CommandHelperTest.java +++ b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/util/CommandHelperTest.java @@ -16,6 +16,9 @@ */ package org.apache.dubbo.qos.command.util; +import java.util.LinkedList; +import java.util.List; + import org.apache.dubbo.qos.command.GreetingCommand; import org.apache.dubbo.qos.command.impl.ChangeTelnet; import org.apache.dubbo.qos.command.impl.CountTelnet; @@ -45,6 +48,7 @@ import org.apache.dubbo.qos.command.impl.PwdTelnet; import org.apache.dubbo.qos.command.impl.Quit; import org.apache.dubbo.qos.command.impl.Ready; import org.apache.dubbo.qos.command.impl.SelectTelnet; +import org.apache.dubbo.qos.command.impl.SerializeCheckStatus; import org.apache.dubbo.qos.command.impl.SetProfilerWarnPercent; import org.apache.dubbo.qos.command.impl.ShutdownTelnet; import org.apache.dubbo.qos.command.impl.Startup; @@ -52,12 +56,8 @@ import org.apache.dubbo.qos.command.impl.SwitchLogLevel; import org.apache.dubbo.qos.command.impl.SwitchLogger; import org.apache.dubbo.qos.command.impl.Version; import org.apache.dubbo.rpc.model.FrameworkModel; - import org.junit.jupiter.api.Test; -import java.util.LinkedList; -import java.util.List; - import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.equalTo; @@ -115,6 +115,7 @@ class CommandHelperTest { expectedClasses.add(LoggerInfo.class); expectedClasses.add(SwitchLogger.class); expectedClasses.add(SwitchLogLevel.class); + expectedClasses.add(SerializeCheckStatus.class); assertThat(classes, containsInAnyOrder(expectedClasses.toArray(new Class[0]))); } @@ -123,4 +124,4 @@ class CommandHelperTest { assertThat(commandHelper.getCommandClass("greeting"), equalTo(GreetingCommand.class)); assertNull(commandHelper.getCommandClass("not-exiting")); } -} \ No newline at end of file +} diff --git a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/util/SerializeCheckUtilsTest.java b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/util/SerializeCheckUtilsTest.java new file mode 100644 index 0000000000..df8ddc93a0 --- /dev/null +++ b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/util/SerializeCheckUtilsTest.java @@ -0,0 +1,48 @@ +/* + * 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.dubbo.qos.command.util; + +import org.apache.dubbo.common.utils.SerializeCheckStatus; +import org.apache.dubbo.common.utils.SerializeSecurityManager; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class SerializeCheckUtilsTest { + @Test + void testNotify() { + FrameworkModel frameworkModel = new FrameworkModel(); + + SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class); + + SerializeCheckUtils serializeCheckUtils = new SerializeCheckUtils(frameworkModel); + + ssm.addToAllowed("Test1234"); + Assertions.assertTrue(serializeCheckUtils.getAllowedList().contains("Test1234")); + + ssm.addToDisAllowed("Test4321"); + Assertions.assertTrue(serializeCheckUtils.getDisAllowedList().contains("Test4321")); + + ssm.setCheckSerializable(false); + Assertions.assertFalse(serializeCheckUtils.isCheckSerializable()); + + ssm.setCheckStatus(SerializeCheckStatus.DISABLE); + Assertions.assertEquals(SerializeCheckStatus.DISABLE, serializeCheckUtils.getStatus()); + + frameworkModel.destroy(); + } +} diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/dispatcher/ChannelEventRunnable.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/dispatcher/ChannelEventRunnable.java index a250d05bf7..4bb558c4cd 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/dispatcher/ChannelEventRunnable.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/dispatcher/ChannelEventRunnable.java @@ -18,7 +18,7 @@ package org.apache.dubbo.remoting.transport.dispatcher; import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.common.threadlocal.InternalThreadLocal; +import org.apache.dubbo.common.threadlocal.InternalThreadLocalMap; import org.apache.dubbo.remoting.Channel; import org.apache.dubbo.remoting.ChannelHandler; @@ -55,51 +55,54 @@ public class ChannelEventRunnable implements Runnable { @Override public void run() { - InternalThreadLocal.removeAll(); - if (state == ChannelState.RECEIVED) { - try { - handler.received(channel, message); - } catch (Exception e) { - logger.warn(INTERNAL_ERROR, "unknown error in remoting module", "", "ChannelEventRunnable handle " + state + " operation error, channel is " + channel - + ", message is " + message, e); - } - } else { - switch (state) { - case CONNECTED: - try { - handler.connected(channel); - } catch (Exception e) { - logger.warn(INTERNAL_ERROR, "unknown error in remoting module", "", "ChannelEventRunnable handle " + state + " operation error, channel is " + channel, e); - } - break; - case DISCONNECTED: - try { - handler.disconnected(channel); - } catch (Exception e) { - logger.warn(INTERNAL_ERROR, "unknown error in remoting module", "", "ChannelEventRunnable handle " + state + " operation error, channel is " + channel, e); - } - break; - case SENT: - try { - handler.sent(channel, message); - } catch (Exception e) { - logger.warn(INTERNAL_ERROR, "unknown error in remoting module", "", "ChannelEventRunnable handle " + state + " operation error, channel is " + channel - + ", message is " + message, e); - } - break; - case CAUGHT: - try { - handler.caught(channel, exception); - } catch (Exception e) { - logger.warn(INTERNAL_ERROR, "unknown error in remoting module", "", "ChannelEventRunnable handle " + state + " operation error, channel is " + channel - + ", message is: " + message + ", exception is " + exception, e); - } - break; - default: - logger.warn(INTERNAL_ERROR, "unknown error in remoting module", "", "unknown state: " + state + ", message is " + message); + InternalThreadLocalMap internalThreadLocalMap = InternalThreadLocalMap.getAndRemove(); + try { + if (state == ChannelState.RECEIVED) { + try { + handler.received(channel, message); + } catch (Exception e) { + logger.warn(INTERNAL_ERROR, "unknown error in remoting module", "", "ChannelEventRunnable handle " + state + " operation error, channel is " + channel + + ", message is " + message, e); + } + } else { + switch (state) { + case CONNECTED: + try { + handler.connected(channel); + } catch (Exception e) { + logger.warn(INTERNAL_ERROR, "unknown error in remoting module", "", "ChannelEventRunnable handle " + state + " operation error, channel is " + channel, e); + } + break; + case DISCONNECTED: + try { + handler.disconnected(channel); + } catch (Exception e) { + logger.warn(INTERNAL_ERROR, "unknown error in remoting module", "", "ChannelEventRunnable handle " + state + " operation error, channel is " + channel, e); + } + break; + case SENT: + try { + handler.sent(channel, message); + } catch (Exception e) { + logger.warn(INTERNAL_ERROR, "unknown error in remoting module", "", "ChannelEventRunnable handle " + state + " operation error, channel is " + channel + + ", message is " + message, e); + } + break; + case CAUGHT: + try { + handler.caught(channel, exception); + } catch (Exception e) { + logger.warn(INTERNAL_ERROR, "unknown error in remoting module", "", "ChannelEventRunnable handle " + state + " operation error, channel is " + channel + + ", message is: " + message + ", exception is " + exception, e); + } + break; + default: + logger.warn(INTERNAL_ERROR, "unknown error in remoting module", "", "unknown state: " + state + ", message is " + message); + } } + } finally { + InternalThreadLocalMap.set(internalThreadLocalMap); } - InternalThreadLocal.removeAll(); } /** diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/ProtocolSecurityWrapper.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/ProtocolSecurityWrapper.java index d343009377..8a0bef3ec0 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/ProtocolSecurityWrapper.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/ProtocolSecurityWrapper.java @@ -16,9 +16,14 @@ */ package org.apache.dubbo.rpc.protocol; +import java.util.List; +import java.util.Optional; + import org.apache.dubbo.common.URL; import org.apache.dubbo.common.extension.Activate; -import org.apache.dubbo.common.utils.SerializeSecurityManager; +import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.utils.SerializeSecurityConfigurator; import org.apache.dubbo.rpc.Exporter; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Protocol; @@ -27,14 +32,16 @@ import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.model.ScopeModel; import org.apache.dubbo.rpc.model.ScopeModelUtil; import org.apache.dubbo.rpc.model.ServiceDescriptor; +import org.apache.dubbo.rpc.model.ServiceMetadata; import org.apache.dubbo.rpc.model.ServiceModel; -import java.util.List; -import java.util.Optional; +import static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR; @Activate(order = 200) public class ProtocolSecurityWrapper implements Protocol { private final Protocol protocol; + + private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ProtocolSecurityWrapper.class); public ProtocolSecurityWrapper(Protocol protocol) { if (protocol == null) { @@ -50,31 +57,48 @@ public class ProtocolSecurityWrapper implements Protocol { @Override public Exporter export(Invoker invoker) throws RpcException { - ServiceModel serviceModel = invoker.getUrl().getServiceModel(); - ScopeModel scopeModel = invoker.getUrl().getScopeModel(); - Optional.ofNullable(serviceModel) - .map(ServiceModel::getServiceModel) - .map(ServiceDescriptor::getServiceInterfaceClass) - .ifPresent((interfaceClass) -> { - SerializeSecurityManager serializeSecurityManager = ScopeModelUtil.getFrameworkModel(scopeModel) - .getBeanFactory().getBean(SerializeSecurityManager.class); - serializeSecurityManager.registerInterface(interfaceClass); - }); + try { + ServiceModel serviceModel = invoker.getUrl().getServiceModel(); + ScopeModel scopeModel = invoker.getUrl().getScopeModel(); + SerializeSecurityConfigurator serializeSecurityConfigurator = ScopeModelUtil.getModuleModel(scopeModel) + .getBeanFactory().getBean(SerializeSecurityConfigurator.class); + + Optional.ofNullable(serviceModel) + .map(ServiceModel::getServiceModel) + .map(ServiceDescriptor::getServiceInterfaceClass) + .ifPresent(serializeSecurityConfigurator::registerInterface); + + Optional.ofNullable(serviceModel) + .map(ServiceModel::getServiceMetadata) + .map(ServiceMetadata::getServiceType) + .ifPresent(serializeSecurityConfigurator::registerInterface); + } catch (Throwable t) { + logger.error(INTERNAL_ERROR, "", "", "Failed to register interface for security check", t); + } return protocol.export(invoker); } @Override public Invoker refer(Class type, URL url) throws RpcException { - ServiceModel serviceModel = url.getServiceModel(); - ScopeModel scopeModel = url.getScopeModel(); - SerializeSecurityManager serializeSecurityManager = ScopeModelUtil.getFrameworkModel(scopeModel) - .getBeanFactory().getBean(SerializeSecurityManager.class); + try { + ServiceModel serviceModel = url.getServiceModel(); + ScopeModel scopeModel = url.getScopeModel(); + SerializeSecurityConfigurator serializeSecurityConfigurator = ScopeModelUtil.getModuleModel(scopeModel) + .getBeanFactory().getBean(SerializeSecurityConfigurator.class); - Optional.ofNullable(serviceModel) - .map(ServiceModel::getServiceModel) - .map(ServiceDescriptor::getServiceInterfaceClass) - .ifPresent(serializeSecurityManager::registerInterface); - serializeSecurityManager.registerInterface(type); + Optional.ofNullable(serviceModel) + .map(ServiceModel::getServiceModel) + .map(ServiceDescriptor::getServiceInterfaceClass) + .ifPresent(serializeSecurityConfigurator::registerInterface); + + Optional.ofNullable(serviceModel) + .map(ServiceModel::getServiceMetadata) + .map(ServiceMetadata::getServiceType) + .ifPresent(serializeSecurityConfigurator::registerInterface); + serializeSecurityConfigurator.registerInterface(type); + } catch (Throwable t) { + logger.error(INTERNAL_ERROR, "", "", "Failed to register interface for security check", t); + } return protocol.refer(type, url); } diff --git a/dubbo-serialization/dubbo-serialization-fastjson2/src/main/java/org/apache/dubbo/common/serialize/fastjson2/FastJson2Serialization.java b/dubbo-serialization/dubbo-serialization-fastjson2/src/main/java/org/apache/dubbo/common/serialize/fastjson2/FastJson2Serialization.java index 1e6b636787..c3143b339f 100644 --- a/dubbo-serialization/dubbo-serialization-fastjson2/src/main/java/org/apache/dubbo/common/serialize/fastjson2/FastJson2Serialization.java +++ b/dubbo-serialization/dubbo-serialization-fastjson2/src/main/java/org/apache/dubbo/common/serialize/fastjson2/FastJson2Serialization.java @@ -16,16 +16,17 @@ */ package org.apache.dubbo.common.serialize.fastjson2; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Optional; + import org.apache.dubbo.common.URL; import org.apache.dubbo.common.serialize.ObjectInput; import org.apache.dubbo.common.serialize.ObjectOutput; import org.apache.dubbo.common.serialize.Serialization; import org.apache.dubbo.rpc.model.FrameworkModel; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - import static org.apache.dubbo.common.serialize.Constants.FASTJSON2_SERIALIZATION_ID; /** @@ -37,15 +38,6 @@ import static org.apache.dubbo.common.serialize.Constants.FASTJSON2_SERIALIZATIO */ public class FastJson2Serialization implements Serialization { - private final Fastjson2CreatorManager fastjson2CreatorManager; - - private final Fastjson2SecurityManager fastjson2SecurityManager; - - public FastJson2Serialization(FrameworkModel frameworkModel) { - this.fastjson2CreatorManager = frameworkModel.getBeanFactory().getBean(Fastjson2CreatorManager.class); - this.fastjson2SecurityManager = frameworkModel.getBeanFactory().getBean(Fastjson2SecurityManager.class); - } - @Override public byte getContentTypeId() { return FASTJSON2_SERIALIZATION_ID; @@ -58,11 +50,25 @@ public class FastJson2Serialization implements Serialization { @Override public ObjectOutput serialize(URL url, OutputStream output) throws IOException { + Fastjson2CreatorManager fastjson2CreatorManager = Optional.ofNullable(url) + .map(URL::getOrDefaultFrameworkModel) + .orElse(FrameworkModel.defaultModel()) + .getBeanFactory().getBean(Fastjson2CreatorManager.class); + return new FastJson2ObjectOutput(fastjson2CreatorManager, output); } @Override public ObjectInput deserialize(URL url, InputStream input) throws IOException { + Fastjson2CreatorManager fastjson2CreatorManager = Optional.ofNullable(url) + .map(URL::getOrDefaultFrameworkModel) + .orElse(FrameworkModel.defaultModel()) + .getBeanFactory().getBean(Fastjson2CreatorManager.class); + Fastjson2SecurityManager fastjson2SecurityManager = Optional.ofNullable(url) + .map(URL::getOrDefaultFrameworkModel) + .orElse(FrameworkModel.defaultModel()) + .getBeanFactory().getBean(Fastjson2SecurityManager.class); + return new FastJson2ObjectInput(fastjson2CreatorManager, fastjson2SecurityManager, input); } diff --git a/dubbo-serialization/dubbo-serialization-fastjson2/src/main/java/org/apache/dubbo/common/serialize/fastjson2/Fastjson2SecurityManager.java b/dubbo-serialization/dubbo-serialization-fastjson2/src/main/java/org/apache/dubbo/common/serialize/fastjson2/Fastjson2SecurityManager.java index e9334278c8..1ff677a7e5 100644 --- a/dubbo-serialization/dubbo-serialization-fastjson2/src/main/java/org/apache/dubbo/common/serialize/fastjson2/Fastjson2SecurityManager.java +++ b/dubbo-serialization/dubbo-serialization-fastjson2/src/main/java/org/apache/dubbo/common/serialize/fastjson2/Fastjson2SecurityManager.java @@ -37,19 +37,43 @@ import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_UNT import static org.apache.dubbo.common.utils.SerializeCheckStatus.STRICT; public class Fastjson2SecurityManager implements AllowClassNotifyListener { - private Filter securityFilter = new Handler(AllowClassNotifyListener.DEFAULT_STATUS, new String[0]); + private Filter securityFilter = new Handler(AllowClassNotifyListener.DEFAULT_STATUS, true, new String[0], new ConcurrentHashSet<>()); private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(Fastjson2SecurityManager.class); private static final Set warnedClasses = new ConcurrentHashSet<>(1); + private volatile SerializeCheckStatus status = AllowClassNotifyListener.DEFAULT_STATUS; + + private volatile boolean checkSerializable = true; + + private volatile Set allowedList = new ConcurrentHashSet<>(1); + + private volatile Set disAllowedList = new ConcurrentHashSet<>(1); + public Fastjson2SecurityManager(FrameworkModel frameworkModel) { SerializeSecurityManager securityManager = frameworkModel.getBeanFactory().getOrRegisterBean(SerializeSecurityManager.class); securityManager.registerListener(this); } - public void notify(SerializeCheckStatus status, Set prefixList) { - this.securityFilter = new Handler(status, prefixList.toArray(new String[0])); + @Override + public synchronized void notifyPrefix(Set allowedList, Set disAllowedList) { + this.allowedList = allowedList; + this.disAllowedList = disAllowedList; + this.securityFilter = new Handler(this.status, this.checkSerializable, this.allowedList.toArray(new String[0]), this.disAllowedList); + } + + @Override + public synchronized void notifyCheckStatus(SerializeCheckStatus status) { + this.status = status; + this.securityFilter = new Handler(this.status, this.checkSerializable, this.allowedList.toArray(new String[0]), this.disAllowedList); + } + + @Override + public synchronized void notifyCheckSerializable(boolean checkSerializable) { + this.checkSerializable = checkSerializable; + this.securityFilter = new Handler(this.status, this.checkSerializable, this.allowedList.toArray(new String[0]), this.disAllowedList); + } public Filter getSecurityFilter() { @@ -60,9 +84,15 @@ public class Fastjson2SecurityManager implements AllowClassNotifyListener { final SerializeCheckStatus status; final Map> classCache = new ConcurrentHashMap<>(16, 0.75f, 1); - public Handler(SerializeCheckStatus status, String[] acceptNames) { + final Set disAllowedList; + + final boolean checkSerializable; + + public Handler(SerializeCheckStatus status, boolean checkSerializable, String[] acceptNames, Set disAllowedList) { super(true, acceptNames); this.status = status; + this.checkSerializable = checkSerializable; + this.disAllowedList = disAllowedList; } @Override @@ -103,9 +133,27 @@ public class Fastjson2SecurityManager implements AllowClassNotifyListener { return null; } + public boolean checkIfDisAllow(String typeName) { + return disAllowedList.stream().anyMatch(typeName::startsWith); + } + + public boolean isCheckSerializable() { + return checkSerializable; + } + public Class loadClassDirectly(String typeName) { Class clazz = classCache.get(typeName); + if (clazz == null && checkIfDisAllow(typeName)) { + clazz = DenyClass.class; + String msg = "[Serialization Security] Serialized class " + typeName + " is in disAllow list. " + + "Current mode is `WARN`, will disallow to deserialize it by default. " + + "Please add it into security/serialize.allowlist or follow FAQ to configure it."; + if (warnedClasses.add(typeName)) { + logger.error(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, "", "", msg); + } + } + if (clazz == null) { clazz = TypeUtils.getMapping(typeName); } @@ -121,8 +169,16 @@ public class Fastjson2SecurityManager implements AllowClassNotifyListener { } } + if (clazz == DenyClass.class) { + return null; + } return clazz; } + + } + + private static class DenyClass { + // To indicate that the target class has been reject } } diff --git a/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2FactoryManager.java b/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2FactoryManager.java index a572925fef..512f67115f 100644 --- a/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2FactoryManager.java +++ b/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2FactoryManager.java @@ -16,14 +16,15 @@ */ package org.apache.dubbo.common.serialize.hessian2; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.dubbo.common.utils.DefaultSerializeClassChecker; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.rpc.model.FrameworkModel; import com.alibaba.com.caucho.hessian.io.SerializerFactory; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - public class Hessian2FactoryManager { String WHITELIST = "dubbo.application.hessian2.whitelist"; @@ -32,10 +33,10 @@ public class Hessian2FactoryManager { private volatile SerializerFactory SYSTEM_SERIALIZER_FACTORY; private final Map CL_2_SERIALIZER_FACTORY = new ConcurrentHashMap<>(); - private final Hessian2AllowClassManager hessian2AllowClassManager; + private final DefaultSerializeClassChecker defaultSerializeClassChecker; public Hessian2FactoryManager(FrameworkModel frameworkModel) { - hessian2AllowClassManager = new Hessian2AllowClassManager(frameworkModel); + defaultSerializeClassChecker = frameworkModel.getBeanFactory().getOrRegisterBean(DefaultSerializeClassChecker.class); } public SerializerFactory getSerializerFactory(ClassLoader classLoader) { @@ -73,14 +74,14 @@ public class Hessian2FactoryManager { } private SerializerFactory createDefaultSerializerFactory() { - Hessian2SerializerFactory hessian2SerializerFactory = new Hessian2SerializerFactory(hessian2AllowClassManager); + Hessian2SerializerFactory hessian2SerializerFactory = new Hessian2SerializerFactory(defaultSerializeClassChecker); hessian2SerializerFactory.setAllowNonSerializable(Boolean.parseBoolean(System.getProperty("dubbo.hessian.allowNonSerializable", "false"))); hessian2SerializerFactory.getClassFactory().allow("org.apache.dubbo.*"); return hessian2SerializerFactory; } public SerializerFactory createWhiteListSerializerFactory() { - SerializerFactory serializerFactory = new Hessian2SerializerFactory(hessian2AllowClassManager); + SerializerFactory serializerFactory = new Hessian2SerializerFactory(defaultSerializeClassChecker); String whiteList = System.getProperty(WHITELIST); if ("true".equals(whiteList)) { serializerFactory.getClassFactory().setWhitelist(true); diff --git a/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2Serialization.java b/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2Serialization.java index aebff2fbf5..4ce04b026f 100644 --- a/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2Serialization.java +++ b/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2Serialization.java @@ -16,16 +16,17 @@ */ package org.apache.dubbo.common.serialize.hessian2; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Optional; + import org.apache.dubbo.common.URL; import org.apache.dubbo.common.serialize.ObjectInput; import org.apache.dubbo.common.serialize.ObjectOutput; import org.apache.dubbo.common.serialize.Serialization; import org.apache.dubbo.rpc.model.FrameworkModel; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - import static org.apache.dubbo.common.serialize.Constants.HESSIAN2_SERIALIZATION_ID; /** @@ -37,12 +38,6 @@ import static org.apache.dubbo.common.serialize.Constants.HESSIAN2_SERIALIZATION */ public class Hessian2Serialization implements Serialization { - private final Hessian2FactoryManager hessian2FactoryManager; - - public Hessian2Serialization(FrameworkModel frameworkModel) { - hessian2FactoryManager = frameworkModel.getBeanFactory().getBean(Hessian2FactoryManager.class); - } - @Override public byte getContentTypeId() { return HESSIAN2_SERIALIZATION_ID; @@ -55,11 +50,19 @@ public class Hessian2Serialization implements Serialization { @Override public ObjectOutput serialize(URL url, OutputStream out) throws IOException { + Hessian2FactoryManager hessian2FactoryManager = Optional.ofNullable(url) + .map(URL::getOrDefaultFrameworkModel) + .orElse(FrameworkModel.defaultModel()) + .getBeanFactory().getBean(Hessian2FactoryManager.class); return new Hessian2ObjectOutput(out, hessian2FactoryManager); } @Override public ObjectInput deserialize(URL url, InputStream is) throws IOException { + Hessian2FactoryManager hessian2FactoryManager = Optional.ofNullable(url) + .map(URL::getOrDefaultFrameworkModel) + .orElse(FrameworkModel.defaultModel()) + .getBeanFactory().getBean(Hessian2FactoryManager.class); return new Hessian2ObjectInput(is, hessian2FactoryManager); } diff --git a/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2SerializerFactory.java b/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2SerializerFactory.java index e319cf7d61..1dcbe4e29b 100644 --- a/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2SerializerFactory.java +++ b/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2SerializerFactory.java @@ -16,18 +16,20 @@ */ package org.apache.dubbo.common.serialize.hessian2; +import org.apache.dubbo.common.utils.DefaultSerializeClassChecker; + import com.alibaba.com.caucho.hessian.io.SerializerFactory; public class Hessian2SerializerFactory extends SerializerFactory { - private Hessian2AllowClassManager hessian2AllowClassManager; + private final DefaultSerializeClassChecker defaultSerializeClassChecker; - public Hessian2SerializerFactory(Hessian2AllowClassManager hessian2AllowClassManager) { - this.hessian2AllowClassManager = hessian2AllowClassManager; + public Hessian2SerializerFactory(DefaultSerializeClassChecker defaultSerializeClassChecker) { + this.defaultSerializeClassChecker = defaultSerializeClassChecker; } @Override public Class loadSerializedClass(String className) throws ClassNotFoundException { - return hessian2AllowClassManager.loadClass(getClassLoader(), className); + return defaultSerializeClassChecker.loadClass(getClassLoader(), className); } }