This is an automated email from the ASF dual-hosted git repository.

wujimin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit 839a52e27c754cb5ce14f20063902f21065bd26c
Author: liubao <bi...@qq.com>
AuthorDate: Fri Dec 4 17:23:24 2020 +0800

    [SCB-2145]fix local yaml unsafe parse problem
---
 .../org/apache/servicecomb/config/YAMLUtil.java    | 13 ++++-
 .../config/archaius/sources/YAMLConfigLoader.java  |  7 +--
 .../apache/servicecomb/config/TestYAMLUtil.java    | 66 ++++++++++++++++++++++
 .../servicecomb/router/cache/RouterRuleCache.java  | 17 +++---
 .../router/custom/RouterInvokeFilter.java          |  7 +--
 .../servicecomb/router/RouterDistributorTest.java  | 60 ++++++++++----------
 .../localregistry/LocalRegistryStore.java          | 35 ++++++------
 .../client/LocalServiceRegistryClientImpl.java     | 17 ++++--
 8 files changed, 151 insertions(+), 71 deletions(-)

diff --git 
a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/YAMLUtil.java
 
b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/YAMLUtil.java
index abcf1fa..e37b4e2 100644
--- 
a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/YAMLUtil.java
+++ 
b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/YAMLUtil.java
@@ -24,12 +24,17 @@ import java.io.InputStream;
 import java.util.LinkedHashMap;
 import java.util.Map;
 
+import org.yaml.snakeyaml.TypeDescription;
 import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.constructor.SafeConstructor;
 
 /**
  * Created by   on 2017/1/5.
  */
 public final class YAMLUtil {
+  private static final Yaml SAFE_PARSER = new Yaml(new SafeConstructor());
+
   private YAMLUtil() {
   }
 
@@ -45,11 +50,15 @@ public final class YAMLUtil {
   @SuppressWarnings("unchecked")
   public static Map<String, Object> yaml2Properties(InputStream input) {
     Map<String, Object> configurations = new LinkedHashMap<>();
-    Yaml yaml = new Yaml();
-    yaml.loadAll(input).forEach(data -> 
configurations.putAll(retrieveItems("", (Map<String, Object>) data)));
+    SAFE_PARSER.loadAll(input).forEach(data -> 
configurations.putAll(retrieveItems("", (Map<String, Object>) data)));
     return configurations;
   }
 
+  public static <T> T parserObject(String yamlContent, Class<T> clazz) {
+    Yaml parser = new Yaml(new Constructor(new TypeDescription(clazz, clazz)));
+    return parser.loadAs(yamlContent, clazz);
+  }
+
   @SuppressWarnings("unchecked")
   public static Map<String, Object> retrieveItems(String prefix, Map<String, 
Object> propertieMap) {
     Map<String, Object> result = new LinkedHashMap<>();
diff --git 
a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/archaius/sources/YAMLConfigLoader.java
 
b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/archaius/sources/YAMLConfigLoader.java
index f0fb453..f50451f 100644
--- 
a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/archaius/sources/YAMLConfigLoader.java
+++ 
b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/archaius/sources/YAMLConfigLoader.java
@@ -22,16 +22,13 @@ import java.io.InputStream;
 import java.net.URL;
 import java.util.Map;
 
-import org.yaml.snakeyaml.Yaml;
+import org.apache.servicecomb.config.YAMLUtil;
 
 public class YAMLConfigLoader extends AbstractConfigLoader {
-  @SuppressWarnings("unchecked")
   @Override
   protected Map<String, Object> loadData(URL url) throws IOException {
-    Yaml yaml = new Yaml();
-
     try (InputStream inputStream = url.openStream()) {
-      return yaml.loadAs(inputStream, Map.class);
+      return YAMLUtil.yaml2Properties(inputStream);
     }
   }
 }
diff --git 
a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestYAMLUtil.java
 
b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestYAMLUtil.java
new file mode 100644
index 0000000..7dd950c
--- /dev/null
+++ 
b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestYAMLUtil.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.config;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestYAMLUtil {
+  public static class Person {
+    String name;
+
+    public String getName() {
+      return name;
+    }
+
+    public void setName(String name) {
+      this.name = name;
+    }
+  }
+
+  public static class UnsafePerson {
+    String name;
+
+    public String getName() {
+      return name;
+    }
+
+    public void setName(String name) {
+      this.name = name;
+    }
+  }
+
+  @Test
+  public void testSafeParser() {
+    Person person = YAMLUtil.parserObject("name: hello", Person.class);
+    Assert.assertEquals("hello", person.getName());
+
+    person = 
YAMLUtil.parserObject("!!org.apache.servicecomb.config.TestYAMLUtil$Person\n"
+        + "name: hello", Person.class);
+    Assert.assertEquals("hello", person.getName());
+
+    person = 
YAMLUtil.parserObject("!!org.apache.servicecomb.config.TestYAMLUtil$UnsafePerson\n"
+        + "name: hello", Person.class);
+    Assert.assertEquals("hello", person.getName());
+
+    // using Object.class is not safe, do not used in product code.
+    Object object = 
YAMLUtil.parserObject("!!org.apache.servicecomb.config.TestYAMLUtil$UnsafePerson\n"
+        + "name: hello", Object.class);
+    Assert.assertEquals("hello", ((UnsafePerson) object).getName());
+  }
+}
diff --git 
a/handlers/handler-router/src/main/java/org/apache/servicecomb/router/cache/RouterRuleCache.java
 
b/handlers/handler-router/src/main/java/org/apache/servicecomb/router/cache/RouterRuleCache.java
index 0136b08..941a8ac 100644
--- 
a/handlers/handler-router/src/main/java/org/apache/servicecomb/router/cache/RouterRuleCache.java
+++ 
b/handlers/handler-router/src/main/java/org/apache/servicecomb/router/cache/RouterRuleCache.java
@@ -16,20 +16,22 @@
  */
 package org.apache.servicecomb.router.cache;
 
-import com.google.common.collect.Interner;
-import com.google.common.collect.Interners;
-import com.netflix.config.DynamicPropertyFactory;
-import com.netflix.config.DynamicStringProperty;
 import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.servicecomb.config.YAMLUtil;
 import org.apache.servicecomb.router.model.PolicyRuleItem;
 import org.apache.servicecomb.router.model.ServiceInfoCache;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.util.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.yaml.snakeyaml.Yaml;
+
+import com.google.common.collect.Interner;
+import com.google.common.collect.Interners;
+import com.netflix.config.DynamicPropertyFactory;
+import com.netflix.config.DynamicStringProperty;
 
 /**
  * @Author GuoYl123
@@ -78,11 +80,10 @@ public class RouterRuleCache {
     if (StringUtils.isEmpty(ruleStr)) {
       return false;
     }
-    Yaml yaml = new Yaml();
     List<PolicyRuleItem> policyRuleItemList;
     try {
       policyRuleItemList = Arrays
-          .asList(yaml.loadAs(ruleStr, PolicyRuleItem[].class));
+          .asList(YAMLUtil.parserObject(ruleStr, PolicyRuleItem[].class));
     } catch (Exception e) {
       LOGGER.error("route management Serialization failed: {}", 
e.getMessage());
       return false;
diff --git 
a/handlers/handler-router/src/main/java/org/apache/servicecomb/router/custom/RouterInvokeFilter.java
 
b/handlers/handler-router/src/main/java/org/apache/servicecomb/router/custom/RouterInvokeFilter.java
index 7e345a9..b381a04 100644
--- 
a/handlers/handler-router/src/main/java/org/apache/servicecomb/router/custom/RouterInvokeFilter.java
+++ 
b/handlers/handler-router/src/main/java/org/apache/servicecomb/router/custom/RouterInvokeFilter.java
@@ -17,10 +17,12 @@
 package org.apache.servicecomb.router.custom;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.commons.lang3.StringUtils;
 import org.apache.servicecomb.common.rest.filter.HttpServerFilter;
 import org.apache.servicecomb.core.Invocation;
 import org.apache.servicecomb.foundation.common.utils.JsonUtils;
@@ -30,8 +32,6 @@ import org.apache.servicecomb.swagger.invocation.Response;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.util.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.yaml.snakeyaml.Yaml;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.netflix.config.DynamicPropertyFactory;
@@ -118,8 +118,7 @@ public class RouterInvokeFilter implements HttpServerFilter 
{
     }
     try {
       if (CollectionUtils.isEmpty(allHeader)) {
-        Yaml yaml = new Yaml();
-        allHeader = yaml.load(str);
+        allHeader = Arrays.asList(str.split(","));
       }
     } catch (Exception e) {
       LOGGER.error("route management Serialization failed: {}", 
e.getMessage());
diff --git 
a/handlers/handler-router/src/test/java/org/apache/servicecomb/router/RouterDistributorTest.java
 
b/handlers/handler-router/src/test/java/org/apache/servicecomb/router/RouterDistributorTest.java
index 89e34e1..2979ab2 100644
--- 
a/handlers/handler-router/src/test/java/org/apache/servicecomb/router/RouterDistributorTest.java
+++ 
b/handlers/handler-router/src/test/java/org/apache/servicecomb/router/RouterDistributorTest.java
@@ -17,27 +17,29 @@
 
 package org.apache.servicecomb.router;
 
-import com.netflix.config.DynamicPropertyFactory;
-import com.netflix.config.DynamicStringProperty;
-import com.netflix.loadbalancer.Server;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import mockit.Expectations;
+
 import org.apache.servicecomb.router.cache.RouterRuleCache;
 import org.apache.servicecomb.router.distribute.AbstractRouterDistributor;
 import org.apache.servicecomb.router.distribute.RouterDistributor;
 import org.junit.Assert;
 import org.junit.Test;
 
+import com.netflix.config.DynamicPropertyFactory;
+import com.netflix.config.DynamicStringProperty;
+import com.netflix.loadbalancer.Server;
+
+import mockit.Expectations;
+
 /**
- * @Author GuoYl123
- * @Date 2019/11/4
+ * @author GuoYl123
  **/
 public class RouterDistributorTest {
 
-  private static String ruleStr = ""
+  private static final String RULE_STRING = ""
       + "      - precedence: 2 #优先级\n"
       + "        match:        #匹配策略\n"
       + "          source: xx #匹配某个服务名\n"
@@ -66,7 +68,7 @@ public class RouterDistributorTest {
       + "              version: 1\n"
       + "              app: a";
 
-  private static String targetServiceName = "test_server";
+  private static final String TARGET_SERVICE_NAME = "test_server";
 
   @Test
   public void testHeaderIsNull() {
@@ -77,13 +79,13 @@ public class RouterDistributorTest {
 
   @Test
   public void testVersionNotMatch() {
-    Map<String, String> headermap = new HashMap<>();
-    headermap.put("userId", "01");
-    headermap.put("appId", "01");
-    headermap.put("formate", "json");
+    Map<String, String> headerMap = new HashMap<>();
+    headerMap.put("userId", "01");
+    headerMap.put("appId", "01");
+    headerMap.put("format", "json");
     List<ServiceIns> list = getMockList();
     list.remove(1);
-    List<ServiceIns> serverList = mainFilter(list, headermap);
+    List<ServiceIns> serverList = mainFilter(list, headerMap);
     Assert.assertEquals(1, serverList.size());
     Assert.assertEquals("01", serverList.get(0).getHost());
   }
@@ -93,43 +95,45 @@ public class RouterDistributorTest {
     Map<String, String> headermap = new HashMap<>();
     headermap.put("userId", "01");
     headermap.put("appId", "01");
-    headermap.put("formate", "json");
+    headermap.put("format", "json");
     List<ServiceIns> serverList = mainFilter(getMockList(), headermap);
     Assert.assertEquals(1, serverList.size());
     Assert.assertEquals("02", serverList.get(0).getHost());
   }
 
   private List<ServiceIns> getMockList() {
-    List<ServiceIns> serverlist = new ArrayList<>();
+    List<ServiceIns> serverList = new ArrayList<>();
     ServiceIns ins1 = new ServiceIns("01");
     ins1.setVersion("2.0");
     ServiceIns ins2 = new ServiceIns("02");
     ins2.addTags("app", "a");
-    serverlist.add(ins1);
-    serverlist.add(ins2);
-    return serverlist;
+    serverList.add(ins1);
+    serverList.add(ins2);
+    return serverList;
   }
 
   private List<ServiceIns> mainFilter(List<ServiceIns> serverlist, Map<String, 
String> headermap) {
-    RouterDistributor<ServiceIns, ServiceIns> testDistributer = new 
TestDistributer();
+    RouterDistributor<ServiceIns, ServiceIns> testDistributer = new 
TestDistributor();
     DynamicPropertyFactory dpf = DynamicPropertyFactory.getInstance();
-    DynamicStringProperty strp = new DynamicStringProperty("", ruleStr);
+    DynamicStringProperty rule = new DynamicStringProperty("", RULE_STRING);
     new Expectations(dpf) {
       {
         dpf.getStringProperty(anyString, null, (Runnable) any);
-        result = strp;
+        result = rule;
       }
     };
     RouterRuleCache.refresh();
     return RouterFilter
-        .getFilteredListOfServers(serverlist, targetServiceName, headermap,
+        .getFilteredListOfServers(serverlist, TARGET_SERVICE_NAME, headermap,
             testDistributer);
   }
 
-  class ServiceIns extends Server {
+  static class ServiceIns extends Server {
 
     String version = "1.1";
-    String serverName = targetServiceName;
+
+    String serverName = TARGET_SERVICE_NAME;
+
     Map<String, String> tags = new HashMap<>();
 
     public ServiceIns(String id) {
@@ -152,18 +156,14 @@ public class RouterDistributorTest {
       this.version = version;
     }
 
-    public void setServerName(String serverName) {
-      this.serverName = serverName;
-    }
-
     public void addTags(String key, String v) {
       tags.put(key, v);
     }
   }
 
-  class TestDistributer extends AbstractRouterDistributor<ServiceIns, 
ServiceIns> {
+  static class TestDistributor extends AbstractRouterDistributor<ServiceIns, 
ServiceIns> {
 
-    public TestDistributer() {
+    public TestDistributor() {
       init(a -> a, ServiceIns::getVersion, ServiceIns::getServerName, 
ServiceIns::getTags);
     }
   }
diff --git 
a/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/LocalRegistryStore.java
 
b/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/LocalRegistryStore.java
index f21bcad..98c43f4 100644
--- 
a/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/LocalRegistryStore.java
+++ 
b/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/LocalRegistryStore.java
@@ -30,6 +30,7 @@ import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Collectors;
 
+import org.apache.servicecomb.config.YAMLUtil;
 import org.apache.servicecomb.foundation.common.utils.BeanUtils;
 import org.apache.servicecomb.foundation.common.utils.JvmUtils;
 import org.apache.servicecomb.localregistry.RegistryBean.Instance;
@@ -40,7 +41,6 @@ import 
org.apache.servicecomb.registry.api.registry.MicroserviceInstance;
 import org.apache.servicecomb.registry.api.registry.MicroserviceInstances;
 import org.apache.servicecomb.swagger.SwaggerUtils;
 import org.apache.servicecomb.swagger.generator.SwaggerGenerator;
-import org.yaml.snakeyaml.Yaml;
 
 import com.google.common.annotations.VisibleForTesting;
 
@@ -111,37 +111,38 @@ public class LocalRegistryStore {
   private List<RegistryBean> loadYamlBeans() {
     List<RegistryBean> beans = new ArrayList<>();
 
-    InputStream is = null;
-
     try {
       ClassLoader loader = JvmUtils.findClassLoader();
       Enumeration<URL> urls = loader.getResources(REGISTRY_FILE_NAME);
+
       while (urls.hasMoreElements()) {
         URL url = urls.nextElement();
-        is = url.openStream();
-        if (is != null) {
-          beans.addAll(initFromData(is));
+
+        InputStream is = null;
+        try {
+          is = url.openStream();
+          if (is != null) {
+            beans.addAll(initFromData(is));
+          }
+        } finally {
+          if (is != null) {
+            try {
+              is.close();
+            } catch (IOException e) {
+              // nothing to do
+            }
+          }
         }
       }
     } catch (IOException e) {
       throw new IllegalStateException(e);
-    } finally {
-      if (is != null) {
-        try {
-          is.close();
-        } catch (IOException e) {
-          // nothing to do
-        }
-      }
     }
 
     return beans;
   }
 
-  @SuppressWarnings("unchecked")
   private List<RegistryBean> initFromData(InputStream is) {
-    Yaml yaml = new Yaml();
-    Map<String, Object> data = yaml.loadAs(is, Map.class);
+    Map<String, Object> data = YAMLUtil.yaml2Properties(is);
     return initFromData(data);
   }
 
diff --git 
a/service-registry/registry-service-center/src/test/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImpl.java
 
b/service-registry/registry-service-center/src/test/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImpl.java
index a63e9b2..202e301 100644
--- 
a/service-registry/registry-service-center/src/test/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImpl.java
+++ 
b/service-registry/registry-service-center/src/test/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImpl.java
@@ -17,6 +17,7 @@
 
 package org.apache.servicecomb.serviceregistry.client;
 
+import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
@@ -30,6 +31,7 @@ import javax.ws.rs.core.Response.Status;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.servicecomb.config.BootStrapProperties;
+import org.apache.servicecomb.config.YAMLUtil;
 import org.apache.servicecomb.foundation.vertx.AsyncResultCallback;
 import 
org.apache.servicecomb.registry.api.event.MicroserviceInstanceChangedEvent;
 import org.apache.servicecomb.registry.api.registry.FindInstancesResponse;
@@ -48,7 +50,6 @@ import 
org.apache.servicecomb.serviceregistry.api.response.HeartbeatResponse;
 import org.apache.servicecomb.serviceregistry.client.http.Holder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.yaml.snakeyaml.Yaml;
 
 import com.google.common.base.Charsets;
 import com.google.common.hash.Hashing;
@@ -94,10 +95,16 @@ public class LocalServiceRegistryClientImpl implements 
ServiceRegistryClient {
   }
 
   private void initFromData(InputStream is) {
-    Yaml yaml = new Yaml();
-    @SuppressWarnings("unchecked")
-    Map<String, Object> data = yaml.loadAs(is, Map.class);
-    initFromData(data);
+    try {
+      Map<String, Object> data = YAMLUtil.yaml2Properties(is);
+      initFromData(data);
+    } finally {
+      try {
+        is.close();
+      } catch (IOException e) {
+        LOGGER.error("", e);
+      }
+    }
   }
 
   private void initFromData(Map<String, Object> data) {

Reply via email to