Skip to content

Commit

Permalink
adds threat intel alert status update API for Acknowledged and Comple…
Browse files Browse the repository at this point in the history
…ted States (opensearch-project#1104)

Signed-off-by: Surya Sashank Nistala <snistala@amazon.com>
  • Loading branch information
eirsep authored and AWSHurneyt committed Jun 27, 2024
1 parent 56a4575 commit c9a4d11
Show file tree
Hide file tree
Showing 15 changed files with 948 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@
import org.opensearch.securityanalytics.threatIntel.action.monitor.GetThreatIntelAlertsAction;
import org.opensearch.securityanalytics.threatIntel.action.monitor.IndexThreatIntelMonitorAction;
import org.opensearch.securityanalytics.threatIntel.action.monitor.SearchThreatIntelMonitorAction;
import org.opensearch.securityanalytics.threatIntel.action.monitor.UpdateThreatIntelAlertStatusAction;
import org.opensearch.securityanalytics.threatIntel.common.TIFLockService;
import org.opensearch.securityanalytics.threatIntel.feedMetadata.BuiltInTIFMetadataLoader;
import org.opensearch.securityanalytics.threatIntel.iocscan.dao.IocFindingService;
Expand All @@ -150,6 +151,7 @@
import org.opensearch.securityanalytics.threatIntel.resthandler.monitor.RestGetThreatIntelAlertsAction;
import org.opensearch.securityanalytics.threatIntel.resthandler.monitor.RestIndexThreatIntelMonitorAction;
import org.opensearch.securityanalytics.threatIntel.resthandler.monitor.RestSearchThreatIntelMonitorAction;
import org.opensearch.securityanalytics.threatIntel.resthandler.monitor.RestUpdateThreatIntelAlertsStatusAction;
import org.opensearch.securityanalytics.threatIntel.service.DetectorThreatIntelService;
import org.opensearch.securityanalytics.threatIntel.service.SATIFSourceConfigManagementService;
import org.opensearch.securityanalytics.threatIntel.service.SATIFSourceConfigService;
Expand All @@ -167,6 +169,7 @@
import org.opensearch.securityanalytics.threatIntel.transport.monitor.TransportGetThreatIntelAlertsAction;
import org.opensearch.securityanalytics.threatIntel.transport.monitor.TransportIndexThreatIntelMonitorAction;
import org.opensearch.securityanalytics.threatIntel.transport.monitor.TransportSearchThreatIntelMonitorAction;
import org.opensearch.securityanalytics.threatIntel.transport.monitor.TransportUpdateThreatIntelAlertStatusAction;
import org.opensearch.securityanalytics.transport.TransportAcknowledgeAlertsAction;
import org.opensearch.securityanalytics.transport.TransportCorrelateFindingAction;
import org.opensearch.securityanalytics.transport.TransportCreateIndexMappingsAction;
Expand Down Expand Up @@ -234,6 +237,7 @@ public class SecurityAnalyticsPlugin extends Plugin implements ActionPlugin, Map
public static final String THREAT_INTEL_MONITOR_URI = PLUGINS_BASE_URI + "/threat_intel/monitors";
public static final String LIST_IOCS_URI = PLUGINS_BASE_URI + "/threat_intel/iocs";
public static final String THREAT_INTEL_ALERTS_URI = PLUGINS_BASE_URI + "/threat_intel/alerts";
public static final String THREAT_INTEL_ALERTS_STATUS_URI = PLUGINS_BASE_URI + "/threat_intel/alerts/status";
public static final String TEST_CONNECTION_BASE_URI = PLUGINS_BASE_URI + "/connections/%s/test";
public static final String TEST_S3_CONNECTION_URI = String.format(TEST_CONNECTION_BASE_URI, "s3");

Expand Down Expand Up @@ -346,6 +350,7 @@ public List<RestHandler> getRestHandlers(Settings settings,
new RestGetMappingsViewAction(),
new RestGetAlertsAction(),
new RestGetThreatIntelAlertsAction(),
new RestUpdateThreatIntelAlertsStatusAction(),
new RestIndexRuleAction(),
new RestSearchRuleAction(),
new RestDeleteRuleAction(),
Expand Down Expand Up @@ -510,6 +515,7 @@ public List<Setting<?>> getSettings() {
new ActionPlugin.ActionHandler<>(ListCorrelationsAction.INSTANCE, TransportListCorrelationAction.class),
new ActionPlugin.ActionHandler<>(SearchCorrelationRuleAction.INSTANCE, TransportSearchCorrelationRuleAction.class),
new ActionPlugin.ActionHandler<>(GetThreatIntelAlertsAction.INSTANCE, TransportGetThreatIntelAlertsAction.class),
new ActionPlugin.ActionHandler<>(UpdateThreatIntelAlertStatusAction.INSTANCE, TransportUpdateThreatIntelAlertStatusAction.class),
new ActionHandler<>(IndexCustomLogTypeAction.INSTANCE, TransportIndexCustomLogTypeAction.class),
new ActionHandler<>(SearchCustomLogTypeAction.INSTANCE, TransportSearchCustomLogTypeAction.class),
new ActionHandler<>(DeleteCustomLogTypeAction.INSTANCE, TransportDeleteCustomLogTypeAction.class),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import org.opensearch.core.common.io.stream.StreamOutput;
import org.opensearch.core.xcontent.XContentBuilder;
import org.opensearch.core.xcontent.XContentParser;
import org.opensearch.index.seqno.SequenceNumbers;
import org.opensearch.securityanalytics.threatIntel.sacommons.monitor.ThreatIntelAlertDto;
import org.opensearch.securityanalytics.util.XContentUtils;

import java.io.IOException;
Expand Down Expand Up @@ -40,13 +42,17 @@ public class ThreatIntelAlert extends BaseEntity {
public static final String IOC_VALUE_FIELD = "ioc_value";
public static final String IOC_TYPE_FIELD = "ioc_type";
public static final String FINDING_IDS_FIELD = "finding_ids";
public static final String SEQ_NO_FIELD = "seq_no";
public static final String PRIMARY_TERM_FIELD = "primary_term";
public static final String NO_ID = "";
public static final long NO_VERSION = 1L;
public static final long NO_SCHEMA_VERSION = 0;

private final String id;
private final long version;
private final long schemaVersion;
private final long seqNo;
private final long primaryTerm;
private final User user;
private final String triggerName;
private final String triggerId;
Expand Down Expand Up @@ -89,6 +95,55 @@ public ThreatIntelAlert(
this.id = id != null ? id : NO_ID;
this.version = version != 0 ? version : NO_VERSION;
this.schemaVersion = schemaVersion;
this.seqNo = SequenceNumbers.UNASSIGNED_SEQ_NO;
this.primaryTerm = SequenceNumbers.UNASSIGNED_PRIMARY_TERM;
this.user = user;
this.triggerId = triggerId;
this.triggerName = triggerName;
this.monitorId = monitorId;
this.monitorName = monitorName;
this.state = state;
this.startTime = startTime;
this.endTime = endTime;
this.acknowledgedTime = acknowledgedTime;
this.errorMessage = errorMessage;
this.severity = severity;
this.iocValue = iocValue;
this.iocType = iocType;
this.actionExecutionResults = actionExecutionResults;
this.lastUpdatedTime = lastUpdatedTime;
this.findingIds = findingIds;
}

public ThreatIntelAlert(
String id,
long version,
long schemaVersion,
long seqNo,
long primaryTerm,
User user,
String triggerId,
String triggerName,
String monitorId,
String monitorName,
Alert.State state,
Instant startTime,
Instant endTime,
Instant lastUpdatedTime,
Instant acknowledgedTime,
String errorMessage,
String severity,
String iocValue,
String iocType,
List<ActionExecutionResult> actionExecutionResults,
List<String> findingIds
) {

this.id = id != null ? id : NO_ID;
this.version = version != 0 ? version : NO_VERSION;
this.schemaVersion = schemaVersion;
this.seqNo = seqNo;
this.primaryTerm = primaryTerm;
this.user = user;
this.triggerId = triggerId;
this.triggerName = triggerName;
Expand All @@ -111,6 +166,8 @@ public ThreatIntelAlert(StreamInput sin) throws IOException {
this.id = sin.readString();
this.version = sin.readLong();
this.schemaVersion = sin.readLong();
this.seqNo = sin.readLong();
this.primaryTerm = sin.readLong();
this.user = sin.readBoolean() ? new User(sin) : null;
this.triggerId = sin.readString();
this.triggerName = sin.readString();
Expand All @@ -134,6 +191,8 @@ public ThreatIntelAlert(ThreatIntelAlert currentAlert, List<String> findingIds)
this.id = currentAlert.id;
this.version = currentAlert.version;
this.schemaVersion = currentAlert.schemaVersion;
this.seqNo =currentAlert.seqNo;
this.primaryTerm =currentAlert.primaryTerm;
this.user = currentAlert.user;
this.triggerId = currentAlert.triggerId;
this.triggerName = currentAlert.triggerName;
Expand All @@ -151,6 +210,32 @@ public ThreatIntelAlert(ThreatIntelAlert currentAlert, List<String> findingIds)
this.lastUpdatedTime = Instant.now();
}

public static ThreatIntelAlert updateStatus(ThreatIntelAlert currentAlert, Alert.State newState) {
return new ThreatIntelAlert(
currentAlert.id,
currentAlert.version,
currentAlert.schemaVersion,
currentAlert.seqNo,
currentAlert.primaryTerm,
currentAlert.user,
currentAlert.triggerId,
currentAlert.triggerName,
currentAlert.monitorId,
currentAlert.monitorName,
newState,
currentAlert.startTime,
newState.equals(Alert.State.COMPLETED) ? Instant.now() : currentAlert.endTime,
Instant.now(),
newState.equals(Alert.State.ACKNOWLEDGED) ? Instant.now() : currentAlert.endTime,
currentAlert.errorMessage,
currentAlert.severity,
currentAlert.iocValue,
currentAlert.iocType,
currentAlert.actionExecutionResults,
currentAlert.getFindingIds()
);
}

public boolean isAcknowledged() {
return state == Alert.State.ACKNOWLEDGED;
}
Expand All @@ -160,6 +245,8 @@ public void writeTo(StreamOutput out) throws IOException {
out.writeString(id);
out.writeLong(version);
out.writeLong(schemaVersion);
out.writeLong(seqNo);
out.writeLong(primaryTerm);
out.writeBoolean(user != null);
if (user != null) {
user.writeTo(out);
Expand All @@ -181,9 +268,128 @@ public void writeTo(StreamOutput out) throws IOException {
out.writeStringCollection(findingIds);
}

public static ThreatIntelAlert parse(XContentParser xcp, long version, long seqNo, long primaryTerm) throws IOException {
String id = NO_ID;
long schemaVersion = NO_SCHEMA_VERSION;
User user = null;
String triggerId = null;
String triggerName = null;
String monitorId = null;
String monitorName = null;
Alert.State state = null;
Instant startTime = null;
String severity = null;
Instant endTime = null;
Instant acknowledgedTime = null;
Instant lastUpdatedTime = null;
String errorMessage = null;
List<ActionExecutionResult> actionExecutionResults = new ArrayList<>();
String iocValue = null;
String iocType = null;
List<String> findingIds = new ArrayList<>();

while (xcp.nextToken() != XContentParser.Token.END_OBJECT) {
String fieldName = xcp.currentName();
xcp.nextToken();
switch (fieldName) {
case USER_FIELD:
user = xcp.currentToken() == XContentParser.Token.VALUE_NULL ? null : User.parse(xcp);
break;
case ALERT_ID_FIELD:
id = xcp.text();
break;
case IOC_VALUE_FIELD:
iocValue = xcp.textOrNull();
break;
case IOC_TYPE_FIELD:
iocType = xcp.textOrNull();
break;
case ALERT_VERSION_FIELD:
version = xcp.longValue();
break;
case SCHEMA_VERSION_FIELD:
schemaVersion = xcp.intValue();
break;
case SEQ_NO_FIELD:
seqNo = xcp.longValue();
break;
case PRIMARY_TERM_FIELD:
primaryTerm = xcp.longValue();
break;
case TRIGGER_ID_FIELD:
triggerId = xcp.text();
break;
case TRIGGER_NAME_FIELD:
triggerName = xcp.text();
break;
case MONITOR_ID_FIELD:
monitorId = xcp.text();
break;
case MONITOR_NAME_FIELD:
monitorName = xcp.text();
break;
case STATE_FIELD:
state = Alert.State.valueOf(xcp.text());
break;
case ERROR_MESSAGE_FIELD:
errorMessage = xcp.textOrNull();
break;
case SEVERITY_FIELD:
severity = xcp.text();
break;
case ACTION_EXECUTION_RESULTS_FIELD:
ensureExpectedToken(XContentParser.Token.START_ARRAY, xcp.currentToken(), xcp);
while (xcp.nextToken() != XContentParser.Token.END_ARRAY) {
actionExecutionResults.add(ActionExecutionResult.parse(xcp));
}
break;
case START_TIME_FIELD:
startTime = getInstant(xcp);
break;
case END_TIME_FIELD:
endTime = getInstant(xcp);
break;
case ACKNOWLEDGED_TIME_FIELD:
acknowledgedTime = getInstant(xcp);
break;
case LAST_UPDATED_TIME_FIELD:
lastUpdatedTime = getInstant(xcp);
break;
case FINDING_IDS_FIELD:
ensureExpectedToken(XContentParser.Token.START_ARRAY, xcp.currentToken(), xcp);
while (xcp.nextToken() != XContentParser.Token.END_ARRAY) {
findingIds.add(xcp.text());
}
default:
xcp.skipChildren();
}
}

return new ThreatIntelAlert(id,
version,
schemaVersion,
seqNo,
primaryTerm,
user,
triggerId,
triggerName,
monitorId,
monitorName,
state,
startTime,
endTime,
acknowledgedTime,
lastUpdatedTime,
errorMessage,
severity,
iocValue, iocType, actionExecutionResults, findingIds);
}

public static ThreatIntelAlert parse(XContentParser xcp, long version) throws IOException {
String id = NO_ID;
long schemaVersion = NO_SCHEMA_VERSION;
long seqNo = SequenceNumbers.UNASSIGNED_SEQ_NO;
long primaryTerm = SequenceNumbers.UNASSIGNED_PRIMARY_TERM;
User user = null;
String triggerId = null;
String triggerName = null;
Expand Down Expand Up @@ -223,6 +429,12 @@ public static ThreatIntelAlert parse(XContentParser xcp, long version) throws IO
case SCHEMA_VERSION_FIELD:
schemaVersion = xcp.intValue();
break;
case SEQ_NO_FIELD:
seqNo = xcp.longValue();
break;
case PRIMARY_TERM_FIELD:
primaryTerm = xcp.longValue();
break;
case TRIGGER_ID_FIELD:
triggerId = xcp.text();
break;
Expand Down Expand Up @@ -275,6 +487,8 @@ public static ThreatIntelAlert parse(XContentParser xcp, long version) throws IO
return new ThreatIntelAlert(id,
version,
schemaVersion,
seqNo,
primaryTerm,
user,
triggerId,
triggerName,
Expand Down Expand Up @@ -313,6 +527,8 @@ private XContentBuilder createXContentBuilder(XContentBuilder builder, boolean s
.field(ALERT_ID_FIELD, id)
.field(ALERT_VERSION_FIELD, version)
.field(SCHEMA_VERSION_FIELD, schemaVersion)
.field(SEQ_NO_FIELD, seqNo)
.field(PRIMARY_TERM_FIELD, primaryTerm)
.field(TRIGGER_NAME_FIELD, triggerName)
.field(TRIGGER_ID_FIELD, triggerId)
.field(MONITOR_ID_FIELD, monitorId)
Expand Down Expand Up @@ -428,4 +644,12 @@ public String getMonitorId() {
public String getMonitorName() {
return monitorName;
}

public long getSeqNo() {
return seqNo;
}

public long getPrimaryTerm() {
return primaryTerm;
}
}
Loading

0 comments on commit c9a4d11

Please sign in to comment.