mirror of https://github.com/apache/dubbo.git
Enhance Check (#11419)
This commit is contained in:
parent
f1b3e55b19
commit
c71a05a58c
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -22,5 +22,9 @@ public interface AllowClassNotifyListener {
|
|||
|
||||
SerializeCheckStatus DEFAULT_STATUS = SerializeCheckStatus.WARN;
|
||||
|
||||
void notify(SerializeCheckStatus status, Set<String> prefixList);
|
||||
void notifyPrefix(Set<String> allowedList, Set<String> disAllowedList);
|
||||
|
||||
void notifyCheckStatus(SerializeCheckStatus status);
|
||||
|
||||
void notifyCheckSerializable(boolean checkSerializable);
|
||||
}
|
||||
|
|
|
@ -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<String> 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<String> prefixList) {
|
||||
public synchronized void notifyPrefix(Set<String> allowedList, Set<String> 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<String> 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);
|
||||
}
|
||||
}
|
|
@ -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<Object, Object>) 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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<String> CLASS_DESERIALIZE_ALLOWED_SET = new ConcurrentHashSet<>();
|
||||
private final Set<String> CLASS_DESERIALIZE_BLOCKED_SET = new ConcurrentHashSet<>();
|
||||
|
||||
private final Object CACHE = new Object();
|
||||
private final LFUCache<String, Object> CLASS_ALLOW_LFU_CACHE = new LFUCache<>();
|
||||
private final LFUCache<String, Object> 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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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<ModuleModel> {
|
||||
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> 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<URL> 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<URL> 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<ApplicationConfig> 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<Class<?>> 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<Class<?>> 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<Class<?>> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,214 +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.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<String> allowedPrefix = new ConcurrentHashSet<>();
|
||||
|
||||
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(SerializeSecurityManager.class);
|
||||
|
||||
private final SerializeClassChecker checker = SerializeClassChecker.getInstance();
|
||||
private final Set<String> allowedPrefix = new ConcurrentHashSet<>();
|
||||
|
||||
private final Set<String> alwaysAllowedPrefix = new ConcurrentHashSet<>();
|
||||
|
||||
private final Set<String> disAllowedPrefix = new ConcurrentHashSet<>();
|
||||
|
||||
private final Set<AllowClassNotifyListener> listeners = new ConcurrentHashSet<>();
|
||||
|
||||
private volatile SerializeCheckStatus checkStatus = AllowClassNotifyListener.DEFAULT_STATUS;
|
||||
private volatile SerializeCheckStatus checkStatus = null;
|
||||
|
||||
public SerializeSecurityManager(FrameworkModel frameworkModel) {
|
||||
try {
|
||||
Set<ClassLoader> classLoaders = frameworkModel.getClassLoaders();
|
||||
List<URL> 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 synchronized void registerInterface(Class<?> clazz) {
|
||||
Set<Class<?>> 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<Class<?>> 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<Class<?>> 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, getAllowedPrefix());
|
||||
listener.notifyPrefix(getAllowedPrefix(), getDisAllowedPrefix());
|
||||
listener.notifyCheckSerializable(isCheckSerializable());
|
||||
listener.notifyCheckStatus(getCheckStatus());
|
||||
}
|
||||
|
||||
private void notifyListeners() {
|
||||
private void notifyPrefix() {
|
||||
for (AllowClassNotifyListener listener : listeners) {
|
||||
listener.notify(checkStatus, getAllowedPrefix());
|
||||
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<String> getAllowedPrefix() {
|
||||
Set<String> set = new ConcurrentHashSet<>();
|
||||
set.addAll(allowedPrefix);
|
||||
set.addAll(alwaysAllowedPrefix);
|
||||
return set;
|
||||
}
|
||||
|
||||
protected Set<String> getDisAllowedPrefix() {
|
||||
Set<String> set = new ConcurrentHashSet<>();
|
||||
set.addAll(disAllowedPrefix);
|
||||
return set;
|
||||
}
|
||||
|
||||
protected boolean isCheckSerializable() {
|
||||
return checkSerializable == null || checkSerializable;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -216,6 +216,14 @@ public class ApplicationConfig extends AbstractConfig {
|
|||
|
||||
private Boolean enableEmptyProtection;
|
||||
|
||||
private String serializeCheckStatus;
|
||||
|
||||
private Boolean autoTrustSerializeClass;
|
||||
|
||||
private Integer trustSerializeClassLevel;
|
||||
|
||||
private Boolean checkSerializable;
|
||||
|
||||
public ApplicationConfig() {
|
||||
}
|
||||
|
||||
|
@ -613,6 +621,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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
super.refresh();
|
||||
|
|
|
@ -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 {
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
}
|
|
@ -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<String, Child> children = new HashMap<String, Child>();
|
||||
private List<Child> list = new ArrayList<Child>();
|
||||
|
||||
|
@ -979,7 +980,7 @@ class PojoUtilsTest {
|
|||
}
|
||||
}
|
||||
|
||||
public static class InnerPojo<T> {
|
||||
public static class InnerPojo<T> implements Serializable {
|
||||
private List<T> list;
|
||||
|
||||
public List<T> getList() {
|
||||
|
@ -991,7 +992,7 @@ class PojoUtilsTest {
|
|||
}
|
||||
}
|
||||
|
||||
public static class ListResult<T> {
|
||||
public static class ListResult<T> implements Serializable {
|
||||
List<T> result;
|
||||
|
||||
public List<T> getResult() {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Set<String>> prefixList = new AtomicReference<>();
|
||||
private final static AtomicReference<SerializeCheckStatus> status = new AtomicReference<>();
|
||||
private final static AtomicReference<Set<String>> allowedList = new AtomicReference<>();
|
||||
private final static AtomicReference<Set<String>> 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<String> prefixList) {
|
||||
TestAllowClassNotifyListener.prefixList.set(prefixList);
|
||||
public void notifyPrefix(Set<String> allowedList, Set<String> disAllowedList) {
|
||||
TestAllowClassNotifyListener.allowedList.set(allowedList);
|
||||
TestAllowClassNotifyListener.disAllowedList.set(disAllowedList);
|
||||
count.incrementAndGet();
|
||||
}
|
||||
|
||||
public static Set<String> 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<String> getAllowedList() {
|
||||
return allowedList.get();
|
||||
}
|
||||
|
||||
public static Set<String> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,5 +16,6 @@
|
|||
# limitations under the License.
|
||||
#
|
||||
#
|
||||
|
||||
com.example.DemoInterface
|
||||
com.sun.Interface1
|
||||
|
|
|
@ -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
|
|
@ -1135,9 +1135,32 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "org.apache.dubbo.common.utils.SerializeSecurityConfigurator",
|
||||
"allPublicMethods": true,
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": [
|
||||
"org.apache.dubbo.rpc.model.ModuleModel"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "org.apache.dubbo.common.utils.SerializeSecurityManager",
|
||||
"allPublicMethods": true,
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": [
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "org.apache.dubbo.common.utils.DefaultSerializeClassChecker",
|
||||
"allPublicMethods": true,
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
|
|
|
@ -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;
|
||||
|
@ -29,12 +34,13 @@ import org.apache.dubbo.rpc.model.ScopeModelUtil;
|
|||
import org.apache.dubbo.rpc.model.ServiceDescriptor;
|
||||
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 +56,39 @@ public class ProtocolSecurityWrapper implements Protocol {
|
|||
|
||||
@Override
|
||||
public <T> Exporter<T> export(Invoker<T> 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();
|
||||
Optional.ofNullable(serviceModel)
|
||||
.map(ServiceModel::getServiceModel)
|
||||
.map(ServiceDescriptor::getServiceInterfaceClass)
|
||||
.ifPresent((interfaceClass) -> {
|
||||
SerializeSecurityConfigurator serializeSecurityConfigurator = ScopeModelUtil.getModuleModel(scopeModel)
|
||||
.getBeanFactory().getBean(SerializeSecurityConfigurator.class);
|
||||
serializeSecurityConfigurator.registerInterface(interfaceClass);
|
||||
});
|
||||
} catch (Throwable t) {
|
||||
logger.error(INTERNAL_ERROR, "", "", "Failed to register interface for security check", t);
|
||||
}
|
||||
return protocol.export(invoker);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Invoker<T> refer(Class<T> 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);
|
||||
serializeSecurityConfigurator.registerInterface(type);
|
||||
} catch (Throwable t) {
|
||||
logger.error(INTERNAL_ERROR, "", "", "Failed to register interface for security check", t);
|
||||
}
|
||||
|
||||
return protocol.refer(type, url);
|
||||
}
|
||||
|
|
|
@ -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<String> warnedClasses = new ConcurrentHashSet<>(1);
|
||||
|
||||
private volatile SerializeCheckStatus status = AllowClassNotifyListener.DEFAULT_STATUS;
|
||||
|
||||
private volatile boolean checkSerializable = true;
|
||||
|
||||
private volatile Set<String> allowedList = new ConcurrentHashSet<>(1);
|
||||
|
||||
private volatile Set<String> disAllowedList = new ConcurrentHashSet<>(1);
|
||||
|
||||
public Fastjson2SecurityManager(FrameworkModel frameworkModel) {
|
||||
SerializeSecurityManager securityManager = frameworkModel.getBeanFactory().getOrRegisterBean(SerializeSecurityManager.class);
|
||||
securityManager.registerListener(this);
|
||||
}
|
||||
|
||||
public void notify(SerializeCheckStatus status, Set<String> prefixList) {
|
||||
this.securityFilter = new Handler(status, prefixList.toArray(new String[0]));
|
||||
@Override
|
||||
public synchronized void notifyPrefix(Set<String> allowedList, Set<String> 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<String, Class<?>> classCache = new ConcurrentHashMap<>(16, 0.75f, 1);
|
||||
|
||||
public Handler(SerializeCheckStatus status, String[] acceptNames) {
|
||||
final Set<String> disAllowedList;
|
||||
|
||||
final boolean checkSerializable;
|
||||
|
||||
public Handler(SerializeCheckStatus status, boolean checkSerializable, String[] acceptNames, Set<String> 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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ClassLoader, SerializerFactory> 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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue