Skip to content

Commit

Permalink
Merge pull request #548 from HXSecurity/beta
Browse files Browse the repository at this point in the history
bump version to 1.12.0-beta1
  • Loading branch information
lostsnow authored Jul 5, 2023
2 parents 2115388 + 09a90e9 commit 5b31d4c
Show file tree
Hide file tree
Showing 76 changed files with 4,368 additions and 440 deletions.
43 changes: 43 additions & 0 deletions dongtai-api-gather/dongtai-api-gather-dubbo-api/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>dongtai-api-gather</artifactId>
<groupId>io.dongtai.iast</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>dongtai-api-gather-dubbo-api</artifactId>

<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<!-- 不要修改这个依赖版本,如果必须改动需要保证在 [2.7.13, 3.0.0) 区间 -->
<version>2.7.21</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.12</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>io.dongtai.iast</groupId>
<artifactId>dongtai-api-gather-openapi</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.dongtai.iast</groupId>
<artifactId>dongtai-log</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package io.dongtai.iast.api.gather.dubbo.convertor;

import io.dongtai.iast.api.openapi.convertor.OpenApiSchemaConvertorManager;
import io.dongtai.iast.api.openapi.domain.MediaType;
import io.dongtai.iast.api.openapi.domain.Operation;
import io.dongtai.iast.api.openapi.domain.Parameter;
import io.dongtai.iast.api.openapi.domain.Response;
import io.dongtai.log.DongTaiLog;

import java.lang.reflect.Method;
import java.util.*;

/**
* 用于把Dubbo的Service的方法转为Open API的Operation结构
*
* @author CC11001100
* @since v1.12.0
*/
public class MethodConvertor {

private OpenApiSchemaConvertorManager manager;
private Method reflectionMethod;

/**
* @param manager
* @param reflectionMethod 要转换的Method,一个Method对应着一个Operation
*/
public MethodConvertor(OpenApiSchemaConvertorManager manager, Method reflectionMethod) {
this.manager = manager;
this.reflectionMethod = reflectionMethod;
}

public Operation convert() {
Operation o = new Operation();

try {
o.mergeParameters(this.parseParameters());
} catch (Throwable e) {
DongTaiLog.debug("MethodConvertor.convert parseParameters exception", e);
}

try {
o.setResponses(this.parseResponse());
} catch (Throwable e) {
DongTaiLog.debug("MethodConvertor.convert parseResponse exception", e);
}

// 设置这两个字段
o.setOperationId(UUID.randomUUID().toString());
// 把类名设置为标签
o.setTags(Collections.singletonList(reflectionMethod.getDeclaringClass().getName()));

return o;
}

/**
* 把Dubbo的Service的方法返回值转换为Open API的Response
*
* @return
*/
private Map<String, Response> parseResponse() {

Class<?> returnType = this.reflectionMethod.getReturnType();
// 这里需要注意,可能会有返回值为空的情况,这种情况就认为是没有响应值
if (Void.TYPE == returnType) {
return null;
}

// 把函数的返回值对应到HTTP的响应体上
Response r = new Response();
Map<String, MediaType> contentMap = new HashMap<>();
MediaType mediaType = new MediaType();
mediaType.setSchema(this.manager.convertClass(returnType));
contentMap.put(MediaType.APPLICATION_JSON, mediaType);
r.setContent(contentMap);

// 这里只处理正常返回的情况,认为是200的情况,至于throws抛出异常500的情况就不再处理了
Map<String, Response> responseMap = new HashMap<>();
r.setDescription(Response.MSG_OK);
responseMap.put(Response.CODE_OK, r);

return responseMap;
}

/**
* 解析Method上的参数为OpenAPI的Parameter
*
* @return
*/
private List<Parameter> parseParameters() {
java.lang.reflect.Parameter[] reflectionParameterArray = this.reflectionMethod.getParameters();
if (reflectionParameterArray == null || reflectionParameterArray.length == 0) {
return Collections.emptyList();
}
List<Parameter> parameterList = new ArrayList<>();
for (java.lang.reflect.Parameter reflectionParameter : reflectionParameterArray) {
try {
Parameter convert = new ParameterConvertor(this.manager, reflectionParameter).convert();
if (convert != null) {
parameterList.add(convert);
}
} catch (Throwable e) {
DongTaiLog.debug("MethodConvertor.parseParameters ParameterConvertor exception", e);
}
}
return parameterList;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package io.dongtai.iast.api.gather.dubbo.convertor;

import io.dongtai.iast.api.openapi.convertor.OpenApiSchemaConvertorManager;
import io.dongtai.iast.api.openapi.domain.Parameter;
import io.dongtai.iast.api.openapi.domain.ParameterIn;
import io.dongtai.iast.api.openapi.domain.Schema;

/**
* 方法参数级别的转换,把Dubbo的Service上的Method的Parameter转为Open API的Parameter的格式
*
* @author CC11001100
* @since v1.12.0
*/
public class ParameterConvertor {

private final OpenApiSchemaConvertorManager manager;
private final java.lang.reflect.Parameter reflectionParameter;

/**
* @param manager
* @param reflectionParameter 要转换的方法参数
*/
public ParameterConvertor(OpenApiSchemaConvertorManager manager, java.lang.reflect.Parameter reflectionParameter) {
this.manager = manager;
this.reflectionParameter = reflectionParameter;
}

public Parameter convert() {

Parameter openApiParameter = new Parameter();

// 2023-6-25 18:23:17 以后得空的时候也许可以把这里优化一下,用asm拿到真正的参数名字,这样前端页面上用户看着心情会好一些
openApiParameter.setName(reflectionParameter.getName());

// 洞态开发人员内部约定:dubbo的参数固定认为是放在query上的,同时是必传的
openApiParameter.setIn(ParameterIn.Query);
openApiParameter.setRequired(true);

// 参数的类型转为Open API的类型,如果有涉及到复合类型的话存储到Open API的组件库中
Schema schema = this.manager.convertClass(this.reflectionParameter.getType());
openApiParameter.setSchema(schema);

return openApiParameter;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package io.dongtai.iast.api.gather.dubbo.convertor;

import io.dongtai.iast.api.openapi.convertor.OpenApiSchemaConvertorManager;
import io.dongtai.iast.api.openapi.domain.Operation;
import io.dongtai.iast.api.openapi.domain.Path;
import io.dongtai.log.DongTaiLog;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;

/**
* 类级别的转换,将dubbo的Service接口转换为open api的格式
*
* @author CC11001100
* @since v1.12.0
*/
public class ServiceConvertor {

private OpenApiSchemaConvertorManager manager;
private Class interfaceClass;

public ServiceConvertor(OpenApiSchemaConvertorManager manager, Class interfaceClass) {
this.manager = manager;
this.interfaceClass = interfaceClass;
}

public Map<String, Path> convert() {
Map<String, Path> pathMap = new HashMap<>();
for (Method parseServiceMethod : this.parseServiceMethods()) {
try {
Operation convert = new MethodConvertor(this.manager, parseServiceMethod).convert();
Path path = new Path();
path.setDubbo(convert);
pathMap.put(this.buildSign(parseServiceMethod), path);
} catch (Throwable e) {
DongTaiLog.debug("ServiceConvertor.convert exception", e);
}
}
return pathMap;
}

/**
* 解析Service上提供的接口
*
* @return
*/
private List<Method> parseServiceMethods() {
List<Method> methodList = new ArrayList<>();
Set<String> distinctSet = new HashSet<>();
Queue<Class> needProcessClassQueue = new LinkedList<>();
needProcessClassQueue.add(this.interfaceClass);
while (!needProcessClassQueue.isEmpty()) {
Class poll = needProcessClassQueue.poll();

// 收集当前类上的方法
Method[] declaredMethods = poll.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
String s = this.buildSign(declaredMethod);
if (distinctSet.contains(s)) {
continue;
}
distinctSet.add(s);
methodList.add(declaredMethod);
}

// 收集父接口,以便等下处理父接口上的方法
needProcessClassQueue.addAll(Arrays.asList(poll.getInterfaces()));
}

return methodList;
}

/**
* 方法的签名需要统一,签名的格式与dubbo流量采集那里保持一致,在server端要靠这个作为path把它们关联到一起
*
* @param method
* @return Example: /app.iast.common.dubbo.vul.VulService/runtimeExec(java.lang.String,java.lang.StringBuilder,byte[])
*/
private String buildSign(Method method) {
StringBuilder sign = new StringBuilder();
sign.append("/").append(method.getDeclaringClass().getName()).append("/").append(method.getName()).append("(");
Parameter[] parameters = method.getParameters();
if (parameters != null && parameters.length != 0) {
for (int i = 0; i < parameters.length; i++) {
sign.append(parameters[i].getType().getCanonicalName());
if (i + 1 < parameters.length) {
sign.append(",");
}
}
}
return sign.append(")").toString();
}

}
Loading

0 comments on commit 5b31d4c

Please sign in to comment.