Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

get all findings as part of findings API enhancement #803

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ public GetFindingsRequest(String detectorId, String logType, Table table) {
@Override
public ActionRequestValidationException validate() {
ActionRequestValidationException validationException = null;
if ((detectorId == null || detectorId.length() == 0) && logType == null) {
if (detectorId != null && detectorId.length() == 0) {
validationException = addValidationError(String.format(Locale.getDefault(),
"At least one of detector type or detector id needs to be passed", DETECTOR_ID),
"%s is missing", DETECTOR_ID),
riysaxen-amzn marked this conversation as resolved.
Show resolved Hide resolved
validationException);
}
return validationException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,65 +104,95 @@
return;
}

if (request.getLogType() == null) {
if (request.getLogType() == null && request.getDetectorId() == null) {
// Get all the Findings
SearchRequest searchRequest = getSearchRequest(request);
transportSearchAction(request, actionListener, searchRequest);

Check warning on line 110 in src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java#L109-L110

Added lines #L109 - L110 were not covered by tests

} else if (request.getLogType() == null) {
findingsService.getFindingsByDetectorId(
request.getDetectorId(),
request.getTable(),
actionListener
);
} else {
// "detector" is nested type, so we have to use nested query
riysaxen-amzn marked this conversation as resolved.
Show resolved Hide resolved
NestedQueryBuilder queryBuilder =
QueryBuilders.nestedQuery(
"detector",
QueryBuilders.boolQuery().must(
QueryBuilders.matchQuery(
DETECTOR_TYPE_PATH,
request.getLogType()
SearchRequest searchRequest = getSearchRequest(request);
transportSearchAction(request, actionListener, searchRequest);

Check warning on line 121 in src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java#L120-L121

Added lines #L120 - L121 were not covered by tests
}
}

Check warning on line 123 in src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java#L123

Added line #L123 was not covered by tests

private void transportSearchAction(GetFindingsRequest request, ActionListener<GetFindingsResponse> actionListener, SearchRequest searchRequest) {
riysaxen-amzn marked this conversation as resolved.
Show resolved Hide resolved
transportSearchDetectorAction.execute(new SearchDetectorRequest(searchRequest), new ActionListener<>() {

Check warning on line 126 in src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java#L126

Added line #L126 was not covered by tests
@Override
public void onResponse(SearchResponse searchResponse) {
try {
List<Detector> detectors = DetectorUtils.getDetectors(searchResponse, xContentRegistry);

Check warning on line 130 in src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java#L130

Added line #L130 was not covered by tests
if (detectors.size() == 0) {
actionListener.onFailure(
riysaxen-amzn marked this conversation as resolved.
Show resolved Hide resolved
SecurityAnalyticsException.wrap(

Check warning on line 133 in src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java#L132-L133

Added lines #L132 - L133 were not covered by tests
new OpenSearchStatusException(
"No detectors found for provided type", RestStatus.NOT_FOUND
)
)
),
ScoreMode.None
);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(queryBuilder);
searchSourceBuilder.fetchSource(true);
SearchRequest searchRequest = new SearchRequest();
searchRequest.indices(Detector.DETECTORS_INDEX);
searchRequest.source(searchSourceBuilder);
searchRequest.preference(Preference.PRIMARY_FIRST.type());

transportSearchDetectorAction.execute(new SearchDetectorRequest(searchRequest), new ActionListener<>() {
@Override
public void onResponse(SearchResponse searchResponse) {
try {
List<Detector> detectors = DetectorUtils.getDetectors(searchResponse, xContentRegistry);
if (detectors.size() == 0) {
actionListener.onFailure(
SecurityAnalyticsException.wrap(
new OpenSearchStatusException(
"No detectors found for provided type", RestStatus.NOT_FOUND
)
)
);
return;
}
findingsService.getFindings(
detectors,
request.getLogType(),
request.getTable(),
actionListener
);
} catch (IOException e) {
actionListener.onFailure(e);
return;

Check warning on line 139 in src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java#L139

Added line #L139 was not covered by tests
}
}

@Override
public void onFailure(Exception e) {
findingsService.getFindings(

Check warning on line 141 in src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java#L141

Added line #L141 was not covered by tests
detectors,
request.getLogType() == null ? "*" : request.getLogType(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how is findings service already handling "*"? I don't see a change in FIndingsService class in this PR

request.getTable(),

Check warning on line 144 in src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java#L144

Added line #L144 was not covered by tests
actionListener
);
} catch (IOException e) {

Check warning on line 147 in src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java#L147

Added line #L147 was not covered by tests
actionListener.onFailure(e);
}
});
}

Check warning on line 150 in src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java#L150

Added line #L150 was not covered by tests

@Override
public void onFailure(Exception e) {
actionListener.onFailure(e);
}

Check warning on line 155 in src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java#L154-L155

Added lines #L154 - L155 were not covered by tests
});
}

Check warning on line 157 in src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java#L157

Added line #L157 was not covered by tests

private static SearchRequest getSearchRequest(GetFindingsRequest request) {
riysaxen-amzn marked this conversation as resolved.
Show resolved Hide resolved
NestedQueryBuilder queryBuilder = getNestedQueryBuilder(request);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(queryBuilder);
searchSourceBuilder.fetchSource(true);
SearchRequest searchRequest = new SearchRequest();
searchRequest.indices(Detector.DETECTORS_INDEX);
searchRequest.source(searchSourceBuilder);
searchRequest.preference(Preference.PRIMARY_FIRST.type());
return searchRequest;

Check warning on line 168 in src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java#L160-L168

Added lines #L160 - L168 were not covered by tests
}

private static NestedQueryBuilder getNestedQueryBuilder(GetFindingsRequest request) {
NestedQueryBuilder queryBuilder;
if (request.getLogType() != null) {
queryBuilder = QueryBuilders.nestedQuery(

Check warning on line 174 in src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java#L174

Added line #L174 was not covered by tests
"detector",
QueryBuilders.boolQuery().must(
QueryBuilders.matchQuery(

Check warning on line 177 in src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java#L176-L177

Added lines #L176 - L177 were not covered by tests
DETECTOR_TYPE_PATH,
request.getLogType()

Check warning on line 179 in src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java#L179

Added line #L179 was not covered by tests
)
),
ScoreMode.None
);
}
else {
queryBuilder =
QueryBuilders.nestedQuery(

Check warning on line 187 in src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java#L186-L187

Added lines #L186 - L187 were not covered by tests
riysaxen-amzn marked this conversation as resolved.
Show resolved Hide resolved
"detector",
QueryBuilders.boolQuery().must(
QueryBuilders.matchAllQuery()

Check warning on line 190 in src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java#L189-L190

Added lines #L189 - L190 were not covered by tests
),
ScoreMode.None
);
}
return queryBuilder;

Check warning on line 195 in src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/org/opensearch/securityanalytics/transport/TransportGetFindingsAction.java#L195

Added line #L195 was not covered by tests
}

private void setFilterByEnabled(boolean filterByEnabled) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.HttpStatus;
import org.junit.Assert;
import org.junit.Ignore;
import org.opensearch.client.Request;
import org.opensearch.client.Response;
import org.opensearch.client.ResponseException;
import org.opensearch.client.RestClient;
import org.opensearch.commons.rest.SecureRestClientBuilder;
import org.opensearch.core.rest.RestStatus;
import org.opensearch.search.SearchHit;
import org.opensearch.securityanalytics.SecurityAnalyticsPlugin;
Expand Down Expand Up @@ -265,6 +268,111 @@ public void testGetFindings_byDetectorType_success() throws IOException {
Assert.assertEquals(1, getFindingsBody.get("total_findings"));
}

public void testGetAllFindings_success() throws IOException {
String index1 = createTestIndex(randomIndex(), windowsIndexMapping());

// 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\":\"" + index1 + "\"," +
" \"rule_topic\":\"" + randomDetectorType() + "\", " +
" \"partial\":true" +
"}"
);

Response response = client().performRequest(createMappingRequest);
assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());

// index 2
String index2 = createTestIndex("netflow_test", netFlowMappings());

// Execute CreateMappingsAction to add alias mapping for index
createMappingRequest = new Request("POST", SecurityAnalyticsPlugin.MAPPER_BASE_URI);
// both req params and req body are supported
createMappingRequest.setJsonEntity(
"{ \"index_name\":\"" + index2 + "\"," +
" \"rule_topic\":\"netflow\", " +
" \"partial\":true" +
"}"
);

response = client().performRequest(createMappingRequest);
assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
// Detector 1 - WINDOWS
Detector detector1 = randomDetectorWithTriggers(getRandomPrePackagedRules(), List.of(new DetectorTrigger(null, "test-trigger", "1", List.of(randomDetectorType()), List.of(), List.of(), List.of(), List.of(), List.of())));
Response createResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.DETECTOR_BASE_URI, Collections.emptyMap(), toHttpEntity(detector1));
Assert.assertEquals("Create detector failed", RestStatus.CREATED, restStatus(createResponse));

Map<String, Object> responseBody = asMap(createResponse);

String createdId = responseBody.get("_id").toString();

String request = "{\n" +
" \"query\" : {\n" +
" \"match\":{\n" +
" \"_id\": \"" + createdId + "\"\n" +
" }\n" +
" }\n" +
"}";
List<SearchHit> hits = executeSearch(Detector.DETECTORS_INDEX, request);
SearchHit hit = hits.get(0);
String monitorId1 = ((List<String>) ((Map<String, Object>) hit.getSourceAsMap().get("detector")).get("monitor_id")).get(0);
// Detector 2 - NETWORK
DetectorInput inputNetflow = new DetectorInput("windows detector for security analytics", List.of("netflow_test"), Collections.emptyList(),
getPrePackagedRules("network").stream().map(DetectorRule::new).collect(Collectors.toList()));
Detector detector2 = randomDetectorWithTriggers(
getPrePackagedRules("network"),
List.of(new DetectorTrigger(null, "test-trigger", "1", List.of("network"), List.of(), List.of(), List.of(), List.of(), List.of())),
"network",
inputNetflow
);

createResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.DETECTOR_BASE_URI, Collections.emptyMap(), toHttpEntity(detector2));
Assert.assertEquals("Create detector failed", RestStatus.CREATED, restStatus(createResponse));

responseBody = asMap(createResponse);

createdId = responseBody.get("_id").toString();

request = "{\n" +
" \"query\" : {\n" +
" \"match\":{\n" +
" \"_id\": \"" + createdId + "\"\n" +
" }\n" +
" }\n" +
"}";
hits = executeSearch(Detector.DETECTORS_INDEX, request);
hit = hits.get(0);
String monitorId2 = ((List<String>) ((Map<String, Object>) hit.getSourceAsMap().get("detector")).get("monitor_id")).get(0);

indexDoc(index1, "1", randomDoc());
indexDoc(index2, "1", randomDoc());
// execute monitor 1
Response executeResponse = executeAlertingMonitor(monitorId1, Collections.emptyMap());
Map<String, Object> executeResults = entityAsMap(executeResponse);

int noOfSigmaRuleMatches = ((List<Map<String, Object>>) ((Map<String, Object>) executeResults.get("input_results")).get("results")).get(0).size();
Assert.assertEquals(5, noOfSigmaRuleMatches);

// execute monitor 2
executeResponse = executeAlertingMonitor(monitorId2, Collections.emptyMap());
executeResults = entityAsMap(executeResponse);

noOfSigmaRuleMatches = ((List<Map<String, Object>>) ((Map<String, Object>) executeResults.get("input_results")).get("results")).get(0).size();
Assert.assertEquals(1, noOfSigmaRuleMatches);

client().performRequest(new Request("POST", "_refresh"));

// Call GetFindings API for all the detectors
Map<String, String> params = new HashMap<>();
Response getFindingsResponse = makeRequest(client(), "GET", SecurityAnalyticsPlugin.FINDINGS_BASE_URI + "/_search", params, null);
Map<String, Object> getFindingsBody = entityAsMap(getFindingsResponse);
Assert.assertEquals(2, getFindingsBody.get("total_findings"));
// Call GetFindings API for second detector
params.clear();
riysaxen-amzn marked this conversation as resolved.
Show resolved Hide resolved
}

public void testGetFindings_rolloverByMaxAge_success() throws IOException, InterruptedException {

updateClusterSetting(FINDING_HISTORY_ROLLOVER_PERIOD.getKey(), "1s");
Expand Down
Loading