[Security Solution] Add unit tests for Network search strategy (#77416) (#77442)

* init tests

* add unit tests for network

* add more tests

* remove reponse from inspect for hostDetails
This commit is contained in:
Angela Chuang 2020-09-15 10:49:51 +01:00 committed by GitHub
parent 4d4dd7952c
commit fa41f53422
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 3344 additions and 891 deletions

View file

@ -29,10 +29,8 @@ export const hostDetails: SecuritySolutionFactory<HostsQueries.details> = {
const aggregations: HostAggEsItem = get('aggregations', response.rawResponse) || {};
const inspect = {
dsl: [inspectStringifyObject(buildHostDetailsQuery(options))],
response: [inspectStringifyObject(response)],
};
const formattedHostItem = formatHostItem(aggregations);
return { ...response, inspect, hostDetails: formattedHostItem };
},
};

View file

@ -3,11 +3,11 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { buildHostDetailsQuery as buildQuery } from './query.host_details.dsl';
import { buildHostDetailsQuery } from './query.host_details.dsl';
import { mockOptions, expectedDsl } from './__mocks__/';
describe('buildQuery', () => {
describe('buildHostDetailsQuery', () => {
test('build query from options correctly', () => {
expect(buildQuery(mockOptions)).toEqual(expectedDsl);
expect(buildHostDetailsQuery(mockOptions)).toEqual(expectedDsl);
});
});

View file

@ -0,0 +1,377 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { IEsSearchResponse } from '../../../../../../../../../../src/plugins/data/common';
import {
NetworkDetailsRequestOptions,
NetworkQueries,
} from '../../../../../../../common/search_strategy';
export const mockOptions: NetworkDetailsRequestOptions = {
defaultIndex: [
'apm-*-transaction*',
'auditbeat-*',
'endgame-*',
'filebeat-*',
'logs-*',
'packetbeat-*',
'winlogbeat-*',
],
docValueFields: [
{ field: '@timestamp', format: 'date_time' },
{ field: 'event.created', format: 'date_time' },
{ field: 'event.end', format: 'date_time' },
{ field: 'event.ingested', format: 'date_time' },
{ field: 'event.start', format: 'date_time' },
{ field: 'file.accessed', format: 'date_time' },
{ field: 'file.created', format: 'date_time' },
{ field: 'file.ctime', format: 'date_time' },
{ field: 'file.mtime', format: 'date_time' },
{ field: 'package.installed', format: 'date_time' },
{ field: 'process.parent.start', format: 'date_time' },
{ field: 'process.start', format: 'date_time' },
{ field: 'system.audit.host.boottime', format: 'date_time' },
{ field: 'system.audit.package.installtime', format: 'date_time' },
{ field: 'system.audit.user.password.last_changed', format: 'date_time' },
{ field: 'tls.client.not_after', format: 'date_time' },
{ field: 'tls.client.not_before', format: 'date_time' },
{ field: 'tls.server.not_after', format: 'date_time' },
{ field: 'tls.server.not_before', format: 'date_time' },
{ field: 'aws.cloudtrail.user_identity.session_context.creation_date', format: 'date_time' },
{ field: 'azure.auditlogs.properties.activity_datetime', format: 'date_time' },
{ field: 'azure.enqueued_time', format: 'date_time' },
{ field: 'azure.signinlogs.properties.created_at', format: 'date_time' },
{ field: 'cef.extensions.agentReceiptTime', format: 'date_time' },
{ field: 'cef.extensions.deviceCustomDate1', format: 'date_time' },
{ field: 'cef.extensions.deviceCustomDate2', format: 'date_time' },
{ field: 'cef.extensions.deviceReceiptTime', format: 'date_time' },
{ field: 'cef.extensions.endTime', format: 'date_time' },
{ field: 'cef.extensions.fileCreateTime', format: 'date_time' },
{ field: 'cef.extensions.fileModificationTime', format: 'date_time' },
{ field: 'cef.extensions.flexDate1', format: 'date_time' },
{ field: 'cef.extensions.managerReceiptTime', format: 'date_time' },
{ field: 'cef.extensions.oldFileCreateTime', format: 'date_time' },
{ field: 'cef.extensions.oldFileModificationTime', format: 'date_time' },
{ field: 'cef.extensions.startTime', format: 'date_time' },
{ field: 'checkpoint.subs_exp', format: 'date_time' },
{ field: 'crowdstrike.event.EndTimestamp', format: 'date_time' },
{ field: 'crowdstrike.event.IncidentEndTime', format: 'date_time' },
{ field: 'crowdstrike.event.IncidentStartTime', format: 'date_time' },
{ field: 'crowdstrike.event.ProcessEndTime', format: 'date_time' },
{ field: 'crowdstrike.event.ProcessStartTime', format: 'date_time' },
{ field: 'crowdstrike.event.StartTimestamp', format: 'date_time' },
{ field: 'crowdstrike.event.Timestamp', format: 'date_time' },
{ field: 'crowdstrike.event.UTCTimestamp', format: 'date_time' },
{ field: 'crowdstrike.metadata.eventCreationTime', format: 'date_time' },
{ field: 'gsuite.admin.email.log_search_filter.end_date', format: 'date_time' },
{ field: 'gsuite.admin.email.log_search_filter.start_date', format: 'date_time' },
{ field: 'gsuite.admin.user.birthdate', format: 'date_time' },
{ field: 'kafka.block_timestamp', format: 'date_time' },
{ field: 'microsoft.defender_atp.lastUpdateTime', format: 'date_time' },
{ field: 'microsoft.defender_atp.resolvedTime', format: 'date_time' },
{ field: 'misp.campaign.first_seen', format: 'date_time' },
{ field: 'misp.campaign.last_seen', format: 'date_time' },
{ field: 'misp.intrusion_set.first_seen', format: 'date_time' },
{ field: 'misp.intrusion_set.last_seen', format: 'date_time' },
{ field: 'misp.observed_data.first_observed', format: 'date_time' },
{ field: 'misp.observed_data.last_observed', format: 'date_time' },
{ field: 'misp.report.published', format: 'date_time' },
{ field: 'misp.threat_indicator.valid_from', format: 'date_time' },
{ field: 'misp.threat_indicator.valid_until', format: 'date_time' },
{ field: 'netflow.collection_time_milliseconds', format: 'date_time' },
{ field: 'netflow.exporter.timestamp', format: 'date_time' },
{ field: 'netflow.flow_end_microseconds', format: 'date_time' },
{ field: 'netflow.flow_end_milliseconds', format: 'date_time' },
{ field: 'netflow.flow_end_nanoseconds', format: 'date_time' },
{ field: 'netflow.flow_end_seconds', format: 'date_time' },
{ field: 'netflow.flow_start_microseconds', format: 'date_time' },
{ field: 'netflow.flow_start_milliseconds', format: 'date_time' },
{ field: 'netflow.flow_start_nanoseconds', format: 'date_time' },
{ field: 'netflow.flow_start_seconds', format: 'date_time' },
{ field: 'netflow.max_export_seconds', format: 'date_time' },
{ field: 'netflow.max_flow_end_microseconds', format: 'date_time' },
{ field: 'netflow.max_flow_end_milliseconds', format: 'date_time' },
{ field: 'netflow.max_flow_end_nanoseconds', format: 'date_time' },
{ field: 'netflow.max_flow_end_seconds', format: 'date_time' },
{ field: 'netflow.min_export_seconds', format: 'date_time' },
{ field: 'netflow.min_flow_start_microseconds', format: 'date_time' },
{ field: 'netflow.min_flow_start_milliseconds', format: 'date_time' },
{ field: 'netflow.min_flow_start_nanoseconds', format: 'date_time' },
{ field: 'netflow.min_flow_start_seconds', format: 'date_time' },
{ field: 'netflow.monitoring_interval_end_milli_seconds', format: 'date_time' },
{ field: 'netflow.monitoring_interval_start_milli_seconds', format: 'date_time' },
{ field: 'netflow.observation_time_microseconds', format: 'date_time' },
{ field: 'netflow.observation_time_milliseconds', format: 'date_time' },
{ field: 'netflow.observation_time_nanoseconds', format: 'date_time' },
{ field: 'netflow.observation_time_seconds', format: 'date_time' },
{ field: 'netflow.system_init_time_milliseconds', format: 'date_time' },
{ field: 'rsa.internal.lc_ctime', format: 'date_time' },
{ field: 'rsa.internal.time', format: 'date_time' },
{ field: 'rsa.time.effective_time', format: 'date_time' },
{ field: 'rsa.time.endtime', format: 'date_time' },
{ field: 'rsa.time.event_queue_time', format: 'date_time' },
{ field: 'rsa.time.event_time', format: 'date_time' },
{ field: 'rsa.time.expire_time', format: 'date_time' },
{ field: 'rsa.time.recorded_time', format: 'date_time' },
{ field: 'rsa.time.stamp', format: 'date_time' },
{ field: 'rsa.time.starttime', format: 'date_time' },
{ field: 'sophos.xg.date', format: 'date_time' },
{ field: 'sophos.xg.eventtime', format: 'date_time' },
{ field: 'sophos.xg.start_time', format: 'date_time' },
],
factoryQueryType: NetworkQueries.details,
filterQuery: '{"bool":{"must":[],"filter":[{"match_all":{}}],"should":[],"must_not":[]}}',
ip: '35.196.65.164',
};
export const mockSearchStrategyResponse: IEsSearchResponse<unknown> = {
isPartial: false,
isRunning: false,
rawResponse: {
took: 2620,
timed_out: false,
_shards: { total: 21, successful: 21, skipped: 0, failed: 0 },
hits: { total: 0, max_score: 0, hits: [] },
aggregations: {
host: {
doc_count: 0,
results: { hits: { total: { value: 0, relation: 'eq' }, max_score: null, hits: [] } },
},
destination: {
meta: {},
doc_count: 5,
geo: {
meta: {},
doc_count: 5,
results: {
hits: {
total: { value: 5, relation: 'eq' },
max_score: null,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'dd4fa2d4bd-1523631609876537',
_score: null,
_source: {
destination: {
geo: {
continent_name: 'North America',
region_iso_code: 'US-VA',
country_iso_code: 'US',
region_name: 'Virginia',
location: { lon: -77.2481, lat: 38.6583 },
},
},
},
sort: [1599703212208],
},
],
},
},
},
as: {
meta: {},
doc_count: 5,
results: {
hits: {
total: { value: 5, relation: 'eq' },
max_score: null,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'dd4fa2d4bd-1523631609876537',
_score: null,
_source: {
destination: { as: { number: 15169, organization: { name: 'Google LLC' } } },
},
sort: [1599703212208],
},
],
},
},
},
lastSeen: { value: 1599703212208, value_as_string: '2020-09-10T02:00:12.208Z' },
firstSeen: { value: 1598802015355, value_as_string: '2020-08-30T15:40:15.355Z' },
},
source: {
meta: {},
doc_count: 5,
geo: {
meta: {},
doc_count: 5,
results: {
hits: {
total: { value: 5, relation: 'eq' },
max_score: null,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'dd4fa2d4bd-1523631486500511',
_score: null,
_source: {
source: {
geo: {
continent_name: 'North America',
region_iso_code: 'US-VA',
country_iso_code: 'US',
region_name: 'Virginia',
location: { lon: -77.2481, lat: 38.6583 },
},
},
},
sort: [1599703214494],
},
],
},
},
},
as: {
meta: {},
doc_count: 5,
results: {
hits: {
total: { value: 5, relation: 'eq' },
max_score: null,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'dd4fa2d4bd-1523631486500511',
_score: null,
_source: {
source: { as: { number: 15169, organization: { name: 'Google LLC' } } },
},
sort: [1599703214494],
},
],
},
},
},
lastSeen: { value: 1599703214494, value_as_string: '2020-09-10T02:00:14.494Z' },
firstSeen: { value: 1598802015107, value_as_string: '2020-08-30T15:40:15.107Z' },
},
},
},
total: 21,
loaded: 21,
};
export const formattedSearchStrategyResponse = {
...mockSearchStrategyResponse,
inspect: {
dsl: [
'{\n "allowNoIndices": true,\n "index": [\n "apm-*-transaction*",\n "auditbeat-*",\n "endgame-*",\n "filebeat-*",\n "logs-*",\n "packetbeat-*",\n "winlogbeat-*"\n ],\n "ignoreUnavailable": true,\n "body": {\n "aggs": {\n "source": {\n "filter": {\n "term": {\n "source.ip": "35.196.65.164"\n }\n },\n "aggs": {\n "firstSeen": {\n "min": {\n "field": "@timestamp"\n }\n },\n "lastSeen": {\n "max": {\n "field": "@timestamp"\n }\n },\n "as": {\n "filter": {\n "exists": {\n "field": "source.as"\n }\n },\n "aggs": {\n "results": {\n "top_hits": {\n "size": 1,\n "_source": [\n "source.as"\n ],\n "sort": [\n {\n "@timestamp": "desc"\n }\n ]\n }\n }\n }\n },\n "geo": {\n "filter": {\n "exists": {\n "field": "source.geo"\n }\n },\n "aggs": {\n "results": {\n "top_hits": {\n "size": 1,\n "_source": [\n "source.geo"\n ],\n "sort": [\n {\n "@timestamp": "desc"\n }\n ]\n }\n }\n }\n }\n }\n },\n "destination": {\n "filter": {\n "term": {\n "destination.ip": "35.196.65.164"\n }\n },\n "aggs": {\n "firstSeen": {\n "min": {\n "field": "@timestamp"\n }\n },\n "lastSeen": {\n "max": {\n "field": "@timestamp"\n }\n },\n "as": {\n "filter": {\n "exists": {\n "field": "destination.as"\n }\n },\n "aggs": {\n "results": {\n "top_hits": {\n "size": 1,\n "_source": [\n "destination.as"\n ],\n "sort": [\n {\n "@timestamp": "desc"\n }\n ]\n }\n }\n }\n },\n "geo": {\n "filter": {\n "exists": {\n "field": "destination.geo"\n }\n },\n "aggs": {\n "results": {\n "top_hits": {\n "size": 1,\n "_source": [\n "destination.geo"\n ],\n "sort": [\n {\n "@timestamp": "desc"\n }\n ]\n }\n }\n }\n }\n }\n },\n "host": {\n "filter": {\n "term": {\n "host.ip": "35.196.65.164"\n }\n },\n "aggs": {\n "results": {\n "top_hits": {\n "size": 1,\n "_source": [\n "host"\n ],\n "sort": [\n {\n "@timestamp": "desc"\n }\n ]\n }\n }\n }\n }\n },\n "query": {\n "bool": {\n "should": []\n }\n },\n "size": 0,\n "track_total_hits": false\n }\n}',
],
},
networkDetails: {
source: {
firstSeen: '2020-08-30T15:40:15.107Z',
lastSeen: '2020-09-10T02:00:14.494Z',
autonomousSystem: { number: 15169, organization: { name: 'Google LLC' } },
geo: {
continent_name: 'North America',
region_iso_code: 'US-VA',
country_iso_code: 'US',
region_name: 'Virginia',
location: { lon: -77.2481, lat: 38.6583 },
},
},
destination: {
firstSeen: '2020-08-30T15:40:15.355Z',
lastSeen: '2020-09-10T02:00:12.208Z',
autonomousSystem: { number: 15169, organization: { name: 'Google LLC' } },
geo: {
continent_name: 'North America',
region_iso_code: 'US-VA',
country_iso_code: 'US',
region_name: 'Virginia',
location: { lon: -77.2481, lat: 38.6583 },
},
},
host: {},
},
};
export const expectedDsl = {
allowNoIndices: true,
index: [
'apm-*-transaction*',
'auditbeat-*',
'endgame-*',
'filebeat-*',
'logs-*',
'packetbeat-*',
'winlogbeat-*',
],
ignoreUnavailable: true,
body: {
aggs: {
source: {
filter: { term: { 'source.ip': '35.196.65.164' } },
aggs: {
firstSeen: { min: { field: '@timestamp' } },
lastSeen: { max: { field: '@timestamp' } },
as: {
filter: { exists: { field: 'source.as' } },
aggs: {
results: {
top_hits: { size: 1, _source: ['source.as'], sort: [{ '@timestamp': 'desc' }] },
},
},
},
geo: {
filter: { exists: { field: 'source.geo' } },
aggs: {
results: {
top_hits: { size: 1, _source: ['source.geo'], sort: [{ '@timestamp': 'desc' }] },
},
},
},
},
},
destination: {
filter: { term: { 'destination.ip': '35.196.65.164' } },
aggs: {
firstSeen: { min: { field: '@timestamp' } },
lastSeen: { max: { field: '@timestamp' } },
as: {
filter: { exists: { field: 'destination.as' } },
aggs: {
results: {
top_hits: {
size: 1,
_source: ['destination.as'],
sort: [{ '@timestamp': 'desc' }],
},
},
},
},
geo: {
filter: { exists: { field: 'destination.geo' } },
aggs: {
results: {
top_hits: {
size: 1,
_source: ['destination.geo'],
sort: [{ '@timestamp': 'desc' }],
},
},
},
},
},
},
host: {
filter: { term: { 'host.ip': '35.196.65.164' } },
aggs: {
results: { top_hits: { size: 1, _source: ['host'], sort: [{ '@timestamp': 'desc' }] } },
},
},
},
query: { bool: { should: [] } },
size: 0,
track_total_hits: false,
},
};

View file

@ -0,0 +1,35 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import * as buildQuery from './query.details_network.dsl';
import { networkDetails } from '.';
import {
mockOptions,
mockSearchStrategyResponse,
formattedSearchStrategyResponse,
} from './__mocks__';
describe('networkDetails search strategy', () => {
const buildNetworkDetailsQuery = jest.spyOn(buildQuery, 'buildNetworkDetailsQuery');
afterEach(() => {
buildNetworkDetailsQuery.mockClear();
});
describe('buildDsl', () => {
test('should build dsl query', () => {
networkDetails.buildDsl(mockOptions);
expect(buildNetworkDetailsQuery).toHaveBeenCalledWith(mockOptions);
});
});
describe('parse', () => {
test('should parse data correctly', async () => {
const result = await networkDetails.parse(mockOptions, mockSearchStrategyResponse);
expect(result).toMatchObject(formattedSearchStrategyResponse);
});
});
});

View file

@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { buildNetworkDetailsQuery } from './query.details_network.dsl';
import { mockOptions, expectedDsl } from './__mocks__';
describe('buildNetworkDetailsQuery', () => {
test('build query from options correctly', () => {
expect(buildNetworkDetailsQuery(mockOptions)).toEqual(expectedDsl);
});
});

View file

@ -0,0 +1,185 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { IEsSearchResponse } from '../../../../../../../../../../src/plugins/data/common';
import {
Direction,
NetworkDnsFields,
NetworkDnsRequestOptions,
NetworkQueries,
} from '../../../../../../../common/search_strategy';
export const mockOptions: NetworkDnsRequestOptions = {
defaultIndex: [
'apm-*-transaction*',
'auditbeat-*',
'endgame-*',
'filebeat-*',
'logs-*',
'packetbeat-*',
'winlogbeat-*',
],
factoryQueryType: NetworkQueries.dns,
filterQuery: '{"bool":{"must":[],"filter":[{"match_all":{}}],"should":[],"must_not":[]}}',
isPtrIncluded: false,
pagination: { activePage: 0, cursorStart: 0, fakePossibleCount: 50, querySize: 10 },
sort: { field: NetworkDnsFields.uniqueDomains, direction: Direction.desc },
timerange: { interval: '12h', from: '2020-09-13T09:00:43.249Z', to: '2020-09-14T09:00:43.249Z' },
};
export const mockSearchStrategyResponse: IEsSearchResponse<unknown> = {
isPartial: false,
isRunning: false,
rawResponse: {
took: 28,
timed_out: false,
_shards: { total: 21, successful: 21, skipped: 0, failed: 0 },
hits: { max_score: 0, hits: [], total: 0 },
aggregations: {
dns_count: { value: 2 },
dns_name_query_count: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [
{
key: 'google.com',
doc_count: 1,
unique_domains: { value: 1 },
dns_bytes_in: { value: 0 },
dns_bytes_out: { value: 0 },
},
{
key: 'google.internal',
doc_count: 1,
unique_domains: { value: 1 },
dns_bytes_in: { value: 0 },
dns_bytes_out: { value: 0 },
},
],
},
},
},
total: 21,
loaded: 21,
};
export const formattedSearchStrategyResponse = {
isPartial: false,
isRunning: false,
rawResponse: {
took: 28,
timed_out: false,
_shards: { total: 21, successful: 21, skipped: 0, failed: 0 },
hits: { max_score: 0, hits: [] },
aggregations: {
dns_count: { value: 2 },
dns_name_query_count: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [
{
key: 'google.com',
doc_count: 1,
unique_domains: { value: 1 },
dns_bytes_in: { value: 0 },
dns_bytes_out: { value: 0 },
},
{
key: 'google.internal',
doc_count: 1,
unique_domains: { value: 1 },
dns_bytes_in: { value: 0 },
dns_bytes_out: { value: 0 },
},
],
},
},
},
total: 21,
loaded: 21,
edges: [
{
node: {
_id: 'google.com',
dnsBytesIn: 0,
dnsBytesOut: 0,
dnsName: 'google.com',
queryCount: 1,
uniqueDomains: 1,
},
cursor: { value: 'google.com', tiebreaker: null },
},
{
node: {
_id: 'google.internal',
dnsBytesIn: 0,
dnsBytesOut: 0,
dnsName: 'google.internal',
queryCount: 1,
uniqueDomains: 1,
},
cursor: { value: 'google.internal', tiebreaker: null },
},
],
inspect: {
dsl: [
'{\n "allowNoIndices": true,\n "index": [\n "apm-*-transaction*",\n "auditbeat-*",\n "endgame-*",\n "filebeat-*",\n "logs-*",\n "packetbeat-*",\n "winlogbeat-*"\n ],\n "ignoreUnavailable": true,\n "body": {\n "aggregations": {\n "dns_count": {\n "cardinality": {\n "field": "dns.question.registered_domain"\n }\n },\n "dns_name_query_count": {\n "terms": {\n "field": "dns.question.registered_domain",\n "size": 10,\n "order": {\n "unique_domains": "desc"\n }\n },\n "aggs": {\n "unique_domains": {\n "cardinality": {\n "field": "dns.question.name"\n }\n },\n "dns_bytes_in": {\n "sum": {\n "field": "source.bytes"\n }\n },\n "dns_bytes_out": {\n "sum": {\n "field": "destination.bytes"\n }\n }\n }\n }\n },\n "query": {\n "bool": {\n "filter": [\n "{\\"bool\\":{\\"must\\":[],\\"filter\\":[{\\"match_all\\":{}}],\\"should\\":[],\\"must_not\\":[]}}",\n {\n "range": {\n "@timestamp": {\n "gte": "2020-09-13T09:00:43.249Z",\n "lte": "2020-09-14T09:00:43.249Z",\n "format": "strict_date_optional_time"\n }\n }\n }\n ],\n "must_not": [\n {\n "term": {\n "dns.question.type": {\n "value": "PTR"\n }\n }\n }\n ]\n }\n }\n },\n "size": 0,\n "track_total_hits": false\n}',
],
},
pageInfo: { activePage: 0, fakeTotalCount: 2, showMorePagesIndicator: false },
totalCount: 2,
};
export const expectedDsl = {
allowNoIndices: true,
index: [
'apm-*-transaction*',
'auditbeat-*',
'endgame-*',
'filebeat-*',
'logs-*',
'packetbeat-*',
'winlogbeat-*',
],
ignoreUnavailable: true,
body: {
aggregations: {
dns_count: { cardinality: { field: 'dns.question.registered_domain' } },
dns_name_query_count: {
terms: {
field: 'dns.question.registered_domain',
size: 10,
order: { unique_domains: 'desc' },
},
aggs: {
unique_domains: { cardinality: { field: 'dns.question.name' } },
dns_bytes_in: { sum: { field: 'source.bytes' } },
dns_bytes_out: { sum: { field: 'destination.bytes' } },
},
},
},
query: {
bool: {
filter: [
'{"bool":{"must":[],"filter":[{"match_all":{}}],"should":[],"must_not":[]}}',
{
range: {
'@timestamp': {
gte: '2020-09-13T09:00:43.249Z',
lte: '2020-09-14T09:00:43.249Z',
format: 'strict_date_optional_time',
},
},
},
],
must_not: [{ term: { 'dns.question.type': { value: 'PTR' } } }],
},
},
},
size: 0,
track_total_hits: false,
};

View file

@ -0,0 +1,35 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import * as buildQuery from './query.dns_network.dsl';
import { networkDns } from '.';
import {
mockOptions,
mockSearchStrategyResponse,
formattedSearchStrategyResponse,
} from './__mocks__';
describe('networkDns search strategy', () => {
const mockBuildDnsQuery = jest.spyOn(buildQuery, 'buildDnsQuery');
afterEach(() => {
mockBuildDnsQuery.mockClear();
});
describe('buildDsl', () => {
test('should build dsl query', () => {
networkDns.buildDsl(mockOptions);
expect(mockBuildDnsQuery).toHaveBeenCalledWith(mockOptions);
});
});
describe('parse', () => {
test('should parse data correctly', async () => {
const result = await networkDns.parse(mockOptions, mockSearchStrategyResponse);
expect(result).toMatchObject(formattedSearchStrategyResponse);
});
});
});

View file

@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { buildDnsQuery } from './query.dns_network.dsl';
import { mockOptions, expectedDsl } from './__mocks__';
describe('buildDnsQuery', () => {
test('build query from options correctly', () => {
expect(buildDnsQuery(mockOptions)).toEqual(expectedDsl);
});
});

View file

@ -0,0 +1,670 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { IEsSearchResponse } from '../../../../../../../../../../src/plugins/data/common';
import {
Direction,
NetworkDnsFields,
NetworkDnsRequestOptions,
NetworkQueries,
SortField,
} from '../../../../../../../common/search_strategy';
export const mockOptions: NetworkDnsRequestOptions = {
defaultIndex: [
'apm-*-transaction*',
'auditbeat-*',
'endgame-*',
'filebeat-*',
'logs-*',
'packetbeat-*',
'winlogbeat-*',
],
factoryQueryType: NetworkQueries.http,
filterQuery: '{"bool":{"must":[],"filter":[{"match_all":{}}],"should":[],"must_not":[]}}',
pagination: { activePage: 0, cursorStart: 0, fakePossibleCount: 50, querySize: 10 },
sort: { direction: Direction.desc } as SortField<NetworkDnsFields>,
timerange: { interval: '12h', from: '2020-09-13T09:00:43.249Z', to: '2020-09-14T09:00:43.249Z' },
} as NetworkDnsRequestOptions;
export const mockSearchStrategyResponse: IEsSearchResponse<unknown> = {
isPartial: false,
isRunning: false,
rawResponse: {
took: 422,
timed_out: false,
_shards: { total: 21, successful: 21, skipped: 0, failed: 0 },
hits: { max_score: 0, hits: [], total: 0 },
aggregations: {
http_count: { value: 1404 },
url: {
doc_count_error_upper_bound: 1440,
sum_other_doc_count: 98077,
buckets: [
{
key: '/_nodes?filter_path=nodes.*.version%2Cnodes.*.http.publish_address%2Cnodes.*.ip',
doc_count: 106704,
methods: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [{ key: 'GET', doc_count: 106704 }],
},
domains: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [
{ key: 'es.siem.estc.dev:9200', doc_count: 68983 },
{ key: 'es.siem.estc.dev', doc_count: 37721 },
],
},
source: {
hits: {
total: { value: 106704, relation: 'eq' },
max_score: 0,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'L4wXh3QBc39KFIJbgXrN',
_score: 0,
_source: {
host: { name: 'bastion00.siem.estc.dev' },
source: { ip: '67.173.227.94' },
},
},
],
},
},
status: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [
{ key: 200, doc_count: 72174 },
{ key: 401, doc_count: 34530 },
],
},
},
{
key: '/_bulk',
doc_count: 76744,
methods: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [{ key: 'POST', doc_count: 76744 }],
},
domains: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [
{ key: 'es.siem.estc.dev:9200', doc_count: 76737 },
{ key: 'es.siem.estc.dev', doc_count: 7 },
],
},
source: {
hits: {
total: { value: 76744, relation: 'eq' },
max_score: 0,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'tEIXh3QBB-gskclyiT2g',
_score: 0,
_source: {
host: { name: 'bastion00.siem.estc.dev' },
source: { ip: '35.227.65.114' },
},
},
],
},
},
status: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [
{ key: 200, doc_count: 75394 },
{ key: 401, doc_count: 1350 },
],
},
},
{
key: '/.reporting-*/_search',
doc_count: 58746,
methods: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [{ key: 'POST', doc_count: 58746 }],
},
domains: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [
{ key: 'es.siem.estc.dev:9200', doc_count: 56305 },
{ key: 'es.siem.estc.dev', doc_count: 2441 },
],
},
source: {
hits: {
total: { value: 58746, relation: 'eq' },
max_score: 0,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'MYwXh3QBc39KFIJbgXrN',
_score: 0,
_source: {
host: { name: 'bastion00.siem.estc.dev' },
source: { ip: '67.173.227.94' },
},
},
],
},
},
status: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [{ key: 200, doc_count: 58746 }],
},
},
{
key:
'/.kibana-task-manager-xavier-m/_update_by_query?ignore_unavailable=true&refresh=true&max_docs=10&conflicts=proceed',
doc_count: 28715,
methods: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [{ key: 'POST', doc_count: 28715 }],
},
domains: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [{ key: 'es.siem.estc.dev:9200', doc_count: 28715 }],
},
source: {
hits: {
total: { value: 28715, relation: 'eq' },
max_score: 0,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'MIwXh3QBc39KFIJbgXrN',
_score: 0,
_source: {
host: { name: 'bastion00.siem.estc.dev' },
source: { ip: '24.168.52.229' },
},
},
],
},
},
status: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [{ key: 200, doc_count: 28715 }],
},
},
{
key:
'/.kibana-task-manager-andrewg-local-testing-7-9-ff/_update_by_query?ignore_unavailable=true&refresh=true&max_docs=10&conflicts=proceed',
doc_count: 28161,
methods: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [{ key: 'POST', doc_count: 28161 }],
},
domains: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [{ key: 'es.siem.estc.dev:9200', doc_count: 28161 }],
},
source: {
hits: {
total: { value: 28161, relation: 'eq' },
max_score: 0,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'MowXh3QBc39KFIJbgXrN',
_score: 0,
_source: {
host: { name: 'bastion00.siem.estc.dev' },
source: { ip: '67.173.227.94' },
},
},
],
},
},
status: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [{ key: 200, doc_count: 28161 }],
},
},
{
key: '/_security/user/_has_privileges',
doc_count: 23283,
methods: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [{ key: 'POST', doc_count: 23283 }],
},
domains: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [
{ key: 'es.siem.estc.dev:9200', doc_count: 21601 },
{ key: 'es.siem.estc.dev', doc_count: 1682 },
],
},
source: {
hits: {
total: { value: 23283, relation: 'eq' },
max_score: 0,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: '6Ywch3QBc39KFIJbVY_k',
_score: 0,
_source: {
host: { name: 'bastion00.siem.estc.dev' },
source: { ip: '67.173.227.94' },
},
},
],
},
},
status: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [{ key: 200, doc_count: 23283 }],
},
},
{
key: '/_xpack',
doc_count: 20724,
methods: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [{ key: 'GET', doc_count: 20724 }],
},
domains: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [
{ key: 'es.siem.estc.dev:9200', doc_count: 17289 },
{ key: 'es.siem.estc.dev', doc_count: 3435 },
],
},
source: {
hits: {
total: { value: 20724, relation: 'eq' },
max_score: 0,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'rkIXh3QBB-gskclyiT2g',
_score: 0,
_source: {
host: { name: 'bastion00.siem.estc.dev' },
source: { ip: '35.226.77.71' },
},
},
],
},
},
status: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [
{ key: 200, doc_count: 12084 },
{ key: 401, doc_count: 8640 },
],
},
},
{
key: '/',
doc_count: 18306,
methods: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [
{ key: 'GET', doc_count: 18274 },
{ key: 'HEAD', doc_count: 29 },
{ key: 'POST', doc_count: 3 },
],
},
domains: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 37,
buckets: [
{ key: 'es.siem.estc.dev', doc_count: 8631 },
{ key: 'es.siem.estc.dev:9200', doc_count: 5757 },
{ key: 'es.siem.estc.dev:443', doc_count: 3858 },
{ key: '35.232.239.42', doc_count: 20 },
],
},
source: {
hits: {
total: { value: 18306, relation: 'eq' },
max_score: 0,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'JEIYh3QBB-gskclyYEfA',
_score: 0,
_source: {
host: { name: 'bastion00.siem.estc.dev' },
source: { ip: '35.171.72.245' },
},
},
],
},
},
status: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 3,
buckets: [
{ key: 401, doc_count: 18220 },
{ key: 404, doc_count: 30 },
{ key: 302, doc_count: 27 },
{ key: 200, doc_count: 26 },
],
},
},
{
key: '/_monitoring/bulk?system_id=kibana&system_api_version=7&interval=10000ms',
doc_count: 18048,
methods: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [{ key: 'POST', doc_count: 18048 }],
},
domains: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [
{ key: 'es.siem.estc.dev:9200', doc_count: 17279 },
{ key: 'es.siem.estc.dev', doc_count: 769 },
],
},
source: {
hits: {
total: { value: 18048, relation: 'eq' },
max_score: 0,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'sUIXh3QBB-gskclyiT2g',
_score: 0,
_source: {
host: { name: 'bastion00.siem.estc.dev' },
source: { ip: '24.168.52.229' },
},
},
],
},
},
status: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [{ key: 200, doc_count: 18048 }],
},
},
{
key: '/s/row-renderer-checking/api/reporting/jobs/count',
doc_count: 14046,
methods: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [{ key: 'GET', doc_count: 14046 }],
},
domains: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [{ key: 'kibana.siem.estc.dev', doc_count: 14046 }],
},
source: {
hits: {
total: { value: 14046, relation: 'eq' },
max_score: 0,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 's0IXh3QBB-gskclyiT2g',
_score: 0,
_source: {
host: { name: 'bastion00.siem.estc.dev' },
source: { ip: '75.134.244.183' },
},
},
],
},
},
status: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [{ key: 200, doc_count: 14046 }],
},
},
],
},
},
},
total: 21,
loaded: 21,
};
export const formattedSearchStrategyResponse = {
...mockSearchStrategyResponse,
edges: [
{
node: {
_id: '/_nodes?filter_path=nodes.*.version%2Cnodes.*.http.publish_address%2Cnodes.*.ip',
domains: ['es.siem.estc.dev:9200', 'es.siem.estc.dev'],
methods: ['GET'],
statuses: ['200', '401'],
lastHost: 'bastion00.siem.estc.dev',
lastSourceIp: '67.173.227.94',
path: '/_nodes?filter_path=nodes.*.version%2Cnodes.*.http.publish_address%2Cnodes.*.ip',
requestCount: 106704,
},
cursor: {
value: '/_nodes?filter_path=nodes.*.version%2Cnodes.*.http.publish_address%2Cnodes.*.ip',
tiebreaker: null,
},
},
{
node: {
_id: '/_bulk',
domains: ['es.siem.estc.dev:9200', 'es.siem.estc.dev'],
methods: ['POST'],
statuses: ['200', '401'],
lastHost: 'bastion00.siem.estc.dev',
lastSourceIp: '35.227.65.114',
path: '/_bulk',
requestCount: 76744,
},
cursor: { value: '/_bulk', tiebreaker: null },
},
{
node: {
_id: '/.reporting-*/_search',
domains: ['es.siem.estc.dev:9200', 'es.siem.estc.dev'],
methods: ['POST'],
statuses: ['200'],
lastHost: 'bastion00.siem.estc.dev',
lastSourceIp: '67.173.227.94',
path: '/.reporting-*/_search',
requestCount: 58746,
},
cursor: { value: '/.reporting-*/_search', tiebreaker: null },
},
{
node: {
_id:
'/.kibana-task-manager-xavier-m/_update_by_query?ignore_unavailable=true&refresh=true&max_docs=10&conflicts=proceed',
domains: ['es.siem.estc.dev:9200'],
methods: ['POST'],
statuses: ['200'],
lastHost: 'bastion00.siem.estc.dev',
lastSourceIp: '24.168.52.229',
path:
'/.kibana-task-manager-xavier-m/_update_by_query?ignore_unavailable=true&refresh=true&max_docs=10&conflicts=proceed',
requestCount: 28715,
},
cursor: {
value:
'/.kibana-task-manager-xavier-m/_update_by_query?ignore_unavailable=true&refresh=true&max_docs=10&conflicts=proceed',
tiebreaker: null,
},
},
{
node: {
_id:
'/.kibana-task-manager-andrewg-local-testing-7-9-ff/_update_by_query?ignore_unavailable=true&refresh=true&max_docs=10&conflicts=proceed',
domains: ['es.siem.estc.dev:9200'],
methods: ['POST'],
statuses: ['200'],
lastHost: 'bastion00.siem.estc.dev',
lastSourceIp: '67.173.227.94',
path:
'/.kibana-task-manager-andrewg-local-testing-7-9-ff/_update_by_query?ignore_unavailable=true&refresh=true&max_docs=10&conflicts=proceed',
requestCount: 28161,
},
cursor: {
value:
'/.kibana-task-manager-andrewg-local-testing-7-9-ff/_update_by_query?ignore_unavailable=true&refresh=true&max_docs=10&conflicts=proceed',
tiebreaker: null,
},
},
{
node: {
_id: '/_security/user/_has_privileges',
domains: ['es.siem.estc.dev:9200', 'es.siem.estc.dev'],
methods: ['POST'],
statuses: ['200'],
lastHost: 'bastion00.siem.estc.dev',
lastSourceIp: '67.173.227.94',
path: '/_security/user/_has_privileges',
requestCount: 23283,
},
cursor: { value: '/_security/user/_has_privileges', tiebreaker: null },
},
{
node: {
_id: '/_xpack',
domains: ['es.siem.estc.dev:9200', 'es.siem.estc.dev'],
methods: ['GET'],
statuses: ['200', '401'],
lastHost: 'bastion00.siem.estc.dev',
lastSourceIp: '35.226.77.71',
path: '/_xpack',
requestCount: 20724,
},
cursor: { value: '/_xpack', tiebreaker: null },
},
{
node: {
_id: '/',
domains: [
'es.siem.estc.dev',
'es.siem.estc.dev:9200',
'es.siem.estc.dev:443',
'35.232.239.42',
],
methods: ['GET', 'HEAD', 'POST'],
statuses: ['401', '404', '302', '200'],
lastHost: 'bastion00.siem.estc.dev',
lastSourceIp: '35.171.72.245',
path: '/',
requestCount: 18306,
},
cursor: { value: '/', tiebreaker: null },
},
{
node: {
_id: '/_monitoring/bulk?system_id=kibana&system_api_version=7&interval=10000ms',
domains: ['es.siem.estc.dev:9200', 'es.siem.estc.dev'],
methods: ['POST'],
statuses: ['200'],
lastHost: 'bastion00.siem.estc.dev',
lastSourceIp: '24.168.52.229',
path: '/_monitoring/bulk?system_id=kibana&system_api_version=7&interval=10000ms',
requestCount: 18048,
},
cursor: {
value: '/_monitoring/bulk?system_id=kibana&system_api_version=7&interval=10000ms',
tiebreaker: null,
},
},
{
node: {
_id: '/s/row-renderer-checking/api/reporting/jobs/count',
domains: ['kibana.siem.estc.dev'],
methods: ['GET'],
statuses: ['200'],
lastHost: 'bastion00.siem.estc.dev',
lastSourceIp: '75.134.244.183',
path: '/s/row-renderer-checking/api/reporting/jobs/count',
requestCount: 14046,
},
cursor: { value: '/s/row-renderer-checking/api/reporting/jobs/count', tiebreaker: null },
},
],
inspect: {
dsl: [
'{\n "allowNoIndices": true,\n "index": [\n "apm-*-transaction*",\n "auditbeat-*",\n "endgame-*",\n "filebeat-*",\n "logs-*",\n "packetbeat-*",\n "winlogbeat-*"\n ],\n "ignoreUnavailable": true,\n "body": {\n "aggregations": {\n "http_count": {\n "cardinality": {\n "field": "url.path"\n }\n },\n "url": {\n "terms": {\n "field": "url.path",\n "size": 10,\n "order": {\n "_count": "desc"\n }\n },\n "aggs": {\n "methods": {\n "terms": {\n "field": "http.request.method",\n "size": 4\n }\n },\n "domains": {\n "terms": {\n "field": "url.domain",\n "size": 4\n }\n },\n "status": {\n "terms": {\n "field": "http.response.status_code",\n "size": 4\n }\n },\n "source": {\n "top_hits": {\n "size": 1,\n "_source": {\n "includes": [\n "host.name",\n "source.ip"\n ]\n }\n }\n }\n }\n }\n },\n "query": {\n "bool": {\n "filter": [\n "{\\"bool\\":{\\"must\\":[],\\"filter\\":[{\\"match_all\\":{}}],\\"should\\":[],\\"must_not\\":[]}}",\n {\n "range": {\n "@timestamp": {\n "gte": "2020-09-13T09:00:43.249Z",\n "lte": "2020-09-14T09:00:43.249Z",\n "format": "strict_date_optional_time"\n }\n }\n },\n {\n "exists": {\n "field": "http.request.method"\n }\n }\n ]\n }\n }\n },\n "size": 0,\n "track_total_hits": false\n}',
],
},
pageInfo: { activePage: 0, fakeTotalCount: 50, showMorePagesIndicator: true },
totalCount: 1404,
};
export const expectedDsl = {
allowNoIndices: true,
index: [
'apm-*-transaction*',
'auditbeat-*',
'endgame-*',
'filebeat-*',
'logs-*',
'packetbeat-*',
'winlogbeat-*',
],
ignoreUnavailable: true,
body: {
aggregations: {
http_count: { cardinality: { field: 'url.path' } },
url: {
terms: { field: 'url.path', size: 10, order: { _count: 'desc' } },
aggs: {
methods: { terms: { field: 'http.request.method', size: 4 } },
domains: { terms: { field: 'url.domain', size: 4 } },
status: { terms: { field: 'http.response.status_code', size: 4 } },
source: { top_hits: { size: 1, _source: { includes: ['host.name', 'source.ip'] } } },
},
},
},
query: {
bool: {
filter: [
'{"bool":{"must":[],"filter":[{"match_all":{}}],"should":[],"must_not":[]}}',
{
range: {
'@timestamp': {
gte: '2020-09-13T09:00:43.249Z',
lte: '2020-09-14T09:00:43.249Z',
format: 'strict_date_optional_time',
},
},
},
{ exists: { field: 'http.request.method' } },
],
},
},
},
size: 0,
track_total_hits: false,
};

View file

@ -0,0 +1,35 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import * as buildQuery from './query.http_network.dsl';
import { networkHttp } from '.';
import {
mockOptions,
mockSearchStrategyResponse,
formattedSearchStrategyResponse,
} from './__mocks__';
describe('networkHttp search strategy', () => {
const buildHttpQuery = jest.spyOn(buildQuery, 'buildHttpQuery');
afterEach(() => {
buildHttpQuery.mockClear();
});
describe('buildDsl', () => {
test('should build dsl query', () => {
networkHttp.buildDsl(mockOptions);
expect(buildHttpQuery).toHaveBeenCalledWith(mockOptions);
});
});
describe('parse', () => {
test('should parse data correctly', async () => {
const result = await networkHttp.parse(mockOptions, mockSearchStrategyResponse);
expect(result).toMatchObject(formattedSearchStrategyResponse);
});
});
});

View file

@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { buildHttpQuery } from './query.http_network.dsl';
import { mockOptions, expectedDsl } from './__mocks__';
describe('buildHttpQuery', () => {
test('build query from options correctly', () => {
expect(buildHttpQuery(mockOptions)).toEqual(expectedDsl);
});
});

View file

@ -69,6 +69,7 @@ export const buildHttpQuery = ({
size: 0,
track_total_hits: false,
};
return dslQuery;
};

View file

@ -0,0 +1,41 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { NetworkQueries } from '../../../../../common/search_strategy/security_solution';
import { networkFactory } from '.';
import { networkDetails } from './details';
import { networkDns } from './dns';
import { networkHttp } from './http';
import { networkOverview } from './overview';
import { networkTls } from './tls';
import { networkTopCountries } from './top_countries';
import { networkTopNFlow } from './top_n_flow';
import { networkUsers } from './users';
jest.mock('./details');
jest.mock('./dns');
jest.mock('./http');
jest.mock('./overview');
jest.mock('./tls');
jest.mock('./top_countries');
jest.mock('./top_n_flow');
jest.mock('./users');
describe('networkFactory', () => {
test('should include correct apis', () => {
const expectedNetworkFactory = {
[NetworkQueries.details]: networkDetails,
[NetworkQueries.dns]: networkDns,
[NetworkQueries.http]: networkHttp,
[NetworkQueries.overview]: networkOverview,
[NetworkQueries.tls]: networkTls,
[NetworkQueries.topCountries]: networkTopCountries,
[NetworkQueries.topNFlow]: networkTopNFlow,
[NetworkQueries.users]: networkUsers,
};
expect(networkFactory).toEqual(expectedNetworkFactory);
});
});

View file

@ -0,0 +1,213 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { IEsSearchResponse } from '../../../../../../../../../../src/plugins/data/common';
import {
NetworkOverviewRequestOptions,
NetworkQueries,
} from '../../../../../../../common/search_strategy';
export const mockOptions: NetworkOverviewRequestOptions = {
defaultIndex: [
'apm-*-transaction*',
'auditbeat-*',
'endgame-*',
'filebeat-*',
'logs-*',
'packetbeat-*',
'winlogbeat-*',
],
factoryQueryType: NetworkQueries.overview,
filterQuery:
'{"bool":{"must":[],"filter":[{"match_all":{}},{"bool":{"filter":[{"bool":{"should":[{"bool":{"should":[{"exists":{"field":"source.ip"}}],"minimum_should_match":1}},{"bool":{"should":[{"exists":{"field":"destination.ip"}}],"minimum_should_match":1}}],"minimum_should_match":1}}]}}],"should":[],"must_not":[]}}',
timerange: { interval: '12h', from: '2020-09-13T12:54:24.685Z', to: '2020-09-14T12:54:24.685Z' },
};
export const mockSearchStrategyResponse: IEsSearchResponse<unknown> = {
isPartial: false,
isRunning: false,
rawResponse: {
took: 141,
timed_out: false,
_shards: {
total: 21,
successful: 21,
skipped: 0,
failed: 0,
},
hits: {
total: 1349108,
max_score: 0,
hits: [],
},
aggregations: {
unique_zeek_count: {
meta: {},
doc_count: 0,
},
unique_packetbeat_count: {
meta: {},
doc_count: 0,
unique_tls_count: {
meta: {},
doc_count: 0,
},
},
unique_filebeat_count: {
meta: {},
doc_count: 1278559,
unique_netflow_count: {
doc_count: 0,
},
unique_cisco_count: {
meta: {},
doc_count: 0,
},
unique_panw_count: {
meta: {},
doc_count: 0,
},
},
unique_dns_count: {
meta: {},
doc_count: 0,
},
unique_flow_count: {
meta: {},
doc_count: 0,
},
unique_socket_count: {
doc_count: 0,
},
unique_suricata_count: {
meta: {},
doc_count: 0,
},
},
},
total: 21,
loaded: 21,
};
export const formattedSearchStrategyResponse = {
...mockSearchStrategyResponse,
inspect: {
dsl: [
'{\n "allowNoIndices": true,\n "index": [\n "apm-*-transaction*",\n "auditbeat-*",\n "endgame-*",\n "filebeat-*",\n "logs-*",\n "packetbeat-*",\n "winlogbeat-*"\n ],\n "ignoreUnavailable": true,\n "body": {\n "aggregations": {\n "unique_flow_count": {\n "filter": {\n "term": {\n "type": "flow"\n }\n }\n },\n "unique_dns_count": {\n "filter": {\n "term": {\n "type": "dns"\n }\n }\n },\n "unique_suricata_count": {\n "filter": {\n "term": {\n "service.type": "suricata"\n }\n }\n },\n "unique_zeek_count": {\n "filter": {\n "term": {\n "service.type": "zeek"\n }\n }\n },\n "unique_socket_count": {\n "filter": {\n "term": {\n "event.dataset": "socket"\n }\n }\n },\n "unique_filebeat_count": {\n "filter": {\n "term": {\n "agent.type": "filebeat"\n }\n },\n "aggs": {\n "unique_netflow_count": {\n "filter": {\n "term": {\n "input.type": "netflow"\n }\n }\n },\n "unique_panw_count": {\n "filter": {\n "term": {\n "event.module": "panw"\n }\n }\n },\n "unique_cisco_count": {\n "filter": {\n "term": {\n "event.module": "cisco"\n }\n }\n }\n }\n },\n "unique_packetbeat_count": {\n "filter": {\n "term": {\n "agent.type": "packetbeat"\n }\n },\n "aggs": {\n "unique_tls_count": {\n "filter": {\n "term": {\n "network.protocol": "tls"\n }\n }\n }\n }\n }\n },\n "query": {\n "bool": {\n "filter": [\n "{\\"bool\\":{\\"must\\":[],\\"filter\\":[{\\"match_all\\":{}},{\\"bool\\":{\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"bool\\":{\\"should\\":[{\\"exists\\":{\\"field\\":\\"source.ip\\"}}],\\"minimum_should_match\\":1}},{\\"bool\\":{\\"should\\":[{\\"exists\\":{\\"field\\":\\"destination.ip\\"}}],\\"minimum_should_match\\":1}}],\\"minimum_should_match\\":1}}]}}],\\"should\\":[],\\"must_not\\":[]}}",\n {\n "range": {\n "@timestamp": {\n "gte": "2020-09-13T12:54:24.685Z",\n "lte": "2020-09-14T12:54:24.685Z",\n "format": "strict_date_optional_time"\n }\n }\n }\n ]\n }\n },\n "size": 0,\n "track_total_hits": false\n }\n}',
],
},
overviewNetwork: {
auditbeatSocket: 0,
filebeatCisco: 0,
filebeatNetflow: 0,
filebeatPanw: 0,
filebeatSuricata: 0,
filebeatZeek: 0,
packetbeatDNS: 0,
packetbeatFlow: 0,
packetbeatTLS: 0,
},
};
export const expectedDsl = {
allowNoIndices: true,
ignoreUnavailable: true,
index: [
'apm-*-transaction*',
'auditbeat-*',
'endgame-*',
'filebeat-*',
'logs-*',
'packetbeat-*',
'winlogbeat-*',
],
body: {
aggregations: {
unique_flow_count: {
filter: {
term: {
type: 'flow',
},
},
},
unique_dns_count: {
filter: {
term: {
type: 'dns',
},
},
},
unique_suricata_count: {
filter: {
term: {
'service.type': 'suricata',
},
},
},
unique_zeek_count: {
filter: {
term: {
'service.type': 'zeek',
},
},
},
unique_socket_count: {
filter: {
term: {
'event.dataset': 'socket',
},
},
},
unique_filebeat_count: {
filter: {
term: {
'agent.type': 'filebeat',
},
},
aggs: {
unique_netflow_count: {
filter: {
term: {
'input.type': 'netflow',
},
},
},
unique_panw_count: {
filter: {
term: {
'event.module': 'panw',
},
},
},
unique_cisco_count: {
filter: {
term: {
'event.module': 'cisco',
},
},
},
},
},
unique_packetbeat_count: {
filter: {
term: {
'agent.type': 'packetbeat',
},
},
aggs: {
unique_tls_count: {
filter: {
term: {
'network.protocol': 'tls',
},
},
},
},
},
},
},
};

View file

@ -0,0 +1,35 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import * as buildQuery from './query.overview_network.dsl';
import { networkOverview } from '.';
import {
mockOptions,
mockSearchStrategyResponse,
formattedSearchStrategyResponse,
} from './__mocks__';
describe('networkOverview search strategy', () => {
const buildOverviewNetworkQuery = jest.spyOn(buildQuery, 'buildOverviewNetworkQuery');
afterEach(() => {
buildOverviewNetworkQuery.mockClear();
});
describe('buildDsl', () => {
test('should build dsl query', () => {
networkOverview.buildDsl(mockOptions);
expect(buildOverviewNetworkQuery).toHaveBeenCalledWith(mockOptions);
});
});
describe('parse', () => {
test('should parse data correctly', async () => {
const result = await networkOverview.parse(mockOptions, mockSearchStrategyResponse);
expect(result).toMatchObject(formattedSearchStrategyResponse);
});
});
});

View file

@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { buildOverviewNetworkQuery } from './query.overview_network.dsl';
import { mockOptions, expectedDsl } from './__mocks__';
describe('buildOverviewNetworkQuery', () => {
test('build query from options correctly', () => {
expect(buildOverviewNetworkQuery(mockOptions)).toMatchObject(expectedDsl);
});
});

View file

@ -0,0 +1,109 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { IEsSearchResponse } from '../../../../../../../../../../src/plugins/data/common';
import {
Direction,
NetworkTlsFields,
NetworkTlsRequestOptions,
NetworkQueries,
FlowTargetSourceDest,
} from '../../../../../../../common/search_strategy';
export const mockOptions: NetworkTlsRequestOptions = {
defaultIndex: [
'apm-*-transaction*',
'auditbeat-*',
'endgame-*',
'filebeat-*',
'logs-*',
'packetbeat-*',
'winlogbeat-*',
],
factoryQueryType: NetworkQueries.tls,
filterQuery: '{"bool":{"must":[],"filter":[{"match_all":{}}],"should":[],"must_not":[]}}',
flowTarget: FlowTargetSourceDest.source,
ip: '',
pagination: { activePage: 0, cursorStart: 0, fakePossibleCount: 50, querySize: 10 },
sort: { field: NetworkTlsFields._id, direction: Direction.desc },
timerange: { interval: '12h', from: '2020-09-13T09:58:58.637Z', to: '2020-09-14T09:58:58.637Z' },
};
export const mockSearchStrategyResponse: IEsSearchResponse<unknown> = {
isPartial: false,
isRunning: false,
rawResponse: {
took: 62,
timed_out: false,
_shards: { total: 21, successful: 21, skipped: 0, failed: 0 },
hits: { total: 0, max_score: 0, hits: [] },
aggregations: {
sha1: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] },
count: { value: 0 },
},
},
total: 21,
loaded: 21,
};
export const formattedSearchStrategyResponse = {
...mockSearchStrategyResponse,
edges: [],
inspect: {
dsl: [
'{\n "allowNoIndices": true,\n "index": [\n "apm-*-transaction*",\n "auditbeat-*",\n "endgame-*",\n "filebeat-*",\n "logs-*",\n "packetbeat-*",\n "winlogbeat-*"\n ],\n "ignoreUnavailable": true,\n "body": {\n "aggs": {\n "count": {\n "cardinality": {\n "field": "tls.server.hash.sha1"\n }\n },\n "sha1": {\n "terms": {\n "field": "tls.server.hash.sha1",\n "size": 10,\n "order": {\n "_key": "desc"\n }\n },\n "aggs": {\n "issuers": {\n "terms": {\n "field": "tls.server.issuer"\n }\n },\n "subjects": {\n "terms": {\n "field": "tls.server.subject"\n }\n },\n "not_after": {\n "terms": {\n "field": "tls.server.not_after"\n }\n },\n "ja3": {\n "terms": {\n "field": "tls.server.ja3s"\n }\n }\n }\n }\n },\n "query": {\n "bool": {\n "filter": [\n "{\\"bool\\":{\\"must\\":[],\\"filter\\":[{\\"match_all\\":{}}],\\"should\\":[],\\"must_not\\":[]}}",\n {\n "range": {\n "@timestamp": {\n "gte": "2020-09-13T09:58:58.637Z",\n "lte": "2020-09-14T09:58:58.637Z",\n "format": "strict_date_optional_time"\n }\n }\n }\n ]\n }\n },\n "size": 0,\n "track_total_hits": false\n }\n}',
],
},
pageInfo: { activePage: 0, fakeTotalCount: 0, showMorePagesIndicator: false },
totalCount: 0,
};
export const expectedDsl = {
allowNoIndices: true,
index: [
'apm-*-transaction*',
'auditbeat-*',
'endgame-*',
'filebeat-*',
'logs-*',
'packetbeat-*',
'winlogbeat-*',
],
ignoreUnavailable: true,
body: {
aggs: {
count: { cardinality: { field: 'tls.server.hash.sha1' } },
sha1: {
terms: { field: 'tls.server.hash.sha1', size: 10, order: { _key: 'desc' } },
aggs: {
issuers: { terms: { field: 'tls.server.issuer' } },
subjects: { terms: { field: 'tls.server.subject' } },
not_after: { terms: { field: 'tls.server.not_after' } },
ja3: { terms: { field: 'tls.server.ja3s' } },
},
},
},
query: {
bool: {
filter: [
'{"bool":{"must":[],"filter":[{"match_all":{}}],"should":[],"must_not":[]}}',
{
range: {
'@timestamp': {
gte: '2020-09-13T09:58:58.637Z',
lte: '2020-09-14T09:58:58.637Z',
format: 'strict_date_optional_time',
},
},
},
],
},
},
size: 0,
track_total_hits: false,
},
};

View file

@ -0,0 +1,35 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import * as buildQuery from './query.tls_network.dsl';
import { networkTls } from '.';
import {
mockOptions,
mockSearchStrategyResponse,
formattedSearchStrategyResponse,
} from './__mocks__';
describe('networkTls search strategy', () => {
const buildNetworkTlsQuery = jest.spyOn(buildQuery, 'buildNetworkTlsQuery');
afterEach(() => {
buildNetworkTlsQuery.mockClear();
});
describe('buildDsl', () => {
test('should build dsl query', () => {
networkTls.buildDsl(mockOptions);
expect(buildNetworkTlsQuery).toHaveBeenCalledWith(mockOptions);
});
});
describe('parse', () => {
test('should parse data correctly', async () => {
const result = await networkTls.parse(mockOptions, mockSearchStrategyResponse);
expect(result).toMatchObject(formattedSearchStrategyResponse);
});
});
});

View file

@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { buildNetworkTlsQuery } from './query.tls_network.dsl';
import { mockOptions, expectedDsl } from './__mocks__';
describe('buildNetworkTlsQuery', () => {
test('build query from options correctly', () => {
expect(buildNetworkTlsQuery(mockOptions)).toEqual(expectedDsl);
});
});

View file

@ -0,0 +1,109 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { IEsSearchResponse } from '../../../../../../../../../../src/plugins/data/common';
import {
Direction,
NetworkTopCountriesRequestOptions,
NetworkQueries,
FlowTargetSourceDest,
NetworkTopTablesFields,
} from '../../../../../../../common/search_strategy';
export const mockOptions: NetworkTopCountriesRequestOptions = {
defaultIndex: [
'apm-*-transaction*',
'auditbeat-*',
'endgame-*',
'filebeat-*',
'logs-*',
'packetbeat-*',
'winlogbeat-*',
],
factoryQueryType: NetworkQueries.topCountries,
filterQuery: '{"bool":{"must":[],"filter":[{"match_all":{}}],"should":[],"must_not":[]}}',
flowTarget: FlowTargetSourceDest.destination,
pagination: { activePage: 0, cursorStart: 0, fakePossibleCount: 50, querySize: 10 },
sort: { field: NetworkTopTablesFields.bytes_in, direction: Direction.desc },
timerange: { interval: '12h', from: '2020-09-13T09:58:58.637Z', to: '2020-09-14T09:58:58.637Z' },
};
export const mockSearchStrategyResponse: IEsSearchResponse<unknown> = {
isPartial: false,
isRunning: false,
rawResponse: {
took: 62,
timed_out: false,
_shards: { total: 21, successful: 21, skipped: 0, failed: 0 },
hits: { total: 0, max_score: 0, hits: [] },
aggregations: {
sha1: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] },
count: { value: 0 },
},
},
total: 21,
loaded: 21,
};
export const formattedSearchStrategyResponse = {
...mockSearchStrategyResponse,
edges: [],
inspect: {
dsl: [
'{\n "allowNoIndices": true,\n "index": [\n "apm-*-transaction*",\n "auditbeat-*",\n "endgame-*",\n "filebeat-*",\n "logs-*",\n "packetbeat-*",\n "winlogbeat-*"\n ],\n "ignoreUnavailable": true,\n "body": {\n "aggregations": {\n "top_countries_count": {\n "cardinality": {\n "field": "destination.geo.country_iso_code"\n }\n },\n "destination": {\n "terms": {\n "field": "destination.geo.country_iso_code",\n "size": 10,\n "order": {\n "bytes_in": "desc"\n }\n },\n "aggs": {\n "bytes_in": {\n "sum": {\n "field": "source.bytes"\n }\n },\n "bytes_out": {\n "sum": {\n "field": "destination.bytes"\n }\n },\n "flows": {\n "cardinality": {\n "field": "network.community_id"\n }\n },\n "source_ips": {\n "cardinality": {\n "field": "source.ip"\n }\n },\n "destination_ips": {\n "cardinality": {\n "field": "destination.ip"\n }\n }\n }\n }\n },\n "query": {\n "bool": {\n "filter": [\n "{\\"bool\\":{\\"must\\":[],\\"filter\\":[{\\"match_all\\":{}}],\\"should\\":[],\\"must_not\\":[]}}",\n {\n "range": {\n "@timestamp": {\n "gte": "2020-09-13T09:58:58.637Z",\n "lte": "2020-09-14T09:58:58.637Z",\n "format": "strict_date_optional_time"\n }\n }\n }\n ]\n }\n }\n },\n "size": 0,\n "track_total_hits": false\n}',
],
},
pageInfo: { activePage: 0, fakeTotalCount: 0, showMorePagesIndicator: false },
totalCount: 0,
};
export const expectedDsl = {
allowNoIndices: true,
index: [
'apm-*-transaction*',
'auditbeat-*',
'endgame-*',
'filebeat-*',
'logs-*',
'packetbeat-*',
'winlogbeat-*',
],
ignoreUnavailable: true,
body: {
aggregations: {
top_countries_count: { cardinality: { field: 'destination.geo.country_iso_code' } },
destination: {
terms: { field: 'destination.geo.country_iso_code', size: 10, order: { bytes_in: 'desc' } },
aggs: {
bytes_in: { sum: { field: 'source.bytes' } },
bytes_out: { sum: { field: 'destination.bytes' } },
flows: { cardinality: { field: 'network.community_id' } },
source_ips: { cardinality: { field: 'source.ip' } },
destination_ips: { cardinality: { field: 'destination.ip' } },
},
},
},
query: {
bool: {
filter: [
'{"bool":{"must":[],"filter":[{"match_all":{}}],"should":[],"must_not":[]}}',
{
range: {
'@timestamp': {
gte: '2020-09-13T09:58:58.637Z',
lte: '2020-09-14T09:58:58.637Z',
format: 'strict_date_optional_time',
},
},
},
],
},
},
},
size: 0,
track_total_hits: false,
};

View file

@ -0,0 +1,35 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import * as buildQuery from './query.top_countries_network.dsl';
import { networkTopCountries } from '.';
import {
mockOptions,
mockSearchStrategyResponse,
formattedSearchStrategyResponse,
} from './__mocks__';
describe('networkTopCountries search strategy', () => {
const buildTopCountriesQuery = jest.spyOn(buildQuery, 'buildTopCountriesQuery');
afterEach(() => {
buildTopCountriesQuery.mockClear();
});
describe('buildDsl', () => {
test('should build dsl query', () => {
networkTopCountries.buildDsl(mockOptions);
expect(buildTopCountriesQuery).toHaveBeenCalledWith(mockOptions);
});
});
describe('parse', () => {
test('should parse data correctly', async () => {
const result = await networkTopCountries.parse(mockOptions, mockSearchStrategyResponse);
expect(result).toMatchObject(formattedSearchStrategyResponse);
});
});
});

View file

@ -43,7 +43,6 @@ export const networkTopCountries: SecuritySolutionFactory<NetworkQueries.topCoun
const edges = networkTopCountriesEdges.splice(cursorStart, querySize - cursorStart);
const inspect = {
dsl: [inspectStringifyObject(buildTopCountriesQuery(options))],
response: [inspectStringifyObject(response)],
};
const showMorePagesIndicator = totalCount > fakeTotalCount;

View file

@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { buildTopCountriesQuery } from './query.top_countries_network.dsl';
import { mockOptions, expectedDsl } from './__mocks__';
describe('buildTopCountriesQuery', () => {
test('build query from options correctly', () => {
expect(buildTopCountriesQuery(mockOptions)).toEqual(expectedDsl);
});
});

View file

@ -0,0 +1,847 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { IEsSearchResponse } from '../../../../../../../../../../src/plugins/data/common';
import {
Direction,
NetworkTopNFlowRequestOptions,
NetworkQueries,
NetworkTopTablesFields,
FlowTargetSourceDest,
} from '../../../../../../../common/search_strategy';
export const mockOptions: NetworkTopNFlowRequestOptions = {
defaultIndex: [
'apm-*-transaction*',
'auditbeat-*',
'endgame-*',
'filebeat-*',
'logs-*',
'packetbeat-*',
'winlogbeat-*',
],
factoryQueryType: NetworkQueries.topNFlow,
filterQuery: '{"bool":{"must":[],"filter":[{"match_all":{}}],"should":[],"must_not":[]}}',
flowTarget: FlowTargetSourceDest.source,
pagination: { activePage: 0, cursorStart: 0, fakePossibleCount: 50, querySize: 10 },
sort: { field: NetworkTopTablesFields.bytes_out, direction: Direction.desc },
timerange: { interval: '12h', from: '2020-09-13T10:16:46.870Z', to: '2020-09-14T10:16:46.870Z' },
};
export const mockSearchStrategyResponse: IEsSearchResponse<unknown> = {
isPartial: false,
isRunning: false,
rawResponse: {
took: 191,
timed_out: false,
_shards: { total: 21, successful: 21, skipped: 0, failed: 0 },
hits: { max_score: 0, hits: [], total: 0 },
aggregations: {
source: {
meta: {},
doc_count_error_upper_bound: -1,
sum_other_doc_count: 500330,
buckets: [
{
key: '10.142.0.7',
doc_count: 12116,
bytes_out: { value: 2581835370 },
flows: { value: 1967 },
bytes_in: { value: 0 },
domain: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [
{
key: 'siem-kibana',
doc_count: 3221,
timestamp: { value: 1600078221017, value_as_string: '2020-09-14T10:10:21.017Z' },
},
],
},
autonomous_system: {
meta: {},
doc_count: 0,
top_as: { hits: { total: { value: 0, relation: 'eq' }, max_score: 0, hits: [] } },
},
location: {
doc_count: 0,
top_geo: { hits: { total: { value: 0, relation: 'eq' }, max_score: 0, hits: [] } },
},
destination_ips: { value: 264 },
},
{
key: '35.232.239.42',
doc_count: 2119,
bytes_out: { value: 86968388 },
flows: { value: 922 },
bytes_in: { value: 0 },
domain: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] },
autonomous_system: {
doc_count: 2119,
top_as: {
hits: {
total: { value: 2119, relation: 'eq' },
max_score: 0,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'dd4fa2d4bd-1526378075029582',
_score: 0,
_source: {
source: { as: { number: 15169, organization: { name: 'Google LLC' } } },
},
},
],
},
},
},
location: {
doc_count: 2119,
top_geo: {
hits: {
total: { value: 2119, relation: 'eq' },
max_score: 0,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'dd4fa2d4bd-1526378075029582',
_score: 0,
_source: {
source: {
geo: {
continent_name: 'North America',
region_iso_code: 'US-VA',
country_iso_code: 'US',
region_name: 'Virginia',
location: { lon: -77.2481, lat: 38.6583 },
},
},
},
},
],
},
},
},
destination_ips: { value: 1 },
},
{
key: '151.101.200.204',
doc_count: 2,
bytes_out: { value: 1394839 },
flows: { value: 2 },
bytes_in: { value: 0 },
domain: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] },
autonomous_system: {
doc_count: 2,
top_as: {
hits: {
total: { value: 2, relation: 'eq' },
max_score: 0,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'dd4fa2d4bd-1527252060367158',
_score: 0,
_source: {
source: { as: { number: 54113, organization: { name: 'Fastly' } } },
},
},
],
},
},
},
location: {
doc_count: 2,
top_geo: {
hits: {
total: { value: 2, relation: 'eq' },
max_score: 0,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'dd4fa2d4bd-1527252060367158',
_score: 0,
_source: {
source: {
geo: {
continent_name: 'North America',
region_iso_code: 'US-VA',
city_name: 'Ashburn',
country_iso_code: 'US',
region_name: 'Virginia',
location: { lon: -77.4728, lat: 39.0481 },
},
},
},
},
],
},
},
},
destination_ips: { value: 1 },
},
{
key: '91.189.92.39',
doc_count: 1,
bytes_out: { value: 570550 },
flows: { value: 1 },
bytes_in: { value: 0 },
domain: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] },
autonomous_system: {
doc_count: 1,
top_as: {
hits: {
total: { value: 1, relation: 'eq' },
max_score: 0,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'dd4fa2d4bd-1526971840437636',
_score: 0,
_source: {
source: {
as: { number: 41231, organization: { name: 'Canonical Group Limited' } },
},
},
},
],
},
},
},
location: {
doc_count: 1,
top_geo: {
hits: {
total: { value: 1, relation: 'eq' },
max_score: 0,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'dd4fa2d4bd-1526971840437636',
_score: 0,
_source: {
source: {
geo: {
continent_name: 'Europe',
region_iso_code: 'GB-ENG',
city_name: 'London',
country_iso_code: 'GB',
region_name: 'England',
location: { lon: -0.0961, lat: 51.5132 },
},
},
},
},
],
},
},
},
destination_ips: { value: 1 },
},
{
key: '10.142.0.5',
doc_count: 514,
bytes_out: { value: 565933 },
flows: { value: 486 },
bytes_in: { value: 0 },
domain: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [
{
key: 'infraops-docker-data',
doc_count: 514,
timestamp: { value: 1600078218215, value_as_string: '2020-09-14T10:10:18.215Z' },
},
],
},
autonomous_system: {
doc_count: 0,
top_as: { hits: { total: { value: 0, relation: 'eq' }, max_score: 0, hits: [] } },
},
location: {
doc_count: 0,
top_geo: { hits: { total: { value: 0, relation: 'eq' }, max_score: 0, hits: [] } },
},
destination_ips: { value: 343 },
},
{
key: '151.101.248.204',
doc_count: 6,
bytes_out: { value: 260903 },
flows: { value: 6 },
bytes_in: { value: 0 },
domain: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] },
autonomous_system: {
doc_count: 6,
top_as: {
hits: {
total: { value: 6, relation: 'eq' },
max_score: 0,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'dd4fa2d4bd-1527003062069535',
_score: 0,
_source: {
source: { as: { number: 54113, organization: { name: 'Fastly' } } },
},
},
],
},
},
},
location: {
doc_count: 6,
top_geo: {
hits: {
total: { value: 6, relation: 'eq' },
max_score: 0,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'dd4fa2d4bd-1527003062069535',
_score: 0,
_source: {
source: {
geo: {
continent_name: 'North America',
region_iso_code: 'US-VA',
city_name: 'Ashburn',
country_iso_code: 'US',
region_name: 'Virginia',
location: { lon: -77.539, lat: 39.018 },
},
},
},
},
],
},
},
},
destination_ips: { value: 1 },
},
{
key: '35.196.129.83',
doc_count: 1,
bytes_out: { value: 164079 },
flows: { value: 1 },
bytes_in: { value: 0 },
domain: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] },
autonomous_system: {
doc_count: 1,
top_as: {
hits: {
total: { value: 1, relation: 'eq' },
max_score: 0,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'dd4fa2d4bd-1526557113311472',
_score: 0,
_source: {
source: { as: { number: 15169, organization: { name: 'Google LLC' } } },
},
},
],
},
},
},
location: {
doc_count: 1,
top_geo: {
hits: {
total: { value: 1, relation: 'eq' },
max_score: 0,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'dd4fa2d4bd-1526557113311472',
_score: 0,
_source: {
source: {
geo: {
continent_name: 'North America',
region_iso_code: 'US-VA',
country_iso_code: 'US',
region_name: 'Virginia',
location: { lon: -77.2481, lat: 38.6583 },
},
},
},
},
],
},
},
},
destination_ips: { value: 1 },
},
{
key: '151.101.2.217',
doc_count: 24,
bytes_out: { value: 158407 },
flows: { value: 24 },
bytes_in: { value: 0 },
domain: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] },
autonomous_system: {
doc_count: 24,
top_as: {
hits: {
total: { value: 24, relation: 'eq' },
max_score: 0,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'dd4fa2d4bd-1526379128390241',
_score: 0,
_source: {
source: { as: { number: 54113, organization: { name: 'Fastly' } } },
},
},
],
},
},
},
location: {
doc_count: 24,
top_geo: {
hits: {
total: { value: 24, relation: 'eq' },
max_score: 0,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'dd4fa2d4bd-1526379128390241',
_score: 0,
_source: {
source: {
geo: {
continent_name: 'North America',
country_iso_code: 'US',
location: { lon: -97.822, lat: 37.751 },
},
},
},
},
],
},
},
},
destination_ips: { value: 1 },
},
{
key: '91.189.91.38',
doc_count: 1,
bytes_out: { value: 89031 },
flows: { value: 1 },
bytes_in: { value: 0 },
domain: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] },
autonomous_system: {
doc_count: 1,
top_as: {
hits: {
total: { value: 1, relation: 'eq' },
max_score: 0,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'dd4fa2d4bd-1526555996515551',
_score: 0,
_source: {
source: {
as: { number: 41231, organization: { name: 'Canonical Group Limited' } },
},
},
},
],
},
},
},
location: {
doc_count: 1,
top_geo: {
hits: {
total: { value: 1, relation: 'eq' },
max_score: 0,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'dd4fa2d4bd-1526555996515551',
_score: 0,
_source: {
source: {
geo: {
continent_name: 'North America',
region_iso_code: 'US-MA',
city_name: 'Boston',
country_iso_code: 'US',
region_name: 'Massachusetts',
location: { lon: -71.0631, lat: 42.3562 },
},
},
},
},
],
},
},
},
destination_ips: { value: 1 },
},
{
key: '193.228.91.123',
doc_count: 33,
bytes_out: { value: 32170 },
flows: { value: 33 },
bytes_in: { value: 0 },
domain: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] },
autonomous_system: {
doc_count: 33,
top_as: {
hits: {
total: { value: 33, relation: 'eq' },
max_score: 0,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'dd4fa2d4bd-1526584379144248',
_score: 0,
_source: {
source: { as: { number: 133766, organization: { name: 'YHSRV.LLC' } } },
},
},
],
},
},
},
location: {
doc_count: 33,
top_geo: {
hits: {
total: { value: 33, relation: 'eq' },
max_score: 0,
hits: [
{
_index: 'filebeat-8.0.0-2020.09.02-000001',
_id: 'dd4fa2d4bd-1526584379144248',
_score: 0,
_source: {
source: {
geo: {
continent_name: 'North America',
country_iso_code: 'US',
location: { lon: -97.822, lat: 37.751 },
},
},
},
},
],
},
},
},
destination_ips: { value: 2 },
},
],
},
top_n_flow_count: { value: 738 },
},
},
total: 21,
loaded: 21,
};
export const formattedSearchStrategyResponse = {
edges: [
{
node: {
_id: '10.142.0.7',
source: {
domain: ['siem-kibana'],
ip: '10.142.0.7',
location: null,
autonomous_system: null,
flows: 1967,
destination_ips: 264,
},
network: { bytes_in: 0, bytes_out: 2581835370 },
},
cursor: { value: '10.142.0.7', tiebreaker: null },
},
{
node: {
_id: '35.232.239.42',
source: {
domain: [],
ip: '35.232.239.42',
location: {
geo: {
continent_name: 'North America',
region_iso_code: 'US-VA',
country_iso_code: 'US',
region_name: 'Virginia',
location: { lon: -77.2481, lat: 38.6583 },
},
flowTarget: 'source',
},
autonomous_system: { number: 15169, name: 'Google LLC' },
flows: 922,
destination_ips: 1,
},
network: { bytes_in: 0, bytes_out: 86968388 },
},
cursor: { value: '35.232.239.42', tiebreaker: null },
},
{
node: {
_id: '151.101.200.204',
source: {
domain: [],
ip: '151.101.200.204',
location: {
geo: {
continent_name: 'North America',
region_iso_code: 'US-VA',
city_name: 'Ashburn',
country_iso_code: 'US',
region_name: 'Virginia',
location: { lon: -77.4728, lat: 39.0481 },
},
flowTarget: 'source',
},
autonomous_system: { number: 54113, name: 'Fastly' },
flows: 2,
destination_ips: 1,
},
network: { bytes_in: 0, bytes_out: 1394839 },
},
cursor: { value: '151.101.200.204', tiebreaker: null },
},
{
node: {
_id: '91.189.92.39',
source: {
domain: [],
ip: '91.189.92.39',
location: {
geo: {
continent_name: 'Europe',
region_iso_code: 'GB-ENG',
city_name: 'London',
country_iso_code: 'GB',
region_name: 'England',
location: { lon: -0.0961, lat: 51.5132 },
},
flowTarget: 'source',
},
autonomous_system: { number: 41231, name: 'Canonical Group Limited' },
flows: 1,
destination_ips: 1,
},
network: { bytes_in: 0, bytes_out: 570550 },
},
cursor: { value: '91.189.92.39', tiebreaker: null },
},
{
node: {
_id: '10.142.0.5',
source: {
domain: ['infraops-docker-data'],
ip: '10.142.0.5',
location: null,
autonomous_system: null,
flows: 486,
destination_ips: 343,
},
network: { bytes_in: 0, bytes_out: 565933 },
},
cursor: { value: '10.142.0.5', tiebreaker: null },
},
{
node: {
_id: '151.101.248.204',
source: {
domain: [],
ip: '151.101.248.204',
location: {
geo: {
continent_name: 'North America',
region_iso_code: 'US-VA',
city_name: 'Ashburn',
country_iso_code: 'US',
region_name: 'Virginia',
location: { lon: -77.539, lat: 39.018 },
},
flowTarget: 'source',
},
autonomous_system: { number: 54113, name: 'Fastly' },
flows: 6,
destination_ips: 1,
},
network: { bytes_in: 0, bytes_out: 260903 },
},
cursor: { value: '151.101.248.204', tiebreaker: null },
},
{
node: {
_id: '35.196.129.83',
source: {
domain: [],
ip: '35.196.129.83',
location: {
geo: {
continent_name: 'North America',
region_iso_code: 'US-VA',
country_iso_code: 'US',
region_name: 'Virginia',
location: { lon: -77.2481, lat: 38.6583 },
},
flowTarget: 'source',
},
autonomous_system: { number: 15169, name: 'Google LLC' },
flows: 1,
destination_ips: 1,
},
network: { bytes_in: 0, bytes_out: 164079 },
},
cursor: { value: '35.196.129.83', tiebreaker: null },
},
{
node: {
_id: '151.101.2.217',
source: {
domain: [],
ip: '151.101.2.217',
location: {
geo: {
continent_name: 'North America',
country_iso_code: 'US',
location: { lon: -97.822, lat: 37.751 },
},
flowTarget: 'source',
},
autonomous_system: { number: 54113, name: 'Fastly' },
flows: 24,
destination_ips: 1,
},
network: { bytes_in: 0, bytes_out: 158407 },
},
cursor: { value: '151.101.2.217', tiebreaker: null },
},
{
node: {
_id: '91.189.91.38',
source: {
domain: [],
ip: '91.189.91.38',
location: {
geo: {
continent_name: 'North America',
region_iso_code: 'US-MA',
city_name: 'Boston',
country_iso_code: 'US',
region_name: 'Massachusetts',
location: { lon: -71.0631, lat: 42.3562 },
},
flowTarget: 'source',
},
autonomous_system: { number: 41231, name: 'Canonical Group Limited' },
flows: 1,
destination_ips: 1,
},
network: { bytes_in: 0, bytes_out: 89031 },
},
cursor: { value: '91.189.91.38', tiebreaker: null },
},
{
node: {
_id: '193.228.91.123',
source: {
domain: [],
ip: '193.228.91.123',
location: {
geo: {
continent_name: 'North America',
country_iso_code: 'US',
location: { lon: -97.822, lat: 37.751 },
},
flowTarget: 'source',
},
autonomous_system: { number: 133766, name: 'YHSRV.LLC' },
flows: 33,
destination_ips: 2,
},
network: { bytes_in: 0, bytes_out: 32170 },
},
cursor: { value: '193.228.91.123', tiebreaker: null },
},
],
inspect: {
dsl: [
'{\n "allowNoIndices": true,\n "index": [\n "apm-*-transaction*",\n "auditbeat-*",\n "endgame-*",\n "filebeat-*",\n "logs-*",\n "packetbeat-*",\n "winlogbeat-*"\n ],\n "ignoreUnavailable": true,\n "body": {\n "aggregations": {\n "top_n_flow_count": {\n "cardinality": {\n "field": "source.ip"\n }\n },\n "source": {\n "terms": {\n "field": "source.ip",\n "size": 10,\n "order": {\n "bytes_out": "desc"\n }\n },\n "aggs": {\n "bytes_in": {\n "sum": {\n "field": "destination.bytes"\n }\n },\n "bytes_out": {\n "sum": {\n "field": "source.bytes"\n }\n },\n "domain": {\n "terms": {\n "field": "source.domain",\n "order": {\n "timestamp": "desc"\n }\n },\n "aggs": {\n "timestamp": {\n "max": {\n "field": "@timestamp"\n }\n }\n }\n },\n "location": {\n "filter": {\n "exists": {\n "field": "source.geo"\n }\n },\n "aggs": {\n "top_geo": {\n "top_hits": {\n "_source": "source.geo.*",\n "size": 1\n }\n }\n }\n },\n "autonomous_system": {\n "filter": {\n "exists": {\n "field": "source.as"\n }\n },\n "aggs": {\n "top_as": {\n "top_hits": {\n "_source": "source.as.*",\n "size": 1\n }\n }\n }\n },\n "flows": {\n "cardinality": {\n "field": "network.community_id"\n }\n },\n "destination_ips": {\n "cardinality": {\n "field": "destination.ip"\n }\n }\n }\n }\n },\n "query": {\n "bool": {\n "filter": [\n "{\\"bool\\":{\\"must\\":[],\\"filter\\":[{\\"match_all\\":{}}],\\"should\\":[],\\"must_not\\":[]}}",\n {\n "range": {\n "@timestamp": {\n "gte": "2020-09-13T10:16:46.870Z",\n "lte": "2020-09-14T10:16:46.870Z",\n "format": "strict_date_optional_time"\n }\n }\n }\n ]\n }\n }\n },\n "size": 0,\n "track_total_hits": false\n}',
],
},
pageInfo: { activePage: 0, fakeTotalCount: 50, showMorePagesIndicator: true },
totalCount: 738,
};
export const expectedDsl = {
allowNoIndices: true,
index: [
'apm-*-transaction*',
'auditbeat-*',
'endgame-*',
'filebeat-*',
'logs-*',
'packetbeat-*',
'winlogbeat-*',
],
ignoreUnavailable: true,
body: {
aggregations: {
top_n_flow_count: { cardinality: { field: 'source.ip' } },
source: {
terms: { field: 'source.ip', size: 10, order: { bytes_out: 'desc' } },
aggs: {
bytes_in: { sum: { field: 'destination.bytes' } },
bytes_out: { sum: { field: 'source.bytes' } },
domain: {
terms: { field: 'source.domain', order: { timestamp: 'desc' } },
aggs: { timestamp: { max: { field: '@timestamp' } } },
},
location: {
filter: { exists: { field: 'source.geo' } },
aggs: { top_geo: { top_hits: { _source: 'source.geo.*', size: 1 } } },
},
autonomous_system: {
filter: { exists: { field: 'source.as' } },
aggs: { top_as: { top_hits: { _source: 'source.as.*', size: 1 } } },
},
flows: { cardinality: { field: 'network.community_id' } },
destination_ips: { cardinality: { field: 'destination.ip' } },
},
},
},
query: {
bool: {
filter: [
'{"bool":{"must":[],"filter":[{"match_all":{}}],"should":[],"must_not":[]}}',
{
range: {
'@timestamp': {
gte: '2020-09-13T10:16:46.870Z',
lte: '2020-09-14T10:16:46.870Z',
format: 'strict_date_optional_time',
},
},
},
],
},
},
},
size: 0,
track_total_hits: false,
};

View file

@ -0,0 +1,35 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import * as buildQuery from './query.top_n_flow_network.dsl';
import { networkTopNFlow } from '.';
import {
mockOptions,
mockSearchStrategyResponse,
formattedSearchStrategyResponse,
} from './__mocks__';
describe('networkTopNFlow search strategy', () => {
const buildTopNFlowQuery = jest.spyOn(buildQuery, 'buildTopNFlowQuery');
afterEach(() => {
buildTopNFlowQuery.mockClear();
});
describe('buildDsl', () => {
test('should build dsl query', () => {
networkTopNFlow.buildDsl(mockOptions);
expect(buildTopNFlowQuery).toHaveBeenCalledWith(mockOptions);
});
});
describe('parse', () => {
test('should parse data correctly', async () => {
const result = await networkTopNFlow.parse(mockOptions, mockSearchStrategyResponse);
expect(result).toMatchObject(formattedSearchStrategyResponse);
});
});
});

View file

@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { buildTopNFlowQuery } from './query.top_n_flow_network.dsl';
import { mockOptions, expectedDsl } from './__mocks__';
describe('buildTopNFlowQuery', () => {
test('build query from options correctly', () => {
expect(buildTopNFlowQuery(mockOptions)).toEqual(expectedDsl);
});
});

View file

@ -0,0 +1,170 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { IEsSearchResponse } from '../../../../../../../../../../src/plugins/data/common';
import {
Direction,
NetworkUsersRequestOptions,
NetworkQueries,
NetworkUsersFields,
FlowTarget,
} from '../../../../../../../common/search_strategy';
export const mockOptions: NetworkUsersRequestOptions = {
defaultIndex: [
'apm-*-transaction*',
'auditbeat-*',
'endgame-*',
'filebeat-*',
'logs-*',
'packetbeat-*',
'winlogbeat-*',
],
factoryQueryType: NetworkQueries.users,
filterQuery: '{"bool":{"must":[],"filter":[{"match_all":{}}],"should":[],"must_not":[]}}',
flowTarget: FlowTarget.source,
ip: '10.142.0.7',
pagination: { activePage: 0, cursorStart: 0, fakePossibleCount: 50, querySize: 10 },
sort: { field: NetworkUsersFields.name, direction: Direction.asc },
timerange: { interval: '12h', from: '2020-09-13T10:16:46.870Z', to: '2020-09-14T10:16:46.870Z' },
};
export const mockSearchStrategyResponse: IEsSearchResponse<unknown> = {
isPartial: false,
isRunning: false,
rawResponse: {
took: 12,
timed_out: false,
_shards: { total: 21, successful: 21, skipped: 0, failed: 0 },
hits: { total: 0, max_score: 0, hits: [] },
aggregations: {
user_count: { value: 3 },
users: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [
{
key: '_apt',
doc_count: 34,
groupName: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] },
groupId: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] },
id: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [{ key: '104', doc_count: 34 }],
},
},
{
key: 'root',
doc_count: 8852,
groupName: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] },
groupId: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] },
id: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [{ key: '0', doc_count: 8852 }],
},
},
{
key: 'tsg',
doc_count: 16,
groupName: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] },
groupId: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] },
id: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [{ key: '1005', doc_count: 16 }],
},
},
],
},
},
},
total: 21,
loaded: 21,
};
export const formattedSearchStrategyResponse = {
...mockSearchStrategyResponse,
edges: [
{
node: {
_id: '_apt',
user: { id: ['104'], name: '_apt', groupId: [], groupName: [], count: 34 },
},
cursor: { value: '_apt', tiebreaker: null },
},
{
node: {
_id: 'root',
user: { id: ['0'], name: 'root', groupId: [], groupName: [], count: 8852 },
},
cursor: { value: 'root', tiebreaker: null },
},
{
node: {
_id: 'tsg',
user: { id: ['1005'], name: 'tsg', groupId: [], groupName: [], count: 16 },
},
cursor: { value: 'tsg', tiebreaker: null },
},
],
inspect: {
dsl: [
'{\n "allowNoIndices": true,\n "index": [\n "apm-*-transaction*",\n "auditbeat-*",\n "endgame-*",\n "filebeat-*",\n "logs-*",\n "packetbeat-*",\n "winlogbeat-*"\n ],\n "ignoreUnavailable": true,\n "body": {\n "aggs": {\n "user_count": {\n "cardinality": {\n "field": "user.name"\n }\n },\n "users": {\n "terms": {\n "field": "user.name",\n "size": 10,\n "order": {\n "_key": "asc"\n }\n },\n "aggs": {\n "id": {\n "terms": {\n "field": "user.id"\n }\n },\n "groupId": {\n "terms": {\n "field": "user.group.id"\n }\n },\n "groupName": {\n "terms": {\n "field": "user.group.name"\n }\n }\n }\n }\n },\n "query": {\n "bool": {\n "filter": [\n "{\\"bool\\":{\\"must\\":[],\\"filter\\":[{\\"match_all\\":{}}],\\"should\\":[],\\"must_not\\":[]}}",\n {\n "range": {\n "@timestamp": {\n "gte": "2020-09-13T10:16:46.870Z",\n "lte": "2020-09-14T10:16:46.870Z",\n "format": "strict_date_optional_time"\n }\n }\n },\n {\n "term": {\n "source.ip": "10.142.0.7"\n }\n }\n ],\n "must_not": [\n {\n "term": {\n "event.category": "authentication"\n }\n }\n ]\n }\n },\n "size": 0,\n "track_total_hits": false\n }\n}',
],
},
pageInfo: { activePage: 0, fakeTotalCount: 3, showMorePagesIndicator: false },
totalCount: 3,
};
export const expectedDsl = {
allowNoIndices: true,
body: {
aggs: {
user_count: { cardinality: { field: 'user.name' } },
users: {
aggs: {
groupId: { terms: { field: 'user.group.id' } },
groupName: { terms: { field: 'user.group.name' } },
id: { terms: { field: 'user.id' } },
},
terms: { field: 'user.name', order: { _key: 'asc' }, size: 10 },
},
},
query: {
bool: {
filter: [
'{"bool":{"must":[],"filter":[{"match_all":{}}],"should":[],"must_not":[]}}',
{
range: {
'@timestamp': {
format: 'strict_date_optional_time',
gte: '2020-09-13T10:16:46.870Z',
lte: '2020-09-14T10:16:46.870Z',
},
},
},
{ term: { 'source.ip': '10.142.0.7' } },
],
must_not: [{ term: { 'event.category': 'authentication' } }],
},
},
size: 0,
track_total_hits: false,
},
ignoreUnavailable: true,
index: [
'apm-*-transaction*',
'auditbeat-*',
'endgame-*',
'filebeat-*',
'logs-*',
'packetbeat-*',
'winlogbeat-*',
],
};

View file

@ -0,0 +1,15 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { getUsersEdges } from './helpers';
import { mockSearchStrategyResponse, formattedSearchStrategyResponse } from './__mocks__';
describe('#getUsers', () => {
test('will format edges correctly', () => {
const edges = getUsersEdges(mockSearchStrategyResponse);
expect(edges).toEqual(formattedSearchStrategyResponse.edges);
});
});

View file

@ -0,0 +1,51 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { DEFAULT_MAX_TABLE_QUERY_SIZE } from '../../../../../../common/constants';
import { NetworkUsersRequestOptions } from '../../../../../../common/search_strategy/security_solution/network';
import * as buildQuery from './query.users_network.dsl';
import { networkUsers } from '.';
import {
mockOptions,
mockSearchStrategyResponse,
formattedSearchStrategyResponse,
} from './__mocks__';
describe('networkUsers search strategy', () => {
const buildUsersQuery = jest.spyOn(buildQuery, 'buildUsersQuery');
afterEach(() => {
buildUsersQuery.mockClear();
});
describe('buildDsl', () => {
test('should build dsl query', () => {
networkUsers.buildDsl(mockOptions);
expect(buildUsersQuery).toHaveBeenCalledWith(mockOptions);
});
test('should throw error if query size is greater equal than DEFAULT_MAX_TABLE_QUERY_SIZE ', () => {
const overSizeOptions = {
...mockOptions,
pagination: {
...mockOptions.pagination,
querySize: DEFAULT_MAX_TABLE_QUERY_SIZE,
},
} as NetworkUsersRequestOptions;
expect(() => {
networkUsers.buildDsl(overSizeOptions);
}).toThrowError(`No query size above ${DEFAULT_MAX_TABLE_QUERY_SIZE}`);
});
});
describe('parse', () => {
test('should parse data correctly', async () => {
const result = await networkUsers.parse(mockOptions, mockSearchStrategyResponse);
expect(result).toMatchObject(formattedSearchStrategyResponse);
});
});
});

View file

@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { buildUsersQuery } from './query.users_network.dsl';
import { mockOptions, expectedDsl } from './__mocks__';
describe('buildUsersQuery', () => {
test('build query from options correctly', () => {
expect(buildUsersQuery(mockOptions)).toEqual(expectedDsl);
});
});