Skip to content

Commit

Permalink
Update log type when detector index is missing
Browse files Browse the repository at this point in the history
Signed-off-by: Megha Goyal <[email protected]>
  • Loading branch information
goyamegh committed Dec 8, 2023
1 parent cc5c570 commit 1e31c99
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ private void deleteRule(String ruleId) {
new DeleteByQueryRequestBuilder(client, DeleteByQueryAction.INSTANCE)
.source(Rule.CUSTOM_RULES_INDEX)
.filter(QueryBuilders.matchQuery("_id", ruleId))
.refresh(true)
.execute(new ActionListener<>() {
@Override
public void onResponse(BulkByScrollResponse response) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,37 +256,7 @@ public void onResponse(SearchResponse response) {
onFailures(new OpenSearchStatusException(String.format(Locale.getDefault(), "Name of Log Type with id %s cannot be updated because active detectors exist", logTypeId), RestStatus.BAD_REQUEST));
return;
}

if (ruleIndices.ruleIndexExists(false)) {
ruleIndices.searchRules(existingLogType.getName(), new ActionListener<>() {
@Override
public void onResponse(SearchResponse response) {
if (response.isTimedOut()) {
onFailures(new OpenSearchStatusException(String.format(Locale.getDefault(), "Search request timed out. Log Type with id %s cannot be updated", logTypeId), RestStatus.REQUEST_TIMEOUT));
return;
}

if (response.getHits().getTotalHits().value > 0) {
onFailures(new OpenSearchStatusException(String.format(Locale.getDefault(), "Name of Log Type with id %s cannot be updated because active rules exist", logTypeId), RestStatus.BAD_REQUEST));
return;
}
updateLogType(existingLogType, logTypeId);
}

@Override
public void onFailure(Exception e) {
if (e instanceof IndexNotFoundException) {
// let log type update if the rule index is missing
updateLogType(existingLogType, logTypeId);
} else {
onFailures(e);
}
}
});
} else {
log.warn("Custom rule index missing, allowing update of custom log type {} to go through", logTypeId);
updateLogType(existingLogType, logTypeId);
}
checkRuleIndexAndUpdateLogType(existingLogType, logTypeId);
}

@Override
Expand All @@ -295,7 +265,7 @@ public void onFailure(Exception e) {
}
});
} else {
updateLogType(existingLogType, logTypeId);
checkRuleIndexAndUpdateLogType(existingLogType, logTypeId);
}
} else {
updateLogType(existingLogType, logTypeId);
Expand Down Expand Up @@ -397,6 +367,40 @@ public void onFailure(Exception e) {
}
}

void checkRuleIndexAndUpdateLogType(CustomLogType existingLogType, String logTypeId) {
if (ruleIndices.ruleIndexExists(false)) {
ruleIndices.searchRules(existingLogType.getName(), new ActionListener<>() {
@Override
public void onResponse(SearchResponse response) {
if (response.isTimedOut()) {
onFailures(new OpenSearchStatusException(String.format(Locale.getDefault(), "Search request timed out. Log Type with id %s cannot be updated", logTypeId), RestStatus.REQUEST_TIMEOUT));
return;
}

if (response.getHits().getTotalHits().value > 0) {
onFailures(new OpenSearchStatusException(String.format(Locale.getDefault(), "Name of Log Type with id %s cannot be updated because active rules exist", logTypeId), RestStatus.BAD_REQUEST));
return;
}
updateLogType(existingLogType, logTypeId);
}

@Override
public void onFailure(Exception e) {
if (e instanceof IndexNotFoundException) {
// let log type update if the rule index is missing
updateLogType(existingLogType, logTypeId);
} else {
onFailures(e);
}
}
});
} else {
log.warn("Custom rule index missing, allowing update of custom log type {} to go through", logTypeId);
updateLogType(existingLogType, logTypeId);
}

}

private void updateLogType(CustomLogType existingLogType, String logTypeId) {
try {
request.getCustomLogType().setTags(existingLogType.getTags());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.apache.hc.core5.http.io.entity.StringEntity;
import org.apache.hc.core5.http.message.BasicHeader;
import org.junit.Assert;
import org.opensearch.action.admin.indices.refresh.RefreshRequest;
import org.opensearch.client.Request;
import org.opensearch.client.Response;
import org.opensearch.client.ResponseException;
Expand All @@ -32,6 +33,8 @@
import java.util.Map;

import static org.opensearch.securityanalytics.TestHelpers.*;
import static org.opensearch.securityanalytics.logtype.LogTypeService.LOG_TYPE_INDEX;
import static org.opensearch.securityanalytics.model.Rule.CUSTOM_RULES_INDEX;

public class CustomLogTypeRestApiIT extends SecurityAnalyticsRestTestCase {

Expand Down Expand Up @@ -445,6 +448,51 @@ public void testEditACustomLogTypeNameWhenCustomRuleIndexMissing() throws IOExce
Assert.assertEquals(customLogType.getCategory(), ((Map<String, Object>) responseBody.get("logType")).get("category"));
}

public void testEditACustomLogTypeNameWhenDetectorIndexMissing() 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<String, Object> responseBody = asMap(createResponse);
String logTypeId = responseBody.get("_id").toString();
Assert.assertEquals(customLogType.getDescription(), ((Map<String, Object>) responseBody.get("logType")).get("description"));

// 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();

Response deleteResponse = makeRequest(client(), "DELETE", SecurityAnalyticsPlugin.RULE_BASE_URI + "/" + createdId, Collections.emptyMap(), new StringEntity(""));
Assert.assertEquals("Delete rule successful", RestStatus.OK, restStatus(deleteResponse));

customLogType = TestHelpers.randomCustomLogType("test", null, "Access Management", "Custom");
Response updatedResponse = makeRequest(client(), "PUT", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI + "/" + logTypeId, Collections.emptyMap(), toHttpEntity(customLogType));
Assert.assertEquals("Update custom log type successful", RestStatus.OK, restStatus(updatedResponse));

responseBody = asMap(updatedResponse);
Assert.assertEquals(customLogType.getCategory(), ((Map<String, Object>) responseBody.get("logType")).get("category"));
}

@SuppressWarnings("unchecked")
public void testEditACustomLogTypeName() throws IOException, InterruptedException {
String index = createTestIndex(randomIndex(), windowsIndexMapping());
Expand Down Expand Up @@ -495,7 +543,6 @@ public void testEditACustomLogTypeName() throws IOException, InterruptedExceptio

deleteResponse = makeRequest(client(), "DELETE", SecurityAnalyticsPlugin.RULE_BASE_URI + "/" + ruleId, Collections.emptyMap(), null);
Assert.assertEquals("Delete rule failed", RestStatus.OK, restStatus(deleteResponse));
Thread.sleep(5000);

CustomLogType updatedCustomLogType = TestHelpers.randomCustomLogType("updated_name", null, null, "Custom");
Response updatedResponse = makeRequest(client(), "PUT", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI + "/" + logTypeId, Collections.emptyMap(), toHttpEntity(updatedCustomLogType));
Expand Down Expand Up @@ -626,9 +673,31 @@ public void testDeleteCustomLogTypeWithDetectorIndexMissing() throws IOException
responseBody = asMap(createResponse);
String ruleId = responseBody.get("_id").toString();

Response deleteResponse = makeRequest(client(), "DELETE", SecurityAnalyticsPlugin.RULE_BASE_URI + "/" + ruleId, Collections.emptyMap(), null);
Response deleteResponse = makeRequest(client(), "DELETE", SecurityAnalyticsPlugin.RULE_BASE_URI + "/" + ruleId, Collections.emptyMap(), new StringEntity(""));
Assert.assertEquals("Delete rule successful", RestStatus.OK, restStatus(deleteResponse));


String request = "{\n" +
" \"query\": {\n" +
" \"nested\": {\n" +
" \"path\": \"rule\",\n" +
" \"query\": {\n" +
" \"bool\": {\n" +
" \"must\": [\n" +
" { \"match\": {\"rule.category\": \"" + customLogType.getName() + "\"}}\n" +
" ]\n" +
" }\n" +
" }\n" +
" }\n" +
" }\n" +
"}";

Response searchResponse = makeRequest(client(), "POST", String.format(Locale.getDefault(), "%s/_search", SecurityAnalyticsPlugin.RULE_BASE_URI), Collections.singletonMap("pre_packaged", "false"),
new StringEntity(request), new BasicHeader("Content-Type", "application/json"));
Assert.assertEquals("Searching rules successful", RestStatus.OK, restStatus(searchResponse));

responseBody = asMap(searchResponse);
Assert.assertEquals(0, ((Map<String, Object>) ((Map<String, Object>) responseBody.get("hits")).get("total")).get("value"));

deleteResponse = makeRequest(client(), "DELETE", SecurityAnalyticsPlugin.CUSTOM_LOG_TYPE_URI + "/" + logTypeId, Collections.emptyMap(), new StringEntity(""));
Assert.assertEquals("Delete custom log type successful", RestStatus.OK, restStatus(deleteResponse));
}
Expand Down

0 comments on commit 1e31c99

Please sign in to comment.