Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
e7f4f3fedd
|
@ -322,8 +322,8 @@ public class MsTCPSampler extends MsTestElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
private String formatMockValue(String value) {
|
private String formatMockValue(String value) {
|
||||||
String patten = ">@[^>@]+</?";
|
String pattern = ">@[^>@]+</?";
|
||||||
Pattern r = Pattern.compile(patten);
|
Pattern r = Pattern.compile(pattern);
|
||||||
try {
|
try {
|
||||||
Matcher m = r.matcher(value);
|
Matcher m = r.matcher(value);
|
||||||
while (m.find()) {
|
while (m.find()) {
|
||||||
|
|
|
@ -59,7 +59,7 @@ public class ResourcePoolCalculation {
|
||||||
NodeDTO node = JSON.parseObject(configuration, NodeDTO.class);
|
NodeDTO node = JSON.parseObject(configuration, NodeDTO.class);
|
||||||
String nodeIp = node.getIp();
|
String nodeIp = node.getIp();
|
||||||
Integer port = node.getPort();
|
Integer port = node.getPort();
|
||||||
String uri = String.format(BASE_URL + "/jmeter/getJvmInfo", nodeIp, port);
|
String uri = String.format(BASE_URL + "/jmeter/get-jvm-info", nodeIp, port);
|
||||||
JvmInfoDTO nodeJvm = this.getNodeJvmInfo(uri);
|
JvmInfoDTO nodeJvm = this.getNodeJvmInfo(uri);
|
||||||
if (nodeJvm == null) {
|
if (nodeJvm == null) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -30,7 +30,7 @@ public interface ExtApiScenarioMapper {
|
||||||
|
|
||||||
int selectTrash(@Param("projectId") String projectId);
|
int selectTrash(@Param("projectId") String projectId);
|
||||||
|
|
||||||
List<ApiScenarioWithBLOBs> selectByIds(@Param("ids") String ids, @Param("oderId") String oderId);
|
List<ApiScenarioWithBLOBs> selectByIds(@Param("ids") String ids, @Param("order") String order);
|
||||||
|
|
||||||
List<ApiScenario> selectReference(@Param("request") ApiScenarioRequest request);
|
List<ApiScenario> selectReference(@Param("request") ApiScenarioRequest request);
|
||||||
|
|
||||||
|
|
|
@ -442,7 +442,7 @@
|
||||||
select *
|
select *
|
||||||
from api_scenario
|
from api_scenario
|
||||||
where id in (${ids})
|
where id in (${ids})
|
||||||
ORDER BY FIND_IN_SET(id, ${oderId})
|
ORDER BY FIND_IN_SET(id, ${order})
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectReference" resultType="io.metersphere.base.domain.ApiScenario">
|
<select id="selectReference" resultType="io.metersphere.base.domain.ApiScenario">
|
||||||
|
|
|
@ -6,7 +6,7 @@ import org.apache.ibatis.annotations.Param;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface ExtApiScenarioReportDetailMapper {
|
public interface ExtApiScenarioReportDetailMapper {
|
||||||
List<ApiScenarioReportDetail> selectByIds(@Param("ids") String ids, @Param("oderId") String oderId);
|
List<ApiScenarioReportDetail> selectByIds(@Param("ids") String ids, @Param("order") String order);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,6 @@
|
||||||
where ad.report_id in (select ar.id from api_scenario_report ar where ar.project_id = #{projectId,jdbcType=VARCHAR} )
|
where ad.report_id in (select ar.id from api_scenario_report ar where ar.project_id = #{projectId,jdbcType=VARCHAR} )
|
||||||
</delete>
|
</delete>
|
||||||
<select id="selectByIds" resultType="io.metersphere.base.domain.ApiScenarioReportDetail">
|
<select id="selectByIds" resultType="io.metersphere.base.domain.ApiScenarioReportDetail">
|
||||||
select t.* from api_scenario_report_detail t where t.report_id in (${ids}) ORDER BY FIND_IN_SET(t.report_id,${oderId})
|
select t.* from api_scenario_report_detail t where t.report_id in (${ids}) ORDER BY FIND_IN_SET(t.report_id,${order})
|
||||||
</select>
|
</select>
|
||||||
</mapper>
|
</mapper>
|
|
@ -25,7 +25,7 @@ public interface ExtTestPlanScenarioCaseMapper {
|
||||||
|
|
||||||
List<String> selectIds(@Param("request")TestPlanScenarioRequest request);
|
List<String> selectIds(@Param("request")TestPlanScenarioRequest request);
|
||||||
|
|
||||||
List<TestPlanApiScenario> selectByIds(@Param("ids")String ids ,@Param("oderId")String oderId );
|
List<TestPlanApiScenario> selectByIds(@Param("ids")String ids ,@Param("order")String order );
|
||||||
|
|
||||||
List<TestPlanApiScenarioInfoDTO> selectLegalDataByTestPlanId(String planId);
|
List<TestPlanApiScenarioInfoDTO> selectLegalDataByTestPlanId(String planId);
|
||||||
|
|
||||||
|
|
|
@ -136,7 +136,7 @@
|
||||||
select t.*
|
select t.*
|
||||||
from test_plan_api_scenario t
|
from test_plan_api_scenario t
|
||||||
where t.id in (${ids})
|
where t.id in (${ids})
|
||||||
ORDER BY FIND_IN_SET(t.id, ${oderId})
|
ORDER BY FIND_IN_SET(t.id, ${order})
|
||||||
</select>
|
</select>
|
||||||
<select id="selectIds" resultType="java.lang.String">
|
<select id="selectIds" resultType="java.lang.String">
|
||||||
select
|
select
|
||||||
|
|
|
@ -1880,7 +1880,7 @@ export default {
|
||||||
apiImport(importData) {
|
apiImport(importData) {
|
||||||
if (importData && importData.data) {
|
if (importData && importData.data) {
|
||||||
importData.data.forEach(item => {
|
importData.data.forEach(item => {
|
||||||
this.setApiParameter(item, "API", "OT_IMPORT");
|
this.setApiParameter(item, "API", "TO_IMPORT");
|
||||||
})
|
})
|
||||||
this.sort();
|
this.sort();
|
||||||
this.reload();
|
this.reload();
|
||||||
|
|
|
@ -20,7 +20,7 @@ export function STEP() {
|
||||||
['DubboSampler', getDefaultSamplerMenu()],
|
['DubboSampler', getDefaultSamplerMenu()],
|
||||||
['JDBCSampler', getDefaultSamplerMenu()],
|
['JDBCSampler', getDefaultSamplerMenu()],
|
||||||
['TCPSampler', getDefaultSamplerMenu()],
|
['TCPSampler', getDefaultSamplerMenu()],
|
||||||
['OT_IMPORT', getDefaultSamplerMenu()],
|
['TO_IMPORT', getDefaultSamplerMenu()],
|
||||||
['AbstractSampler', getDefaultSamplerMenu()],
|
['AbstractSampler', getDefaultSamplerMenu()],
|
||||||
['IfController', getAll()],
|
['IfController', getAll()],
|
||||||
['TransactionController', getAll()],
|
['TransactionController', getAll()],
|
||||||
|
@ -48,7 +48,7 @@ export function STEP() {
|
||||||
export const ELEMENT_TYPE = {
|
export const ELEMENT_TYPE = {
|
||||||
scenario: 'scenario',
|
scenario: 'scenario',
|
||||||
HTTPSamplerProxy: 'HTTPSamplerProxy',
|
HTTPSamplerProxy: 'HTTPSamplerProxy',
|
||||||
OT_IMPORT: 'OT_IMPORT',
|
TO_IMPORT: 'TO_IMPORT',
|
||||||
IfController: 'IfController',
|
IfController: 'IfController',
|
||||||
TransactionController: 'TransactionController',
|
TransactionController: 'TransactionController',
|
||||||
ConstantTimer: 'ConstantTimer',
|
ConstantTimer: 'ConstantTimer',
|
||||||
|
|
|
@ -339,7 +339,7 @@ export default {
|
||||||
return (this.request.referenced && verifies.indexOf(this.request.referenced) !== -1);
|
return (this.request.referenced && verifies.indexOf(this.request.referenced) !== -1);
|
||||||
},
|
},
|
||||||
isExternalImport() {
|
isExternalImport() {
|
||||||
return (this.request.referenced && this.request.referenced === 'OT_IMPORT');
|
return (this.request.referenced && this.request.referenced === 'TO_IMPORT');
|
||||||
},
|
},
|
||||||
isCustomizeReq() {
|
isCustomizeReq() {
|
||||||
return (!this.request.referenced || this.request.referenced === 'Created');
|
return (!this.request.referenced || this.request.referenced === 'Created');
|
||||||
|
@ -712,12 +712,6 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.ms-api-col-ot-import-button {
|
|
||||||
background-color: #EEF5FE;
|
|
||||||
margin-right: 20px;
|
|
||||||
color: #409EFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon.is-active {
|
.icon.is-active {
|
||||||
transform: rotate(90deg);
|
transform: rotate(90deg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -226,7 +226,7 @@ export default {
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
isExternalImport() {
|
isExternalImport() {
|
||||||
if (this.request.referenced && this.request.referenced === 'OT_IMPORT') {
|
if (this.request.referenced && this.request.referenced === 'TO_IMPORT') {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -899,7 +899,7 @@ export default {
|
||||||
apiImport(importData) {
|
apiImport(importData) {
|
||||||
if (importData && importData.data) {
|
if (importData && importData.data) {
|
||||||
importData.data.forEach(item => {
|
importData.data.forEach(item => {
|
||||||
this.setApiParameter(item, "API", "OT_IMPORT");
|
this.setApiParameter(item, "API", "TO_IMPORT");
|
||||||
})
|
})
|
||||||
this.sort();
|
this.sort();
|
||||||
this.reload();
|
this.reload();
|
||||||
|
|
|
@ -22,11 +22,11 @@ export class Environment extends BaseConfig {
|
||||||
export class SSLConfig extends BaseConfig {
|
export class SSLConfig extends BaseConfig {
|
||||||
constructor(options = {}) {
|
constructor(options = {}) {
|
||||||
super();
|
super();
|
||||||
this.entrys = [];
|
this.entry = [];
|
||||||
this.files = [];
|
this.files = [];
|
||||||
this.set(options);
|
this.set(options);
|
||||||
this.sets({files: KeyValue}, options);
|
this.sets({files: KeyValue}, options);
|
||||||
this.sets({entrys: KeyValue}, options);
|
this.sets({entry: KeyValue}, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
initOptions(options = {}) {
|
initOptions(options = {}) {
|
||||||
|
|
|
@ -85,7 +85,7 @@
|
||||||
<el-header style="height:20px;padding: 0px;margin-bottom: 5px;font-size: 14px">
|
<el-header style="height:20px;padding: 0px;margin-bottom: 5px;font-size: 14px">
|
||||||
<el-row>
|
<el-row>
|
||||||
<span style="float: left">
|
<span style="float: left">
|
||||||
{{ $t('api_test.home_page.detail_card.rate.case_pase') + ":" }}
|
{{ $t('home.table.case_pass') + ":" }}
|
||||||
</span>
|
</span>
|
||||||
<span class="rows-count-number" style="font-size: 14px">
|
<span class="rows-count-number" style="font-size: 14px">
|
||||||
<b>
|
<b>
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
<el-header style="height:20px;padding: 0px;margin-bottom: 5px;font-size: 14px">
|
<el-header style="height:20px;padding: 0px;margin-bottom: 5px;font-size: 14px">
|
||||||
<el-row>
|
<el-row>
|
||||||
<span style="float: left">
|
<span style="float: left">
|
||||||
{{ $t('api_test.home_page.detail_card.rate.scenario_pase') + ":" }}
|
{{ $t('home.table.scenario_pass') + ":" }}
|
||||||
</span>
|
</span>
|
||||||
<span class="rows-count-number" style="font-size: 14px">
|
<span class="rows-count-number" style="font-size: 14px">
|
||||||
<b>
|
<b>
|
||||||
|
|
|
@ -29,6 +29,8 @@ const message = {
|
||||||
next_execution_time: "Next Execution Time",
|
next_execution_time: "Next Execution Time",
|
||||||
create_user: "Creator",
|
create_user: "Creator",
|
||||||
update_time: "Update time",
|
update_time: "Update time",
|
||||||
|
case_pass: "Case pass rate",
|
||||||
|
scenario_pass: "Scenario pass rate",
|
||||||
},
|
},
|
||||||
case: {
|
case: {
|
||||||
index: "Ranking",
|
index: "Ranking",
|
||||||
|
|
|
@ -29,6 +29,8 @@ const message = {
|
||||||
next_execution_time: "下次执行时间",
|
next_execution_time: "下次执行时间",
|
||||||
create_user: "创建人",
|
create_user: "创建人",
|
||||||
update_time: "更新时间",
|
update_time: "更新时间",
|
||||||
|
case_pass: "用例通过率",
|
||||||
|
scenario_pass: "场景通过率",
|
||||||
},
|
},
|
||||||
case: {
|
case: {
|
||||||
index: "排名",
|
index: "排名",
|
||||||
|
|
|
@ -29,6 +29,8 @@ const message = {
|
||||||
next_execution_time: "下次執行時間",
|
next_execution_time: "下次執行時間",
|
||||||
create_user: "創建人",
|
create_user: "創建人",
|
||||||
update_time: "更新時間",
|
update_time: "更新時間",
|
||||||
|
case_pass: "用例通過率",
|
||||||
|
scenario_pass: "場景通過率",
|
||||||
},
|
},
|
||||||
case: {
|
case: {
|
||||||
index: "排名",
|
index: "排名",
|
||||||
|
|
|
@ -46,10 +46,12 @@ public class LoginController {
|
||||||
private ReactiveRedisSessionRepository reactiveRedisSessionRepository;
|
private ReactiveRedisSessionRepository reactiveRedisSessionRepository;
|
||||||
|
|
||||||
@GetMapping(value = "/is-login")
|
@GetMapping(value = "/is-login")
|
||||||
public Mono<ResultHolder> isLogin(@RequestHeader(name = SessionConstants.HEADER_TOKEN, required = false) String sessionId) throws Exception {
|
public Mono<ResultHolder> isLogin(@RequestHeader(name = SessionConstants.HEADER_TOKEN, required = false) String sessionId,
|
||||||
|
@RequestHeader(name = SessionConstants.CSRF_TOKEN, required = false) String csrfToken) throws Exception {
|
||||||
RsaKey rsaKey = RsaUtil.getRsaKey();
|
RsaKey rsaKey = RsaUtil.getRsaKey();
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(sessionId)) {
|
if (StringUtils.isNotBlank(sessionId) && StringUtils.isNotBlank(csrfToken)) {
|
||||||
|
userLoginService.validateCsrfToken(sessionId, csrfToken);
|
||||||
return reactiveRedisSessionRepository.getSessionRedisOperations().opsForHash().get("spring:session:sessions:" + sessionId, "sessionAttr:user")
|
return reactiveRedisSessionRepository.getSessionRedisOperations().opsForHash().get("spring:session:sessions:" + sessionId, "sessionAttr:user")
|
||||||
.switchIfEmpty(Mono.just(rsaKey))
|
.switchIfEmpty(Mono.just(rsaKey))
|
||||||
.map(r -> {
|
.map(r -> {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package io.metersphere.gateway.controller;
|
||||||
|
|
||||||
import io.metersphere.commons.constants.OperLogConstants;
|
import io.metersphere.commons.constants.OperLogConstants;
|
||||||
import io.metersphere.commons.constants.OperLogModule;
|
import io.metersphere.commons.constants.OperLogModule;
|
||||||
|
import io.metersphere.commons.user.SessionUser;
|
||||||
import io.metersphere.commons.utils.CodingUtil;
|
import io.metersphere.commons.utils.CodingUtil;
|
||||||
import io.metersphere.gateway.service.SSOService;
|
import io.metersphere.gateway.service.SSOService;
|
||||||
import io.metersphere.log.annotation.MsAuditLog;
|
import io.metersphere.log.annotation.MsAuditLog;
|
||||||
|
@ -13,6 +14,7 @@ import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@RequestMapping("sso")
|
@RequestMapping("sso")
|
||||||
|
@ -23,24 +25,24 @@ public class SSOController {
|
||||||
@GetMapping("callback/{authId}")
|
@GetMapping("callback/{authId}")
|
||||||
@MsAuditLog(module = OperLogModule.AUTH_TITLE, type = OperLogConstants.LOGIN, title = "登录")
|
@MsAuditLog(module = OperLogModule.AUTH_TITLE, type = OperLogConstants.LOGIN, title = "登录")
|
||||||
public Rendering callbackWithAuthId(@RequestParam("code") String code, @PathVariable("authId") String authId, WebSession session, Locale locale) throws Exception {
|
public Rendering callbackWithAuthId(@RequestParam("code") String code, @PathVariable("authId") String authId, WebSession session, Locale locale) throws Exception {
|
||||||
ssoService.exchangeToken(code, authId, session, locale);
|
Optional<SessionUser> sessionUser = ssoService.exchangeToken(code, authId, session, locale);
|
||||||
return Rendering.redirectTo("/#/?_token=" + CodingUtil.base64Encoding(session.getId()))
|
return Rendering.redirectTo("/#/?_token=" + CodingUtil.base64Encoding(session.getId()) + "&_csrf=" + sessionUser.get().getCsrfToken())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("callback")
|
@GetMapping("callback")
|
||||||
@MsAuditLog(module = OperLogModule.AUTH_TITLE, type = OperLogConstants.LOGIN, title = "登录")
|
@MsAuditLog(module = OperLogModule.AUTH_TITLE, type = OperLogConstants.LOGIN, title = "登录")
|
||||||
public Rendering callback(@RequestParam("code") String code, @RequestParam("state") String authId, WebSession session, Locale locale) throws Exception {
|
public Rendering callback(@RequestParam("code") String code, @RequestParam("state") String authId, WebSession session, Locale locale) throws Exception {
|
||||||
ssoService.exchangeToken(code, authId, session, locale);
|
Optional<SessionUser> sessionUser = ssoService.exchangeToken(code, authId, session, locale);
|
||||||
return Rendering.redirectTo("/#/?_token=" + CodingUtil.base64Encoding(session.getId()))
|
return Rendering.redirectTo("/#/?_token=" + CodingUtil.base64Encoding(session.getId()) + "&_csrf=" + sessionUser.get().getCsrfToken())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/callback/cas/{authId}")
|
@GetMapping("/callback/cas/{authId}")
|
||||||
@MsAuditLog(module = OperLogModule.AUTH_TITLE, type = OperLogConstants.LOGIN, title = "登录")
|
@MsAuditLog(module = OperLogModule.AUTH_TITLE, type = OperLogConstants.LOGIN, title = "登录")
|
||||||
public Rendering casCallback(@RequestParam("ticket") String ticket, @PathVariable("authId") String authId, WebSession session, Locale locale) throws Exception {
|
public Rendering casCallback(@RequestParam("ticket") String ticket, @PathVariable("authId") String authId, WebSession session, Locale locale) throws Exception {
|
||||||
ssoService.serviceValidate(ticket, authId, session, locale);
|
Optional<SessionUser> sessionUser = ssoService.serviceValidate(ticket, authId, session, locale);
|
||||||
return Rendering.redirectTo("/#/?_token=" + CodingUtil.base64Encoding(session.getId()))
|
return Rendering.redirectTo("/#/?_token=" + CodingUtil.base64Encoding(session.getId()) + "&_csrf=" + sessionUser.get().getCsrfToken())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ package io.metersphere.gateway.service;
|
||||||
|
|
||||||
import io.metersphere.base.domain.AuthSource;
|
import io.metersphere.base.domain.AuthSource;
|
||||||
import io.metersphere.base.domain.User;
|
import io.metersphere.base.domain.User;
|
||||||
import io.metersphere.commons.constants.UserSource;
|
|
||||||
import io.metersphere.commons.exception.MSException;
|
import io.metersphere.commons.exception.MSException;
|
||||||
import io.metersphere.commons.user.SessionUser;
|
import io.metersphere.commons.user.SessionUser;
|
||||||
import io.metersphere.commons.utils.CodingUtil;
|
import io.metersphere.commons.utils.CodingUtil;
|
||||||
|
@ -61,7 +60,7 @@ public class SSOService {
|
||||||
@Resource
|
@Resource
|
||||||
private UserLoginService userLoginService;
|
private UserLoginService userLoginService;
|
||||||
|
|
||||||
public void exchangeToken(String code, String authId, WebSession session, Locale locale) throws Exception {
|
public Optional<SessionUser> exchangeToken(String code, String authId, WebSession session, Locale locale) throws Exception {
|
||||||
AuthSource authSource = authSourceService.getAuthSource(authId);
|
AuthSource authSource = authSourceService.getAuthSource(authId);
|
||||||
Map config = JSON.parseObject(authSource.getConfiguration(), Map.class);
|
Map config = JSON.parseObject(authSource.getConfiguration(), Map.class);
|
||||||
String tokenUrl = (String) config.get("tokenUrl");
|
String tokenUrl = (String) config.get("tokenUrl");
|
||||||
|
@ -92,7 +91,7 @@ public class SSOService {
|
||||||
MSException.throwException(content);
|
MSException.throwException(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
doOICDLogin(authSource, accessToken, session, locale);
|
return doOICDLogin(authSource, accessToken, session, locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
private RestTemplate getRestTemplateIgnoreSSL() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException {
|
private RestTemplate getRestTemplateIgnoreSSL() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException {
|
||||||
|
@ -118,7 +117,7 @@ public class SSOService {
|
||||||
return new RestTemplate(requestFactory);
|
return new RestTemplate(requestFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doOICDLogin(AuthSource authSource, String accessToken, WebSession session, Locale locale) throws Exception {
|
private Optional<SessionUser> doOICDLogin(AuthSource authSource, String accessToken, WebSession session, Locale locale) throws Exception {
|
||||||
Map config = JSON.parseObject(authSource.getConfiguration(), Map.class);
|
Map config = JSON.parseObject(authSource.getConfiguration(), Map.class);
|
||||||
String userInfoUrl = (String) config.get("userInfoUrl");
|
String userInfoUrl = (String) config.get("userInfoUrl");
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
@ -157,12 +156,13 @@ public class SSOService {
|
||||||
session.getAttributes().put("authenticate", authSource.getType());
|
session.getAttributes().put("authenticate", authSource.getType());
|
||||||
session.getAttributes().put("authId", authSource.getId());
|
session.getAttributes().put("authId", authSource.getId());
|
||||||
session.getAttributes().put("user", userOptional.get());
|
session.getAttributes().put("user", userOptional.get());
|
||||||
|
return userOptional;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cas callback
|
* cas callback
|
||||||
*/
|
*/
|
||||||
public void serviceValidate(String ticket, String authId, WebSession session, Locale locale) throws Exception {
|
public Optional<SessionUser> serviceValidate(String ticket, String authId, WebSession session, Locale locale) throws Exception {
|
||||||
AuthSource authSource = authSourceService.getAuthSource(authId);
|
AuthSource authSource = authSourceService.getAuthSource(authId);
|
||||||
Map config = JSON.parseObject(authSource.getConfiguration(), Map.class);
|
Map config = JSON.parseObject(authSource.getConfiguration(), Map.class);
|
||||||
String redirectUrl = ((String) config.get("redirectUrl")).replace("${authId}", authId);
|
String redirectUrl = ((String) config.get("redirectUrl")).replace("${authId}", authId);
|
||||||
|
@ -196,9 +196,12 @@ public class SSOService {
|
||||||
session.getAttributes().put("authenticate", authSource.getType());
|
session.getAttributes().put("authenticate", authSource.getType());
|
||||||
session.getAttributes().put("authId", authSource.getId());
|
session.getAttributes().put("authId", authSource.getId());
|
||||||
session.getAttributes().put("user", userOptional.get());
|
session.getAttributes().put("user", userOptional.get());
|
||||||
|
session.getAttributes().put("casTicket", ticket);
|
||||||
// 记录cas对应关系
|
// 记录cas对应关系
|
||||||
Long timeout = env.getProperty("spring.session.timeout", Long.class);
|
Long timeout = env.getProperty("spring.session.timeout", Long.class);
|
||||||
stringRedisTemplate.opsForValue().set(ticket, name, timeout, TimeUnit.SECONDS);
|
stringRedisTemplate.opsForValue().set(ticket, name, timeout, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
return userOptional;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void kickOutUser(String logoutToken) {
|
public void kickOutUser(String logoutToken) {
|
||||||
|
|
|
@ -8,7 +8,6 @@ import io.metersphere.commons.constants.UserStatus;
|
||||||
import io.metersphere.commons.exception.MSException;
|
import io.metersphere.commons.exception.MSException;
|
||||||
import io.metersphere.commons.user.SessionUser;
|
import io.metersphere.commons.user.SessionUser;
|
||||||
import io.metersphere.commons.utils.CodingUtil;
|
import io.metersphere.commons.utils.CodingUtil;
|
||||||
import io.metersphere.commons.utils.SessionUtils;
|
|
||||||
import io.metersphere.dto.GroupResourceDTO;
|
import io.metersphere.dto.GroupResourceDTO;
|
||||||
import io.metersphere.dto.UserDTO;
|
import io.metersphere.dto.UserDTO;
|
||||||
import io.metersphere.dto.UserGroupPermissionDTO;
|
import io.metersphere.dto.UserGroupPermissionDTO;
|
||||||
|
@ -18,6 +17,7 @@ import org.apache.commons.collections4.CollectionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.context.i18n.LocaleContextHolder;
|
import org.springframework.context.i18n.LocaleContextHolder;
|
||||||
|
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.server.WebSession;
|
import org.springframework.web.server.WebSession;
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ public class UserLoginService {
|
||||||
userDTO = loginLocalMode(request.getUsername(), request.getPassword());
|
userDTO = loginLocalMode(request.getUsername(), request.getPassword());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
autoSwitch(userDTO);
|
autoSwitch(session, userDTO);
|
||||||
return Optional.of(SessionUser.fromUser(userDTO, session.getId()));
|
return Optional.of(SessionUser.fromUser(userDTO, session.getId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ public class UserLoginService {
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void autoSwitch(UserDTO user) {
|
public void autoSwitch(WebSession session, UserDTO user) {
|
||||||
// 用户有 last_project_id 权限
|
// 用户有 last_project_id 权限
|
||||||
if (hasLastProjectPermission(user)) {
|
if (hasLastProjectPermission(user)) {
|
||||||
return;
|
return;
|
||||||
|
@ -94,7 +94,7 @@ public class UserLoginService {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 判断其他权限
|
// 判断其他权限
|
||||||
checkNewWorkspaceAndProject(user);
|
checkNewWorkspaceAndProject(session, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasLastProjectPermission(UserDTO user) {
|
private boolean hasLastProjectPermission(UserDTO user) {
|
||||||
|
@ -162,7 +162,7 @@ public class UserLoginService {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkNewWorkspaceAndProject(UserDTO user) {
|
private void checkNewWorkspaceAndProject(WebSession session, UserDTO user) {
|
||||||
List<UserGroup> userGroups = user.getUserGroups();
|
List<UserGroup> userGroups = user.getUserGroups();
|
||||||
List<String> projectGroupIds = user.getGroups()
|
List<String> projectGroupIds = user.getGroups()
|
||||||
.stream().filter(ug -> StringUtils.equals(ug.getType(), UserGroupType.PROJECT))
|
.stream().filter(ug -> StringUtils.equals(ug.getType(), UserGroupType.PROJECT))
|
||||||
|
@ -180,7 +180,7 @@ public class UserLoginService {
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
if (workspaces.size() > 0) {
|
if (workspaces.size() > 0) {
|
||||||
String wsId = workspaces.get(0).getSourceId();
|
String wsId = workspaces.get(0).getSourceId();
|
||||||
switchUserResource("workspace", wsId, user);
|
switchUserResource(session, "workspace", wsId, user);
|
||||||
} else {
|
} else {
|
||||||
// 用户登录之后没有项目和工作空间的权限就把值清空
|
// 用户登录之后没有项目和工作空间的权限就把值清空
|
||||||
user.setLastWorkspaceId("");
|
user.setLastWorkspaceId("");
|
||||||
|
@ -200,7 +200,7 @@ public class UserLoginService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void switchUserResource(String sign, String sourceId, UserDTO sessionUser) {
|
public void switchUserResource(WebSession session, String sign, String sourceId, UserDTO sessionUser) {
|
||||||
// 获取最新UserDTO
|
// 获取最新UserDTO
|
||||||
UserDTO user = getUserDTO(sessionUser.getId());
|
UserDTO user = getUserDTO(sessionUser.getId());
|
||||||
User newUser = new User();
|
User newUser = new User();
|
||||||
|
@ -217,9 +217,11 @@ public class UserLoginService {
|
||||||
}
|
}
|
||||||
BeanUtils.copyProperties(user, newUser);
|
BeanUtils.copyProperties(user, newUser);
|
||||||
// 切换工作空间或组织之后更新 session 里的 user
|
// 切换工作空间或组织之后更新 session 里的 user
|
||||||
SessionUtils.putUser(SessionUser.fromUser(user, SessionUtils.getSessionId()));
|
session.getAttributes().put("user", SessionUser.fromUser(user, session.getId()));
|
||||||
|
session.getAttributes().put(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, sessionUser.getId());
|
||||||
userMapper.updateByPrimaryKeySelective(newUser);
|
userMapper.updateByPrimaryKeySelective(newUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserDTO getLoginUser(String userId, List<String> list) {
|
public UserDTO getLoginUser(String userId, List<String> list) {
|
||||||
UserExample example = new UserExample();
|
UserExample example = new UserExample();
|
||||||
example.createCriteria().andIdEqualTo(userId).andSourceIn(list);
|
example.createCriteria().andIdEqualTo(userId).andSourceIn(list);
|
||||||
|
@ -381,9 +383,6 @@ public class UserLoginService {
|
||||||
}
|
}
|
||||||
// 执行变更
|
// 执行变更
|
||||||
userMapper.updateByPrimaryKeySelective(user);
|
userMapper.updateByPrimaryKeySelective(user);
|
||||||
if (StringUtils.equals(user.getStatus(), UserStatus.DISABLED)) {
|
|
||||||
SessionUtils.kickOutUser(user.getId());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Project> getProjectListByWsAndUserId(String userId, String workspaceId) {
|
private List<Project> getProjectListByWsAndUserId(String userId, String workspaceId) {
|
||||||
|
@ -404,4 +403,20 @@ public class UserLoginService {
|
||||||
}));
|
}));
|
||||||
return projectList;
|
return projectList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void validateCsrfToken(String sessionId, String csrfToken) {
|
||||||
|
if (StringUtils.isBlank(csrfToken)) {
|
||||||
|
throw new RuntimeException("csrf token is empty");
|
||||||
|
}
|
||||||
|
csrfToken = CodingUtil.aesDecrypt(csrfToken, SessionUser.secret, SessionUser.iv);
|
||||||
|
|
||||||
|
String[] signatureArray = StringUtils.split(StringUtils.trimToNull(csrfToken), "|");
|
||||||
|
if (signatureArray.length != 4) {
|
||||||
|
throw new RuntimeException("invalid token");
|
||||||
|
}
|
||||||
|
if (!StringUtils.equals(sessionId, signatureArray[2])) {
|
||||||
|
throw new RuntimeException("Please check csrf token.");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
</div>
|
</div>
|
||||||
<p class="tip">{{ this.$t('commons.ssl.entry') }} </p>
|
<p class="tip">{{ this.$t('commons.ssl.entry') }} </p>
|
||||||
<div class="ms-border">
|
<div class="ms-border">
|
||||||
<el-table :data="sslConfig.entrys" highlight-current-row v-if="!loading">
|
<el-table :data="sslConfig.entry" highlight-current-row v-if="!loading">
|
||||||
<el-table-column prop="originalAsName" :label="$t('commons.ssl.original_as_name')" show-overflow-tooltip
|
<el-table-column prop="originalAsName" :label="$t('commons.ssl.original_as_name')" show-overflow-tooltip
|
||||||
width="180"/>
|
width="180"/>
|
||||||
<el-table-column prop="newAsName" :label="$t('commons.ssl.new_as_name')" show-overflow-tooltip
|
<el-table-column prop="newAsName" :label="$t('commons.ssl.new_as_name')" show-overflow-tooltip
|
||||||
|
@ -145,7 +145,7 @@ export default {
|
||||||
item.password = "";
|
item.password = "";
|
||||||
item.default = false;
|
item.default = false;
|
||||||
|
|
||||||
this.sslConfig.entrys.unshift(item);
|
this.sslConfig.entry.unshift(item);
|
||||||
})
|
})
|
||||||
this.sslConfig.files.unshift(sslFile);
|
this.sslConfig.files.unshift(sslFile);
|
||||||
} else {
|
} else {
|
||||||
|
@ -159,7 +159,7 @@ export default {
|
||||||
}
|
}
|
||||||
item.password = "";
|
item.password = "";
|
||||||
item.default = false;
|
item.default = false;
|
||||||
this.sslConfig.entrys.unshift(item);
|
this.sslConfig.entry.unshift(item);
|
||||||
})
|
})
|
||||||
this.sslConfig.files.unshift(sslFile);
|
this.sslConfig.files.unshift(sslFile);
|
||||||
}
|
}
|
||||||
|
@ -170,24 +170,24 @@ export default {
|
||||||
const index = this.sslConfig.files.findIndex((d) => d.id === row.id);
|
const index = this.sslConfig.files.findIndex((d) => d.id === row.id);
|
||||||
this.sslConfig.files.splice(index, 1);
|
this.sslConfig.files.splice(index, 1);
|
||||||
// 同时删除条目
|
// 同时删除条目
|
||||||
if (this.sslConfig.entrys) {
|
if (this.sslConfig.entry) {
|
||||||
let removeKeys = [];
|
let removeKeys = [];
|
||||||
this.sslConfig.entrys.forEach(item => {
|
this.sslConfig.entry.forEach(item => {
|
||||||
if (item && item.sourceId === row.id) {
|
if (item && item.sourceId === row.id) {
|
||||||
const index = this.sslConfig.entrys.findIndex((d) => d.sourceId === row.id);
|
const index = this.sslConfig.entry.findIndex((d) => d.sourceId === row.id);
|
||||||
removeKeys.push(index);
|
removeKeys.push(index);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
removeKeys.forEach(index => {
|
removeKeys.forEach(index => {
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
this.sslConfig.entrys.splice(index, 1);
|
this.sslConfig.entry.splice(index, 1);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
changeCheck(row) {
|
changeCheck(row) {
|
||||||
if (row.default) {
|
if (row.default) {
|
||||||
this.sslConfig.entrys.forEach(item => {
|
this.sslConfig.entry.forEach(item => {
|
||||||
if (item && item.sourceId !== row.id) {
|
if (item && item.sourceId !== row.id) {
|
||||||
item.default = false;
|
item.default = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<div style="padding-bottom: 10px;float: left">
|
<div style="padding-bottom: 10px;float: left">
|
||||||
<el-input :placeholder="$t('commons.search_by_name')" size="mini" v-model="selectVariable"
|
<el-input :placeholder="$t('api_test.search_by_variables')" size="mini" v-model="selectVariable"
|
||||||
@change="filter"
|
@change="filter"
|
||||||
@keyup.enter="filter">
|
@keyup.enter="filter">
|
||||||
</el-input>
|
</el-input>
|
||||||
|
|
|
@ -1217,6 +1217,7 @@ const message = {
|
||||||
buttons: {
|
buttons: {
|
||||||
to_xml: "To xml",
|
to_xml: "To xml",
|
||||||
},
|
},
|
||||||
|
search_by_variables: "Search by variable",
|
||||||
case_jump_message: "The jump use case has been removed!",
|
case_jump_message: "The jump use case has been removed!",
|
||||||
scenario_jump_message: "The jumped scene has been deleted!",
|
scenario_jump_message: "The jumped scene has been deleted!",
|
||||||
is_continue: "Is continue",
|
is_continue: "Is continue",
|
||||||
|
|
|
@ -1227,6 +1227,7 @@ const message = {
|
||||||
buttons: {
|
buttons: {
|
||||||
to_xml: "转xml结构",
|
to_xml: "转xml结构",
|
||||||
},
|
},
|
||||||
|
search_by_variables: "根据变量名搜索",
|
||||||
case_jump_message: "跳转的用例已经删除!",
|
case_jump_message: "跳转的用例已经删除!",
|
||||||
scenario_jump_message: "跳转的场景已经删除!",
|
scenario_jump_message: "跳转的场景已经删除!",
|
||||||
is_continue: "是否继续",
|
is_continue: "是否继续",
|
||||||
|
|
|
@ -1224,6 +1224,7 @@ const message = {
|
||||||
buttons: {
|
buttons: {
|
||||||
to_xml: "轉xml結構",
|
to_xml: "轉xml結構",
|
||||||
},
|
},
|
||||||
|
search_by_variables: "根據變量名搜索",
|
||||||
case_jump_message: "跳轉的用例已經刪除!",
|
case_jump_message: "跳轉的用例已經刪除!",
|
||||||
scenario_jump_message: "跳轉的場景已經刪除!",
|
scenario_jump_message: "跳轉的場景已經刪除!",
|
||||||
is_continue: "是否繼續",
|
is_continue: "是否繼續",
|
||||||
|
|
|
@ -23,11 +23,11 @@ export class Environment extends BaseConfig {
|
||||||
export class SSLConfig extends BaseConfig {
|
export class SSLConfig extends BaseConfig {
|
||||||
constructor(options = {}) {
|
constructor(options = {}) {
|
||||||
super();
|
super();
|
||||||
this.entrys = [];
|
this.entry = [];
|
||||||
this.files = [];
|
this.files = [];
|
||||||
this.set(options);
|
this.set(options);
|
||||||
this.sets({files: KeyValue}, options);
|
this.sets({files: KeyValue}, options);
|
||||||
this.sets({entrys: KeyValue}, options);
|
this.sets({entry: KeyValue}, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
initOptions(options = {}) {
|
initOptions(options = {}) {
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {$error} from "./message"
|
||||||
import {getCurrentProjectID, getCurrentWorkspaceId} from "../utils/token";
|
import {getCurrentProjectID, getCurrentWorkspaceId} from "../utils/token";
|
||||||
import {PROJECT_ID, TokenKey, WORKSPACE_ID} from "../utils/constants";
|
import {PROJECT_ID, TokenKey, WORKSPACE_ID} from "../utils/constants";
|
||||||
import packageJSON from '@/../package.json'
|
import packageJSON from '@/../package.json'
|
||||||
import {getUUID} from "../utils";
|
import {getUrlParams, getUUID} from "../utils";
|
||||||
import {Base64} from "js-base64";
|
import {Base64} from "js-base64";
|
||||||
|
|
||||||
// baseURL 根据是否是独立运行修改
|
// baseURL 根据是否是独立运行修改
|
||||||
|
@ -21,6 +21,8 @@ if (window.location.pathname.startsWith('/' + packageJSON.name)) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let urlParams = getUrlParams(window.location.href);
|
||||||
|
|
||||||
const instance = axios.create({
|
const instance = axios.create({
|
||||||
baseURL, // url = base url + request url
|
baseURL, // url = base url + request url
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
|
@ -39,12 +41,18 @@ instance.interceptors.request.use(
|
||||||
}
|
}
|
||||||
// sso callback 过来的会有sessionId在url上
|
// sso callback 过来的会有sessionId在url上
|
||||||
if (!config.headers['X-AUTH-TOKEN']) {
|
if (!config.headers['X-AUTH-TOKEN']) {
|
||||||
const paramsStr = window.location.href
|
let sessionId = urlParams['_token']
|
||||||
let sessionId = paramsStr.split('_token=')[1]
|
|
||||||
if (sessionId) {
|
if (sessionId) {
|
||||||
config.headers['X-AUTH-TOKEN'] = Base64.decode(sessionId);
|
config.headers['X-AUTH-TOKEN'] = Base64.decode(sessionId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// sso callback 过来的会有csrf在url上
|
||||||
|
if (!config.headers['CSRF-TOKEN']) {
|
||||||
|
let csrf = urlParams['_csrf']
|
||||||
|
if (csrf) {
|
||||||
|
config.headers['CSRF-TOKEN'] = csrf;
|
||||||
|
}
|
||||||
|
}
|
||||||
// 包含 工作空间 项目的标识
|
// 包含 工作空间 项目的标识
|
||||||
config.headers['WORKSPACE'] = getCurrentWorkspaceId();
|
config.headers['WORKSPACE'] = getCurrentWorkspaceId();
|
||||||
config.headers['PROJECT'] = getCurrentProjectID();
|
config.headers['PROJECT'] = getCurrentProjectID();
|
||||||
|
|
|
@ -328,3 +328,14 @@ function _resizeTextarea(i, size, textareaList) {
|
||||||
export function checkMicroMode() {
|
export function checkMicroMode() {
|
||||||
return sessionStorage.getItem("MICRO_MODE");
|
return sessionStorage.getItem("MICRO_MODE");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getUrlParams(url) {
|
||||||
|
const arrSearch = url.split('?').pop().split('#').shift().split('&');
|
||||||
|
let obj = {};
|
||||||
|
arrSearch.forEach((item) => {
|
||||||
|
const [k, v] = item.split('=');
|
||||||
|
obj[k] = v;
|
||||||
|
return obj;
|
||||||
|
});
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
|
@ -59,7 +59,10 @@ public class SessionUtils {
|
||||||
}
|
}
|
||||||
Map<String, ?> users = sessionRepository.findByPrincipalName(username);
|
Map<String, ?> users = sessionRepository.findByPrincipalName(username);
|
||||||
if (MapUtils.isNotEmpty(users)) {
|
if (MapUtils.isNotEmpty(users)) {
|
||||||
users.keySet().forEach(sessionRepository::deleteById);
|
users.keySet().forEach(k -> {
|
||||||
|
sessionRepository.deleteById(k);
|
||||||
|
sessionRepository.getSessionRedisOperations().delete("spring:session:sessions:" + k);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ public class LoginController {
|
||||||
@GetMapping(value = "/signout")
|
@GetMapping(value = "/signout")
|
||||||
@MsAuditLog(module = OperLogModule.AUTH_TITLE, beforeEvent = "#msClass.getUserId(id)", type = OperLogConstants.LOGIN, title = "登出", msClass = SessionUtils.class)
|
@MsAuditLog(module = OperLogModule.AUTH_TITLE, beforeEvent = "#msClass.getUserId(id)", type = OperLogConstants.LOGIN, title = "登出", msClass = SessionUtils.class)
|
||||||
public ResultHolder logout() throws Exception {
|
public ResultHolder logout() throws Exception {
|
||||||
ssoLogoutService.logout();
|
ssoLogoutService.logout(SecurityUtils.getSubject().getSession());
|
||||||
SecurityUtils.getSubject().logout();
|
SecurityUtils.getSubject().logout();
|
||||||
return ResultHolder.success(StringUtils.EMPTY);
|
return ResultHolder.success(StringUtils.EMPTY);
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,8 +101,8 @@ public class CommandService {
|
||||||
this.createKeyStore("ms-run", newKeyStore);
|
this.createKeyStore("ms-run", newKeyStore);
|
||||||
// 修改别名
|
// 修改别名
|
||||||
Map<String, List<KeyStoreEntry>> entryMap = new HashMap<>();
|
Map<String, List<KeyStoreEntry>> entryMap = new HashMap<>();
|
||||||
if (sslConfig != null && CollectionUtils.isNotEmpty(sslConfig.getEntrys())) {
|
if (sslConfig != null && CollectionUtils.isNotEmpty(sslConfig.getEntry())) {
|
||||||
sslConfig.getEntrys().forEach(item -> {
|
sslConfig.getEntry().forEach(item -> {
|
||||||
if (entryMap.containsKey(item.getSourceId())) {
|
if (entryMap.containsKey(item.getSourceId())) {
|
||||||
entryMap.get(item.getSourceId()).add(item);
|
entryMap.get(item.getSourceId()).add(item);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -9,12 +9,12 @@ import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class KeyStoreConfig {
|
public class KeyStoreConfig {
|
||||||
private List<KeyStoreEntry> entrys;
|
private List<KeyStoreEntry> entry;
|
||||||
private List<KeyStoreFile> files;
|
private List<KeyStoreFile> files;
|
||||||
|
|
||||||
public String getDefaultAlias() {
|
public String getDefaultAlias() {
|
||||||
if (CollectionUtils.isNotEmpty(entrys)) {
|
if (CollectionUtils.isNotEmpty(entry)) {
|
||||||
List<KeyStoreEntry> entryList = this.entrys.stream().filter(KeyStoreEntry::isDefault).collect(Collectors.toList());
|
List<KeyStoreEntry> entryList = this.entry.stream().filter(KeyStoreEntry::isDefault).collect(Collectors.toList());
|
||||||
if (CollectionUtils.isNotEmpty(entryList)) {
|
if (CollectionUtils.isNotEmpty(entryList)) {
|
||||||
if (StringUtils.isNotEmpty(entryList.get(0).getNewAsName())) {
|
if (StringUtils.isNotEmpty(entryList.get(0).getNewAsName())) {
|
||||||
return entryList.get(0).getNewAsName();
|
return entryList.get(0).getNewAsName();
|
||||||
|
@ -27,8 +27,8 @@ public class KeyStoreConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAlias(String asName) {
|
public String getAlias(String asName) {
|
||||||
if (CollectionUtils.isNotEmpty(entrys)) {
|
if (CollectionUtils.isNotEmpty(entry)) {
|
||||||
List<KeyStoreEntry> entryList = this.entrys.stream().filter(ks -> StringUtils.equals(asName, ks.getNewAsName())).collect(Collectors.toList());
|
List<KeyStoreEntry> entryList = this.entry.stream().filter(ks -> StringUtils.equals(asName, ks.getNewAsName())).collect(Collectors.toList());
|
||||||
if (CollectionUtils.isNotEmpty(entryList) && CollectionUtils.isNotEmpty(files) && files.size() == 1) {
|
if (CollectionUtils.isNotEmpty(entryList) && CollectionUtils.isNotEmpty(files) && files.size() == 1) {
|
||||||
return entryList.get(0).getOriginalAsName();
|
return entryList.get(0).getOriginalAsName();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import io.metersphere.commons.utils.JSON;
|
||||||
import io.metersphere.commons.utils.SessionUtils;
|
import io.metersphere.commons.utils.SessionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.shiro.SecurityUtils;
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
import org.apache.shiro.session.Session;
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
@ -27,7 +28,7 @@ public class SSOLogoutService {
|
||||||
/**
|
/**
|
||||||
* oidc logout
|
* oidc logout
|
||||||
*/
|
*/
|
||||||
public void logout() throws Exception {
|
public void logout(Session session) throws Exception {
|
||||||
String authId = (String) SecurityUtils.getSubject().getSession().getAttribute("authId");
|
String authId = (String) SecurityUtils.getSubject().getSession().getAttribute("authId");
|
||||||
AuthSource authSource = authSourceMapper.selectByPrimaryKey(authId);
|
AuthSource authSource = authSourceMapper.selectByPrimaryKey(authId);
|
||||||
if (authSource != null) {
|
if (authSource != null) {
|
||||||
|
@ -38,6 +39,12 @@ public class SSOLogoutService {
|
||||||
|
|
||||||
restTemplate.getForEntity(logoutUrl + "?id_token_hint=" + idToken, String.class);
|
restTemplate.getForEntity(logoutUrl + "?id_token_hint=" + idToken, String.class);
|
||||||
}
|
}
|
||||||
|
if (StringUtils.equals(UserSource.CAS.name(), authSource.getType())) {
|
||||||
|
String casTicket = (String) session.getAttribute("casTicket");
|
||||||
|
if (StringUtils.isNotEmpty(casTicket)) {
|
||||||
|
stringRedisTemplate.delete(casTicket);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<!-- 表头 -->
|
<!-- 表头 -->
|
||||||
<template v-slot:header>
|
<template v-slot:header>
|
||||||
<ms-table-header :create-permission="['WORKSPACE_PROJECT_ENVIRONMENT:READ+CREATE']"
|
<ms-table-header :create-permission="['WORKSPACE_PROJECT_ENVIRONMENT:READ+CREATE']"
|
||||||
:create-tip="btnTips"
|
:create-tip="btnTips" :tip="$t('system.search_by_environment_name')"
|
||||||
:condition.sync="condition" @search="search" @create="createEnv">
|
:condition.sync="condition" @search="search" @create="createEnv">
|
||||||
<template v-slot:button>
|
<template v-slot:button>
|
||||||
<ms-table-button v-permission="['WORKSPACE_PROJECT_ENVIRONMENT:READ+IMPORT']" icon="el-icon-box"
|
<ms-table-button v-permission="['WORKSPACE_PROJECT_ENVIRONMENT:READ+IMPORT']" icon="el-icon-box"
|
||||||
|
@ -27,14 +27,14 @@
|
||||||
<show-more-btn :is-show="scope.row.showMore" :buttons="buttons" :size="selectDataCounts"/>
|
<show-more-btn :is-show="scope.row.showMore" :buttons="buttons" :size="selectDataCounts"/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<el-table-column :label="$t('api_test.environment.name')" prop="name" show-overflow-tooltip>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column :label="$t('commons.project')" width="250" :filters="projectFilters" column-key="projectId"
|
<el-table-column :label="$t('commons.project')" width="250" :filters="projectFilters" column-key="projectId"
|
||||||
show-overflow-tooltip>
|
show-overflow-tooltip>
|
||||||
<template v-slot="scope">
|
<template v-slot="scope">
|
||||||
<span>{{ idNameMap.get(scope.row.projectId) }}</span>
|
<span>{{ idNameMap.get(scope.row.projectId) }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :label="$t('api_test.environment.name')" prop="name" show-overflow-tooltip>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column :label="$t('api_test.environment.socket')" show-overflow-tooltip>
|
<el-table-column :label="$t('api_test.environment.socket')" show-overflow-tooltip>
|
||||||
<template v-slot="scope">
|
<template v-slot="scope">
|
||||||
<span v-if="parseDomainName(scope.row)!=='SHOW_INFO'">{{ parseDomainName(scope.row) }}</span>
|
<span v-if="parseDomainName(scope.row)!=='SHOW_INFO'">{{ parseDomainName(scope.row) }}</span>
|
||||||
|
|
|
@ -7,7 +7,8 @@ const message = {
|
||||||
search_get_more_tip: 'Search for other options'
|
search_get_more_tip: 'Search for other options'
|
||||||
},
|
},
|
||||||
system: {
|
system: {
|
||||||
environment_import_repeat_tip: "(Environment configuration with the same name filtered {0})"
|
environment_import_repeat_tip: "(Environment configuration with the same name filtered {0})",
|
||||||
|
search_by_environment_name: "search by environment name",
|
||||||
},
|
},
|
||||||
display: {
|
display: {
|
||||||
title: 'Theme',
|
title: 'Theme',
|
||||||
|
|
|
@ -7,7 +7,8 @@ const message = {
|
||||||
search_get_more_tip: '搜索获取其他选项'
|
search_get_more_tip: '搜索获取其他选项'
|
||||||
},
|
},
|
||||||
system: {
|
system: {
|
||||||
environment_import_repeat_tip: "(已过滤同名称的环境配置 {0})"
|
environment_import_repeat_tip: "(已过滤同名称的环境配置 {0})",
|
||||||
|
search_by_environment_name: "根据环境的名称搜索",
|
||||||
},
|
},
|
||||||
display: {
|
display: {
|
||||||
title: '显示设置',
|
title: '显示设置',
|
||||||
|
|
|
@ -7,7 +7,8 @@ const message = {
|
||||||
search_get_more_tip: '搜索獲取其他選項'
|
search_get_more_tip: '搜索獲取其他選項'
|
||||||
},
|
},
|
||||||
system: {
|
system: {
|
||||||
environment_import_repeat_tip: "(已過濾同名稱的環境配置 {0})"
|
environment_import_repeat_tip: "(已過濾同名稱的環境配置 {0})",
|
||||||
|
search_by_environment_name: "根據環境的名稱搜索",
|
||||||
},
|
},
|
||||||
display: {
|
display: {
|
||||||
title: '顯示設置',
|
title: '顯示設置',
|
||||||
|
|
|
@ -520,8 +520,10 @@ public class TestPlanTestCaseService {
|
||||||
if (CollectionUtils.isNotEmpty(cases)) {
|
if (CollectionUtils.isNotEmpty(cases)) {
|
||||||
Map<String, Project> projectMap = ServiceUtils.getProjectMap(
|
Map<String, Project> projectMap = ServiceUtils.getProjectMap(
|
||||||
cases.stream().map(TestPlanCaseDTO::getProjectId).collect(Collectors.toList()));
|
cases.stream().map(TestPlanCaseDTO::getProjectId).collect(Collectors.toList()));
|
||||||
Map<String, String> userNameMap = ServiceUtils.getUserNameMap(
|
List<String> userIds = new ArrayList();
|
||||||
cases.stream().map(TestPlanCaseDTO::getExecutor).collect(Collectors.toList()));
|
userIds.addAll(cases.stream().map(TestPlanCaseDTO::getExecutor).collect(Collectors.toList()));
|
||||||
|
userIds.addAll(cases.stream().map(TestPlanCaseDTO::getMaintainer).collect(Collectors.toList()));
|
||||||
|
Map<String, String> userNameMap = ServiceUtils.getUserNameMap(userIds);
|
||||||
cases.forEach(item -> {
|
cases.forEach(item -> {
|
||||||
if (projectMap.containsKey(item.getProjectId())) {
|
if (projectMap.containsKey(item.getProjectId())) {
|
||||||
item.setProjectName(projectMap.get(item.getProjectId()).getName());
|
item.setProjectName(projectMap.get(item.getProjectId()).getName());
|
||||||
|
|
|
@ -16,14 +16,16 @@ public class ZentaoGetClient extends ZentaoClient {
|
||||||
private static final String STORY_GET="&module=story&methodName=getProductStories¶ms=productID={key}&t=json&zentaosid=";
|
private static final String STORY_GET="&module=story&methodName=getProductStories¶ms=productID={key}&t=json&zentaosid=";
|
||||||
private static final String USER_GET="&module=user&methodName=getList&t=json&zentaosid=";
|
private static final String USER_GET="&module=user&methodName=getList&t=json&zentaosid=";
|
||||||
private static final String BUILDS_GET="&module=build&methodName=getProductBuildPairs&productID={0}&zentaosid={1}";
|
private static final String BUILDS_GET="&module=build&methodName=getProductBuildPairs&productID={0}&zentaosid={1}";
|
||||||
private static final String FILE_UPLOAD="&module=file&methodName=saveUpload¶ms=objectType={1},objectID={2},zentaosid={3}";
|
private static final String FILE_UPLOAD="&module=file&methodName=saveUpload¶ms=objectType=bug&zentaosid={1}";
|
||||||
private static final String FILE_DELETE="/?m=file&f=delete&t=json&fileID={1}&confirm=yes&zentaosid={2}";
|
private static final String FILE_DELETE="/?m=file&f=delete&t=json&fileID={1}&confirm=yes&zentaosid={2}";
|
||||||
private static final String FILE_DOWNLOAD="/?m=file&f=download&t=json&fileID={1}&mouse=click&zentaosid={2}";
|
private static final String FILE_DOWNLOAD="/?m=file&f=download&t=json&fileID={1}&mouse=click&zentaosid={2}";
|
||||||
private static final String CREATE_META_DATA="?m=bug&f=create&productID={0}&t=json&zentaosid={1}";
|
private static final String CREATE_META_DATA="?m=bug&f=create&productID={0}&t=json&zentaosid={1}";
|
||||||
private static final String REPLACE_IMG_URL="<img src=\"%s/index.php?m=file&f=read&fileID=$1\"/>";
|
private static final String REPLACE_IMG_URL="<img src=\"%s/index.php?m=file&f=read&fileID=$1\"/>";
|
||||||
private static final Pattern IMG_PATTERN = Pattern.compile("m=file&f=read&fileID=(.*?)\"/>");
|
private static final Pattern IMG_PATTERN = Pattern.compile("m=file&f=read&fileID=(.*?)\"/>");
|
||||||
private static final String PRODUCT_GET = "&module=product&methodName=getById¶ms=productID={0}&zentaosid={1}";
|
private static final String PRODUCT_GET = "&module=product&methodName=getById¶ms=productID={0}&zentaosid={1}";
|
||||||
// 注意 recTotal={1}&recPerPage={2}&pageID={3} 顺序不能调换,有点恶心
|
/**
|
||||||
|
* 注意 recTotal={1}&recPerPage={2}&pageID={3} 顺序不能调换,有点恶心
|
||||||
|
*/
|
||||||
private static final String BUG_LIST_URL = "/?m=bug&f=browse&productID={0}&branch=&browseType=all¶m=0&orderBy=&recTotal={1}&recPerPage={2}&pageID={3}&t=json&zentaosid={4}";
|
private static final String BUG_LIST_URL = "/?m=bug&f=browse&productID={0}&branch=&browseType=all¶m=0&orderBy=&recTotal={1}&recPerPage={2}&pageID={3}&t=json&zentaosid={4}";
|
||||||
|
|
||||||
RequestUrl request = new RequestUrl();
|
RequestUrl request = new RequestUrl();
|
||||||
|
|
|
@ -16,7 +16,7 @@ public class ZentaoPathInfoClient extends ZentaoClient {
|
||||||
private static final String USER_GET = "/api-getModel-user-getList?zentaosid=";
|
private static final String USER_GET = "/api-getModel-user-getList?zentaosid=";
|
||||||
private static final String BUILDS_GET = "/api-getModel-build-getProductBuildPairs-productID={0}?zentaosid={1}";
|
private static final String BUILDS_GET = "/api-getModel-build-getProductBuildPairs-productID={0}?zentaosid={1}";
|
||||||
private static final String CREATE_META_DATA="/bug-create-{0}.json?zentaosid={1}";
|
private static final String CREATE_META_DATA="/bug-create-{0}.json?zentaosid={1}";
|
||||||
private static final String FILE_UPLOAD = "/api-getModel-file-saveUpload-objectType={1},objectID={2}?zentaosid={3}";
|
private static final String FILE_UPLOAD = "/api-getModel-file-saveUpload-objectType=bug?zentaosid={1}";
|
||||||
private static final String FILE_DELETE = "/file-delete-{1}-.yes.json?zentaosid={2}";
|
private static final String FILE_DELETE = "/file-delete-{1}-.yes.json?zentaosid={2}";
|
||||||
private static final String FILE_DOWNLOAD="/file-download-{1}-.click.json?zentaosid={2}";
|
private static final String FILE_DOWNLOAD="/file-download-{1}-.click.json?zentaosid={2}";
|
||||||
private static final String REPLACE_IMG_URL = "<img src=\"%s/file-read-$1\"/>";
|
private static final String REPLACE_IMG_URL = "<img src=\"%s/file-read-$1\"/>";
|
||||||
|
|
|
@ -26,6 +26,8 @@ import io.metersphere.service.issue.domain.zentao.ZentaoConfig;
|
||||||
import io.metersphere.xpack.track.dto.PlatformStatusDTO;
|
import io.metersphere.xpack.track.dto.PlatformStatusDTO;
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.http.entity.mime.MultipartEntity;
|
||||||
|
import org.apache.http.entity.mime.content.FileBody;
|
||||||
import org.apache.logging.log4j.util.Strings;
|
import org.apache.logging.log4j.util.Strings;
|
||||||
import org.springframework.core.io.FileSystemResource;
|
import org.springframework.core.io.FileSystemResource;
|
||||||
import org.springframework.http.HttpEntity;
|
import org.springframework.http.HttpEntity;
|
||||||
|
@ -437,16 +439,16 @@ public class ZentaoPlatform extends AbstractIssuePlatform {
|
||||||
String session = zentaoClient.login();
|
String session = zentaoClient.login();
|
||||||
HttpHeaders httpHeaders = new HttpHeaders();
|
HttpHeaders httpHeaders = new HttpHeaders();
|
||||||
MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
|
MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
|
||||||
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(paramMap, httpHeaders);
|
|
||||||
paramMap.add("files", resource);
|
paramMap.add("files", resource);
|
||||||
|
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(paramMap, httpHeaders);
|
||||||
RestTemplate restTemplate = new RestTemplate();
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
try {
|
try {
|
||||||
String fileUpload = zentaoClient.requestUrl.getFileUpload();
|
String fileUpload = zentaoClient.requestUrl.getFileUpload();
|
||||||
ResponseEntity<String> responseEntity = restTemplate.exchange(fileUpload, HttpMethod.POST, requestEntity,
|
ResponseEntity<String> responseEntity = restTemplate.exchange(fileUpload, HttpMethod.POST, requestEntity,
|
||||||
String.class, "bug", null, session);
|
String.class, session);
|
||||||
String body = responseEntity.getBody();
|
String body = responseEntity.getBody();
|
||||||
Map obj = JSON.parseMap(body);
|
Map obj = JSON.parseMap(body);
|
||||||
Map data = (Map) obj.get("data");
|
Map data = (Map) JSON.parseObject(obj.get("data").toString());
|
||||||
Set<String> set = data.keySet();
|
Set<String> set = data.keySet();
|
||||||
if (!set.isEmpty()) {
|
if (!set.isEmpty()) {
|
||||||
id = (String) set.toArray()[0];
|
id = (String) set.toArray()[0];
|
||||||
|
|
|
@ -95,7 +95,7 @@ export default {
|
||||||
if (values.indexOf(status) == -1) {
|
if (values.indexOf(status) == -1) {
|
||||||
statusFilter.push({
|
statusFilter.push({
|
||||||
value: status,
|
value: status,
|
||||||
text: ISSUE_STATUS_MAP[status] ? ISSUE_STATUS_MAP[status] : status
|
text: ISSUE_STATUS_MAP[status] && item.platform === 'Local' ? ISSUE_STATUS_MAP[status] : status
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue