diff --git a/src/main/java/org/opensearch/securityanalytics/action/IndexCustomLogTypeRequest.java b/src/main/java/org/opensearch/securityanalytics/action/IndexCustomLogTypeRequest.java index 9c8ba2dae..1d2b12505 100644 --- a/src/main/java/org/opensearch/securityanalytics/action/IndexCustomLogTypeRequest.java +++ b/src/main/java/org/opensearch/securityanalytics/action/IndexCustomLogTypeRequest.java @@ -61,6 +61,10 @@ public ActionRequestValidationException validate() { if (!find) { throw new ActionRequestValidationException(); } + String category = customLogType.getCategory(); + if (!CustomLogType.VALID_LOG_CATEGORIES.contains(category)) { + throw new ActionRequestValidationException(); + } return null; } diff --git a/src/main/java/org/opensearch/securityanalytics/model/CustomLogType.java b/src/main/java/org/opensearch/securityanalytics/model/CustomLogType.java index fb9a05055..73bb0869e 100644 --- a/src/main/java/org/opensearch/securityanalytics/model/CustomLogType.java +++ b/src/main/java/org/opensearch/securityanalytics/model/CustomLogType.java @@ -17,6 +17,7 @@ import org.opensearch.core.xcontent.XContentParser; import java.io.IOException; +import java.util.List; import java.util.Map; import static org.opensearch.securityanalytics.action.IndexCustomLogTypeResponse.CUSTOM_LOG_TYPES_FIELD; @@ -27,11 +28,23 @@ public class CustomLogType implements Writeable, ToXContentObject { private static final Logger log = LogManager.getLogger(CustomLogType.class); + public static final List VALID_LOG_CATEGORIES = List.of( + "Access Management", + "Applications", + "Cloud Services", + "Network Activity", + "Security", + "System Activity", + "Other" + ); + public static final String CUSTOM_LOG_TYPE_ID_FIELD = "custom_logtype_id"; private static final String NAME_FIELD = "name"; private static final String DESCRIPTION_FIELD = "description"; + + private static final String CATEGORY_FIELD = "category"; private static final String SOURCE_FIELD = "source"; private static final String TAGS_FIELD = "tags"; @@ -44,6 +57,8 @@ public class CustomLogType implements Writeable, ToXContentObject { private String description; + private String category; + private String source; private Map tags; @@ -58,12 +73,14 @@ public CustomLogType(String id, Long version, String name, String description, + String category, String source, Map tags) { this.id = id != null ? id : NO_ID; this.version = version != null ? version : NO_VERSION; this.name = name; this.description = description; + this.category = category != null? category: "Other"; this.source = source; this.tags = tags; } @@ -75,6 +92,7 @@ public CustomLogType(StreamInput sin) throws IOException { sin.readString(), sin.readString(), sin.readString(), + sin.readString(), sin.readMap() ); } @@ -86,6 +104,7 @@ public CustomLogType(Map input) { null, input.get(NAME_FIELD).toString(), input.get(DESCRIPTION_FIELD).toString(), + input.containsKey(CATEGORY_FIELD)? input.get(CATEGORY_FIELD).toString(): null, input.get(SOURCE_FIELD).toString(), (Map) input.get(TAGS_FIELD) ); @@ -97,6 +116,7 @@ public void writeTo(StreamOutput out) throws IOException { out.writeLong(version); out.writeString(name); out.writeString(description); + out.writeString(category); out.writeString(source); out.writeMap(tags); } @@ -106,6 +126,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws return builder.startObject() .field(NAME_FIELD, name) .field(DESCRIPTION_FIELD, description) + .field(CATEGORY_FIELD, category) .field(SOURCE_FIELD, source) .field(TAGS_FIELD, tags) .endObject(); @@ -121,6 +142,7 @@ public static CustomLogType parse(XContentParser xcp, String id, Long version) t String name = null; String description = null; + String category = null; String source = null; Map tags = null; @@ -136,6 +158,9 @@ public static CustomLogType parse(XContentParser xcp, String id, Long version) t case DESCRIPTION_FIELD: description = xcp.text(); break; + case CATEGORY_FIELD: + category = xcp.textOrNull(); + break; case SOURCE_FIELD: source = xcp.text(); break; @@ -146,7 +171,7 @@ public static CustomLogType parse(XContentParser xcp, String id, Long version) t xcp.skipChildren(); } } - return new CustomLogType(id, version, name, description, source, tags); + return new CustomLogType(id, version, name, description, category, source, tags); } public static CustomLogType readFrom(StreamInput sin) throws IOException { @@ -177,6 +202,10 @@ public String getDescription() { return description; } + public String getCategory() { + return category; + } + public String getSource() { return source; } diff --git a/src/main/resources/OSMapping/logtypes.json b/src/main/resources/OSMapping/logtypes.json index 13e90587e..911629b4d 100644 --- a/src/main/resources/OSMapping/logtypes.json +++ b/src/main/resources/OSMapping/logtypes.json @@ -2,6 +2,7 @@ "others_application": { "name": "others_application", "description": "Application logs", + "category": "Other", "source": "Sigma", "tags": { "correlation_id": 0 @@ -10,6 +11,7 @@ "others_apt": { "name": "others_apt", "description": "Apt logs", + "category": "Other", "source": "Sigma", "tags": { "correlation_id": 1 @@ -18,6 +20,7 @@ "others_cloud": { "name": "others_cloud", "description": "Cloud logs", + "category": "Other", "source": "Sigma", "tags": { "correlation_id": 2 @@ -26,6 +29,7 @@ "others_compliance": { "name": "others_compliance", "description": "Compliance logs", + "category": "Other", "source": "Sigma", "tags": { "correlation_id": 4 @@ -34,6 +38,7 @@ "linux": { "name": "linux", "description": "Sys logs", + "category": "System Activity", "source": "Sigma", "tags": { "correlation_id": 5 @@ -42,6 +47,7 @@ "others_macos": { "name": "others_macos", "description": "MacOS logs", + "category": "System Activity", "source": "Sigma", "tags": { "correlation_id": 6 @@ -50,6 +56,7 @@ "network": { "name": "network", "description": "Network logs", + "category": "Network Activity", "source": "Sigma", "tags": { "correlation_id": 7 @@ -58,6 +65,7 @@ "others_proxy": { "name": "others_proxy", "description": "Proxy logs", + "category": "Other", "source": "Sigma", "tags": { "correlation_id": 8 @@ -66,6 +74,7 @@ "others_web": { "name": "others_web", "description": "Web logs", + "category": "Other", "source": "Sigma", "tags": { "correlation_id": 9 @@ -74,6 +83,7 @@ "windows": { "name": "windows", "description": "Windows logs", + "category": "System Activity", "source": "Sigma", "tags": { "correlation_id": 10 @@ -82,6 +92,7 @@ "ad_ldap": { "name": "ad_ldap", "description": "Ad/ldap logs", + "category": "Access Management", "source": "Sigma", "tags": { "correlation_id": 11 @@ -89,7 +100,8 @@ }, "apache_access": { "name": "apache_access", - "description": "Apt logs", + "description": "Apache Access logs", + "category": "Access Management", "source": "Sigma", "tags": { "correlation_id": 12 @@ -98,6 +110,7 @@ "cloudtrail": { "name": "cloudtrail", "description": "Cloudtrail Raw or OCSF based logs", + "category": "Cloud Services", "source": "Sigma", "tags": { "correlation_id": 14 @@ -106,6 +119,7 @@ "dns": { "name": "dns", "description": "DNS Raw or Route53 OCSF based logs", + "category": "Network Activity", "source": "Sigma", "tags": { "correlation_id": 15 @@ -114,6 +128,7 @@ "github": { "name": "github", "description": "Github logs", + "category": "Applications", "source": "Sigma", "tags": { "correlation_id": 16 @@ -122,6 +137,7 @@ "m365": { "name": "m365", "description": "M365 logs", + "category": "Applications", "source": "Sigma", "tags": { "correlation_id": 17 @@ -130,6 +146,7 @@ "gworkspace": { "name": "gworkspace", "description": "GWorkspace logs", + "category": "Applications", "source": "Sigma", "tags": { "correlation_id": 18 @@ -138,6 +155,7 @@ "okta": { "name": "okta", "description": "Okta logs", + "category": "Access Management", "source": "Sigma", "tags": { "correlation_id": 19 @@ -146,6 +164,7 @@ "azure": { "name": "azure", "description": "Azure logs", + "category": "Cloud Services", "source": "Sigma", "tags": { "correlation_id": 20 @@ -154,6 +173,7 @@ "s3": { "name": "s3", "description": "S3 logs", + "category": "Cloud Services", "source": "Sigma", "tags": { "correlation_id": 21 @@ -162,6 +182,7 @@ "test_windows": { "name": "test_windows", "description": "Test Windows Log Type for integ tests. Please do not use.", + "category": "Other", "source": "Sigma", "tags": { "correlation_id": 22 @@ -170,6 +191,7 @@ "vpcflow": { "name": "vpcflow", "description": "VPC Flow Raw or OCSF based logs", + "category": "Network Activity", "source": "Sigma", "tags": { "correlation_id": 23 diff --git a/src/main/resources/mappings/log_type_config_mapping.json b/src/main/resources/mappings/log_type_config_mapping.json index 16c84f810..431745a1c 100644 --- a/src/main/resources/mappings/log_type_config_mapping.json +++ b/src/main/resources/mappings/log_type_config_mapping.json @@ -1,6 +1,6 @@ { "_meta" : { - "schema_version": 1 + "schema_version": 2 }, "dynamic_templates": [ { @@ -50,6 +50,15 @@ } } }, + "category": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, "source": { "type": "text", "fields": { diff --git a/src/test/java/org/opensearch/securityanalytics/TestHelpers.java b/src/test/java/org/opensearch/securityanalytics/TestHelpers.java index 7a1232958..5333df17a 100644 --- a/src/test/java/org/opensearch/securityanalytics/TestHelpers.java +++ b/src/test/java/org/opensearch/securityanalytics/TestHelpers.java @@ -147,17 +147,20 @@ public static Detector randomDetector(String name, return new Detector(null, null, name, enabled, schedule, lastUpdateTime, enabledTime, detectorType, user, inputs, triggers, Collections.singletonList(""), "", "", "", "", "", "", Collections.emptyMap(), Collections.emptyList()); } - public static CustomLogType randomCustomLogType(String name, String description, String source) { + public static CustomLogType randomCustomLogType(String name, String description, String category, String source) { if (name == null) { name = "custom-log-type"; } if (description == null) { description = "custom-log-type-desc"; } + if (category == null) { + category = "Other"; + } if (source == null) { source = "Sigma"; } - return new CustomLogType(null, null, name, description, source, null); + return new CustomLogType(null, null, name, description, category, source, null); } public static Detector randomDetectorWithNoUser() { diff --git a/src/test/java/org/opensearch/securityanalytics/resthandler/CustomLogTypeRestApiIT.java b/src/test/java/org/opensearch/securityanalytics/resthandler/CustomLogTypeRestApiIT.java index d2316db23..e35c3354a 100644 --- a/src/test/java/org/opensearch/securityanalytics/resthandler/CustomLogTypeRestApiIT.java +++ b/src/test/java/org/opensearch/securityanalytics/resthandler/CustomLogTypeRestApiIT.java @@ -39,7 +39,7 @@ public class CustomLogTypeRestApiIT extends SecurityAnalyticsRestTestCase { public void testCreateACustomLogType() throws IOException { String index = createTestIndex(randomIndex(), windowsIndexMapping()); - CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, "Custom"); + CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, null, "Custom"); Response createResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI, Collections.emptyMap(), toHttpEntity(customLogType)); Assert.assertEquals("Create custom log type failed", RestStatus.CREATED, restStatus(createResponse)); @@ -103,7 +103,7 @@ public void testCreateACustomLogType() throws IOException { public void testCreateACustomLogTypeWithMappings() throws IOException { String index = createTestIndex(randomIndex(), windowsIndexMapping()); - CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, "Custom"); + CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, null, "Custom"); Response createResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI, Collections.emptyMap(), toHttpEntity(customLogType)); Assert.assertEquals("Create custom log type failed", RestStatus.CREATED, restStatus(createResponse)); @@ -167,7 +167,7 @@ public void testCreateACustomLogTypeWithMappings() throws IOException { public void testEditACustomLogTypeDescription() throws IOException { String index = createTestIndex(randomIndex(), windowsIndexMapping()); - CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, "Custom"); + CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, null, "Custom"); Response createResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI, Collections.emptyMap(), toHttpEntity(customLogType)); Assert.assertEquals("Create custom log type failed", RestStatus.CREATED, restStatus(createResponse)); @@ -206,7 +206,7 @@ public void testEditACustomLogTypeDescription() throws IOException { createResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.DETECTOR_BASE_URI, Collections.emptyMap(), toHttpEntity(detector)); Assert.assertEquals("Create detector failed", RestStatus.CREATED, restStatus(createResponse)); - customLogType = TestHelpers.randomCustomLogType(null, "updated desc", "Custom"); + customLogType = TestHelpers.randomCustomLogType(null, "updated desc", null, "Custom"); Response updatedResponse = makeRequest(client(), "PUT", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI + "/" + logTypeId, Collections.emptyMap(), toHttpEntity(customLogType)); Assert.assertEquals("Create custom log type failed", RestStatus.OK, restStatus(updatedResponse)); @@ -215,9 +215,61 @@ public void testEditACustomLogTypeDescription() throws IOException { Assert.assertEquals(correlationId, Integer.parseInt(((Map)(((Map) responseBody.get("logType")).get("tags"))).get("correlation_id").toString())); } + @SuppressWarnings("unchecked") + public void testEditACustomLogTypeCategory() throws IOException { + String index = createTestIndex(randomIndex(), windowsIndexMapping()); + + CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, null, "Custom"); + Response createResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI, Collections.emptyMap(), toHttpEntity(customLogType)); + Assert.assertEquals("Create custom log type failed", RestStatus.CREATED, restStatus(createResponse)); + + Map responseBody = asMap(createResponse); + String logTypeId = responseBody.get("_id").toString(); + int correlationId = Integer.parseInt(((Map)(((Map) responseBody.get("logType")).get("tags"))).get("correlation_id").toString()); + Assert.assertEquals(customLogType.getCategory(), ((Map) responseBody.get("logType")).get("category")); + + // Execute CreateMappingsAction to add alias mapping for index + Request createMappingRequest = new Request("POST", SecurityAnalyticsPlugin.MAPPER_BASE_URI); + // both req params and req body are supported + createMappingRequest.setJsonEntity( + "{ \"index_name\":\"" + index + "\"," + + " \"rule_topic\":\"" + customLogType.getName() + "\", " + + " \"partial\":true, " + + " \"alias_mappings\":{}" + + "}" + ); + + Response response = client().performRequest(createMappingRequest); + assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); + + String rule = randomRule(); + + createResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.RULE_BASE_URI, Collections.singletonMap("category", customLogType.getName()), + new StringEntity(rule), new BasicHeader("Content-Type", "application/json")); + Assert.assertEquals("Create rule failed", RestStatus.CREATED, restStatus(createResponse)); + + responseBody = asMap(createResponse); + String createdId = responseBody.get("_id").toString(); + + DetectorInput input = new DetectorInput("custom log type detector for security analytics", List.of(index), List.of(new DetectorRule(createdId)), + List.of()); + Detector detector = randomDetectorWithInputs(List.of(input), customLogType.getName()); + + createResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.DETECTOR_BASE_URI, Collections.emptyMap(), toHttpEntity(detector)); + Assert.assertEquals("Create detector failed", RestStatus.CREATED, restStatus(createResponse)); + + customLogType = TestHelpers.randomCustomLogType(null, null, "Access Management", "Custom"); + Response updatedResponse = makeRequest(client(), "PUT", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI + "/" + logTypeId, Collections.emptyMap(), toHttpEntity(customLogType)); + Assert.assertEquals("Create custom log type failed", RestStatus.OK, restStatus(updatedResponse)); + + responseBody = asMap(updatedResponse); + Assert.assertEquals(customLogType.getCategory(), ((Map) responseBody.get("logType")).get("category")); + Assert.assertEquals(correlationId, Integer.parseInt(((Map)(((Map) responseBody.get("logType")).get("tags"))).get("correlation_id").toString())); + } + @SuppressWarnings("unchecked") public void testEditACustomLogTypeWithoutDetectors() throws IOException { - CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, "Custom"); + CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, null, "Custom"); Response createResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI, Collections.emptyMap(), toHttpEntity(customLogType)); Assert.assertEquals("Create custom log type failed", RestStatus.CREATED, restStatus(createResponse)); @@ -225,7 +277,7 @@ public void testEditACustomLogTypeWithoutDetectors() throws IOException { String logTypeId = responseBody.get("_id").toString(); Assert.assertEquals(customLogType.getDescription(), ((Map) responseBody.get("logType")).get("description")); - CustomLogType updatedCustomLogType = TestHelpers.randomCustomLogType("updated_name", null, "Custom"); + CustomLogType updatedCustomLogType = TestHelpers.randomCustomLogType("updated_name", null, null, "Custom"); Response updatedResponse = makeRequest(client(), "PUT", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI + "/" + logTypeId, Collections.emptyMap(), toHttpEntity(updatedCustomLogType)); Assert.assertEquals("Update custom log type failed", RestStatus.OK, restStatus(updatedResponse)); @@ -237,7 +289,7 @@ public void testEditACustomLogTypeWithoutDetectors() throws IOException { public void testEditACustomLogTypeNameFailsAsDetectorExist() throws IOException { String index = createTestIndex(randomIndex(), windowsIndexMapping()); - CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, "Custom"); + CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, null, "Custom"); Response createResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI, Collections.emptyMap(), toHttpEntity(customLogType)); Assert.assertEquals("Create custom log type failed", RestStatus.CREATED, restStatus(createResponse)); @@ -276,7 +328,7 @@ public void testEditACustomLogTypeNameFailsAsDetectorExist() throws IOException Assert.assertEquals("Create detector failed", RestStatus.CREATED, restStatus(createResponse)); expectThrows(ResponseException.class, () -> { - CustomLogType updatedCustomLogType = TestHelpers.randomCustomLogType("updated name", null, "Custom"); + CustomLogType updatedCustomLogType = TestHelpers.randomCustomLogType("updated name", null, null, "Custom"); makeRequest(client(), "PUT", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI + "/" + logTypeId, Collections.emptyMap(), toHttpEntity(updatedCustomLogType)); }); } @@ -285,7 +337,7 @@ public void testEditACustomLogTypeNameFailsAsDetectorExist() throws IOException public void testEditACustomLogTypeNameFailsAsCustomRuleExist() throws IOException { String index = createTestIndex(randomIndex(), windowsIndexMapping()); - CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, "Custom"); + CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, null, "Custom"); Response createResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI, Collections.emptyMap(), toHttpEntity(customLogType)); Assert.assertEquals("Create custom log type failed", RestStatus.CREATED, restStatus(createResponse)); @@ -330,7 +382,7 @@ public void testEditACustomLogTypeNameFailsAsCustomRuleExist() throws IOExceptio Assert.assertEquals("Delete detector failed", RestStatus.OK, restStatus(deleteResponse)); expectThrows(ResponseException.class, () -> { - CustomLogType updatedCustomLogType = TestHelpers.randomCustomLogType("updated name", null, "Custom"); + CustomLogType updatedCustomLogType = TestHelpers.randomCustomLogType("updated name", null, null, "Custom"); makeRequest(client(), "PUT", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI + "/" + logTypeId, Collections.emptyMap(), toHttpEntity(updatedCustomLogType)); }); } @@ -339,7 +391,7 @@ public void testEditACustomLogTypeNameFailsAsCustomRuleExist() throws IOExceptio public void testEditACustomLogTypeName() throws IOException, InterruptedException { String index = createTestIndex(randomIndex(), windowsIndexMapping()); - CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, "Custom"); + CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, null, "Custom"); Response createResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI, Collections.emptyMap(), toHttpEntity(customLogType)); Assert.assertEquals("Create custom log type failed", RestStatus.CREATED, restStatus(createResponse)); @@ -387,7 +439,7 @@ public void testEditACustomLogTypeName() throws IOException, InterruptedExceptio Assert.assertEquals("Delete rule failed", RestStatus.OK, restStatus(deleteResponse)); Thread.sleep(5000); - CustomLogType updatedCustomLogType = TestHelpers.randomCustomLogType("updated_name", null, "Custom"); + CustomLogType updatedCustomLogType = TestHelpers.randomCustomLogType("updated_name", null, null, "Custom"); Response updatedResponse = makeRequest(client(), "PUT", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI + "/" + logTypeId, Collections.emptyMap(), toHttpEntity(updatedCustomLogType)); responseBody = asMap(updatedResponse); Assert.assertEquals(updatedCustomLogType.getName(), ((Map) responseBody.get("logType")).get("name")); @@ -395,7 +447,7 @@ public void testEditACustomLogTypeName() throws IOException, InterruptedExceptio @SuppressWarnings("unchecked") public void testSearchLogTypes() throws IOException, InterruptedException { - CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, "Custom"); + CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, null, "Custom"); Response createResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI, Collections.emptyMap(), toHttpEntity(customLogType)); Assert.assertEquals("Create custom log type failed", RestStatus.CREATED, restStatus(createResponse)); Thread.sleep(5000); @@ -430,11 +482,29 @@ public void testSearchLogTypes() throws IOException, InterruptedException { Assert.assertEquals(1, ((Map) ((Map) responseBody.get("hits")).get("total")).get("value")); } + @SuppressWarnings("unchecked") + public void testSearchLogTypesByCategory() throws IOException { + String request = "{\n" + + " \"query\": {\n" + + " \"match\": {\n" + + " \"category\": \"Access Management\"\n" + + " }\n" + + " }\n" + + "}"; + + Response searchResponse = makeRequest(client(), "POST", String.format(Locale.getDefault(), "%s/_search", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI),Collections.emptyMap(), + new StringEntity(request), new BasicHeader("Content-Type", "application/json")); + Assert.assertEquals("Searching rules failed", RestStatus.OK, restStatus(searchResponse)); + + Map responseBody = asMap(searchResponse); + Assert.assertEquals(3, ((Map) ((Map) responseBody.get("hits")).get("total")).get("value")); + } + @SuppressWarnings("unchecked") public void testDeleteCustomLogTypeFailsAsDetectorExist() throws IOException { String index = createTestIndex(randomIndex(), windowsIndexMapping()); - CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, "Custom"); + CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, null, "Custom"); Response createResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI, Collections.emptyMap(), toHttpEntity(customLogType)); Assert.assertEquals("Create custom log type failed", RestStatus.CREATED, restStatus(createResponse)); @@ -481,7 +551,7 @@ public void testDeleteCustomLogTypeFailsAsDetectorExist() throws IOException { public void testDeleteCustomLogTypeFailsAsRulesExist() throws IOException { String index = createTestIndex(randomIndex(), windowsIndexMapping()); - CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, "Custom"); + CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, null, "Custom"); Response createResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI, Collections.emptyMap(), toHttpEntity(customLogType)); Assert.assertEquals("Create custom log type failed", RestStatus.CREATED, restStatus(createResponse)); @@ -532,7 +602,7 @@ public void testDeleteCustomLogTypeFailsAsRulesExist() throws IOException { @SuppressWarnings("unchecked") public void testDeleteCustomLogTypeWithoutDetectors() throws IOException { - CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, "Custom"); + CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, null, "Custom"); Response createResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI, Collections.emptyMap(), toHttpEntity(customLogType)); Assert.assertEquals("Create custom log type failed", RestStatus.CREATED, restStatus(createResponse)); @@ -548,7 +618,7 @@ public void testDeleteCustomLogTypeWithoutDetectors() throws IOException { public void testDeleteCustomLogType() throws IOException, InterruptedException { String index = createTestIndex(randomIndex(), windowsIndexMapping()); - CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, "Custom"); + CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, null, "Custom"); Response createResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI, Collections.emptyMap(), toHttpEntity(customLogType)); Assert.assertEquals("Create custom log type failed", RestStatus.CREATED, restStatus(createResponse)); @@ -602,7 +672,7 @@ public void testDeleteCustomLogType() throws IOException, InterruptedException { public void testCreateMultipleLogTypes() throws IOException { String index = createTestIndex(randomIndex(), windowsIndexMapping()); - CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, "Custom"); + CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, null, "Custom"); Response createResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI, Collections.emptyMap(), toHttpEntity(customLogType)); Assert.assertEquals("Create custom log type failed", RestStatus.CREATED, restStatus(createResponse)); @@ -654,7 +724,7 @@ public void testCreateMultipleLogTypes() throws IOException { String monitorId = ((List) ((Map) hit.getSourceAsMap().get("detector")).get("monitor_id")).get(0); - customLogType = TestHelpers.randomCustomLogType("custom-again", null, "Custom"); + customLogType = TestHelpers.randomCustomLogType("custom-again", null, null, "Custom"); createResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI, Collections.emptyMap(), toHttpEntity(customLogType)); Assert.assertEquals("Create custom log type failed", RestStatus.CREATED, restStatus(createResponse)); @@ -724,7 +794,7 @@ public void testCreateMultipleLogTypes() throws IOException { public void testGetMappingsView() throws IOException { String index = createTestIndex(randomIndex(), windowsIndexMapping()); - CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, "Custom"); + CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, null, "Custom"); Response createResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI, Collections.emptyMap(), toHttpEntity(customLogType)); Assert.assertEquals("Create custom log type failed", RestStatus.CREATED, restStatus(createResponse)); @@ -751,7 +821,7 @@ public void testGetMappingsView() throws IOException { public void testMultipleLogTypesUpdateFieldMappings() throws IOException { String index = createTestIndex(randomIndex(), windowsIndexMapping()); - CustomLogType customLogType = TestHelpers.randomCustomLogType("logtype1", null, "Custom"); + CustomLogType customLogType = TestHelpers.randomCustomLogType("logtype1", null, null, "Custom"); Response createResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI, Collections.emptyMap(), toHttpEntity(customLogType)); Assert.assertEquals("Create custom log type failed", RestStatus.CREATED, restStatus(createResponse)); @@ -761,7 +831,7 @@ public void testMultipleLogTypesUpdateFieldMappings() throws IOException { new StringEntity(rule), new BasicHeader("Content-Type", "application/json")); Assert.assertEquals("Create rule failed", RestStatus.CREATED, restStatus(createResponse)); - customLogType = TestHelpers.randomCustomLogType("logtype2", null, "Custom"); + customLogType = TestHelpers.randomCustomLogType("logtype2", null, null, "Custom"); createResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI, Collections.emptyMap(), toHttpEntity(customLogType)); Assert.assertEquals("Create custom log type failed", RestStatus.CREATED, restStatus(createResponse)); @@ -801,18 +871,25 @@ public void testMultipleLogTypesUpdateFieldMappings() throws IOException { } public void testLogTypeNamesAlwaysLowercase() throws IOException { - CustomLogType customLogType = TestHelpers.randomCustomLogType("Logtype1", null, "Custom"); + CustomLogType customLogType = TestHelpers.randomCustomLogType("Logtype1", null, null, "Custom"); expectThrows(ResponseException.class, () -> { makeRequest(client(), "POST", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI, Collections.emptyMap(), toHttpEntity(customLogType)); }); } public void testMultipleLogTypesCannotBeCreatedWithSameName() throws IOException { - CustomLogType customLogType = TestHelpers.randomCustomLogType("logtype", null, "Custom"); + CustomLogType customLogType = TestHelpers.randomCustomLogType("logtype", null, null, "Custom"); Response createResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI, Collections.emptyMap(), toHttpEntity(customLogType)); Assert.assertEquals("Create custom log type failed", RestStatus.CREATED, restStatus(createResponse)); expectThrows(ResponseException.class, () -> { makeRequest(client(), "POST", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI, Collections.emptyMap(), toHttpEntity(customLogType)); }); } + + public void testCreateACustomLogTypeInvalidCategory() throws IOException { + CustomLogType customLogType = TestHelpers.randomCustomLogType(null, null, "Invalid", "Custom"); + expectThrows(ResponseException.class, () -> { + makeRequest(client(), "POST", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI, Collections.emptyMap(), toHttpEntity(customLogType)); + }); + } } \ No newline at end of file