feat: ASW-30 新增 Application 分析重定向接口
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package net.geedge.asw.module.app.controller;
|
package net.geedge.asw.module.app.controller;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import net.geedge.asw.common.util.ASWException;
|
import net.geedge.asw.common.util.ASWException;
|
||||||
import net.geedge.asw.common.util.R;
|
import net.geedge.asw.common.util.R;
|
||||||
import net.geedge.asw.common.util.RCode;
|
import net.geedge.asw.common.util.RCode;
|
||||||
@@ -12,6 +13,7 @@ import net.geedge.asw.module.sys.service.ISysUserService;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -122,4 +124,12 @@ public class ApplicationController {
|
|||||||
applicationService.restore(id, version);
|
applicationService.restore(id, version);
|
||||||
return R.ok();
|
return R.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/analyze")
|
||||||
|
public void analyze(@RequestParam String workspaceId,
|
||||||
|
@RequestParam String pcapIds,
|
||||||
|
HttpServletResponse response) throws IOException {
|
||||||
|
applicationService.redirectDiscoverPage(workspaceId, pcapIds, response);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ package net.geedge.asw.module.app.service;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import net.geedge.asw.module.app.entity.ApplicationEntity;
|
import net.geedge.asw.module.app.entity.ApplicationEntity;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -24,4 +26,7 @@ public interface IApplicationService extends IService<ApplicationEntity>{
|
|||||||
List<ApplicationEntity> queryLogList(String id);
|
List<ApplicationEntity> queryLogList(String id);
|
||||||
|
|
||||||
void restore(String id, String version);
|
void restore(String id, String version);
|
||||||
|
|
||||||
|
void redirectDiscoverPage(String workspaceId, String pcapIds, HttpServletResponse response) throws IOException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,17 @@
|
|||||||
package net.geedge.asw.module.app.service.impl;
|
package net.geedge.asw.module.app.service.impl;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.stp.SaTokenInfo;
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import cn.hutool.core.net.url.UrlBuilder;
|
||||||
|
import cn.hutool.log.Log;
|
||||||
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import net.geedge.asw.module.feign.client.KibanaClient;
|
||||||
import net.geedge.asw.common.util.ASWException;
|
import net.geedge.asw.common.util.ASWException;
|
||||||
import net.geedge.asw.common.util.RCode;
|
import net.geedge.asw.common.util.RCode;
|
||||||
import net.geedge.asw.common.util.T;
|
import net.geedge.asw.common.util.T;
|
||||||
@@ -12,20 +20,41 @@ import net.geedge.asw.module.app.entity.ApplicationEntity;
|
|||||||
import net.geedge.asw.module.app.entity.ApplicationLogEntity;
|
import net.geedge.asw.module.app.entity.ApplicationLogEntity;
|
||||||
import net.geedge.asw.module.app.service.IApplicationLogService;
|
import net.geedge.asw.module.app.service.IApplicationLogService;
|
||||||
import net.geedge.asw.module.app.service.IApplicationService;
|
import net.geedge.asw.module.app.service.IApplicationService;
|
||||||
|
import net.geedge.asw.module.runner.entity.PcapEntity;
|
||||||
|
import net.geedge.asw.module.runner.service.IPcapService;
|
||||||
|
import net.geedge.asw.module.workspace.entity.WorkspaceEntity;
|
||||||
|
import net.geedge.asw.module.workspace.service.IWorkspaceService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class ApplicationServiceImpl extends ServiceImpl<ApplicationDao, ApplicationEntity> implements IApplicationService {
|
public class ApplicationServiceImpl extends ServiceImpl<ApplicationDao, ApplicationEntity> implements IApplicationService {
|
||||||
|
|
||||||
|
private static final Log log = Log.get();
|
||||||
|
|
||||||
|
@Value("${kibana.url:127.0.0.1:5601}")
|
||||||
|
private String kibanaUrl;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IApplicationLogService applicationLogService;
|
private IApplicationLogService applicationLogService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IWorkspaceService workspaceService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IPcapService pcapService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private KibanaClient kibanaClient;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ApplicationEntity queryByApplicationAndLog(String id, String version) {
|
public ApplicationEntity queryByApplicationAndLog(String id, String version) {
|
||||||
ApplicationEntity entity = this.baseMapper.queryByApplicationAndLog(id, version);
|
ApplicationEntity entity = this.baseMapper.queryByApplicationAndLog(id, version);
|
||||||
@@ -131,4 +160,91 @@ public class ApplicationServiceImpl extends ServiceImpl<ApplicationDao, Applicat
|
|||||||
ApplicationEntity application = T.BeanUtil.toBean(oldApplication, ApplicationEntity.class);
|
ApplicationEntity application = T.BeanUtil.toBean(oldApplication, ApplicationEntity.class);
|
||||||
this.updateById(application);
|
this.updateById(application);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. 根据 workspace_name 查询 index-pattern 是否存在
|
||||||
|
* 2. 不存在则创建索引
|
||||||
|
*
|
||||||
|
* 维护格式示例:
|
||||||
|
* {
|
||||||
|
* "type": "index-pattern",
|
||||||
|
* "id": "workspace_id",
|
||||||
|
* "attributes": {
|
||||||
|
* "title": "workspace-{workspace_name}-*"
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* @param workspaceId
|
||||||
|
* @param pcapIds
|
||||||
|
* @param response
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void redirectDiscoverPage(String workspaceId, String pcapIds, HttpServletResponse response) throws IOException {
|
||||||
|
// verify
|
||||||
|
WorkspaceEntity workspace = workspaceService.getById(workspaceId);
|
||||||
|
T.VerifyUtil.is(workspace).notNull(RCode.SYS_RECORD_NOT_FOUND);
|
||||||
|
|
||||||
|
List<String> pcapIdList = T.StrUtil.split(pcapIds, ",").stream().filter(s -> T.StrUtil.isNotEmpty(s)).collect(Collectors.toList());
|
||||||
|
List<PcapEntity> pcapList = pcapService.list(new LambdaQueryWrapper<PcapEntity>().in(PcapEntity::getId, pcapIdList));
|
||||||
|
T.VerifyUtil.is(pcapList).notEmpty(RCode.SYS_RECORD_NOT_FOUND);
|
||||||
|
|
||||||
|
// index name
|
||||||
|
String indexName = String.format("workspace-%s-*", workspace.getName());
|
||||||
|
|
||||||
|
SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
|
||||||
|
String token = tokenInfo.getTokenValue();
|
||||||
|
|
||||||
|
JSONObject index = kibanaClient.findIndexPattern(token, indexName);
|
||||||
|
JSONArray savedObjects = index.getJSONArray("saved_objects");
|
||||||
|
|
||||||
|
// check if index exists
|
||||||
|
boolean indexExists = savedObjects.stream()
|
||||||
|
.filter(obj -> {
|
||||||
|
JSONObject attributes = ((JSONObject) obj).getJSONObject("attributes");
|
||||||
|
if (T.ObjectUtil.isEmpty(attributes)) return false;
|
||||||
|
String title = attributes.getString("title");
|
||||||
|
return T.StrUtil.equals(indexName, title);
|
||||||
|
})
|
||||||
|
.findFirst()
|
||||||
|
.isPresent();
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("[redirectDiscoverPage] [idnex-pattern: {}] [exists: {}]", indexName, indexExists);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create index
|
||||||
|
if (T.BooleanUtil.negate(indexExists)) {
|
||||||
|
JSONObject attributes = new JSONObject();
|
||||||
|
attributes.put("title", indexName);
|
||||||
|
|
||||||
|
JSONObject body = new JSONObject();
|
||||||
|
body.put("attributes", attributes);
|
||||||
|
kibanaClient.saveIndexPattern(token, workspaceId, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
// build url
|
||||||
|
String baseUrl = UrlBuilder.ofHttp(kibanaUrl)
|
||||||
|
.addPath("/app/data-explorer/discover")
|
||||||
|
.addQuery("jwt", token)
|
||||||
|
.toString();
|
||||||
|
|
||||||
|
// build query param
|
||||||
|
String param1 = String.format("_a=(discover:(columns:!(_source),isDirty:!f,sort:!()),metadata:(indexPattern:'%s',view:discover))", workspaceId);
|
||||||
|
String param2 = "_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))";
|
||||||
|
|
||||||
|
String source = pcapList.stream()
|
||||||
|
.map(PcapEntity::getName)
|
||||||
|
.map(fileName -> "\"" + fileName + "\"")
|
||||||
|
.collect(Collectors.joining("|", "source: (", ")"));
|
||||||
|
String param3 = String.format("_q=(filters:!(),query:(language:lucene,query:'%s'))", source);
|
||||||
|
|
||||||
|
String query = String.format("?%s&%s&%s", param1, param2, param3);
|
||||||
|
String redirectUrl = baseUrl + "#" + query;
|
||||||
|
|
||||||
|
if(log.isDebugEnabled()){
|
||||||
|
log.debug("[redirectDiscoverPage] [url: {}]", redirectUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// redirect
|
||||||
|
response.sendRedirect(redirectUrl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
package net.geedge.asw.module.runner.client;
|
package net.geedge.asw.module.feign;
|
||||||
|
|
||||||
import cn.hutool.core.net.url.UrlBuilder;
|
import cn.hutool.core.net.url.UrlBuilder;
|
||||||
import cn.hutool.log.Log;
|
import cn.hutool.log.Log;
|
||||||
import feign.Feign;
|
import feign.Feign;
|
||||||
import feign.form.FormEncoder;
|
import feign.form.FormEncoder;
|
||||||
import net.geedge.asw.common.config.feign.Fastjson2Decoder;
|
import net.geedge.asw.module.feign.client.GeoipClient;
|
||||||
import net.geedge.asw.common.config.feign.Fastjson2Encoder;
|
import net.geedge.asw.module.feign.client.KibanaClient;
|
||||||
import net.geedge.asw.common.config.feign.Http2Client;
|
import net.geedge.asw.module.feign.client.ZeekClient;
|
||||||
|
import net.geedge.asw.module.feign.support.Fastjson2Decoder;
|
||||||
|
import net.geedge.asw.module.feign.support.Fastjson2Encoder;
|
||||||
|
import net.geedge.asw.module.feign.support.Http2Client;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
@@ -22,6 +25,8 @@ public class FeignClientConfiguration {
|
|||||||
@Value("${geoip.url:127.0.0.1:8087}")
|
@Value("${geoip.url:127.0.0.1:8087}")
|
||||||
private String geoipUrl;
|
private String geoipUrl;
|
||||||
|
|
||||||
|
@Value("${kibana.url:127.0.0.1:5601}")
|
||||||
|
private String kibanaUrl;
|
||||||
|
|
||||||
@Bean("zeekClient")
|
@Bean("zeekClient")
|
||||||
public ZeekClient zeekClient() {
|
public ZeekClient zeekClient() {
|
||||||
@@ -45,4 +50,15 @@ public class FeignClientConfiguration {
|
|||||||
.target(GeoipClient.class, url);
|
.target(GeoipClient.class, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean("kibanaClient")
|
||||||
|
public KibanaClient kibanaClient() {
|
||||||
|
String url = UrlBuilder.ofHttp(kibanaUrl).toString();
|
||||||
|
log.info("[kibanaClient] [url: {}]", url);
|
||||||
|
return Feign.builder()
|
||||||
|
.encoder(new Fastjson2Encoder())
|
||||||
|
.decoder(new Fastjson2Decoder())
|
||||||
|
.client(new Http2Client())
|
||||||
|
.target(KibanaClient.class, url);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package net.geedge.asw.module.runner.client;
|
package net.geedge.asw.module.feign;
|
||||||
|
|
||||||
import cn.hutool.log.Log;
|
import cn.hutool.log.Log;
|
||||||
import net.geedge.asw.common.util.T;
|
import net.geedge.asw.common.util.T;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package net.geedge.asw.module.runner.client;
|
package net.geedge.asw.module.feign.client;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONArray;
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
import feign.Param;
|
import feign.Param;
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package net.geedge.asw.module.feign.client;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import feign.Headers;
|
||||||
|
import feign.Param;
|
||||||
|
import feign.RequestLine;
|
||||||
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
|
|
||||||
|
@FeignClient(name = "kibanaClient")
|
||||||
|
@Headers("Authorization: Bearer {token}")
|
||||||
|
public interface KibanaClient {
|
||||||
|
|
||||||
|
@RequestLine("GET /api/saved_objects/_find?fields=title&per_page=10000&type=index-pattern&search_fields=title&search={name}")
|
||||||
|
JSONObject findIndexPattern(@Param("token") String token, @Param("name") String name);
|
||||||
|
|
||||||
|
@Headers({
|
||||||
|
"Content-Type: application/json",
|
||||||
|
"osd-xsrf: true"
|
||||||
|
})
|
||||||
|
@RequestLine("POST /api/saved_objects/index-pattern/{id}")
|
||||||
|
JSONObject saveIndexPattern(@Param("token") String token, @Param("id") String id, JSONObject body);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package net.geedge.asw.module.runner.client;
|
package net.geedge.asw.module.feign.client;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONArray;
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
import feign.Headers;
|
import feign.Headers;
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
* or implied. See the License for the specific language governing permissions and limitations under
|
||||||
* the License.
|
* the License.
|
||||||
*/
|
*/
|
||||||
package net.geedge.asw.common.config.feign;
|
package net.geedge.asw.module.feign.support;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import com.alibaba.fastjson2.JSONException;
|
import com.alibaba.fastjson2.JSONException;
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
* or implied. See the License for the specific language governing permissions and limitations under
|
||||||
* the License.
|
* the License.
|
||||||
*/
|
*/
|
||||||
package net.geedge.asw.common.config.feign;
|
package net.geedge.asw.module.feign.support;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import com.alibaba.fastjson2.JSONWriter;
|
import com.alibaba.fastjson2.JSONWriter;
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
* or implied. See the License for the specific language governing permissions and limitations under
|
* or implied. See the License for the specific language governing permissions and limitations under
|
||||||
* the License.
|
* the License.
|
||||||
*/
|
*/
|
||||||
package net.geedge.asw.common.config.feign;
|
package net.geedge.asw.module.feign.support;
|
||||||
|
|
||||||
import feign.*;
|
import feign.*;
|
||||||
import feign.Request.Options;
|
import feign.Request.Options;
|
||||||
@@ -7,8 +7,8 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import net.geedge.asw.common.config.SpringContextUtils;
|
import net.geedge.asw.common.config.SpringContextUtils;
|
||||||
import net.geedge.asw.common.util.T;
|
import net.geedge.asw.common.util.T;
|
||||||
import net.geedge.asw.module.runner.client.GeoipClient;
|
import net.geedge.asw.module.feign.client.GeoipClient;
|
||||||
import net.geedge.asw.module.runner.client.ZeekClient;
|
import net.geedge.asw.module.feign.client.ZeekClient;
|
||||||
import net.geedge.asw.module.runner.entity.PcapEntity;
|
import net.geedge.asw.module.runner.entity.PcapEntity;
|
||||||
import net.geedge.asw.module.runner.service.IPcapService;
|
import net.geedge.asw.module.runner.service.IPcapService;
|
||||||
import org.apache.commons.lang3.time.StopWatch;
|
import org.apache.commons.lang3.time.StopWatch;
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ public class SysAuthController {
|
|||||||
|
|
||||||
String sign = jwt.sign(JWTSignerUtil.hs256(saTokenConfig.getJwtSecretKey().getBytes()));
|
String sign = jwt.sign(JWTSignerUtil.hs256(saTokenConfig.getJwtSecretKey().getBytes()));
|
||||||
tokenInfo.setTokenValue(sign);
|
tokenInfo.setTokenValue(sign);
|
||||||
|
StpUtil.setTokenValue(sign);
|
||||||
|
|
||||||
userEntity.setPwd(null);
|
userEntity.setPwd(null);
|
||||||
return R.ok().putData("tokenInfo", tokenInfo).putData("user", userEntity);
|
return R.ok().putData("tokenInfo", tokenInfo).putData("user", userEntity);
|
||||||
|
|||||||
Reference in New Issue
Block a user