Skip to content

Commit 803e6e0

Browse files
committed
【Doe_V1.2.0】 增加沙箱隔离jar包
1 parent de449b2 commit 803e6e0

File tree

6 files changed

+251
-10
lines changed

6 files changed

+251
-10
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
* 增加mac系统判断
7575
* 增加泛型接口测试
7676
* 修改dubbo依赖为starter方式
77+
* 修改类加载方式,增加沙箱隔离
7778

7879
##### 三. 缺陷修复
7980
*
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
/*
2+
* Copyright (c) 2010-2020 Founder Ltd. All Rights Reserved.
3+
*
4+
* This software is the confidential and proprietary information of
5+
* Founder. You shall not disclose such Confidential Information
6+
* and shall use it only in accordance with the terms of the agreements
7+
* you entered into with Founder.
8+
*
9+
*/
10+
package com.mmc.dubbo.doe.context;
11+
12+
import com.alibaba.dubbo.common.utils.StringUtils;
13+
import com.mmc.dubbo.doe.exception.DoeException;
14+
import com.mmc.dubbo.doe.util.StringUtil;
15+
import lombok.extern.slf4j.Slf4j;
16+
17+
import java.io.ByteArrayOutputStream;
18+
import java.io.File;
19+
import java.io.IOException;
20+
import java.io.InputStream;
21+
import java.nio.file.Files;
22+
import java.nio.file.Paths;
23+
import java.util.Enumeration;
24+
import java.util.Map;
25+
import java.util.Objects;
26+
import java.util.concurrent.ConcurrentHashMap;
27+
import java.util.jar.JarEntry;
28+
import java.util.jar.JarFile;
29+
30+
/**
31+
* 自定义类加载器,做沙箱隔离.
32+
*
33+
* @author Joey
34+
* @date 2019/6/28 14:20
35+
*/
36+
@Slf4j
37+
public class DoeClassLoader extends ClassLoader {
38+
39+
40+
private final String path;
41+
42+
private static Map<String, byte[]> classMap = new ConcurrentHashMap<>();
43+
44+
45+
/**
46+
* destroy the Parental Entrustment.
47+
*/
48+
public DoeClassLoader(String path) {
49+
super(null);
50+
this.path = path;
51+
}
52+
53+
54+
private void scanJarFile(File file) throws Exception {
55+
56+
JarFile jar = new JarFile(file);
57+
58+
Enumeration<JarEntry> en = jar.entries();
59+
while (en.hasMoreElements()) {
60+
JarEntry je = en.nextElement();
61+
je.getName();
62+
String name = je.getName();
63+
if (name.endsWith(".class")) {
64+
65+
String className = makeClassName(name);
66+
67+
try (InputStream input = jar.getInputStream(je); ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
68+
int bufferSize = 1024;
69+
byte[] buffer = new byte[bufferSize];
70+
int bytesNumRead;
71+
while ((bytesNumRead = input.read(buffer)) != -1) {
72+
baos.write(buffer, 0, bytesNumRead);
73+
}
74+
addClass(className, baos.toByteArray());
75+
}
76+
}
77+
}
78+
}
79+
80+
private String makeClassName(String name) {
81+
String ret = name.replace("\\", ".")
82+
.replace("/", ".")
83+
.replace(".class", "");
84+
return ret;
85+
}
86+
87+
/**
88+
* load jars from the Specified path.
89+
*/
90+
public void loadJars() throws Exception {
91+
92+
if (StringUtils.isEmpty(path)) {
93+
throw new DoeException(StringUtil.format("can't found the path {}", path));
94+
}
95+
96+
File libPath = new File(path);
97+
if (!libPath.exists()) {
98+
throw new DoeException(StringUtil.format("the path[{}] is not exists.", path));
99+
}
100+
101+
File[] files = libPath.listFiles((dir, name) -> name.endsWith(".jar") || name.endsWith(".zip"));
102+
103+
if (files != null) {
104+
for (File file : files) {
105+
scanJarFile(file);
106+
}
107+
}
108+
}
109+
110+
/**
111+
* Add one class dynamically.
112+
*/
113+
public static boolean addClass(String className, byte[] byteCode) {
114+
if (!classMap.containsKey(className)) {
115+
classMap.put(className, byteCode);
116+
return true;
117+
}
118+
return false;
119+
}
120+
121+
@Override
122+
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
123+
124+
name = makeClassName(name);
125+
126+
byte[] stream = get(name);
127+
128+
if (null != stream) {
129+
130+
return defineClass(name, stream, 0, stream.length);
131+
}
132+
133+
return super.loadClass(name, resolve);
134+
135+
}
136+
137+
/**
138+
* Get class in our classloader rather than system classloader.
139+
*/
140+
public static Class<?> getClass(String name) throws ClassNotFoundException {
141+
return new DoeClassLoader("").loadClass(name, false);
142+
}
143+
144+
private static byte[] get(String className) {
145+
return classMap.getOrDefault(className, null);
146+
}
147+
148+
private void scanClassFile(File file) {
149+
if (file.exists()) {
150+
if (file.isFile() && file.getName().endsWith(".class")) {
151+
try {
152+
byte[] byteCode = Files.readAllBytes(Paths.get(file.getAbsolutePath()));
153+
String className = file.getAbsolutePath().replace(this.path, "")
154+
.replace(File.separator, ".");
155+
156+
className = makeClassName(className);
157+
158+
addClass(className, byteCode);
159+
} catch (IOException e) {
160+
e.printStackTrace();
161+
}
162+
} else if (file.isDirectory()) {
163+
for (File f : Objects.requireNonNull(file.listFiles())) {
164+
scanClassFile(f);
165+
}
166+
}
167+
}
168+
}
169+
170+
/**
171+
* load classes from the Specified path.
172+
*/
173+
public void loadClassFile() {
174+
File[] files = new File(path).listFiles();
175+
if (files != null) {
176+
for (File file : files) {
177+
scanClassFile(file);
178+
}
179+
}
180+
}
181+
182+
}

mmc-dubbo-doe/src/main/java/com/mmc/dubbo/doe/crontroller/RegistryController.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@
99
*/
1010
package com.mmc.dubbo.doe.crontroller;
1111

12-
import com.alibaba.dubbo.common.utils.StringUtils;
1312
import com.alibaba.fastjson.JSON;
1413
import com.mmc.dubbo.doe.dto.ResultDTO;
1514
import com.mmc.dubbo.doe.model.RegistryModel;
1615
import com.mmc.dubbo.doe.service.ConfigService;
1716
import lombok.extern.slf4j.Slf4j;
17+
import org.slf4j.MDC;
1818
import org.springframework.beans.factory.annotation.Autowired;
1919
import org.springframework.web.bind.annotation.RequestMapping;
2020
import org.springframework.web.bind.annotation.RestController;
@@ -46,7 +46,7 @@ public String doListZk() {
4646
List<RegistryModel> models = configService.listRegistry();
4747
result = JSON.toJSONString(models);
4848

49-
} catch(Exception e) {
49+
} catch (Exception e) {
5050

5151
result = "[]";
5252
}
@@ -59,6 +59,11 @@ public String doListZk() {
5959
public ResultDTO<Object> doListRegistry() {
6060

6161
log.info("RegistryController.doListRegistry()");
62+
MDC.put("CUSTOM_PATTERN", "presstest");
63+
log.info("hhhh");
64+
log.warn("hh");
65+
log.error("h");
66+
System.out.println(MDC.get("PtxId"));
6267

6368
ResultDTO<Object> resultDTO = new ResultDTO<>();
6469

@@ -68,7 +73,7 @@ public ResultDTO<Object> doListRegistry() {
6873
resultDTO.setData(models);
6974
resultDTO.setSuccess(true);
7075

71-
} catch(Exception e) {
76+
} catch (Exception e) {
7277

7378
resultDTO = ResultDTO.createExceptionResult("occur an error when list registry address : ", e, Object.class);
7479
}
@@ -87,7 +92,7 @@ public ResultDTO<RegistryModel> addRegistry(@NotNull RegistryModel dto) {
8792

8893
resultDTO = configService.addRegistry(dto);
8994

90-
} catch(Exception e) {
95+
} catch (Exception e) {
9196

9297
resultDTO = ResultDTO.createExceptionResult(e, RegistryModel.class);
9398
}
@@ -106,7 +111,7 @@ public ResultDTO<RegistryModel> delRegistry(@NotNull RegistryModel dto) {
106111

107112
resultDTO = configService.delRegistry(dto);
108113

109-
} catch(Exception e) {
114+
} catch (Exception e) {
110115

111116
resultDTO = ResultDTO.createExceptionResult(e, RegistryModel.class);
112117
}

mmc-dubbo-doe/src/main/java/com/mmc/dubbo/doe/service/impl/ClassServiceImpl.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import com.mmc.dubbo.doe.cache.MethodCaches;
1717
import com.mmc.dubbo.doe.cache.UrlCaches;
1818
import com.mmc.dubbo.doe.context.Const;
19+
import com.mmc.dubbo.doe.context.DoeClassLoader;
1920
import com.mmc.dubbo.doe.dto.ConnectDTO;
2021
import com.mmc.dubbo.doe.dto.MethodModelDTO;
2122
import com.mmc.dubbo.doe.dto.ResultDTO;
@@ -68,12 +69,12 @@ public List<MethodModelDTO> listMethods(ConnectDTO dto) {
6869
try {
6970

7071
// show only public method
71-
Class<?> clazz = Class.forName(interfaceName);
72+
// Class<?> clazz = Class.forName(interfaceName);
73+
// load classes without affect system class since v1.2.0
74+
Class<?> clazz = DoeClassLoader.getClass(interfaceName);
7275
Method[] methods = clazz.getMethods();
7376
// convert and cache method object associate witch the unique key
74-
List<MethodModelDTO> models = MethodCaches.cache(interfaceName, methods);
75-
76-
return models;
77+
return MethodCaches.cache(interfaceName, methods);
7778

7879
} catch (ClassNotFoundException e) {
7980
throw new DoeException("can't found the interface from classpath, please add the dependency first.");

mmc-dubbo-doe/src/main/java/com/mmc/dubbo/doe/service/impl/PomServiceImpl.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import com.mmc.dubbo.doe.cache.RedisResolver;
1515
import com.mmc.dubbo.doe.client.ProcessClient;
1616
import com.mmc.dubbo.doe.context.Const;
17+
import com.mmc.dubbo.doe.context.DoeClassLoader;
1718
import com.mmc.dubbo.doe.context.TaskContainer;
1819
import com.mmc.dubbo.doe.dto.PomDTO;
1920
import com.mmc.dubbo.doe.dto.ResultDTO;
@@ -292,7 +293,21 @@ public ResultDTO<String> getRealTimeMsg(@NotNull String requestId) {
292293
}
293294

294295
@Override
295-
public ResultDTO<String> loadJars(String path) throws NoSuchMethodException, MalformedURLException {
296+
public ResultDTO<String> loadJars(String path) {
297+
298+
String realPath = (StringUtils.isEmpty(path)) ? this.libPath : path;
299+
DoeClassLoader classLoader = new DoeClassLoader(realPath);
300+
try {
301+
classLoader.loadJars();
302+
return ResultDTO.createSuccessResult("load jars completely and successfully", String.class);
303+
} catch (Exception e) {
304+
return ResultDTO.handleException("occur an error when load jars", null, e);
305+
}
306+
307+
}
308+
309+
@Deprecated // since v1.1.0
310+
public ResultDTO<String> loadJars$$(String path) throws NoSuchMethodException, MalformedURLException {
296311

297312
String fullLibPath = StringUtils.isEmpty(path) ? this.libPath : path;
298313

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright (c) 2010-2020 Founder Ltd. All Rights Reserved.
3+
*
4+
* This software is the confidential and proprietary information of
5+
* Founder. You shall not disclose such Confidential Information
6+
* and shall use it only in accordance with the terms of the agreements
7+
* you entered into with Founder.
8+
*
9+
*/
10+
package com.mmc.dubbo.doe.test;
11+
12+
import com.mmc.dubbo.doe.context.DoeClassLoader;
13+
import org.junit.Test;
14+
15+
/**
16+
* @author Joey
17+
* @date 2019/6/28 14:54
18+
*/
19+
public class TestDoeClassLoader {
20+
21+
@Test
22+
public void testLoad() throws Exception {
23+
24+
String path = "F:\\app\\doe\\lib";
25+
26+
DoeClassLoader doeClassLoader = new DoeClassLoader(path);
27+
28+
doeClassLoader.loadJars();
29+
doeClassLoader.loadClassFile();
30+
Class<?> clazz = doeClassLoader.loadClass("com.fcbox.edms.terminal.api.CabinetServiceFacade");
31+
32+
33+
System.out.println(clazz.getClassLoader());
34+
35+
}
36+
37+
}

0 commit comments

Comments
 (0)