diff --git a/backend/src/main/java/com/park/utmstack/domain/alert_response_rule/UtmAlertResponseRule.java b/backend/src/main/java/com/park/utmstack/domain/alert_response_rule/UtmAlertResponseRule.java index 3c8f547c1..3df026eda 100644 --- a/backend/src/main/java/com/park/utmstack/domain/alert_response_rule/UtmAlertResponseRule.java +++ b/backend/src/main/java/com/park/utmstack/domain/alert_response_rule/UtmAlertResponseRule.java @@ -9,8 +9,10 @@ import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; import javax.persistence.*; +import javax.validation.constraints.Size; import java.io.Serializable; import java.time.Instant; @@ -38,6 +40,9 @@ public class UtmAlertResponseRule implements Serializable { private String agentPlatform; @Column(name = "excluded_agents") private String excludedAgents; + @Size(max = 500) + @Column(name = "default_agent" , length = 500) + private String defaultAgent; @CreatedBy @Column(name = "created_by", nullable = false, length = 50, updatable = false) private String createdBy; @@ -62,6 +67,7 @@ public UtmAlertResponseRule(UtmAlertResponseRuleDTO dto) { this.ruleCmd = dto.getCommand(); this.ruleActive = dto.getActive(); this.agentPlatform = dto.getAgentPlatform(); + this.defaultAgent = dto.getDefaultAgent(); if (!CollectionUtils.isEmpty(dto.getExcludedAgents())) this.excludedAgents = String.join(",", dto.getExcludedAgents()); else @@ -132,6 +138,14 @@ public void setExcludedAgents(String excludedAgents) { this.excludedAgents = excludedAgents; } + public String getDefaultAgent() { + return defaultAgent; + } + + public void setDefaultAgent(String defaultAgent) { + this.defaultAgent = defaultAgent; + } + public String getCreatedBy() { return createdBy; } diff --git a/backend/src/main/java/com/park/utmstack/service/alert_response_rule/UtmAlertResponseRuleService.java b/backend/src/main/java/com/park/utmstack/service/alert_response_rule/UtmAlertResponseRuleService.java index 2b17708d3..9038a4068 100644 --- a/backend/src/main/java/com/park/utmstack/service/alert_response_rule/UtmAlertResponseRuleService.java +++ b/backend/src/main/java/com/park/utmstack/service/alert_response_rule/UtmAlertResponseRuleService.java @@ -129,37 +129,74 @@ public void evaluateRules(List alerts) { return; List rules = alertResponseRuleRepository.findAllByRuleActiveIsTrue(); - if (CollectionUtils.isEmpty(rules)) - return; // Excluding alerts tagged as false positive alerts = alerts.stream().filter(a -> (CollectionUtils.isEmpty(a.getTags()) || !a.getTags().contains("False positive"))) .collect(Collectors.toList()); + // Do nothing if there is no valid alerts to check + if (CollectionUtils.isEmpty(alerts)) + return; + String alertJsonArray = new Gson().toJson(alerts); for (UtmAlertResponseRule rule : rules) { - List conditions = new ArrayList<>(); List agentNames = networkScanRepository.findAgentNamesByPlatform(rule.getAgentPlatform()); - if (!CollectionUtils.isEmpty(agentNames)) - conditions.add(new FilterType(Constants.alertDataSourceKeyword, OperatorType.IS_ONE_OF, agentNames)); - if (StringUtils.hasText(rule.getRuleConditions())) - conditions.addAll(new Gson().fromJson(rule.getRuleConditions(), TypeToken.getParameterized(List.class, FilterType.class).getType())); + if (CollectionUtils.isEmpty(agentNames)) + continue; + + // Matching agents (these are the alerts made from logs coming from an agent) + //------------------------------------------------------------------------------------------ + createResponseRuleExecution(rule,alertJsonArray,agentNames,true); + + // Then the alerts that match the filters but aren't from an agent, gets executed using the default agent if there is one + //----------------------------------------------------------------------------------------------------------------------- + if (StringUtils.hasText(rule.getDefaultAgent())) { + createResponseRuleExecution(rule,alertJsonArray,agentNames,false); + } + } + } catch (Exception e) { + String msg = ctx + ": " + e.getLocalizedMessage(); + log.error(msg); + eventService.createEvent(msg, ApplicationEventType.ERROR); + } + } + + private void createResponseRuleExecution (UtmAlertResponseRule rule, String alertJsonArray, List agentNames, boolean isAgent) throws Exception { + final String ctx = CLASSNAME + ".createResponseRuleExecution"; + List conditions = new ArrayList<>(); + try { + // Common conditions + if (StringUtils.hasText(rule.getRuleConditions())) + conditions.addAll(new Gson().fromJson(rule.getRuleConditions(), TypeToken.getParameterized(List.class, FilterType.class).getType())); - if (StringUtils.hasText(rule.getExcludedAgents())) - conditions.add(new FilterType(Constants.alertDataSourceKeyword, OperatorType.IS_NOT_ONE_OF, List.of(rule.getExcludedAgents().split(",")))); + if (StringUtils.hasText(rule.getExcludedAgents())) + conditions.add(new FilterType(Constants.alertDataSourceKeyword, OperatorType.IS_NOT_ONE_OF, List.of(rule.getExcludedAgents().split(",")))); - Filter filter = buildFilters(conditions); - List matches = UtilJson.read("$[?]", alertJsonArray, filter); + // Specific condition for agent and non agents + if (isAgent) { + conditions.add(new FilterType(Constants.alertDataSourceKeyword, OperatorType.IS_ONE_OF, agentNames)); + } else { + conditions.add(new FilterType(Constants.alertDataSourceKeyword, OperatorType.IS_NOT_ONE_OF, agentNames)); + } - if (CollectionUtils.isEmpty(matches)) - continue; + // Processing the alerts and generating the rule executions + Filter filter = buildFilters(conditions); + List matches = UtilJson.read("$[?]", alertJsonArray, filter); + + if (!CollectionUtils.isEmpty(matches)) { for (Object match : matches) { String matchAsJson = new Gson().toJson(match); UtmAlertResponseRuleExecution exe = new UtmAlertResponseRuleExecution(); - exe.setAgent(UtilJson.read("$.dataSource", matchAsJson)); + // Execution agent takes the rule's default agent if the alert was generated by logs from non agent datasource + if (isAgent) { + exe.setAgent(UtilJson.read("$.dataSource", matchAsJson)); + } else { + exe.setAgent(rule.getDefaultAgent()); + } + exe.setAlertId(UtilJson.read("$.id", matchAsJson)); exe.setRuleId(rule.getId()); exe.setCommand(buildCommand(rule.getRuleCmd(), matchAsJson)); @@ -167,10 +204,10 @@ public void evaluateRules(List alerts) { alertResponseRuleExecutionRepository.save(exe); } } + } catch (Exception e) { String msg = ctx + ": " + e.getLocalizedMessage(); - log.error(msg); - eventService.createEvent(msg, ApplicationEventType.ERROR); + throw new Exception(msg); } } diff --git a/backend/src/main/java/com/park/utmstack/service/dto/UtmAlertResponseRuleDTO.java b/backend/src/main/java/com/park/utmstack/service/dto/UtmAlertResponseRuleDTO.java index 037afd98c..a8b369a16 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/UtmAlertResponseRuleDTO.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/UtmAlertResponseRuleDTO.java @@ -31,6 +31,8 @@ public class UtmAlertResponseRuleDTO { private Boolean active; @NotBlank private String agentPlatform; + @Size(max = 500) + private String defaultAgent; private List excludedAgents = new ArrayList<>(); @JsonProperty(access = JsonProperty.Access.READ_ONLY) private String createdBy; @@ -52,6 +54,7 @@ public UtmAlertResponseRuleDTO(UtmAlertResponseRule rule) { this.command = rule.getRuleCmd(); this.active = rule.getRuleActive(); this.agentPlatform = rule.getAgentPlatform(); + this.defaultAgent = rule.getDefaultAgent(); if (StringUtils.hasText(rule.getExcludedAgents())) this.excludedAgents.addAll(Arrays.asList(rule.getExcludedAgents().split(","))); this.createdBy = rule.getCreatedBy(); @@ -112,6 +115,14 @@ public String getAgentPlatform() { return agentPlatform; } + public String getDefaultAgent() { + return defaultAgent; + } + + public void setDefaultAgent(String defaultAgent) { + this.defaultAgent = defaultAgent; + } + public void setAgentPlatform(String agentPlatform) { this.agentPlatform = agentPlatform; } diff --git a/backend/src/main/resources/config/liquibase/changelog/20240131001_add_default_agent_utm_alert_response_rule.xml b/backend/src/main/resources/config/liquibase/changelog/20240131001_add_default_agent_utm_alert_response_rule.xml new file mode 100644 index 000000000..994b0a742 --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20240131001_add_default_agent_utm_alert_response_rule.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/master.xml b/backend/src/main/resources/config/liquibase/master.xml index 6cb2c778f..6823824e7 100644 --- a/backend/src/main/resources/config/liquibase/master.xml +++ b/backend/src/main/resources/config/liquibase/master.xml @@ -32,4 +32,6 @@ + +