Skip to content

Commit 08b3615

Browse files
committed
feat: implement service to automatically assign asset groups to alerts
1 parent 5cc2ab7 commit 08b3615

15 files changed

Lines changed: 181 additions & 70 deletions

File tree

backend/src/main/java/com/park/utmstack/aop/logging/impl/AlertLoggingAspect.java

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import com.park.utmstack.domain.chart_builder.types.query.FilterType;
66
import com.park.utmstack.domain.chart_builder.types.query.OperatorType;
77
import com.park.utmstack.domain.index_pattern.enums.SystemIndexPattern;
8-
import com.park.utmstack.domain.shared_types.alert.AlertType;
8+
import com.park.utmstack.domain.shared_types.alert.UtmAlert;
99
import com.park.utmstack.security.SecurityUtils;
1010
import com.park.utmstack.service.UtmAlertLogService;
1111
import com.park.utmstack.service.elasticsearch.ElasticsearchService;
@@ -87,14 +87,14 @@ public Object logManualAlertStatusChange(ProceedingJoinPoint joinPoint) throws T
8787
Integer status = (Integer) args[1];
8888
String statusObservation = (String) args[2];
8989

90-
List<AlertType> alerts = getAlerts(alertIds);
90+
List<UtmAlert> alerts = getAlerts(alertIds);
9191

9292
joinPoint.proceed();
9393

9494
if (CollectionUtils.isEmpty(alerts))
9595
return null;
9696

97-
for (AlertType alert : alerts) {
97+
for (UtmAlert alert : alerts) {
9898
UtmAlertLog alertLog = new UtmAlertLog();
9999
alertLog.setAlertId(alert.getId());
100100
alertLog.setLogUser(SecurityUtils.getCurrentUserLogin().orElse("system"));
@@ -146,19 +146,19 @@ public Object logAutomaticAlertStatusChange(ProceedingJoinPoint joinPoint) throw
146146
.size(Constants.LOG_ANALYZER_TOTAL_RESULTS)
147147
.query(query));
148148

149-
HitsMetadata<AlertType> response = elasticsearchService.search(sr, AlertType.class).hits();
149+
HitsMetadata<UtmAlert> response = elasticsearchService.search(sr, UtmAlert.class).hits();
150150

151151
joinPoint.proceed();
152152

153153
if (response.total().value() <= 0)
154154
return null;
155155

156-
List<AlertType> alerts = response.hits().stream().map(Hit::source).collect(Collectors.toList());
156+
List<UtmAlert> alerts = response.hits().stream().map(Hit::source).collect(Collectors.toList());
157157

158158
if (CollectionUtils.isEmpty(alerts))
159159
return null;
160160

161-
for (AlertType alert : alerts) {
161+
for (UtmAlert alert : alerts) {
162162
UtmAlertLog alertLog = new UtmAlertLog();
163163
alertLog.setAlertId(alert.getId());
164164
alertLog.setLogUser("system");
@@ -197,7 +197,7 @@ public Object logManualAlertTagsChange(ProceedingJoinPoint joinPoint) throws Thr
197197
List alertIds = (List) args[0];
198198
List tags = (List) args[1];
199199

200-
List<AlertType> alerts = getAlerts(alertIds);
200+
List<UtmAlert> alerts = getAlerts(alertIds);
201201

202202
joinPoint.proceed();
203203

@@ -206,7 +206,7 @@ public Object logManualAlertTagsChange(ProceedingJoinPoint joinPoint) throws Thr
206206

207207
String user = SecurityUtils.getCurrentUserLogin().orElse("system");
208208

209-
for (AlertType alert : alerts) {
209+
for (UtmAlert alert : alerts) {
210210
UtmAlertLog alertLog = new UtmAlertLog();
211211
alertLog.setAlertId(alert.getId());
212212
alertLog.setLogUser(user);
@@ -247,21 +247,21 @@ public Object logAutomaticAlertTagsChange(ProceedingJoinPoint joinPoint) throws
247247
SearchRequest request = SearchRequest.of(s -> s.query(query)
248248
.size(Constants.LOG_ANALYZER_TOTAL_RESULTS).index(indexPattern));
249249

250-
HitsMetadata<AlertType> hits = elasticsearchService.search(request, AlertType.class).hits();
250+
HitsMetadata<UtmAlert> hits = elasticsearchService.search(request, UtmAlert.class).hits();
251251

252252
joinPoint.proceed();
253253

254254
if (hits.total().value() <= 0)
255255
return null;
256256

257-
List<AlertType> alerts = hits.hits().stream().map(Hit::source).collect(Collectors.toList());
257+
List<UtmAlert> alerts = hits.hits().stream().map(Hit::source).collect(Collectors.toList());
258258

259259
if (CollectionUtils.isEmpty(alerts))
260260
return null;
261261

262262
String user = SecurityUtils.getCurrentUserLogin().orElse("system");
263263

264-
for (AlertType alert : alerts) {
264+
for (UtmAlert alert : alerts) {
265265
UtmAlertLog alertLog = new UtmAlertLog();
266266
alertLog.setAlertId(alert.getId());
267267
alertLog.setLogUser(user);
@@ -294,7 +294,7 @@ public Object logManualAlertNotesChange(ProceedingJoinPoint joinPoint) throws Th
294294
String alertId = (String) args[0];
295295
String notes = (String) args[1];
296296

297-
List<AlertType> alerts = getAlerts(Collections.singletonList(alertId));
297+
List<UtmAlert> alerts = getAlerts(Collections.singletonList(alertId));
298298

299299
joinPoint.proceed();
300300

@@ -303,7 +303,7 @@ public Object logManualAlertNotesChange(ProceedingJoinPoint joinPoint) throws Th
303303

304304
String user = SecurityUtils.getCurrentUserLogin().orElse("system");
305305

306-
for (AlertType alert : alerts) {
306+
for (UtmAlert alert : alerts) {
307307
UtmAlertLog alertLog = new UtmAlertLog();
308308
alertLog.setAlertId(alert.getId());
309309
alertLog.setLogUser(user);
@@ -347,19 +347,19 @@ public Object logConvertToIncident(ProceedingJoinPoint joinPoint) throws Throwab
347347
SearchRequest request = SearchRequest.of(s -> s.size(Constants.LOG_ANALYZER_TOTAL_RESULTS)
348348
.query(query).index(indexPattern));
349349

350-
HitsMetadata<AlertType> hits = elasticsearchService.search(request, AlertType.class).hits();
350+
HitsMetadata<UtmAlert> hits = elasticsearchService.search(request, UtmAlert.class).hits();
351351

352352
joinPoint.proceed();
353353

354354
if (hits.total().value() <= 0)
355355
return null;
356356

357-
List<AlertType> alerts = hits.hits().stream().map(Hit::source).collect(Collectors.toList());
357+
List<UtmAlert> alerts = hits.hits().stream().map(Hit::source).collect(Collectors.toList());
358358

359359
if (CollectionUtils.isEmpty(alerts))
360360
return null;
361361

362-
for (AlertType alert : alerts) {
362+
for (UtmAlert alert : alerts) {
363363
UtmAlertLog alertLog = new UtmAlertLog();
364364
alertLog.setAlertId(alert.getId());
365365
alertLog.setLogUser(incidentCreatedBy);
@@ -393,14 +393,14 @@ public Object logConvertToIncident(ProceedingJoinPoint joinPoint) throws Throwab
393393
* @return
394394
* @throws Exception
395395
*/
396-
private List<AlertType> getAlerts(List<?> ids) throws Exception {
396+
private List<UtmAlert> getAlerts(List<?> ids) throws Exception {
397397
final String ctx = CLASS_NAME + ".getAlerts";
398398
try {
399399
List<FilterType> filters = new ArrayList<>();
400400
filters.add(new FilterType(Constants.alertIdKeyword, OperatorType.IS_ONE_OF_TERMS, ids));
401401
SearchRequest request = SearchRequest.of(s -> s.query(SearchUtil.toQuery(filters))
402402
.index(Constants.SYS_INDEX_PATTERN.get(SystemIndexPattern.ALERTS)));
403-
HitsMetadata<AlertType> hits = elasticsearchService.search(request, AlertType.class).hits();
403+
HitsMetadata<UtmAlert> hits = elasticsearchService.search(request, UtmAlert.class).hits();
404404
if (hits.total().value() <= 0)
405405
return Collections.emptyList();
406406
return hits.hits().stream().map(Hit::source).collect(Collectors.toList());

backend/src/main/java/com/park/utmstack/domain/reports/types/IncidentType.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
package com.park.utmstack.domain.reports.types;
22

33
import com.park.utmstack.domain.incident_response.UtmIncidentJob;
4-
import com.park.utmstack.domain.shared_types.alert.AlertType;
4+
import com.park.utmstack.domain.shared_types.alert.UtmAlert;
55

66
import java.util.List;
77

88
public class IncidentType {
9-
private AlertType incident;
9+
private UtmAlert incident;
1010
private List<UtmIncidentJob> srcResponses;
1111
private List<UtmIncidentJob> destResponses;
1212

13-
public AlertType getIncident() {
13+
public UtmAlert getIncident() {
1414
return incident;
1515
}
1616

17-
public void setIncident(AlertType incident) {
17+
public void setIncident(UtmAlert incident) {
1818
this.incident = incident;
1919
}
2020

backend/src/main/java/com/park/utmstack/domain/shared_types/alert/AlertType.java renamed to backend/src/main/java/com/park/utmstack/domain/shared_types/alert/UtmAlert.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
@JsonIgnoreProperties(ignoreUnknown = true)
1919
@Getter
2020
@Setter
21-
public class AlertType {
21+
public class UtmAlert {
2222
@JsonProperty("@timestamp")
2323
private String timestamp;
2424

@@ -106,6 +106,10 @@ public class AlertType {
106106
@JsonProperty("logs")
107107
private List<String> logs;
108108

109+
private String assetGroupName;
110+
111+
private Long assetGroupId;
112+
109113
public Instant getTimestampAsInstant() {
110114
if (StringUtils.hasText(timestamp))
111115
return Instant.parse(timestamp);

backend/src/main/java/com/park/utmstack/repository/network_scan/UtmNetworkScanRepository.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,10 @@ void updateGroup(@Param("assetIds") List<Long> assetIds,
123123

124124
@Query(nativeQuery = true, value = "select n.asset_name from utm_network_scan n where n.asset_name is not null and n.is_agent is true and n.asset_alive is true and n.asset_status <> 'MISSING' and n.asset_os_platform = :platform")
125125
List<String> findAgentNamesByPlatform(@Param("platform") String platform);
126+
127+
@Query("SELECT ns.assetName, ns.groupId, ag.groupName " +
128+
"FROM UtmNetworkScan ns " +
129+
"JOIN UtmAssetGroup ag ON ns.groupId = ag.id " +
130+
"WHERE ns.groupId IS NOT NULL")
131+
List<Object[]> findAllAssetGroupMappings();
126132
}

backend/src/main/java/com/park/utmstack/service/MailService.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import com.park.utmstack.domain.application_events.enums.ApplicationEventType;
66
import com.park.utmstack.domain.incident.UtmIncident;
77
import com.park.utmstack.domain.mail_sender.MailConfig;
8-
import com.park.utmstack.domain.shared_types.alert.AlertType;
8+
import com.park.utmstack.domain.shared_types.alert.UtmAlert;
99
import com.park.utmstack.domain.shared_types.LogType;
1010
import com.park.utmstack.service.application_events.ApplicationEventService;
1111
import com.park.utmstack.service.mail_sender.BaseMailSender;
@@ -250,7 +250,7 @@ public void sendPasswordResetMail(User user) {
250250
}
251251

252252
@Async
253-
public void sendAlertEmail(List<String> emailsTo, AlertType alert, List<LogType> relatedLogs) {
253+
public void sendAlertEmail(List<String> emailsTo, UtmAlert alert, List<LogType> relatedLogs) {
254254
final String ctx = CLASS_NAME + ".sendAlertEmail";
255255
try {
256256
JavaMailSender javaMailSender = getJavaMailSender();
@@ -289,7 +289,7 @@ public void sendAlertEmail(List<String> emailsTo, AlertType alert, List<LogType>
289289
}
290290

291291
@Async
292-
public void sendIncidentEmail(List<String> emailsTo, List<AlertType> alerts, UtmIncident incident) {
292+
public void sendIncidentEmail(List<String> emailsTo, List<UtmAlert> alerts, UtmIncident incident) {
293293
final String ctx = CLASS_NAME + ".sendIncidentEmail";
294294
try {
295295
JavaMailSender javaMailSender = getJavaMailSender();
@@ -332,7 +332,7 @@ public void sendIncidentEmail(List<String> emailsTo, List<AlertType> alerts, Utm
332332
* @return ByteArrayResource object with attachment to alert mail
333333
* @throws Exception In case of any error
334334
*/
335-
private ByteArrayResource buildAlertEmailAttachment(Context context, AlertType alert,
335+
private ByteArrayResource buildAlertEmailAttachment(Context context, UtmAlert alert,
336336
List<LogType> relatedLogs) throws Exception {
337337
final String ctx = CLASS_NAME + ".buildAlertEmailAttachment";
338338
try {

backend/src/main/java/com/park/utmstack/service/UtmAlertService.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.park.utmstack.service;
22

33
import com.park.utmstack.domain.chart_builder.types.query.FilterType;
4-
import com.park.utmstack.domain.shared_types.alert.AlertType;
4+
import com.park.utmstack.domain.shared_types.alert.UtmAlert;
55
import com.park.utmstack.domain.shared_types.static_dashboard.CardType;
66
import com.park.utmstack.util.exceptions.DashboardOverviewException;
77
import com.park.utmstack.util.exceptions.ElasticsearchIndexDocumentUpdateException;
@@ -26,7 +26,7 @@ void updateStatus(List<String> alertIds, int status, String statusObservation) t
2626

2727
void convertToIncident(List<String> eventIds, String incidentName, Integer incidentId, String incidentSource) throws ElasticsearchIndexDocumentUpdateException;
2828

29-
List<AlertType> getAlertsByIds(List<String> ids) throws UtmElasticsearchException;
29+
List<UtmAlert> getAlertsByIds(List<String> ids) throws UtmElasticsearchException;
3030

3131
void updateStatusAndTag(List<String> alertIds, int status, String statusObservation) throws UtmElasticsearchException,
3232
IOException, ElasticsearchIndexDocumentUpdateException;

backend/src/main/java/com/park/utmstack/service/UtmAlertTagRuleService.java

Lines changed: 65 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@
1212
import com.park.utmstack.service.application_events.ApplicationEventService;
1313
import com.park.utmstack.service.elasticsearch.ElasticsearchService;
1414
import com.park.utmstack.service.elasticsearch.SearchUtil;
15+
import com.park.utmstack.service.network_scan.AlertAssetGroupService;
1516
import com.park.utmstack.util.AlertUtil;
1617
import com.park.utmstack.util.enums.AlertStatus;
1718
import com.park.utmstack.util.events.RulesEvaluationEndEvent;
1819
import com.park.utmstack.web.rest.vm.AlertTagRuleFilterVM;
20+
import lombok.RequiredArgsConstructor;
1921
import org.hibernate.jpa.TypedParameterValue;
2022
import org.hibernate.type.BooleanType;
2123
import org.hibernate.type.LongType;
@@ -38,6 +40,7 @@
3840
import java.time.temporal.ChronoUnit;
3941
import java.util.ArrayList;
4042
import java.util.List;
43+
import java.util.Map;
4144
import java.util.Optional;
4245
import java.util.stream.Collectors;
4346

@@ -46,6 +49,7 @@
4649
*/
4750
@Service
4851
@Transactional
52+
@RequiredArgsConstructor
4953
public class UtmAlertTagRuleService {
5054

5155
private final Logger log = LoggerFactory.getLogger(UtmAlertTagRuleService.class);
@@ -58,22 +62,8 @@ public class UtmAlertTagRuleService {
5862
private final AlertPointcut alertPointcut;
5963
private final UtmAlertTagService alertTagService;
6064
private final ElasticsearchService elasticsearchService;
65+
private final AlertAssetGroupService alertAssetGroupService;
6166

62-
public UtmAlertTagRuleService(UtmAlertTagRuleRepository alertTagRuleRepository,
63-
AlertUtil alertUtil,
64-
ApplicationEventPublisher publisher,
65-
ApplicationEventService eventService,
66-
AlertPointcut alertPointcut,
67-
UtmAlertTagService alertTagService,
68-
ElasticsearchService elasticsearchService) {
69-
this.alertTagRuleRepository = alertTagRuleRepository;
70-
this.alertUtil = alertUtil;
71-
this.publisher = publisher;
72-
this.eventService = eventService;
73-
this.alertPointcut = alertPointcut;
74-
this.alertTagService = alertTagService;
75-
this.elasticsearchService = elasticsearchService;
76-
}
7767

7868
/**
7969
* Save a utmTagRule.
@@ -148,6 +138,9 @@ public void automaticReview() {
148138
if (alertUtil.countAllAlertsByStatus(AlertStatus.AUTOMATIC_REVIEW.getCode()) == 0)
149139
return;
150140

141+
// Assigning asset groups to alerts in automatic review
142+
this.assignAssetGroupsToReviewAlerts();
143+
151144
// Getting all registered rules
152145
List<UtmAlertTagRule> tagRules = alertTagRuleRepository.findAll();
153146

@@ -247,4 +240,61 @@ private void applyTagRule(List<UtmAlertTagRule> rules, Instant rulesEvaluationSt
247240
}
248241
}
249242
}
243+
244+
245+
private void assignAssetGroupsToReviewAlerts() {
246+
final String ctx = CLASSNAME + ".assignAssetGroupsToReviewAlerts";
247+
try {
248+
249+
Map<String, Map<String, Object>> assetGroups =
250+
alertAssetGroupService.getAssetGroupsMapForAlerts();
251+
252+
if (assetGroups.isEmpty()) {
253+
log.debug("{}: No asset-group mappings found", ctx);
254+
return;
255+
}
256+
257+
StringBuilder scriptBuilder = new StringBuilder();
258+
scriptBuilder.append("if (ctx._source.containsKey('dataSource') && ctx._source.dataSource != null) {\n");
259+
260+
for (Map.Entry<String, Map<String, Object>> entry : assetGroups.entrySet()) {
261+
String assetName = entry.getKey();
262+
Long groupId = (Long) entry.getValue().get("id");
263+
String groupName = (String) entry.getValue().get("name");
264+
265+
scriptBuilder.append(String.format(
266+
"""
267+
if (ctx._source.dataSource == '%s') {
268+
ctx._source.assetGroupId = %dL;
269+
ctx._source.assetGroupName = '%s';
270+
}
271+
""",
272+
assetName.replace("'", "\\'"), // Escapar comillas simples
273+
groupId,
274+
groupName.replace("'", "\\'")
275+
));
276+
}
277+
278+
scriptBuilder.append("}");
279+
String script = scriptBuilder.toString();
280+
281+
282+
List<FilterType> filters = new ArrayList<>();
283+
filters.add(new FilterType(Constants.alertStatus, OperatorType.IS,
284+
AlertStatus.AUTOMATIC_REVIEW.getCode()));
285+
filters.add(new FilterType("dataSource", OperatorType.IS_NOT, null));
286+
287+
Query query = SearchUtil.toQuery(filters);
288+
String indexPattern = Constants.SYS_INDEX_PATTERN.get(SystemIndexPattern.ALERTS);
289+
290+
elasticsearchService.updateByQuery(query, indexPattern, script);
291+
292+
log.info("{}: Asset groups assigned to {} alerts", ctx, assetGroups.size());
293+
294+
} catch (Exception e) {
295+
String msg = ctx + ": " + e.getMessage();
296+
eventService.createEvent(msg, ApplicationEventType.ERROR);
297+
log.error(msg, e);
298+
}
299+
}
250300
}

0 commit comments

Comments
 (0)