fix(测试跟踪): 缺陷平台请求转发添加白名单
This commit is contained in:
parent
c51cb6e5e0
commit
d0f95b5073
|
@ -21,7 +21,7 @@ public class SessionFilter implements WebFilter {
|
||||||
private static final String[] TO_SUB_SERVICE = new String[]{"/license", "/system", "/resource", "/sso/callback/logout", "/sso/callback/cas/logout"};
|
private static final String[] TO_SUB_SERVICE = new String[]{"/license", "/system", "/resource", "/sso/callback/logout", "/sso/callback/cas/logout"};
|
||||||
private static final String PERFORMANCE_DOWNLOAD_PREFIX = "/jmeter/";
|
private static final String PERFORMANCE_DOWNLOAD_PREFIX = "/jmeter/";
|
||||||
private static final String API_DOWNLOAD_PREFIX = "/api/jmeter/";
|
private static final String API_DOWNLOAD_PREFIX = "/api/jmeter/";
|
||||||
private static final String TRACK_IMAGE_PREFIX = "/resource/md/get/url";
|
private static final String TRACK_IMAGE_PREFIX = "/resource/md/get/path";
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private DiscoveryClient discoveryClient;
|
private DiscoveryClient discoveryClient;
|
||||||
|
|
|
@ -106,10 +106,10 @@ public interface IssuesPlatform {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get请求的代理
|
* Get请求的代理
|
||||||
* @param url
|
* @param path
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
ResponseEntity proxyForGet(String url, Class responseEntityClazz);
|
ResponseEntity proxyForGet(String path, Class responseEntityClazz);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同步MS缺陷附件到第三方平台
|
* 同步MS缺陷附件到第三方平台
|
||||||
|
|
2
pom.xml
2
pom.xml
|
@ -23,7 +23,7 @@
|
||||||
<spring-cloud.version>2021.0.5</spring-cloud.version>
|
<spring-cloud.version>2021.0.5</spring-cloud.version>
|
||||||
<spring-security.version>5.7.5</spring-security.version>
|
<spring-security.version>5.7.5</spring-security.version>
|
||||||
<dubbo.version>2.7.18</dubbo.version>
|
<dubbo.version>2.7.18</dubbo.version>
|
||||||
<platform-plugin-sdk.version>1.0.0</platform-plugin-sdk.version>
|
<platform-plugin-sdk.version>1.1.0</platform-plugin-sdk.version>
|
||||||
<flyway.version>7.15.0</flyway.version>
|
<flyway.version>7.15.0</flyway.version>
|
||||||
<shiro.version>1.10.1</shiro.version>
|
<shiro.version>1.10.1</shiro.version>
|
||||||
<mssql-jdbc.version>7.4.1.jre8</mssql-jdbc.version>
|
<mssql-jdbc.version>7.4.1.jre8</mssql-jdbc.version>
|
||||||
|
|
|
@ -15,9 +15,10 @@ public class IssueProxyResourceController {
|
||||||
@Resource
|
@Resource
|
||||||
IssueProxyResourceService issueProxyResourceService;
|
IssueProxyResourceService issueProxyResourceService;
|
||||||
|
|
||||||
@GetMapping(value = "/md/get/url")
|
@GetMapping(value = "/md/get/path")
|
||||||
public ResponseEntity<byte[]> getFileByUrl(@RequestParam ("url") String url, @RequestParam (value = "platform", required = false) String platform,
|
public ResponseEntity<byte[]> getFileByPath(@RequestParam ("path") String path,
|
||||||
@RequestParam (value = "workspace_id", required = false) String workspaceId) {
|
@RequestParam (value = "platform") String platform,
|
||||||
return issueProxyResourceService.getMdImageByUrl(url, platform, workspaceId);
|
@RequestParam (value = "workspaceId") String workspaceId) {
|
||||||
|
return issueProxyResourceService.getMdImageByPath(path, platform, workspaceId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,6 @@ import io.metersphere.xpack.track.dto.*;
|
||||||
import io.metersphere.xpack.track.dto.request.IssuesRequest;
|
import io.metersphere.xpack.track.dto.request.IssuesRequest;
|
||||||
import io.metersphere.xpack.track.dto.request.IssuesUpdateRequest;
|
import io.metersphere.xpack.track.dto.request.IssuesUpdateRequest;
|
||||||
import io.metersphere.xpack.track.issue.IssuesPlatform;
|
import io.metersphere.xpack.track.issue.IssuesPlatform;
|
||||||
import jodd.util.CollectionUtil;
|
|
||||||
import io.metersphere.xpack.track.service.XpackIssueService;
|
import io.metersphere.xpack.track.service.XpackIssueService;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.commons.collections.MapUtils;
|
import org.apache.commons.collections.MapUtils;
|
||||||
|
@ -697,8 +696,6 @@ public class IssuesService {
|
||||||
item.setCaseCount(caseIdSet.size());
|
item.setCaseCount(caseIdSet.size());
|
||||||
});
|
});
|
||||||
buildCustomField(issues);
|
buildCustomField(issues);
|
||||||
//处理MD图片链接内容
|
|
||||||
handleJiraIssueMdUrl(request.getWorkspaceId(), request.getProjectId(), issues);
|
|
||||||
return issues;
|
return issues;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -789,35 +786,6 @@ public class IssuesService {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleJiraIssueMdUrl(String workPlaceId, String projectId, List<IssuesDao> issues) {
|
|
||||||
issues.forEach(issue -> {
|
|
||||||
if (StringUtils.isNotEmpty(issue.getDescription()) && issue.getDescription().contains("platform=Jira&")) {
|
|
||||||
issue.setDescription(replaceJiraMdUrlParam(issue.getDescription(), workPlaceId, projectId));
|
|
||||||
}
|
|
||||||
if (StringUtils.isNotEmpty(issue.getCustomFields()) && issue.getCustomFields().contains("platform=Jira&")) {
|
|
||||||
issue.setCustomFields(replaceJiraMdUrlParam(issue.getCustomFields(), workPlaceId, projectId));
|
|
||||||
}
|
|
||||||
if (CollectionUtils.isNotEmpty(issue.getFields())) {
|
|
||||||
issue.getFields().forEach(field -> {
|
|
||||||
if (StringUtils.isNotEmpty(field.getTextValue()) && field.getTextValue().contains("platform=Jira&")) {
|
|
||||||
field.setTextValue(replaceJiraMdUrlParam(field.getTextValue(), workPlaceId, projectId));
|
|
||||||
}
|
|
||||||
if (StringUtils.isNotEmpty(field.getValue()) && field.getValue().contains("platform=Jira&")) {
|
|
||||||
field.setValue(replaceJiraMdUrlParam(field.getValue(), workPlaceId, projectId));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private String replaceJiraMdUrlParam(String url, String workspaceId, String projectId) {
|
|
||||||
if (url.contains("&workspace_id=")) {
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
return url.replaceAll("platform=Jira&",
|
|
||||||
"platform=Jira&workspace_id=" + workspaceId + "&");
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, List<IssueCommentDTO>> getCommentMap(List<IssuesDao> issues) {
|
private Map<String, List<IssueCommentDTO>> getCommentMap(List<IssuesDao> issues) {
|
||||||
List<String> issueIds = issues.stream().map(IssuesDao::getId).collect(Collectors.toList());
|
List<String> issueIds = issues.stream().map(IssuesDao::getId).collect(Collectors.toList());
|
||||||
List<IssueCommentDTO> comments = extIssueCommentMapper.getCommentsByIssueIds(issueIds);
|
List<IssueCommentDTO> comments = extIssueCommentMapper.getCommentsByIssueIds(issueIds);
|
||||||
|
|
|
@ -88,6 +88,7 @@ public class PlatformPluginService {
|
||||||
ServiceIntegration serviceIntegration = baseIntegrationService.get(integrationRequest);
|
ServiceIntegration serviceIntegration = baseIntegrationService.get(integrationRequest);
|
||||||
|
|
||||||
PlatformRequest pluginRequest = new PlatformRequest();
|
PlatformRequest pluginRequest = new PlatformRequest();
|
||||||
|
pluginRequest.setWorkspaceId(workspaceId);
|
||||||
pluginRequest.setIntegrationConfig(serviceIntegration.getConfiguration());
|
pluginRequest.setIntegrationConfig(serviceIntegration.getConfiguration());
|
||||||
Platform platform = getPluginManager().getPlatformByKey(platformKey, pluginRequest);
|
Platform platform = getPluginManager().getPlatformByKey(platformKey, pluginRequest);
|
||||||
if (platform == null) {
|
if (platform == null) {
|
||||||
|
|
|
@ -4,7 +4,6 @@ import io.metersphere.commons.exception.MSException;
|
||||||
import io.metersphere.commons.utils.JSON;
|
import io.metersphere.commons.utils.JSON;
|
||||||
import io.metersphere.commons.utils.LogUtil;
|
import io.metersphere.commons.utils.LogUtil;
|
||||||
import io.metersphere.commons.utils.UnicodeConvertUtils;
|
import io.metersphere.commons.utils.UnicodeConvertUtils;
|
||||||
import io.metersphere.i18n.Translator;
|
|
||||||
import io.metersphere.service.issue.domain.zentao.*;
|
import io.metersphere.service.issue.domain.zentao.*;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.core.io.FileSystemResource;
|
import org.springframework.core.io.FileSystemResource;
|
||||||
|
@ -13,6 +12,8 @@ import org.springframework.util.LinkedMultiValueMap;
|
||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public abstract class ZentaoClient extends BaseClient {
|
public abstract class ZentaoClient extends BaseClient {
|
||||||
|
@ -244,4 +245,19 @@ public abstract class ZentaoClient extends BaseClient {
|
||||||
null, byte[].class, fileId, sessionId);
|
null, byte[].class, fileId, sessionId);
|
||||||
return response.getBody();
|
return response.getBody();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ResponseEntity proxyForGet(String path, Class responseEntityClazz) {
|
||||||
|
im.metersphere.plugin.utils.LogUtil.info("zentao proxyForGet: " + path);
|
||||||
|
String url = this.ENDPOINT + path;
|
||||||
|
try {
|
||||||
|
if (!StringUtils.containsAny(new URI(url).getPath(), "/index.php", "/file-read-")) {
|
||||||
|
// 只允许访问图片
|
||||||
|
MSException.throwException("illegal path");
|
||||||
|
}
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
LogUtil.error(e);
|
||||||
|
MSException.throwException("illegal path");
|
||||||
|
}
|
||||||
|
return restTemplate.exchange(url, HttpMethod.GET, null, responseEntityClazz);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ import io.metersphere.base.mapper.IssuesMapper;
|
||||||
import io.metersphere.base.mapper.TestCaseIssuesMapper;
|
import io.metersphere.base.mapper.TestCaseIssuesMapper;
|
||||||
import io.metersphere.base.mapper.ext.ExtIssuesMapper;
|
import io.metersphere.base.mapper.ext.ExtIssuesMapper;
|
||||||
import io.metersphere.commons.constants.CustomFieldType;
|
import io.metersphere.commons.constants.CustomFieldType;
|
||||||
import io.metersphere.commons.constants.IssueRefType;
|
|
||||||
import io.metersphere.commons.constants.IssuesStatus;
|
import io.metersphere.commons.constants.IssuesStatus;
|
||||||
import io.metersphere.commons.exception.MSException;
|
import io.metersphere.commons.exception.MSException;
|
||||||
import io.metersphere.commons.utils.*;
|
import io.metersphere.commons.utils.*;
|
||||||
|
@ -32,6 +31,7 @@ import org.springframework.util.MultiValueMap;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
|
import java.net.URLEncoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
@ -65,6 +65,8 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform {
|
||||||
protected AttachmentModuleRelationMapper attachmentModuleRelationMapper;
|
protected AttachmentModuleRelationMapper attachmentModuleRelationMapper;
|
||||||
protected BaseProjectService baseProjectService;
|
protected BaseProjectService baseProjectService;
|
||||||
|
|
||||||
|
public static final String PROXY_PATH = "/resource/md/get/path?platform=%s&workspaceId=%s&path=%s";
|
||||||
|
|
||||||
public String getKey() {
|
public String getKey() {
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
@ -114,6 +116,10 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform {
|
||||||
return integration.getConfiguration();
|
return integration.getConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected String getProxyPath(String path) {
|
||||||
|
return String.format(PROXY_PATH, this.key, this.workspaceId, URLEncoder.encode(path, StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
protected HttpHeaders auth(String apiUser, String password) {
|
protected HttpHeaders auth(String apiUser, String password) {
|
||||||
String authKey = EncryptUtils.base64Encoding(apiUser + ":" + password);
|
String authKey = EncryptUtils.base64Encoding(apiUser + ":" + password);
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
@ -333,7 +339,7 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform {
|
||||||
while (matcher.find()) {
|
while (matcher.find()) {
|
||||||
try {
|
try {
|
||||||
String path = matcher.group(2);
|
String path = matcher.group(2);
|
||||||
if (!path.contains("/resource/md/get/url")) {
|
if (!path.contains("/resource/md/get/url") && !path.contains("/resource/md/get/path")) {
|
||||||
if (path.contains("/resource/md/get/")) { // 兼容旧数据
|
if (path.contains("/resource/md/get/")) { // 兼容旧数据
|
||||||
String name = path.substring(path.indexOf("/resource/md/get/") + 17);
|
String name = path.substring(path.indexOf("/resource/md/get/") + 17);
|
||||||
files.add(new File(FileUtils.MD_IMAGE_DIR + "/" + name));
|
files.add(new File(FileUtils.MD_IMAGE_DIR + "/" + name));
|
||||||
|
|
|
@ -492,7 +492,7 @@ public class ZentaoPlatform extends AbstractIssuePlatform {
|
||||||
while (matcher.find()) {
|
while (matcher.find()) {
|
||||||
// get file name
|
// get file name
|
||||||
String originSubUrl = matcher.group(1);
|
String originSubUrl = matcher.group(1);
|
||||||
if (originSubUrl.contains("/url?url=")) {
|
if (originSubUrl.contains("/url?url=") || originSubUrl.contains("/path?")) {
|
||||||
String path = URLDecoder.decode(originSubUrl, StandardCharsets.UTF_8);
|
String path = URLDecoder.decode(originSubUrl, StandardCharsets.UTF_8);
|
||||||
String fileName;
|
String fileName;
|
||||||
if (path.indexOf("fileID") > 0) {
|
if (path.indexOf("fileID") > 0) {
|
||||||
|
@ -565,15 +565,17 @@ public class ZentaoPlatform extends AbstractIssuePlatform {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
name = name.replaceAll("&", "&");
|
name = name.replaceAll("&", "&");
|
||||||
try {
|
path = path.replaceAll("&", "&");
|
||||||
URI uri = new URI(zentaoClient.getBaseUrl());
|
}
|
||||||
path = uri.getScheme() + "://" + uri.getHost() + path.replaceAll("&", "&");
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
} catch (URISyntaxException e) {
|
for (String item : path.split("&")) {
|
||||||
path = zentaoClient.getBaseUrl() + path.replaceAll("&", "&");
|
// 去掉多余的参数
|
||||||
LogUtil.error(e);
|
if (!StringUtils.containsAny(item, "platform", "workspaceId")) {
|
||||||
|
stringBuilder.append(item);
|
||||||
|
stringBuilder.append("&");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
path = "/resource/md/get/url?url=" + URLEncoder.encode(path, StandardCharsets.UTF_8);
|
path = getProxyPath(stringBuilder.toString());
|
||||||
}
|
}
|
||||||
// 图片与描述信息之间需换行,否则无法预览图片
|
// 图片与描述信息之间需换行,否则无法预览图片
|
||||||
result = "\n\n![" + name + "](" + path + ")";
|
result = "\n\n![" + name + "](" + path + ")";
|
||||||
|
@ -682,4 +684,9 @@ public class ZentaoPlatform extends AbstractIssuePlatform {
|
||||||
}
|
}
|
||||||
return platformStatusDTOS;
|
return platformStatusDTOS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity proxyForGet(String path, Class responseEntityClazz) {
|
||||||
|
return zentaoClient.proxyForGet(path, responseEntityClazz);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package io.metersphere.service.wapper;
|
package io.metersphere.service.wapper;
|
||||||
|
|
||||||
import io.metersphere.commons.exception.MSException;
|
import io.metersphere.commons.constants.IssuesManagePlatform;
|
||||||
import io.metersphere.i18n.Translator;
|
|
||||||
import io.metersphere.service.PlatformPluginService;
|
import io.metersphere.service.PlatformPluginService;
|
||||||
|
import io.metersphere.service.issue.platform.IssueFactory;
|
||||||
|
import io.metersphere.xpack.track.dto.request.IssuesRequest;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.http.HttpMethod;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
@ -25,19 +25,20 @@ public class IssueProxyResourceService {
|
||||||
* http 代理
|
* http 代理
|
||||||
* 如果当前访问地址是 https,直接访问 http 的图片资源
|
* 如果当前访问地址是 https,直接访问 http 的图片资源
|
||||||
* 由于浏览器的安全机制,http 会被转成 https
|
* 由于浏览器的安全机制,http 会被转成 https
|
||||||
* @param url
|
* @param path
|
||||||
* @param platform
|
* @param platform
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public ResponseEntity<byte[]> getMdImageByUrl(String url, String platform, String workspaceId) {
|
public ResponseEntity<byte[]> getMdImageByPath(String path, String platform, String workspaceId) {
|
||||||
if (url.contains("md/get/url")) {
|
if (StringUtils.equals(IssuesManagePlatform.Zentao.name(), platform)) {
|
||||||
MSException.throwException(Translator.get("invalid_parameter"));
|
IssuesRequest issuesRequest = new IssuesRequest();
|
||||||
}
|
issuesRequest.setWorkspaceId(workspaceId);
|
||||||
if (StringUtils.isNotBlank(platform)) {
|
return IssueFactory.createPlatform(platform, issuesRequest)
|
||||||
return platformPluginService.getPlatform(platform, workspaceId)
|
.proxyForGet(path, byte[].class);
|
||||||
.proxyForGet(url, byte[].class);
|
|
||||||
|
|
||||||
}
|
} else {
|
||||||
return restTemplate.exchange(url, HttpMethod.GET, null, byte[].class);
|
return platformPluginService.getPlatform(platform, workspaceId)
|
||||||
|
.proxyForGet(path, byte[].class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue