Skip to content

Commit 33b1fdb

Browse files
eirsepriysaxen-amzn
authored andcommitted
fix detector writeTo() method missing fields (#695)
* fix detector writeTo() method missing fields Signed-off-by: Surya Sashank Nistala <[email protected]> * fix test Signed-off-by: Surya Sashank Nistala <[email protected]> --------- Signed-off-by: Surya Sashank Nistala <[email protected]> # Conflicts: # src/main/java/org/opensearch/securityanalytics/model/Detector.java
1 parent e44e5d4 commit 33b1fdb

File tree

2 files changed

+112
-22
lines changed

2 files changed

+112
-22
lines changed

src/main/java/org/opensearch/securityanalytics/model/Detector.java

Lines changed: 85 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,28 @@
88
import java.util.Map;
99
import org.apache.logging.log4j.LogManager;
1010
import org.apache.logging.log4j.Logger;
11-
import org.opensearch.common.io.stream.StreamInput;
12-
import org.opensearch.common.io.stream.StreamOutput;
13-
import org.opensearch.common.io.stream.Writeable;
14-
import org.opensearch.common.xcontent.XContentParserUtils;
15-
import org.opensearch.commons.alerting.model.CronSchedule;
16-
import org.opensearch.commons.alerting.model.Schedule;
17-
import org.opensearch.commons.authuser.User;
11+
import org.opensearch.core.common.io.stream.StreamInput;
12+
import org.opensearch.core.common.io.stream.StreamOutput;
13+
import org.opensearch.core.common.io.stream.Writeable;
14+
import org.opensearch.core.xcontent.XContentParserUtils;
1815
import org.opensearch.core.ParseField;
1916
import org.opensearch.core.xcontent.NamedXContentRegistry;
2017
import org.opensearch.core.xcontent.ToXContent;
2118
import org.opensearch.core.xcontent.ToXContentObject;
2219
import org.opensearch.core.xcontent.XContentBuilder;
2320
import org.opensearch.core.xcontent.XContentParser;
21+
import org.opensearch.commons.alerting.model.CronSchedule;
22+
import org.opensearch.commons.alerting.model.Schedule;
23+
import org.opensearch.commons.authuser.User;
24+
2425
import java.io.IOException;
2526
import java.time.Instant;
2627
import java.util.ArrayList;
27-
import java.util.Arrays;
2828
import java.util.Collections;
2929
import java.util.List;
3030
import java.util.Locale;
3131
import java.util.Objects;
3232

33-
import java.util.stream.Collectors;
34-
3533
public class Detector implements Writeable, ToXContentObject {
3634

3735
private static final Logger log = LogManager.getLogger(Detector.class);
@@ -50,8 +48,11 @@ public class Detector implements Writeable, ToXContentObject {
5048
public static final String TRIGGERS_FIELD = "triggers";
5149
public static final String LAST_UPDATE_TIME_FIELD = "last_update_time";
5250
public static final String ENABLED_TIME_FIELD = "enabled_time";
51+
public static final String THREAT_INTEL_ENABLED_FIELD = "threat_intel_enabled";
5352
public static final String ALERTING_MONITOR_ID = "monitor_id";
5453

54+
public static final String ALERTING_WORKFLOW_ID = "workflow_ids";
55+
5556
public static final String BUCKET_MONITOR_ID_RULE_ID = "bucket_monitor_id_rule_id";
5657
private static final String RULE_TOPIC_INDEX = "rule_topic_index";
5758

@@ -79,6 +80,8 @@ public class Detector implements Writeable, ToXContentObject {
7980

8081
private String name;
8182

83+
private Boolean threatIntelEnabled;
84+
8285
private Boolean enabled;
8386

8487
private Schedule schedule;
@@ -99,6 +102,8 @@ public class Detector implements Writeable, ToXContentObject {
99102

100103
private Map<String, String> ruleIdMonitorIdMap;
101104

105+
private List<String> workflowIds;
106+
102107
private String ruleIndex;
103108

104109
private String alertsIndex;
@@ -117,7 +122,8 @@ public Detector(String id, Long version, String name, Boolean enabled, Schedule
117122
Instant lastUpdateTime, Instant enabledTime, String logType,
118123
User user, List<DetectorInput> inputs, List<DetectorTrigger> triggers, List<String> monitorIds,
119124
String ruleIndex, String alertsIndex, String alertsHistoryIndex, String alertsHistoryIndexPattern,
120-
String findingsIndex, String findingsIndexPattern, Map<String, String> rulePerMonitor) {
125+
String findingsIndex, String findingsIndexPattern, Map<String, String> rulePerMonitor,
126+
List<String> workflowIds, Boolean threatIntelEnabled) {
121127
this.type = DETECTOR_TYPE;
122128

123129
this.id = id != null ? id : NO_ID;
@@ -139,6 +145,8 @@ public Detector(String id, Long version, String name, Boolean enabled, Schedule
139145
this.findingsIndexPattern = findingsIndexPattern;
140146
this.ruleIdMonitorIdMap = rulePerMonitor;
141147
this.logType = logType;
148+
this.workflowIds = workflowIds != null ? workflowIds : null;
149+
this.threatIntelEnabled = threatIntelEnabled != null && threatIntelEnabled;
142150

143151
if (enabled) {
144152
Objects.requireNonNull(enabledTime);
@@ -159,13 +167,15 @@ public Detector(StreamInput sin) throws IOException {
159167
sin.readList(DetectorInput::readFrom),
160168
sin.readList(DetectorTrigger::readFrom),
161169
sin.readStringList(),
162-
sin.readString(),
163-
sin.readString(),
164-
sin.readString(),
165-
sin.readString(),
166-
sin.readString(),
167-
sin.readString(),
168-
sin.readMap(StreamInput::readString, StreamInput::readString)
170+
sin.readOptionalString(),
171+
sin.readOptionalString(),
172+
sin.readOptionalString(),
173+
sin.readOptionalString(),
174+
sin.readOptionalString(),
175+
sin.readOptionalString(),
176+
sin.readMap(StreamInput::readString, StreamInput::readString),
177+
sin.readStringList(),
178+
sin.readBoolean()
169179
);
170180
}
171181

@@ -197,9 +207,18 @@ public void writeTo(StreamOutput out) throws IOException {
197207
it.writeTo(out);
198208
}
199209
out.writeStringCollection(monitorIds);
200-
out.writeString(ruleIndex);
201-
210+
out.writeOptionalString(ruleIndex);
211+
out.writeOptionalString(alertsIndex);
212+
out.writeOptionalString(alertsHistoryIndex);
213+
out.writeOptionalString(alertsHistoryIndexPattern);
214+
out.writeOptionalString(findingsIndex);
215+
out.writeOptionalString(findingsIndexPattern);
202216
out.writeMap(ruleIdMonitorIdMap, StreamOutput::writeString, StreamOutput::writeString);
217+
218+
if (workflowIds != null) {
219+
out.writeStringCollection(workflowIds);
220+
}
221+
out.writeBoolean(threatIntelEnabled);
203222
}
204223

205224
public XContentBuilder toXContentWithUser(XContentBuilder builder, Params params) throws IOException {
@@ -228,6 +247,7 @@ private XContentBuilder createXContentBuilder(XContentBuilder builder, ToXConten
228247
}
229248
}
230249

250+
builder.field(THREAT_INTEL_ENABLED_FIELD, threatIntelEnabled);
231251
builder.field(ENABLED_FIELD, enabled);
232252

233253
if (enabledTime == null) {
@@ -253,6 +273,14 @@ private XContentBuilder createXContentBuilder(XContentBuilder builder, ToXConten
253273
}
254274

255275
builder.field(ALERTING_MONITOR_ID, monitorIds);
276+
277+
if (workflowIds == null) {
278+
builder.nullField(ALERTING_WORKFLOW_ID);
279+
} else {
280+
builder.field(ALERTING_WORKFLOW_ID, workflowIds);
281+
}
282+
283+
256284
builder.field(BUCKET_MONITOR_ID_RULE_ID, ruleIdMonitorIdMap);
257285
builder.field(RULE_TOPIC_INDEX, ruleIndex);
258286
builder.field(ALERTS_INDEX, alertsIndex);
@@ -261,7 +289,6 @@ private XContentBuilder createXContentBuilder(XContentBuilder builder, ToXConten
261289
builder.field(FINDINGS_INDEX, findingsIndex);
262290
builder.field(FINDINGS_INDEX_PATTERN, findingsIndexPattern);
263291

264-
265292
if (params.paramAsBoolean("with_type", false)) {
266293
builder.endObject();
267294
}
@@ -299,6 +326,7 @@ public static Detector parse(XContentParser xcp, String id, Long version) throws
299326
List<DetectorInput> inputs = new ArrayList<>();
300327
List<DetectorTrigger> triggers = new ArrayList<>();
301328
List<String> monitorIds = new ArrayList<>();
329+
List<String> workflowIds = new ArrayList<>();
302330
Map<String, String> rulePerMonitor = new HashMap<>();
303331

304332
String ruleIndex = null;
@@ -307,6 +335,7 @@ public static Detector parse(XContentParser xcp, String id, Long version) throws
307335
String alertsHistoryIndexPattern = null;
308336
String findingsIndex = null;
309337
String findingsIndexPattern = null;
338+
Boolean enableThreatIntel = false;
310339

311340
XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, xcp.currentToken(), xcp);
312341
while (xcp.nextToken() != XContentParser.Token.END_OBJECT) {
@@ -330,6 +359,9 @@ public static Detector parse(XContentParser xcp, String id, Long version) throws
330359
case ENABLED_FIELD:
331360
enabled = xcp.booleanValue();
332361
break;
362+
case THREAT_INTEL_ENABLED_FIELD:
363+
enableThreatIntel = xcp.booleanValue();
364+
break;
333365
case SCHEDULE_FIELD:
334366
schedule = Schedule.parse(xcp);
335367
break;
@@ -374,6 +406,15 @@ public static Detector parse(XContentParser xcp, String id, Long version) throws
374406
monitorIds.add(monitorId);
375407
}
376408
break;
409+
case ALERTING_WORKFLOW_ID:
410+
XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_ARRAY, xcp.currentToken(), xcp);
411+
while (xcp.nextToken() != XContentParser.Token.END_ARRAY) {
412+
String workflowId = xcp.textOrNull();
413+
if (workflowId != null) {
414+
workflowIds.add(workflowId);
415+
}
416+
}
417+
break;
377418
case BUCKET_MONITOR_ID_RULE_ID:
378419
rulePerMonitor= xcp.mapStrings();
379420
break;
@@ -429,7 +470,9 @@ public static Detector parse(XContentParser xcp, String id, Long version) throws
429470
alertsHistoryIndexPattern,
430471
findingsIndex,
431472
findingsIndexPattern,
432-
rulePerMonitor
473+
rulePerMonitor,
474+
workflowIds,
475+
enableThreatIntel
433476
);
434477
}
435478

@@ -566,10 +609,30 @@ public void setRuleIdMonitorIdMap(Map<String, String> ruleIdMonitorIdMap) {
566609
this.ruleIdMonitorIdMap = ruleIdMonitorIdMap;
567610
}
568611

612+
public void setWorkflowIds(List<String> workflowIds) {
613+
this.workflowIds = workflowIds;
614+
}
615+
616+
public void setThreatIntelEnabled(boolean threatIntelEnabled) {
617+
this.threatIntelEnabled = threatIntelEnabled;
618+
}
619+
620+
public List<String> getWorkflowIds() {
621+
return workflowIds;
622+
}
623+
569624
public String getDocLevelMonitorId() {
570625
return ruleIdMonitorIdMap.get(DOC_LEVEL_MONITOR);
571626
}
572627

628+
public boolean isWorkflowSupported() {
629+
return workflowIds != null && !workflowIds.isEmpty();
630+
}
631+
632+
public Boolean getThreatIntelEnabled() {
633+
return threatIntelEnabled;
634+
}
635+
573636
@Override
574637
public boolean equals(Object o) {
575638
if (this == o) return true;

src/test/java/org/opensearch/securityanalytics/model/WriteableTests.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,42 @@
1313
import java.io.IOException;
1414
import java.util.List;
1515

16+
import static org.opensearch.securityanalytics.TestHelpers.parser;
1617
import static org.opensearch.securityanalytics.TestHelpers.randomDetector;
1718
import static org.opensearch.securityanalytics.TestHelpers.randomUser;
1819
import static org.opensearch.securityanalytics.TestHelpers.randomUserEmpty;
20+
import static org.opensearch.securityanalytics.TestHelpers.toJsonStringWithUser;
1921

2022
public class WriteableTests extends OpenSearchTestCase {
2123

2224
public void testDetectorAsStream() throws IOException {
2325
Detector detector = randomDetector(List.of());
2426
detector.setInputs(List.of(new DetectorInput("", List.of(), List.of(), List.of())));
27+
logger.error(toJsonStringWithUser(detector));
28+
BytesStreamOutput out = new BytesStreamOutput();
29+
detector.writeTo(out);
30+
StreamInput sin = StreamInput.wrap(out.bytes().toBytesRef().bytes);
31+
Detector newDetector = new Detector(sin);
32+
Assert.assertEquals("Round tripping Detector doesn't work", detector, newDetector);
33+
}
34+
35+
public void testDetector() throws IOException { // an edge case of detector serialization that failed testDetectorAsAStream() intermittently
36+
String detectorString = "{\"type\":\"detector\",\"name\":\"MczAuRCrve\",\"detector_type\":\"test_windows\"," +
37+
"\"user\":{\"name\":\"QhKrfthgxw\",\"backend_roles\":[\"uYvGLCPhfX\",\"fOLkcRxMWR\"],\"roles\"" +
38+
":[\"YuucNpVzTm\",\"all_access\"],\"custom_attribute_names\":[\"test_attr=test\"]," +
39+
"\"user_requested_tenant\":null},\"threat_intel_enabled\":false,\"enabled\":false,\"enabled_time\"" +
40+
":null,\"schedule\":{\"period\":{\"interval\":5,\"unit\":\"MINUTES\"}},\"inputs\":[{\"detector_input\"" +
41+
":{\"description\":\"\",\"indices\":[],\"custom_rules\":[],\"pre_packaged_rules\":[]}}],\"triggers\"" +
42+
":[{\"id\":\"SiWfaosBBiNA8if0E1bC\",\"name\":\"windows-trigger\",\"severity\":\"1\",\"types\"" +
43+
":[\"test_windows\"],\"ids\":[\"QuarksPwDump Clearing Access History\"],\"sev_levels\":[\"high\"]," +
44+
"\"tags\":[\"T0008\"],\"actions\":[],\"detection_types\":[\"rules\"]}],\"last_update_time\":" +
45+
"1698300892093,\"monitor_id\":[\"\"],\"workflow_ids\":[],\"bucket_monitor_id_rule_id\"" +
46+
":{},\"rule_topic_index\":\"\",\"alert_index\":\"\",\"alert_history_index\":\"\"," +
47+
"\"alert_history_index_pattern\":\"\",\"findings_index\":\"\",\"findings_index_pattern\":\"\"}";
48+
Detector detector = Detector.parse(parser(detectorString), null, null);
49+
// Detector detector = randomDetector(List.of());
50+
// detector.setInputs(List.of(new DetectorInput("", List.of(), List.of(), List.of())));
51+
// logger.error(toJsonStringWithUser(detector));
2552
BytesStreamOutput out = new BytesStreamOutput();
2653
detector.writeTo(out);
2754
StreamInput sin = StreamInput.wrap(out.bytes().toBytesRef().bytes);

0 commit comments

Comments
 (0)