[3.0]Fix security problem (#7779)
This commit is contained in:
parent
63d319b60e
commit
5eedd4970a
|
|
@ -16,26 +16,25 @@
|
|||
*/
|
||||
package org.apache.dubbo.rpc.cluster.configurator.parser;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONValidator;
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.rpc.cluster.configurator.parser.model.ConfigItem;
|
||||
import org.apache.dubbo.rpc.cluster.configurator.parser.model.ConfiguratorConfig;
|
||||
|
||||
import org.yaml.snakeyaml.TypeDescription;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONValidator;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.Constructor;
|
||||
import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.apache.dubbo.rpc.cluster.Constants.OVERRIDE_PROVIDERS_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.APP_DYNAMIC_CONFIGURATORS_CATEGORY;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_CONFIGURATORS_CATEGORY;
|
||||
import static org.apache.dubbo.rpc.cluster.Constants.OVERRIDE_PROVIDERS_KEY;
|
||||
|
||||
/**
|
||||
* Config parser
|
||||
|
|
@ -72,14 +71,10 @@ public class ConfigParser {
|
|||
return urls;
|
||||
}
|
||||
|
||||
private static <T> T parseObject(String rawConfig) {
|
||||
Constructor constructor = new Constructor(ConfiguratorConfig.class);
|
||||
TypeDescription itemDescription = new TypeDescription(ConfiguratorConfig.class);
|
||||
itemDescription.addPropertyParameters("items", ConfigItem.class);
|
||||
constructor.addTypeDescription(itemDescription);
|
||||
|
||||
Yaml yaml = new Yaml(constructor);
|
||||
return yaml.load(rawConfig);
|
||||
private static ConfiguratorConfig parseObject(String rawConfig) {
|
||||
Yaml yaml = new Yaml(new SafeConstructor());
|
||||
Map<String, Object> map = yaml.load(rawConfig);
|
||||
return ConfiguratorConfig.parseFromMap(map);
|
||||
}
|
||||
|
||||
private static List<URL> serviceItemToUrls(ConfigItem item, ConfiguratorConfig config) {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package org.apache.dubbo.rpc.cluster.configurator.parser.model;
|
|||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -37,6 +38,50 @@ public class ConfigItem {
|
|||
private Map<String, String> parameters;
|
||||
private String side;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static ConfigItem parseFromMap(Map<String, Object> map) {
|
||||
ConfigItem configItem = new ConfigItem();
|
||||
configItem.setType((String) map.get("type"));
|
||||
|
||||
Object enabled = map.get("enabled");
|
||||
if (enabled != null) {
|
||||
configItem.setEnabled(Boolean.parseBoolean(enabled.toString()));
|
||||
}
|
||||
|
||||
Object addresses = map.get("addresses");
|
||||
if (addresses != null && List.class.isAssignableFrom(addresses.getClass())) {
|
||||
configItem.setAddresses(((List<Object>) addresses).stream()
|
||||
.map(String::valueOf).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
Object providerAddresses = map.get("providerAddresses");
|
||||
if (providerAddresses != null && List.class.isAssignableFrom(providerAddresses.getClass())) {
|
||||
configItem.setProviderAddresses(((List<Object>) providerAddresses).stream()
|
||||
.map(String::valueOf).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
Object services = map.get("services");
|
||||
if (services != null && List.class.isAssignableFrom(services.getClass())) {
|
||||
configItem.setServices(((List<Object>) services).stream()
|
||||
.map(String::valueOf).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
Object applications = map.get("applications");
|
||||
if (applications != null && List.class.isAssignableFrom(applications.getClass())) {
|
||||
configItem.setApplications(((List<Object>) applications).stream()
|
||||
.map(String::valueOf).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
Object parameters = map.get("parameters");
|
||||
if (parameters != null && Map.class.isAssignableFrom(parameters.getClass())) {
|
||||
configItem.setParameters(((Map<String, Object>) parameters).entrySet()
|
||||
.stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().toString())));
|
||||
}
|
||||
|
||||
configItem.setSide((String) map.get("side"));
|
||||
return configItem;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
package org.apache.dubbo.rpc.cluster.configurator.parser.model;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -31,6 +33,26 @@ public class ConfiguratorConfig {
|
|||
private Boolean enabled = true;
|
||||
private List<ConfigItem> configs;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static ConfiguratorConfig parseFromMap(Map<String, Object> map) {
|
||||
ConfiguratorConfig configuratorConfig = new ConfiguratorConfig();
|
||||
configuratorConfig.setConfigVersion((String) map.get("configVersion"));
|
||||
configuratorConfig.setScope((String) map.get("scope"));
|
||||
configuratorConfig.setKey((String) map.get("key"));
|
||||
|
||||
Object enabled = map.get("enabled");
|
||||
if (enabled != null) {
|
||||
configuratorConfig.setEnabled(Boolean.parseBoolean(enabled.toString()));
|
||||
}
|
||||
|
||||
Object configs = map.get("configs");
|
||||
if (configs != null && List.class.isAssignableFrom(configs.getClass())) {
|
||||
configuratorConfig.setConfigs(((List<Map<String, Object>>) configs).stream()
|
||||
.map(ConfigItem::parseFromMap).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
return configuratorConfig;
|
||||
}
|
||||
|
||||
public String getConfigVersion() {
|
||||
return configVersion;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
*/
|
||||
package org.apache.dubbo.rpc.cluster.router;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* TODO Extract more code here if necessary
|
||||
*/
|
||||
|
|
@ -31,6 +33,43 @@ public abstract class AbstractRouterRule {
|
|||
private String scope;
|
||||
private String key;
|
||||
|
||||
protected void parseFromMap0(Map<String, Object> map) {
|
||||
setRawRule((String) map.get("rawRule"));
|
||||
|
||||
Object runtime = map.get("runtime");
|
||||
if (runtime != null) {
|
||||
setRuntime(Boolean.parseBoolean(runtime.toString()));
|
||||
}
|
||||
|
||||
Object force = map.get("force");
|
||||
if (force != null) {
|
||||
setForce(Boolean.parseBoolean(force.toString()));
|
||||
}
|
||||
|
||||
Object valid = map.get("valid");
|
||||
if (valid != null) {
|
||||
setValid(Boolean.parseBoolean(valid.toString()));
|
||||
}
|
||||
|
||||
Object enabled = map.get("enabled");
|
||||
if (enabled != null) {
|
||||
setEnabled(Boolean.parseBoolean(enabled.toString()));
|
||||
}
|
||||
|
||||
Object priority = map.get("priority");
|
||||
if (priority != null) {
|
||||
setPriority(Integer.parseInt(priority.toString()));
|
||||
}
|
||||
|
||||
Object dynamic = map.get("dynamic");
|
||||
if (dynamic != null) {
|
||||
setDynamic(Boolean.parseBoolean(dynamic.toString()));
|
||||
}
|
||||
|
||||
setScope((String) map.get("scope"));
|
||||
setKey((String) map.get("key"));
|
||||
}
|
||||
|
||||
public String getRawRule() {
|
||||
return rawRule;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,15 +19,31 @@ package org.apache.dubbo.rpc.cluster.router.condition.config.model;
|
|||
import org.apache.dubbo.rpc.cluster.router.AbstractRouterRule;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class ConditionRouterRule extends AbstractRouterRule {
|
||||
public ConditionRouterRule() {
|
||||
private List<String> conditions;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static ConditionRouterRule parseFromMap(Map<String, Object> map) {
|
||||
ConditionRouterRule conditionRouterRule = new ConditionRouterRule();
|
||||
conditionRouterRule.parseFromMap0(map);
|
||||
|
||||
Object conditions = map.get("conditions");
|
||||
if (conditions != null && List.class.isAssignableFrom(conditions.getClass())) {
|
||||
conditionRouterRule.setConditions(((List<Object>) conditions).stream()
|
||||
.map(String::valueOf).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
return conditionRouterRule;
|
||||
}
|
||||
|
||||
private List<String> conditions;
|
||||
public ConditionRouterRule() {
|
||||
}
|
||||
|
||||
public List<String> getConditions() {
|
||||
return conditions;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@ package org.apache.dubbo.rpc.cluster.router.condition.config.model;
|
|||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.Constructor;
|
||||
import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* %YAML1.2
|
||||
|
|
@ -38,10 +40,9 @@ import org.yaml.snakeyaml.constructor.Constructor;
|
|||
public class ConditionRuleParser {
|
||||
|
||||
public static ConditionRouterRule parse(String rawRule) {
|
||||
Constructor constructor = new Constructor(ConditionRouterRule.class);
|
||||
|
||||
Yaml yaml = new Yaml(constructor);
|
||||
ConditionRouterRule rule = yaml.load(rawRule);
|
||||
Yaml yaml = new Yaml(new SafeConstructor());
|
||||
Map<String, Object> map = yaml.load(rawRule);
|
||||
ConditionRouterRule rule = ConditionRouterRule.parseFromMap(map);
|
||||
rule.setRawRule(rawRule);
|
||||
if (CollectionUtils.isEmpty(rule.getConditions())) {
|
||||
rule.setValid(false);
|
||||
|
|
|
|||
|
|
@ -32,6 +32,13 @@ import javax.script.CompiledScript;
|
|||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.security.CodeSource;
|
||||
import java.security.Permissions;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
|
@ -62,6 +69,17 @@ public class ScriptRouter extends AbstractRouter {
|
|||
|
||||
private CompiledScript function;
|
||||
|
||||
private AccessControlContext accessControlContext;
|
||||
|
||||
{
|
||||
//Just give permission of reflect to access member.
|
||||
Permissions perms = new Permissions();
|
||||
perms.add(new RuntimePermission("accessDeclaredMembers"));
|
||||
// Cast to Certificate[] required because of ambiguity:
|
||||
ProtectionDomain domain = new ProtectionDomain(new CodeSource(null, (Certificate[]) null), perms);
|
||||
accessControlContext = new AccessControlContext(new ProtectionDomain[]{domain});
|
||||
}
|
||||
|
||||
public ScriptRouter(URL url) {
|
||||
this.url = url;
|
||||
this.priority = url.getParameter(PRIORITY_KEY, SCRIPT_ROUTER_DEFAULT_PRIORITY);
|
||||
|
|
@ -75,8 +93,6 @@ public class ScriptRouter extends AbstractRouter {
|
|||
logger.error("route error, rule has been ignored. rule: " + rule +
|
||||
", url: " + RpcContext.getServiceContext().getUrl(), e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -107,17 +123,19 @@ public class ScriptRouter extends AbstractRouter {
|
|||
|
||||
@Override
|
||||
public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {
|
||||
try {
|
||||
Bindings bindings = createBindings(invokers, invocation);
|
||||
if (function == null) {
|
||||
return invokers;
|
||||
}
|
||||
return getRoutedInvokers(function.eval(bindings));
|
||||
} catch (ScriptException e) {
|
||||
logger.error("route error, rule has been ignored. rule: " + rule + ", method:" +
|
||||
invocation.getMethodName() + ", url: " + RpcContext.getServiceContext().getUrl(), e);
|
||||
if (engine == null || function == null) {
|
||||
return invokers;
|
||||
}
|
||||
Bindings bindings = createBindings(invokers, invocation);
|
||||
return getRoutedInvokers(AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
|
||||
try {
|
||||
return function.eval(bindings);
|
||||
} catch (ScriptException e) {
|
||||
logger.error("route error, rule has been ignored. rule: " + rule + ", method:" +
|
||||
invocation.getMethodName() + ", url: " + RpcContext.getContext().getUrl(), e);
|
||||
return invokers;
|
||||
}
|
||||
}, accessControlContext));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
package org.apache.dubbo.rpc.cluster.router.tag.model;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -25,6 +27,19 @@ public class Tag {
|
|||
private String name;
|
||||
private List<String> addresses;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Tag parseFromMap(Map<String, Object> map) {
|
||||
Tag tag = new Tag();
|
||||
tag.setName((String) map.get("name"));
|
||||
|
||||
Object addresses = map.get("addresses");
|
||||
if (addresses != null && List.class.isAssignableFrom(addresses.getClass())) {
|
||||
tag.setAddresses(((List<Object>) addresses).stream().map(String::valueOf).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,20 @@ public class TagRouterRule extends AbstractRouterRule {
|
|||
private Map<String, List<String>> addressToTagnames = new HashMap<>();
|
||||
private Map<String, List<String>> tagnameToAddresses = new HashMap<>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static TagRouterRule parseFromMap(Map<String, Object> map) {
|
||||
TagRouterRule tagRouterRule = new TagRouterRule();
|
||||
tagRouterRule.parseFromMap0(map);
|
||||
|
||||
Object tags = map.get("tags");
|
||||
if (tags != null && List.class.isAssignableFrom(tags.getClass())) {
|
||||
tagRouterRule.setTags(((List<Map<String, Object>>) tags).stream()
|
||||
.map(Tag::parseFromMap).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
return tagRouterRule;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -17,9 +17,11 @@
|
|||
package org.apache.dubbo.rpc.cluster.router.tag.model;
|
||||
|
||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
import org.yaml.snakeyaml.TypeDescription;
|
||||
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.Constructor;
|
||||
import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -27,13 +29,9 @@ import org.yaml.snakeyaml.constructor.Constructor;
|
|||
public class TagRuleParser {
|
||||
|
||||
public static TagRouterRule parse(String rawRule) {
|
||||
Constructor constructor = new Constructor(TagRouterRule.class);
|
||||
TypeDescription tagDescription = new TypeDescription(TagRouterRule.class);
|
||||
tagDescription.addPropertyParameters("tags", Tag.class);
|
||||
constructor.addTypeDescription(tagDescription);
|
||||
|
||||
Yaml yaml = new Yaml(constructor);
|
||||
TagRouterRule rule = yaml.load(rawRule);
|
||||
Yaml yaml = new Yaml(new SafeConstructor());
|
||||
Map<String, Object> map = yaml.load(rawRule);
|
||||
TagRouterRule rule = TagRouterRule.parseFromMap(map);
|
||||
rule.setRawRule(rawRule);
|
||||
if (CollectionUtils.isEmpty(rule.getTags())) {
|
||||
rule.setValid(false);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
file=org.apache.dubbo.rpc.cluster.router.file.FileRouterFactory
|
||||
script=org.apache.dubbo.rpc.cluster.router.script.ScriptRouterFactory
|
||||
condition=org.apache.dubbo.rpc.cluster.router.condition.ConditionRouterFactory
|
||||
service=org.apache.dubbo.rpc.cluster.router.condition.config.ServiceRouterFactory
|
||||
app=org.apache.dubbo.rpc.cluster.router.condition.config.AppRouterFactory
|
||||
|
|
|
|||
|
|
@ -17,18 +17,17 @@
|
|||
package org.apache.dubbo.rpc.cluster.configurator.parser;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.rpc.cluster.configurator.parser.model.ConfigItem;
|
||||
import org.apache.dubbo.rpc.cluster.configurator.parser.model.ConfiguratorConfig;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.yaml.snakeyaml.TypeDescription;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.Constructor;
|
||||
import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.LOADBALANCE_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
|
||||
|
|
@ -49,14 +48,9 @@ public class ConfigParserTest {
|
|||
@Test
|
||||
public void snakeYamlBasicTest() throws IOException {
|
||||
try (InputStream yamlStream = this.getClass().getResourceAsStream("/ServiceNoApp.yml")) {
|
||||
|
||||
Constructor constructor = new Constructor(ConfiguratorConfig.class);
|
||||
TypeDescription carDescription = new TypeDescription(ConfiguratorConfig.class);
|
||||
carDescription.addPropertyParameters("items", ConfigItem.class);
|
||||
constructor.addTypeDescription(carDescription);
|
||||
|
||||
Yaml yaml = new Yaml(constructor);
|
||||
ConfiguratorConfig config = yaml.load(yamlStream);
|
||||
Yaml yaml = new Yaml(new SafeConstructor());
|
||||
Map<String, Object> map = yaml.load(yamlStream);
|
||||
ConfiguratorConfig config = ConfiguratorConfig.parseFromMap(map);
|
||||
System.out.println(config);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,6 +97,8 @@ public class TagRouterTest {
|
|||
TagRouterRule tagRouterRule = TagRuleParser.parse(tagRouterRuleConfig);
|
||||
|
||||
// assert tags
|
||||
assert tagRouterRule.getKey().equals("demo-provider");
|
||||
assert tagRouterRule.getPriority() == 1;
|
||||
assert tagRouterRule.getTagNames().contains("tag1");
|
||||
assert tagRouterRule.getTagNames().contains("tag2");
|
||||
assert tagRouterRule.getTagNames().contains("tag3");
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
script=org.apache.dubbo.rpc.cluster.router.script.ScriptRouterFactory
|
||||
|
|
@ -109,6 +109,12 @@ public final class URLStrParser {
|
|||
*/
|
||||
private static URL parseURLBody(String fullURLStr, String decodedBody, Map<String, String> parameters, boolean modifiable) {
|
||||
int starIdx = 0, endIdx = decodedBody.length();
|
||||
// ignore the url content following '#'
|
||||
int poundIndex = decodedBody.indexOf('#');
|
||||
if (poundIndex != -1) {
|
||||
endIdx = poundIndex;
|
||||
}
|
||||
|
||||
String protocol = null;
|
||||
int protoEndIdx = decodedBody.indexOf("://");
|
||||
if (protoEndIdx >= 0) {
|
||||
|
|
@ -132,7 +138,7 @@ public final class URLStrParser {
|
|||
String path = null;
|
||||
int pathStartIdx = indexOf(decodedBody, '/', starIdx, endIdx);
|
||||
if (pathStartIdx >= 0) {
|
||||
path = decodedBody.substring(pathStartIdx + 1);
|
||||
path = decodedBody.substring(pathStartIdx + 1, endIdx);
|
||||
endIdx = pathStartIdx;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ 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;
|
||||
|
|
@ -464,6 +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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -377,6 +377,16 @@ public interface CommonConstants {
|
|||
*/
|
||||
String DEFAULT_SERVICE_NAME_MAPPING_PROPERTIES_PATH = "META-INF/dubbo/service-name-mapping.properties";
|
||||
|
||||
String CLASS_DESERIALIZE_BLOCK_ALL = "dubbo.security.serialize.blockAllClassExceptAllow";
|
||||
|
||||
String CLASS_DESERIALIZE_ALLOWED_LIST = "dubbo.security.serialize.allowedClassList";
|
||||
|
||||
String CLASS_DESERIALIZE_BLOCKED_LIST = "dubbo.security.serialize.blockedClassList";
|
||||
|
||||
String ENABLE_NATIVE_JAVA_GENERIC_SERIALIZE = "dubbo.security.serialize.generic.native-java-enable";
|
||||
|
||||
String SERIALIZE_BLOCKED_LIST_FILE_PATH = "security/serialize.blockedlist";
|
||||
|
||||
String QOS_LIVE_PROBE_EXTENSION = "dubbo.application.liveness-probe";
|
||||
|
||||
String QOS_READY_PROBE_EXTENSION = "dubbo.application.readiness-probe";
|
||||
|
|
|
|||
|
|
@ -386,6 +386,7 @@ 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);
|
||||
try {
|
||||
type = ClassUtils.forName((String) className);
|
||||
} catch (ClassNotFoundException e) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* 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.logger.Logger;
|
||||
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;
|
||||
|
||||
public class SerializeClassChecker {
|
||||
private static final Logger logger = LoggerFactory.getLogger(SerializeClassChecker.class);
|
||||
|
||||
private static volatile SerializeClassChecker INSTANCE = null;
|
||||
|
||||
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 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("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
|
||||
*
|
||||
* @throws IllegalArgumentException if class is blocked
|
||||
* @param name class name ( all are convert to lower case )
|
||||
*/
|
||||
public void validateClass(String name) {
|
||||
name = name.toLowerCase(Locale.ROOT);
|
||||
if (CACHE == CLASS_ALLOW_LFU_CACHE.get(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (CACHE == CLASS_BLOCK_LFU_CACHE.get(name)) {
|
||||
error(name);
|
||||
}
|
||||
|
||||
for (String allowedPrefix : CLASS_DESERIALIZE_ALLOWED_SET) {
|
||||
if (name.startsWith(allowedPrefix)) {
|
||||
CLASS_ALLOW_LFU_CACHE.put(name, CACHE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (String blockedPrefix : CLASS_DESERIALIZE_BLOCKED_SET) {
|
||||
if (BLOCK_ALL_CLASS_EXCEPT_ALLOW || name.startsWith(blockedPrefix)) {
|
||||
CLASS_BLOCK_LFU_CACHE.put(name, CACHE);
|
||||
error(name);
|
||||
}
|
||||
}
|
||||
|
||||
CLASS_ALLOW_LFU_CACHE.put(name, CACHE);
|
||||
}
|
||||
|
||||
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(notice);
|
||||
}
|
||||
throw new IllegalArgumentException(notice);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
#
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
aj.org.objectweb.asm.
|
||||
br.com.anteros.
|
||||
ch.qos.logback.
|
||||
clojure.core$constantly
|
||||
clojure.main$eval_opt
|
||||
com.alibaba.citrus.springext.support.parser.abstractnamedproxybeandefinitionparser$proxytargetfactory
|
||||
com.alibaba.citrus.springext.util.springextutil.abstractproxy
|
||||
com.alibaba.druid.pool.druiddatasource
|
||||
com.alibaba.druid.stat.jdbcdatasourcestat
|
||||
com.alibaba.fastjson.annotation
|
||||
com.alipay.custrelation.service.model.redress.pair
|
||||
com.caucho.
|
||||
com.ibatis.
|
||||
com.mchange
|
||||
com.mysql.cj.jdbc.admin.
|
||||
com.mysql.cj.jdbc.mysqlconnectionpooldatasource
|
||||
com.mysql.cj.jdbc.mysqldatasource
|
||||
com.mysql.cj.jdbc.mysqlxadatasource
|
||||
com.mysql.cj.log.
|
||||
com.p6spy.engine.
|
||||
com.rometools.rome.feed.impl.equalsbean
|
||||
com.rometools.rome.feed.impl.tostringbean
|
||||
com.sun.
|
||||
com.taobao.eagleeye.wrapper
|
||||
com.zaxxer.hikari.
|
||||
flex.messaging.util.concurrent.
|
||||
java.awt.i
|
||||
java.awt.p
|
||||
java.beans.expression
|
||||
java.io.closeable
|
||||
java.io.serializable
|
||||
java.lang.autocloseable
|
||||
java.lang.class
|
||||
java.lang.cloneable
|
||||
java.lang.iterable
|
||||
java.lang.object
|
||||
java.lang.readable
|
||||
java.lang.runnable
|
||||
java.lang.thread
|
||||
java.lang.unixprocess
|
||||
java.net.inetaddress
|
||||
java.net.socket
|
||||
java.net.url
|
||||
java.rmi
|
||||
java.security.signedobject
|
||||
java.util.collection
|
||||
java.util.eventlistener
|
||||
java.util.jar.
|
||||
java.util.logging.
|
||||
java.util.prefs.
|
||||
java.util.serviceloader$lazyiterator
|
||||
javassist.
|
||||
javax.activation.
|
||||
javax.imageio.imageio$containsfilter
|
||||
javax.imageio.spi.serviceregistry
|
||||
javax.management.
|
||||
javax.naming.
|
||||
javax.net.
|
||||
javax.print.
|
||||
javax.script.
|
||||
javax.sound.
|
||||
javax.swing.j
|
||||
javax.tools.
|
||||
javax.xml
|
||||
jdk.internal.
|
||||
jodd.db.connection.
|
||||
junit.
|
||||
net.bytebuddy.dynamic.loading.bytearrayclassloader
|
||||
net.sf.cglib.
|
||||
net.sf.ehcache.hibernate.
|
||||
net.sf.ehcache.transaction.manager.
|
||||
oracle.jdbc.
|
||||
oracle.jms.aq
|
||||
oracle.net
|
||||
org.aoju.bus.proxy.provider.
|
||||
org.apache.activemq.activemqconnectionfactory
|
||||
org.apache.activemq.activemqxaconnectionfactory
|
||||
org.apache.activemq.jms.pool.
|
||||
org.apache.activemq.pool.
|
||||
org.apache.activemq.spring.
|
||||
org.apache.aries.transaction.
|
||||
org.apache.axis2.jaxws.spi.handler.
|
||||
org.apache.axis2.transport.jms.
|
||||
org.apache.bcel
|
||||
org.apache.carbondata.core.scan.expression.expressionresult
|
||||
org.apache.catalina.
|
||||
org.apache.cocoon.
|
||||
org.apache.commons.beanutils
|
||||
org.apache.commons.collections.comparators.
|
||||
org.apache.commons.collections.functors
|
||||
org.apache.commons.collections.functors.
|
||||
org.apache.commons.collections.transformer
|
||||
org.apache.commons.collections4.comparators
|
||||
org.apache.commons.collections4.functors
|
||||
org.apache.commons.collections4.transformer
|
||||
org.apache.commons.configuration
|
||||
org.apache.commons.dbcp
|
||||
org.apache.commons.fileupload
|
||||
org.apache.commons.jelly.
|
||||
org.apache.commons.logging.
|
||||
org.apache.commons.proxy.
|
||||
org.apache.cxf.jaxrs.provider.
|
||||
org.apache.hadoop.shaded.com.zaxxer.hikari.
|
||||
org.apache.http.auth.
|
||||
org.apache.http.conn.
|
||||
org.apache.http.cookie.
|
||||
org.apache.http.impl.
|
||||
org.apache.ibatis.datasource
|
||||
org.apache.ibatis.executor.
|
||||
org.apache.ibatis.javassist.
|
||||
org.apache.ibatis.ognl.
|
||||
org.apache.ibatis.parsing.
|
||||
org.apache.ibatis.reflection.
|
||||
org.apache.ibatis.scripting.
|
||||
org.apache.ignite.cache.jta.
|
||||
org.apache.log4j.
|
||||
org.apache.logging.
|
||||
org.apache.myfaces.context.servlet
|
||||
org.apache.openjpa.ee.
|
||||
org.apache.shiro.jndi.
|
||||
org.apache.shiro.realm.
|
||||
org.apache.tomcat
|
||||
org.apache.wicket.util
|
||||
org.apache.xalan
|
||||
org.apache.xbean.
|
||||
org.apache.xpath.xpathcontext
|
||||
org.codehaus.groovy.runtime
|
||||
org.codehaus.jackson.
|
||||
org.eclipse.jetty.
|
||||
org.geotools.filter.constantexpression
|
||||
org.h2.jdbcx.
|
||||
org.h2.server.
|
||||
org.hibernate
|
||||
org.javasimon.
|
||||
org.jaxen.
|
||||
org.jboss
|
||||
org.jdom.
|
||||
org.jdom2.transform.
|
||||
org.logicalcobwebs.
|
||||
org.mortbay.jetty.
|
||||
org.mozilla.javascript
|
||||
org.objectweb.asm.
|
||||
org.osjava.sj.
|
||||
org.python.core
|
||||
org.quartz.
|
||||
org.slf4j.
|
||||
org.springframework.
|
||||
org.yaml.snakeyaml.tokens.directivetoken
|
||||
sun.rmi.server.unicastref
|
||||
|
|
@ -38,6 +38,22 @@ import static org.junit.jupiter.api.Assertions.fail;
|
|||
|
||||
public class URLTest {
|
||||
|
||||
@Test
|
||||
public void test_ignore_pond() {
|
||||
URL url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path#index?version=1.0.0&id=org.apache.dubbo.config.RegistryConfig#0");
|
||||
assertURLStrDecoder(url);
|
||||
assertEquals("dubbo", url.getProtocol());
|
||||
assertEquals("admin", url.getUsername());
|
||||
assertEquals("hello1234", url.getPassword());
|
||||
assertEquals("10.20.130.230", url.getHost());
|
||||
assertEquals("10.20.130.230:20880", url.getAddress());
|
||||
assertEquals(20880, url.getPort());
|
||||
assertEquals("context/path", url.getPath());
|
||||
assertEquals(2, url.getParameters().size());
|
||||
assertEquals("1.0.0", url.getVersion());
|
||||
assertEquals("org.apache.dubbo.config.RegistryConfig#0", url.getParameter("id"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_valueOf_noProtocolAndHost() throws Exception {
|
||||
URL url = URL.valueOf("/context/path?version=1.0.0&application=morgan");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* 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.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;
|
||||
|
||||
public class SerializeClassCheckerTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
SerializeClassChecker.clearInstance();
|
||||
}
|
||||
|
||||
@Test
|
||||
public 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
|
||||
public 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
|
||||
public 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
|
||||
public 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -16,11 +16,30 @@
|
|||
*/
|
||||
package org.apache.dubbo.registry.client.migration.model;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ApplicationMigrationRule {
|
||||
private String name;
|
||||
private MigrationStep step;
|
||||
private Float threshold;
|
||||
|
||||
public static ApplicationMigrationRule parseFromMap(Map<String, Object> map) {
|
||||
ApplicationMigrationRule applicationMigrationRule = new ApplicationMigrationRule();
|
||||
applicationMigrationRule.setName((String) map.get("name"));
|
||||
|
||||
Object step = map.get("step");
|
||||
if (step != null) {
|
||||
applicationMigrationRule.setStep(MigrationStep.valueOf(step.toString()));
|
||||
}
|
||||
|
||||
Object threshold = map.get("threshold");
|
||||
if (threshold != null) {
|
||||
applicationMigrationRule.setThreshold(Float.valueOf(threshold.toString()));
|
||||
}
|
||||
|
||||
return applicationMigrationRule;
|
||||
}
|
||||
|
||||
public ApplicationMigrationRule() {
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,12 +16,32 @@
|
|||
*/
|
||||
package org.apache.dubbo.registry.client.migration.model;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class InterfaceMigrationRule {
|
||||
private String appName;
|
||||
private String serviceKey;
|
||||
private MigrationStep step;
|
||||
private Float threshold;
|
||||
|
||||
public static InterfaceMigrationRule parseFromMap(Map<String, Object> map) {
|
||||
InterfaceMigrationRule interfaceMigrationRule = new InterfaceMigrationRule();
|
||||
interfaceMigrationRule.setAppName((String) map.get("appName"));
|
||||
interfaceMigrationRule.setServiceKey((String) map.get("serviceKey"));
|
||||
|
||||
Object step = map.get("step");
|
||||
if (step != null) {
|
||||
interfaceMigrationRule.setStep(MigrationStep.valueOf(step.toString()));
|
||||
}
|
||||
|
||||
Object threshold = map.get("threshold");
|
||||
if (threshold != null) {
|
||||
interfaceMigrationRule.setThreshold(Float.valueOf(threshold.toString()));
|
||||
}
|
||||
|
||||
return interfaceMigrationRule;
|
||||
}
|
||||
|
||||
public InterfaceMigrationRule(){}
|
||||
|
||||
public InterfaceMigrationRule(String appName, String serviceKey, MigrationStep step, Float threshold) {
|
||||
|
|
|
|||
|
|
@ -20,12 +20,14 @@ import org.apache.dubbo.common.utils.CollectionUtils;
|
|||
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.Constructor;
|
||||
import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* # key = demo-consumer.migration
|
||||
|
|
@ -55,6 +57,42 @@ public class MigrationRule {
|
|||
private transient Map<String, InterfaceMigrationRule> interfaceRules;
|
||||
private transient Map<String, ApplicationMigrationRule> applicationRules;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static MigrationRule parseFromMap(Map<String, Object> map) {
|
||||
MigrationRule migrationRule = new MigrationRule();
|
||||
migrationRule.setKey((String) map.get("key"));
|
||||
|
||||
Object step = map.get("step");
|
||||
if (step != null) {
|
||||
migrationRule.setStep(MigrationStep.valueOf(step.toString()));
|
||||
}
|
||||
|
||||
Object threshold = map.get("threshold");
|
||||
if (threshold != null) {
|
||||
migrationRule.setThreshold(Float.valueOf(threshold.toString()));
|
||||
}
|
||||
|
||||
Object targetIps = map.get("targetIps");
|
||||
if (targetIps != null && List.class.isAssignableFrom(targetIps.getClass())) {
|
||||
migrationRule.setTargetIps(((List<Object>) targetIps).stream()
|
||||
.map(String::valueOf).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
Object interfaces = map.get("interfaces");
|
||||
if (interfaces != null && List.class.isAssignableFrom(interfaces.getClass())) {
|
||||
migrationRule.setInterfaces(((List<Map<String, Object>>) interfaces).stream()
|
||||
.map(InterfaceMigrationRule::parseFromMap).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
Object applications = map.get("applications");
|
||||
if (applications != null && List.class.isAssignableFrom(applications.getClass())) {
|
||||
migrationRule.setApplications(((List<Map<String, Object>>) applications).stream()
|
||||
.map(ApplicationMigrationRule::parseFromMap).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
return migrationRule;
|
||||
}
|
||||
|
||||
public MigrationRule() {
|
||||
}
|
||||
|
||||
|
|
@ -233,9 +271,9 @@ public class MigrationRule {
|
|||
}
|
||||
|
||||
public static MigrationRule parse(String rawRule) {
|
||||
Constructor constructor = new Constructor(MigrationRule.class);
|
||||
Yaml yaml = new Yaml(constructor);
|
||||
return yaml.load(rawRule);
|
||||
Yaml yaml = new Yaml(new SafeConstructor());
|
||||
Map<String, Object> map = yaml.load(rawRule);
|
||||
return parseFromMap(map);
|
||||
}
|
||||
|
||||
public static String toYaml(MigrationRule rule) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.registry.client.migration.model;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
public class MigrationRuleTest {
|
||||
|
||||
@Test
|
||||
public void test_parse() {
|
||||
String rule = "key: demo-consumer\n" +
|
||||
"step: APPLICATION_FIRST\n" +
|
||||
"threshold: 1.0\n" +
|
||||
"interfaces:\n" +
|
||||
" - serviceKey: DemoService:1.0.0\n" +
|
||||
" threshold: 1.0\n" +
|
||||
" step: APPLICATION_FIRST\n" +
|
||||
" - serviceKey: GreetingService:1.0.0\n" +
|
||||
" step: FORCE_APPLICATION";
|
||||
|
||||
MigrationRule migrationRule = MigrationRule.parse(rule);
|
||||
assertEquals(migrationRule.getKey(), "demo-consumer");
|
||||
assertEquals(migrationRule.getStep(), MigrationStep.APPLICATION_FIRST);
|
||||
assertEquals(migrationRule.getThreshold(), 1.0f);
|
||||
assertEquals(migrationRule.getInterfaces().size(), 2);
|
||||
assertNotNull(migrationRule.getInterfaceRule("DemoService:1.0.0"));
|
||||
assertNotNull(migrationRule.getInterfaceRule("GreetingService:1.0.0"));
|
||||
assertNull(migrationRule.getApplications());
|
||||
}
|
||||
}
|
||||
|
|
@ -19,11 +19,14 @@ package org.apache.dubbo.rpc.filter;
|
|||
import org.apache.dubbo.common.beanutil.JavaBeanAccessor;
|
||||
import org.apache.dubbo.common.beanutil.JavaBeanDescriptor;
|
||||
import org.apache.dubbo.common.beanutil.JavaBeanSerializeUtil;
|
||||
import org.apache.dubbo.common.config.Configuration;
|
||||
import org.apache.dubbo.common.constants.CommonConstants;
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.common.extension.ExtensionLoader;
|
||||
import org.apache.dubbo.common.io.UnsafeByteArrayInputStream;
|
||||
import org.apache.dubbo.common.io.UnsafeByteArrayOutputStream;
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.common.serialize.Serialization;
|
||||
import org.apache.dubbo.common.utils.PojoUtils;
|
||||
import org.apache.dubbo.common.utils.ReflectUtils;
|
||||
|
|
@ -35,6 +38,7 @@ import org.apache.dubbo.rpc.Result;
|
|||
import org.apache.dubbo.rpc.RpcContext;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
import org.apache.dubbo.rpc.service.GenericException;
|
||||
import org.apache.dubbo.rpc.service.GenericService;
|
||||
import org.apache.dubbo.rpc.support.ProtocolUtils;
|
||||
|
|
@ -54,6 +58,7 @@ import static org.apache.dubbo.rpc.Constants.GENERIC_KEY;
|
|||
*/
|
||||
@Activate(group = CommonConstants.PROVIDER, order = -20000)
|
||||
public class GenericFilter implements Filter, Filter.Listener {
|
||||
private final Logger logger = LoggerFactory.getLogger(GenericFilter.class);
|
||||
|
||||
@Override
|
||||
public Result invoke(Invoker<?> invoker, Invocation inv) throws RpcException {
|
||||
|
|
@ -85,6 +90,18 @@ public class GenericFilter implements Filter, Filter.Listener {
|
|||
|| ProtocolUtils.isGenericReturnRawResult(generic)) {
|
||||
args = PojoUtils.realize(args, params, method.getGenericParameterTypes());
|
||||
} else if (ProtocolUtils.isJavaGenericSerialization(generic)) {
|
||||
Configuration configuration = ApplicationModel.getEnvironment().getConfiguration();
|
||||
if (!configuration.getBoolean(CommonConstants.ENABLE_NATIVE_JAVA_GENERIC_SERIALIZE, false)) {
|
||||
String notice = "Trigger the safety barrier! " +
|
||||
"Native Java Serializer is not allowed by default." +
|
||||
"This means currently maybe being attacking by others. " +
|
||||
"If you are sure this is a mistake, " +
|
||||
"please set `" + CommonConstants.ENABLE_NATIVE_JAVA_GENERIC_SERIALIZE + "` enable in configuration! " +
|
||||
"Before doing so, please make sure you have configure JEP290 to prevent serialization attack.";
|
||||
logger.error(notice);
|
||||
throw new RpcException(new IllegalStateException(notice));
|
||||
}
|
||||
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (byte[].class == args[i].getClass()) {
|
||||
try (UnsafeByteArrayInputStream is = new UnsafeByteArrayInputStream((byte[]) args[i])) {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.$INVOKE;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.ENABLE_NATIVE_JAVA_GENERIC_SERIALIZE;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_NATIVE_JAVA;
|
||||
import static org.apache.dubbo.rpc.Constants.GENERIC_KEY;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
|
|
@ -75,6 +76,8 @@ public class GenericFilterTest {
|
|||
|
||||
@Test
|
||||
public void testInvokeWithJavaException() throws Exception {
|
||||
// temporary enable native java generic serialize
|
||||
System.setProperty(ENABLE_NATIVE_JAVA_GENERIC_SERIALIZE, "true");
|
||||
Assertions.assertThrows(RpcException.class, () -> {
|
||||
Method genericInvoke = GenericService.class.getMethods()[0];
|
||||
|
||||
|
|
@ -95,6 +98,7 @@ public class GenericFilterTest {
|
|||
|
||||
genericFilter.invoke(invoker, invocation);
|
||||
});
|
||||
System.clearProperty(ENABLE_NATIVE_JAVA_GENERIC_SERIALIZE);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
Loading…
Reference in New Issue