Skip to content

Commit

Permalink
terrible commit because it has a lot, but has tests passing for searc…
Browse files Browse the repository at this point in the history
…h strategy all, need to update details search strategy
  • Loading branch information
yctercero committed Jul 20, 2021
1 parent cd764da commit 7f93d65
Show file tree
Hide file tree
Showing 24 changed files with 1,058 additions and 545 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

/**
Expand All @@ -13,7 +14,18 @@
* This doesn't work in combination with the `xpack.ruleRegistry.index`
* setting, with which the user can change the index prefix.
*/
export const mapConsumerToIndexName = {

export const ALERTS_CONSUMERS = {
APM: 'apm',
LOGS: 'logs',
INFRASTRUCTURE: 'infrastructure',
OBSERVABILITY: 'observability',
SIEM: 'siem',
SYNTHETICS: 'synthetics',
} as const;
export type ALERTS_CONSUMERS = typeof ALERTS_CONSUMERS[keyof typeof ALERTS_CONSUMERS];

export const mapConsumerToIndexName: Record<ALERTS_CONSUMERS, string | string[]> = {
apm: '.alerts-observability-apm',
logs: '.alerts-observability.logs',
infrastructure: '.alerts-observability.metrics',
Expand Down
1 change: 1 addition & 0 deletions packages/kbn-rule-data-utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
*/

export * from './technical_field_names';
export * from './alerts_as_data_rbac';
1 change: 1 addition & 0 deletions src/plugins/data/server/search/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export function createSearchSetupMock(): jest.Mocked<ISearchSetup> {
export function createSearchStartMock(): jest.Mocked<ISearchStart> {
return {
aggs: searchAggsStartMock(),
searchAsInternalUser: jest.fn().mockReturnValue(createSearchRequestHandlerContext()),
getSearchStrategy: jest.fn(),
asScoped: jest.fn().mockReturnValue(createSearchRequestHandlerContext()),
searchSource: searchSourceMock.createStartContract(),
Expand Down
1 change: 1 addition & 0 deletions src/plugins/data/server/search/search_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
private searchStrategies: StrategyMap = {};
private sessionService: ISearchSessionService;
private asScoped!: ISearchStart['asScoped'];
private searchAsInternalUser!: ISearchStrategy;

constructor(
private initializerContext: PluginInitializerContext<ConfigSchema>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,6 @@ export class AlertingAuthorization {
// manually authorize each rule type in the management UI.
this.exemptConsumerIds = exemptConsumerIds;

this.spaceId = getSpace(request).then((maybeSpace) => maybeSpace?.id);

this.featuresIds = getSpace(request)
.then((maybeSpace) => new Set(maybeSpace?.disabledFeatures ?? []))
.then(
Expand All @@ -127,6 +125,12 @@ export class AlertingAuthorization {
return new Set();
});

this.spaceId = getSpace(request)
.then((maybeSpace) => maybeSpace?.id)
.catch((e) => {
return undefined;
});

this.allPossibleConsumers = this.featuresIds.then((featuresIds) => {
return featuresIds.size
? asAuthorizedConsumers([...this.exemptConsumerIds, ...featuresIds], {
Expand Down Expand Up @@ -302,8 +306,11 @@ export class AlertingAuthorization {
);

const authorizedEntries: Map<string, Set<string>> = new Map();
const alertsSpaceId =
authorizationEntity === AlertingAuthorizationEntity.Alert ? await this.spaceId : undefined;

return {
filter: asFiltersByRuleTypeAndConsumer(authorizedRuleTypes, filterOpts),
filter: asFiltersByRuleTypeAndConsumer(authorizedRuleTypes, filterOpts, alertsSpaceId),
ensureRuleTypeIsAuthorized: (ruleTypeId: string, consumer: string, authType: string) => {
if (!authorizedRuleTypeIdsToConsumers.has(`${ruleTypeId}/${consumer}/${authType}`)) {
throw Boom.forbidden(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
* 2.0.
*/

import { remove } from 'lodash';
import { JsonObject } from '@kbn/common-utils';
import { nodeBuilder, EsQueryConfig } from '../../../../../src/plugins/data/common';
import { toElasticsearchQuery } from '../../../../../src/plugins/data/common/es_query';
import { remove } from 'lodash';

import { nodeBuilder } from '../../../../../src/plugins/data/common';
import { KueryNode } from '../../../../../src/plugins/data/server';
import { RegistryAlertTypeWithAuth } from './alerting_authorization';

Expand All @@ -25,15 +25,9 @@ export interface AlertingAuthorizationFilterOpts {
interface AlertingAuthorizationFilterFieldNames {
ruleTypeId: string;
consumer: string;
spaceIds?: string;
}

const esQueryConfig: EsQueryConfig = {
allowLeadingWildcards: true,
dateFormatTZ: 'Zulu',
ignoreFilterIfFieldNotInIndex: false,
queryStringOptions: { analyze_wildcard: true },
};

export function asFiltersByRuleTypeAndConsumer(
ruleTypes: Set<RegistryAlertTypeWithAuth>,
opts: AlertingAuthorizationFilterOpts,
Expand Down Expand Up @@ -82,8 +76,8 @@ export const buildRuleTypeFilter = (
ruleTypes: Set<RegistryAlertTypeWithAuth>,
opts: AlertingAuthorizationFilterOpts,
alertSpaceId?: string
) => {
const allFilters = Array.from(ruleTypes).map<JSON.Object[]>(({ id, authorizedConsumers }) => {
): JsonObject => {
const allFilters = Array.from(ruleTypes).map(({ id, authorizedConsumers }) => {
const ruleIdFilter = {
bool: {
should: [
Expand All @@ -97,7 +91,7 @@ export const buildRuleTypeFilter = (
},
};
const spaceIdFilter =
alertSpaceId != null
alertSpaceId != null && opts.fieldNames.spaceIds != null
? {
bool: {
filter: [{ term: { [opts.fieldNames.spaceIds]: alertSpaceId } }],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
*/
import { PublicMethodsOf } from '@kbn/utility-types';
import { decodeVersion, encodeHitVersion } from '@kbn/securitysolution-es-utils';
import {
mapConsumerToIndexName,
validFeatureIds,
isValidFeatureId,
} from '@kbn/rule-data-utils/target/alerts_as_data_rbac';

import { AlertTypeParams } from '../../../alerting/server';
import {
Expand All @@ -24,7 +29,6 @@ import {
SPACE_IDS,
} from '../../common/technical_rule_data_field_names';
import { ParsedTechnicalFields } from '../../common/parse_technical_fields';
import { mapConsumerToIndexName, validFeatureIds, isValidFeatureId } from '../utils/rbac';

// TODO: Fix typings https://github.com/elastic/kibana/issues/101776
type NonNullableProps<Obj extends {}, Props extends keyof Obj> = Omit<Obj, Props> &
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
import { IRouter } from 'kibana/server';
import { id as _id } from '@kbn/securitysolution-io-ts-list-types';
import { transformError } from '@kbn/securitysolution-es-utils';
import { validFeatureIds } from '@kbn/rule-data-utils/target/alerts_as_data_rbac';

import { RacRequestHandlerContext } from '../types';
import { BASE_RAC_ALERTS_API_PATH } from '../../common/constants';
import { validFeatureIds } from '../utils/rbac';

export const getAlertsIndexRoute = (router: IRouter<RacRequestHandlerContext>) => {
router.get(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@

import { ApiResponse } from '@elastic/elasticsearch';
import { BulkRequest, BulkResponse } from '@elastic/elasticsearch/api/types';
import { ValidFeatureId } from '@kbn/rule-data-utils/target/alerts_as_data_rbac';

import { ElasticsearchClient } from 'kibana/server';
import { FieldDescriptor } from 'src/plugins/data/server';
import { ESSearchRequest, ESSearchResponse } from 'src/core/types/elasticsearch';
import { TechnicalRuleDataFieldName } from '../../common/technical_rule_data_field_names';
import { ValidFeatureId } from '../utils/rbac';

export interface RuleDataReader {
search<TSearchRequest extends ESSearchRequest>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
*/
import { ClusterPutComponentTemplate } from '@elastic/elasticsearch/api/requestParams';
import { estypes } from '@elastic/elasticsearch';
import { ValidFeatureId } from '@kbn/rule-data-utils/target/alerts_as_data_rbac';

import { ElasticsearchClient, Logger } from 'kibana/server';
import { get, isEmpty } from 'lodash';
import { technicalComponentTemplate } from '../../common/assets/component_templates/technical_component_template';
Expand All @@ -20,7 +22,6 @@ import { ClusterPutComponentTemplateBody, PutIndexTemplateRequest } from '../../
import { RuleDataClient } from '../rule_data_client';
import { RuleDataWriteDisabledError } from './errors';
import { incrementIndexName } from './utils';
import { ValidFeatureId } from '../utils/rbac';

const BOOTSTRAP_TIMEOUT = 60000;

Expand Down
6 changes: 5 additions & 1 deletion x-pack/plugins/security_solution/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import {
PluginSetupContract as AlertingSetup,
PluginStartContract as AlertPluginStartContract,
} from '../../alerting/server';
import { mappingFromFieldMap } from '../../rule_registry/common/mapping_from_field_map';
import { technicalRuleFieldMap } from '../../rule_registry/common/assets/field_maps/technical_rule_field_map';

import { PluginStartContract as CasesPluginStartContract } from '../../cases/server';
import {
Expand Down Expand Up @@ -67,6 +69,7 @@ import {
NOTIFICATIONS_ID,
REFERENCE_RULE_ALERT_TYPE_ID,
REFERENCE_RULE_PERSISTENCE_ALERT_TYPE_ID,
CUSTOM_ALERT_TYPE_ID,
} from '../common/constants';
import { registerEndpointRoutes } from './endpoint/routes/metadata';
import { registerLimitedConcurrencyRoutes } from './endpoint/routes/limited_concurrency';
Expand Down Expand Up @@ -212,7 +215,7 @@ export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, S
settings: {
number_of_shards: 1,
},
mappings: {}, // TODO: Add mappings here via `mappingFromFieldMap()`
mappings: { dynamic: false, ...mappingFromFieldMap(technicalRuleFieldMap) },
},
},
});
Expand Down Expand Up @@ -271,6 +274,7 @@ export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, S
const referenceRuleTypes = [
REFERENCE_RULE_ALERT_TYPE_ID,
REFERENCE_RULE_PERSISTENCE_ALERT_TYPE_ID,
CUSTOM_ALERT_TYPE_ID,
];
const ruleTypes = [
SIGNALS_ID,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
* 2.0.
*/

import { JsonObject } from '@kbn/common-utils';

import type { IEsSearchResponse } from '../../../../../../../../src/plugins/data/common';
import type { Ecs } from '../../../../ecs';
import type { CursorType, Inspect, Maybe, PaginationInputPaginated } from '../../../common';
Expand Down Expand Up @@ -39,4 +41,5 @@ export interface TimelineEventsAllRequestOptions extends TimelineRequestOptionsP
fieldRequested: string[];
language: 'eql' | 'kuery' | 'lucene';
excludeEcsData?: boolean;
authFilter?: JsonObject;
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,9 @@ export enum TimelineEventsQueries {
kpi = 'eventsKpi',
lastEventTime = 'eventsLastEventTime',
}

export enum EntityType {
ALERTS = 'alerts',
EVENTS = 'events',
ALL = 'all',
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import type { ALERTS_CONSUMERS } from '@kbn/rule-data-utils/target/alerts_as_data_rbac';

import { IEsSearchRequest } from '../../../../../../src/plugins/data/common';
import { ESQuery } from '../../typed_json';
Expand All @@ -16,6 +17,7 @@ import {
TimelineEventsLastEventTimeRequestOptions,
TimelineEventsLastEventTimeStrategyResponse,
TimelineKpiStrategyResponse,
EntityType,
} from './events';
import {
DocValueFields,
Expand All @@ -41,6 +43,8 @@ export interface TimelineRequestBasicOptions extends IEsSearchRequest {
defaultIndex: string[];
docValueFields?: DocValueFields[];
factoryQueryType?: TimelineFactoryQueryTypes;
entityType?: EntityType;
alertConsumers?: ALERTS_CONSUMERS[];
}

export interface TimelineRequestSortField<Field = string> extends SortField<Field> {
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/timelines/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
"extraPublicDirs": ["common"],
"server": true,
"ui": true,
"requiredPlugins": ["data", "dataEnhanced", "kibanaReact", "kibanaUtils"],
"requiredPlugins": ["alerting", "data", "dataEnhanced", "kibanaReact", "kibanaUtils"],
"optionalPlugins": []
}
5 changes: 4 additions & 1 deletion x-pack/plugins/timelines/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ export class TimelinesPlugin

// Register search strategy
core.getStartServices().then(([_, depsStart]) => {
const TimelineSearchStrategy = timelineSearchStrategyProvider(depsStart.data);
const TimelineSearchStrategy = timelineSearchStrategyProvider(
depsStart.data,
depsStart.alerting
);
const TimelineEqlSearchStrategy = timelineEqlSearchStrategyProvider(depsStart.data);
const IndexFields = indexFieldsProvider();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ import { buildFieldsRequest, formatTimelineData } from './helpers';
import { inspectStringifyObject } from '../../../../../utils/build_query';

export const timelineEventsAll: TimelineFactory<TimelineEventsQueries.all> = {
buildDsl: (options: TimelineEventsAllRequestOptions) => {
buildDsl: ({ authFilter, ...options }: TimelineEventsAllRequestOptions) => {
if (options.pagination && options.pagination.querySize >= DEFAULT_MAX_TABLE_QUERY_SIZE) {
throw new Error(`No query size above ${DEFAULT_MAX_TABLE_QUERY_SIZE}`);
}
const { fieldRequested, ...queryOptions } = cloneDeep(options);
queryOptions.fields = buildFieldsRequest(fieldRequested, queryOptions.excludeEcsData);
return buildTimelineEventsAllQuery(queryOptions);
return buildTimelineEventsAllQuery({ ...queryOptions, authFilter });
},
parse: async (
options: TimelineEventsAllRequestOptions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const buildTimelineEventsAllQuery = ({
pagination: { activePage, querySize },
sort,
timerange,
authFilter,
}: Omit<TimelineEventsAllRequestOptions, 'fieldRequested'>) => {
const filterClause = [...createQueryFilterClauses(filterQuery)];

Expand All @@ -46,7 +47,8 @@ export const buildTimelineEventsAllQuery = ({
return [];
};

const filter = [...filterClause, ...getTimerangeFilter(timerange), { match_all: {} }];
const filters = [...filterClause, ...getTimerangeFilter(timerange), { match_all: {} }];
const filter = authFilter != null ? [...filters, { ...authFilter }] : filters;

const getSortField = (sortFields: TimelineRequestSortField[]) =>
sortFields.map((item) => {
Expand Down
Loading

0 comments on commit 7f93d65

Please sign in to comment.