From 3b07dcdd4bf6ffd067209b7baf2d2f5776891b66 Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Mon, 3 Oct 2022 12:54:40 +0200 Subject: [PATCH 01/10] [ML] Add a tooltip for the Avg inference time column (#142355) * add a tooltip for avg inference time * update message --- .../nodes_overview/allocated_models.tsx | 47 ++++++++++++++++--- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/ml/public/application/trained_models/nodes_overview/allocated_models.tsx b/x-pack/plugins/ml/public/application/trained_models/nodes_overview/allocated_models.tsx index d1808c2c82135..198c01806e06b 100644 --- a/x-pack/plugins/ml/public/application/trained_models/nodes_overview/allocated_models.tsx +++ b/x-pack/plugins/ml/public/application/trained_models/nodes_overview/allocated_models.tsx @@ -5,8 +5,17 @@ * 2.0. */ import React, { FC } from 'react'; -import { EuiBadge, EuiIcon, EuiInMemoryTable, EuiToolTip } from '@elastic/eui'; +import { + EuiBadge, + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiInMemoryTable, + EuiToolTip, + useEuiTheme, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; import { EuiBasicTableColumn } from '@elastic/eui/src/components/basic_table/basic_table'; import { FIELD_FORMAT_IDS } from '@kbn/field-formats-plugin/common'; import type { @@ -27,6 +36,7 @@ export const AllocatedModels: FC = ({ const bytesFormatter = useFieldFormatter(FIELD_FORMAT_IDS.BYTES); const dateFormatter = useFieldFormatter(FIELD_FORMAT_IDS.DATE); const durationFormatter = useFieldFormatter(FIELD_FORMAT_IDS.DURATION); + const euiTheme = useEuiTheme(); const columns: Array> = [ { @@ -97,11 +107,36 @@ export const AllocatedModels: FC = ({ 'data-test-subj': 'mlAllocatedModelsTableThroughput', }, { - name: i18n.translate( - 'xpack.ml.trainedModels.nodesList.modelsList.modelAvgInferenceTimeHeader', - { - defaultMessage: 'Avg inference time', - } + name: ( + + } + content={ + + } + > + + + + + + + + + + + ), width: '100px', truncateText: false, From fe2210b96da19379e115349f3ac7800ed173e081 Mon Sep 17 00:00:00 2001 From: Stratoula Kalafateli Date: Mon, 3 Oct 2022 14:21:24 +0300 Subject: [PATCH 02/10] [Unified search] Fixes the problem with the button popover buttons on DSL filters (#142402) * [Unified search] Fixes the problem with the button popover buttons on DSL filters * Add comment * Apply comments --- .../public/filter_bar/filter_editor/filter_editor.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/plugins/unified_search/public/filter_bar/filter_editor/filter_editor.tsx b/src/plugins/unified_search/public/filter_bar/filter_editor/filter_editor.tsx index cdf4af1746e5c..1b336acd024ae 100644 --- a/src/plugins/unified_search/public/filter_bar/filter_editor/filter_editor.tsx +++ b/src/plugins/unified_search/public/filter_bar/filter_editor/filter_editor.tsx @@ -169,7 +169,13 @@ class FilterEditorUI extends Component { - + {/* Adding isolation here fixes this bug https://github.com/elastic/kibana/issues/142211 */} + Date: Mon, 3 Oct 2022 13:30:08 +0200 Subject: [PATCH 03/10] Fix time filter in alerts table (#142377) --- .../__snapshots__/build_es_query.test.ts.snap | 33 +++++++++++++++++++ .../build_es_query/build_es_query.test.ts | 7 ++++ .../utils/build_es_query/build_es_query.ts | 6 ++-- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/observability/public/utils/build_es_query/__snapshots__/build_es_query.test.ts.snap b/x-pack/plugins/observability/public/utils/build_es_query/__snapshots__/build_es_query.test.ts.snap index fcadce3f18b19..8e6559830cd90 100644 --- a/x-pack/plugins/observability/public/utils/build_es_query/__snapshots__/build_es_query.test.ts.snap +++ b/x-pack/plugins/observability/public/utils/build_es_query/__snapshots__/build_es_query.test.ts.snap @@ -166,3 +166,36 @@ Object { }, } `; + +exports[`buildEsQuery should generate correct es query for {"timeRange":{"from":"now-15min","to":"now"},"kuery":"kibana.alert.status: \\"recovered\\""} 1`] = ` +Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match_phrase": Object { + "kibana.alert.status": "recovered", + }, + }, + ], + }, + }, + Object { + "range": Object { + "@timestamp": Object { + "format": "strict_date_optional_time", + "gte": "now-15min", + "lte": "now", + }, + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, +} +`; diff --git a/x-pack/plugins/observability/public/utils/build_es_query/build_es_query.test.ts b/x-pack/plugins/observability/public/utils/build_es_query/build_es_query.test.ts index 4bbacaa7bb1ad..39029a03bb267 100644 --- a/x-pack/plugins/observability/public/utils/build_es_query/build_es_query.test.ts +++ b/x-pack/plugins/observability/public/utils/build_es_query/build_es_query.test.ts @@ -34,6 +34,13 @@ describe('buildEsQuery', () => { timeRange: defaultTimeRange, kuery: 'kibana.alert.status: "recovered" and kibana.alert.duration.us >= 120', }, + { + timeRange: { + from: 'now-15min', + to: 'now', + }, + kuery: 'kibana.alert.status: "recovered"', + }, ]; test.each(testData)('should generate correct es query for %j', ({ kuery, timeRange }) => { diff --git a/x-pack/plugins/observability/public/utils/build_es_query/build_es_query.ts b/x-pack/plugins/observability/public/utils/build_es_query/build_es_query.ts index 28e2942c1f606..12711c54f9784 100644 --- a/x-pack/plugins/observability/public/utils/build_es_query/build_es_query.ts +++ b/x-pack/plugins/observability/public/utils/build_es_query/build_es_query.ts @@ -7,15 +7,15 @@ import { buildEsQuery as kbnBuildEsQuery, TimeRange } from '@kbn/es-query'; import { TIMESTAMP } from '@kbn/rule-data-utils'; -import { getTime } from '@kbn/data-plugin/common'; +import { getRelativeTime } from '@kbn/data-plugin/common'; export function buildEsQuery(timeRange: TimeRange, kuery?: string) { const timeFilter = timeRange && - getTime(undefined, timeRange, { + getRelativeTime(undefined, timeRange, { fieldName: TIMESTAMP, }); - const filtersToUse = [...(timeFilter ? [timeFilter] : [])]; + const filtersToUse = timeFilter ? [timeFilter] : []; const queryToUse = kuery ? { query: kuery, language: 'kuery' } : []; return kbnBuildEsQuery(undefined, queryToUse, filtersToUse); From 08e2425e4f67b18a7e8f3869afa614a3719c2423 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Mon, 3 Oct 2022 13:15:20 +0100 Subject: [PATCH 04/10] skip flaky suite (#142397) --- x-pack/test/functional/apps/ml/short_tests/pages.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/functional/apps/ml/short_tests/pages.ts b/x-pack/test/functional/apps/ml/short_tests/pages.ts index e17454d0fa222..87fb9d03ca0c9 100644 --- a/x-pack/test/functional/apps/ml/short_tests/pages.ts +++ b/x-pack/test/functional/apps/ml/short_tests/pages.ts @@ -10,7 +10,8 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const ml = getService('ml'); - describe('page navigation', function () { + // FLAKY: https://github.com/elastic/kibana/issues/142397 + describe.skip('page navigation', function () { this.tags(['skipFirefox', 'ml']); before(async () => { await ml.api.cleanMlIndices(); From 4db7564209fd894f4cb94441b6fc76d10fdd47c4 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Mon, 3 Oct 2022 15:26:47 +0300 Subject: [PATCH 05/10] [Lens] Migrate away from EuiPageTemplate/EuiPageContent (#142367) * [Lens] Migrate away from EuiPageTemplate/EuiPageContent Closes: #139905 * fix FF issue Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../geo_field_workspace_panel.tsx | 6 +- .../workspace_panel/workspace_panel.tsx | 5 +- .../workspace_panel_wrapper.tsx | 154 +++++++++--------- 3 files changed, 82 insertions(+), 83 deletions(-) diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/geo_field_workspace_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/geo_field_workspace_panel.tsx index f7a0d8304296c..01370d7919c29 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/geo_field_workspace_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/geo_field_workspace_panel.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { EuiPageContentBody_Deprecated as EuiPageContentBody, EuiText } from '@elastic/eui'; +import { EuiText } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { UiActionsStart, VISUALIZE_GEO_FIELD_TRIGGER } from '@kbn/ui-actions-plugin/public'; @@ -45,7 +45,7 @@ export function GeoFieldWorkspacePanel(props: Props) { } return ( - +

@@ -72,6 +72,6 @@ export function GeoFieldWorkspacePanel(props: Props) {

- +
); } diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx index 0a6d0391c15a1..38f62b6e928b6 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx @@ -18,7 +18,6 @@ import { EuiText, EuiButtonEmpty, EuiLink, - EuiPageContentBody_Deprecated as EuiPageContentBody, EuiButton, EuiSpacer, EuiTextColor, @@ -618,9 +617,7 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ value={dropProps.value} order={dropProps.order} > - - {renderWorkspaceContents()} - +
{renderWorkspaceContents()}
); }; diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.tsx index cdc293dc78bc5..865dbb4e859e4 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.tsx @@ -9,7 +9,8 @@ import './workspace_panel_wrapper.scss'; import React, { useCallback } from 'react'; import { - EuiPageContent_Deprecated as EuiPageContent, + EuiPageSection, + EuiPageTemplate, EuiFlexGroup, EuiFlexItem, EuiButton, @@ -117,92 +118,93 @@ export function WorkspacePanelWrapper({ warningMessages.push(...requestWarnings); } return ( - <> + {!(isFullscreen && (autoApplyEnabled || warningMessages?.length)) && ( - - {!isFullscreen && ( - - - - - - - {activeVisualization && activeVisualization.renderToolbar && ( + + + {!isFullscreen && ( + + - + + {activeVisualization && activeVisualization.renderToolbar && ( + + + + )} + + + )} + + + + {warningMessages?.length ? ( + + {warningMessages} + + ) : null} + + {!autoApplyEnabled && ( + + dispatchLens(applyChanges())} + size="m" + data-test-subj="lnsApplyChanges__toolbar" + minWidth="auto" + > + + + )} - )} - - - - {warningMessages?.length ? ( - - {warningMessages} - - ) : null} - - {!autoApplyEnabled && ( - - dispatchLens(applyChanges())} - size="m" - data-test-subj="lnsApplyChanges__toolbar" - minWidth="auto" - > - - - - )} - - - + + )} - - {children} - - + + ); } From bea422856900b8167f128642169ce81a1c50968a Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Mon, 3 Oct 2022 13:28:43 +0100 Subject: [PATCH 06/10] [ML] Api tests for ml/results/anomaly_search (#142454) * [ML] Api tests for ml/results/anomaly_search * changes based on review --- .../apis/ml/results/get_anomaly_search.ts | 106 ++++++++++++++++++ .../api_integration/apis/ml/results/index.ts | 1 + 2 files changed, 107 insertions(+) create mode 100644 x-pack/test/api_integration/apis/ml/results/get_anomaly_search.ts diff --git a/x-pack/test/api_integration/apis/ml/results/get_anomaly_search.ts b/x-pack/test/api_integration/apis/ml/results/get_anomaly_search.ts new file mode 100644 index 0000000000000..ce4b5b600e579 --- /dev/null +++ b/x-pack/test/api_integration/apis/ml/results/get_anomaly_search.ts @@ -0,0 +1,106 @@ +/* + * 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. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; +import { USER } from '../../../../functional/services/ml/security_common'; +import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api'; + +export default ({ getService }: FtrProviderContext) => { + const esArchiver = getService('esArchiver'); + const ml = getService('ml'); + const spacesService = getService('spaces'); + const supertest = getService('supertestWithoutAuth'); + + const adJobId = 'fq_single'; + const idSpace1 = 'space1'; + const idSpace2 = 'space2'; + + const jobQuery = { + size: 1, + body: { + query: { + bool: { + filter: [{ term: { job_id: adJobId } }], + }, + }, + }, + }; + + async function runRequest( + requestBody: { + jobIds: string[]; + query: any; + }, + space: string, + expectedStatusCode: number, + user: USER + ) { + const { body, status } = await supertest + .post(`/s/${space}/api/ml/results/anomaly_search`) + .auth(user, ml.securityCommon.getPasswordForUser(user)) + .set(COMMON_REQUEST_HEADERS) + .send(requestBody); + ml.api.assertResponseStatusCode(expectedStatusCode, status, body); + + return body; + } + + describe('POST results/anomaly_search', () => { + before(async () => { + await ml.testResources.setKibanaTimeZoneToUTC(); + await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); + + // create spaces + await spacesService.create({ id: idSpace1, name: 'space_one', disabledFeatures: [] }); + await spacesService.create({ id: idSpace2, name: 'space_two', disabledFeatures: [] }); + + await ml.api.createAndRunAnomalyDetectionLookbackJob( + ml.commonConfig.getADFqSingleMetricJobConfig(adJobId), + ml.commonConfig.getADFqDatafeedConfig(adJobId), + idSpace1 + ); + await ml.api.assertJobSpaces(adJobId, 'anomaly-detector', [idSpace1]); + }); + + after(async () => { + await ml.api.cleanMlIndices(); + await ml.testResources.cleanMLSavedObjects(); + await spacesService.delete(idSpace1); + await spacesService.delete(idSpace2); + }); + + it('should see results in current space', async () => { + const body = await runRequest( + { + jobIds: [adJobId], + query: jobQuery, + }, + idSpace1, + 200, + USER.ML_POWERUSER + ); + expect(body.hits.hits[0]._source.job_id).to.eql( + adJobId, + `Expected job_id to equal ${adJobId}` + ); + }); + + it('should not see results in different space', async () => { + const body = await runRequest( + { + jobIds: [adJobId], + query: jobQuery, + }, + idSpace2, + 404, + USER.ML_POWERUSER + ); + expect(body.message).to.eql(`${adJobId} missing`); + }); + }); +}; diff --git a/x-pack/test/api_integration/apis/ml/results/index.ts b/x-pack/test/api_integration/apis/ml/results/index.ts index 1580055df6d0e..e9accf88eadab 100644 --- a/x-pack/test/api_integration/apis/ml/results/index.ts +++ b/x-pack/test/api_integration/apis/ml/results/index.ts @@ -16,5 +16,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./get_category_examples')); loadTestFile(require.resolve('./max_anomaly_score')); loadTestFile(require.resolve('./get_partition_fields_values')); + loadTestFile(require.resolve('./get_anomaly_search')); }); } From c1d0b9387fdd673ebcc9e6e139ce50d53d578a2f Mon Sep 17 00:00:00 2001 From: Thom Heymann <190132+thomheymann@users.noreply.github.com> Date: Mon, 3 Oct 2022 13:30:12 +0100 Subject: [PATCH 07/10] Add user profile ID to audit log events (#141092) * Add user profile ID to audit log events * Fix merge conflict * Fix integration tests * Fix integration tests * Fix type * Refactor * updated functional tests * updated functional tests * Added tests for enrichment logic Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- docs/user/security/audit-logging.asciidoc | 3 + .../common/model/authenticated_user.mock.ts | 1 + .../common/model/authenticated_user.ts | 5 ++ .../server/audit/audit_events.test.ts | 4 + .../security/server/audit/audit_events.ts | 22 +++-- .../server/audit/audit_service.test.ts | 6 +- .../security/server/audit/audit_service.ts | 1 + .../authentication_service.test.ts | 27 ++++++ .../authentication/authenticator.test.ts | 87 ++++++++++++++++++- .../server/authentication/authenticator.ts | 76 ++++++++++++---- .../apis/security/basic_login.js | 4 +- .../tests/kerberos/kerberos_login.ts | 38 ++++---- .../login_selector/basic_functionality.ts | 2 +- .../oidc/authorization_code_flow/oidc_auth.ts | 4 +- .../tests/oidc/implicit_flow/oidc_auth.ts | 2 +- .../tests/pki/pki_auth.ts | 79 +++++++++-------- .../tests/saml/saml_login.ts | 2 +- .../tests/user_profiles/get_current.ts | 6 ++ 18 files changed, 282 insertions(+), 87 deletions(-) diff --git a/docs/user/security/audit-logging.asciidoc b/docs/user/security/audit-logging.asciidoc index ce1e63c20d1c6..5f6fe746814e5 100644 --- a/docs/user/security/audit-logging.asciidoc +++ b/docs/user/security/audit-logging.asciidoc @@ -325,6 +325,9 @@ Possible values: | *Field* | *Description* +| `user.id` +| Unique identifier of the user across sessions (See {ref}/user-profile.html[user profiles]). + | `user.name` | Login name of the user. diff --git a/x-pack/plugins/security/common/model/authenticated_user.mock.ts b/x-pack/plugins/security/common/model/authenticated_user.mock.ts index 73641d2fa5983..84b300d5c982b 100644 --- a/x-pack/plugins/security/common/model/authenticated_user.mock.ts +++ b/x-pack/plugins/security/common/model/authenticated_user.mock.ts @@ -24,6 +24,7 @@ export function mockAuthenticatedUser(user: MockAuthenticatedUserProps = {}) { authentication_provider: { type: 'basic', name: 'basic1' }, authentication_type: 'realm', elastic_cloud_user: false, + profile_uid: 'uid', metadata: { _reserved: false }, ...user, }; diff --git a/x-pack/plugins/security/common/model/authenticated_user.ts b/x-pack/plugins/security/common/model/authenticated_user.ts index 7f7e965994e4b..fd78b250a5ccc 100644 --- a/x-pack/plugins/security/common/model/authenticated_user.ts +++ b/x-pack/plugins/security/common/model/authenticated_user.ts @@ -57,6 +57,11 @@ export interface AuthenticatedUser extends User { * Indicates whether user is authenticated via Elastic Cloud built-in SAML realm. */ elastic_cloud_user: boolean; + + /** + * User profile ID of this user. + */ + profile_uid?: string; } export function isUserAnonymous(user: Pick) { diff --git a/x-pack/plugins/security/server/audit/audit_events.test.ts b/x-pack/plugins/security/server/audit/audit_events.test.ts index 73523b4a3e009..1f9ab461e0b00 100644 --- a/x-pack/plugins/security/server/audit/audit_events.test.ts +++ b/x-pack/plugins/security/server/audit/audit_events.test.ts @@ -240,6 +240,7 @@ describe('#userLoginEvent', () => { authenticationProvider: 'basic1', authenticationType: 'basic', sessionId: '123', + userProfileId: 'uid', }) ).toMatchInlineSnapshot(` Object { @@ -261,6 +262,7 @@ describe('#userLoginEvent', () => { }, "message": "User [user] has logged in using basic provider [name=basic1]", "user": Object { + "id": "uid", "name": "user", "roles": Array [ "user-role", @@ -311,6 +313,7 @@ describe('#userLogoutEvent', () => { userLogoutEvent({ username: 'elastic', provider: { name: 'basic1', type: 'basic' }, + userProfileId: 'uid', }) ).toMatchInlineSnapshot(` Object { @@ -327,6 +330,7 @@ describe('#userLogoutEvent', () => { }, "message": "User [elastic] is logging out using basic provider [name=basic1]", "user": Object { + "id": "uid", "name": "elastic", }, } diff --git a/x-pack/plugins/security/server/audit/audit_events.ts b/x-pack/plugins/security/server/audit/audit_events.ts index dd767df83b692..deb4b356c9f95 100644 --- a/x-pack/plugins/security/server/audit/audit_events.ts +++ b/x-pack/plugins/security/server/audit/audit_events.ts @@ -98,6 +98,7 @@ export interface UserLoginParams { authenticationProvider?: string; authenticationType?: string; sessionId?: string; + userProfileId?: string; } export function userLoginEvent({ @@ -105,6 +106,7 @@ export function userLoginEvent({ authenticationProvider, authenticationType, sessionId, + userProfileId, }: UserLoginParams): AuditEvent { return { message: authenticationResult.user @@ -116,6 +118,7 @@ export function userLoginEvent({ outcome: authenticationResult.user ? 'success' : 'failure', }, user: authenticationResult.user && { + id: userProfileId, name: authenticationResult.user.username, roles: authenticationResult.user.roles as string[], }, @@ -137,9 +140,14 @@ export function userLoginEvent({ export interface UserLogoutParams { username?: string; provider: AuthenticationProvider; + userProfileId?: string; } -export function userLogoutEvent({ username, provider }: UserLogoutParams): AuditEvent { +export function userLogoutEvent({ + username, + provider, + userProfileId, +}: UserLogoutParams): AuditEvent { return { message: `User [${username}] is logging out using ${provider.type} provider [name=${provider.name}]`, event: { @@ -147,11 +155,13 @@ export function userLogoutEvent({ username, provider }: UserLogoutParams): Audit category: ['authentication'], outcome: 'unknown', }, - user: username - ? { - name: username, - } - : undefined, + user: + userProfileId || username + ? { + id: userProfileId, + name: username, + } + : undefined, kibana: { authentication_provider: provider.name, authentication_type: provider.type, diff --git a/x-pack/plugins/security/server/audit/audit_service.test.ts b/x-pack/plugins/security/server/audit/audit_service.test.ts index d750fa2fc36b9..dfd42c2260c5e 100644 --- a/x-pack/plugins/security/server/audit/audit_service.test.ts +++ b/x-pack/plugins/security/server/audit/audit_service.test.ts @@ -38,7 +38,9 @@ const createAuditConfig = (settings: Partial) => { const config = createAuditConfig({ enabled: true }); const { logging } = coreMock.createSetup(); const http = httpServiceMock.createSetupContract(); -const getCurrentUser = jest.fn().mockReturnValue({ username: 'jdoe', roles: ['admin'] }); +const getCurrentUser = jest + .fn() + .mockReturnValue({ username: 'jdoe', roles: ['admin'], profile_uid: 'uid' }); const getSpaceId = jest.fn().mockReturnValue('default'); const getSID = jest.fn().mockResolvedValue('SESSION_ID'); const recordAuditLoggingUsage = jest.fn(); @@ -192,7 +194,7 @@ describe('#asScoped', () => { event: { action: 'ACTION' }, kibana: { space_id: 'default', session_id: 'SESSION_ID' }, trace: { id: 'REQUEST_ID' }, - user: { name: 'jdoe', roles: ['admin'] }, + user: { id: 'uid', name: 'jdoe', roles: ['admin'] }, }); audit.stop(); }); diff --git a/x-pack/plugins/security/server/audit/audit_service.ts b/x-pack/plugins/security/server/audit/audit_service.ts index 89b288d07e9fe..ff8a09df40198 100644 --- a/x-pack/plugins/security/server/audit/audit_service.ts +++ b/x-pack/plugins/security/server/audit/audit_service.ts @@ -166,6 +166,7 @@ export class AuditService { ...event, user: (user && { + id: user.profile_uid, name: user.username, roles: user.roles as string[], }) || diff --git a/x-pack/plugins/security/server/authentication/authentication_service.test.ts b/x-pack/plugins/security/server/authentication/authentication_service.test.ts index 0f2657a419a0a..55357be756e7e 100644 --- a/x-pack/plugins/security/server/authentication/authentication_service.test.ts +++ b/x-pack/plugins/security/server/authentication/authentication_service.test.ts @@ -273,6 +273,33 @@ describe('AuthenticationService', () => { expect(authenticate).toHaveBeenCalledWith(mockRequest); }); + it('sets authenticated state correctly with user profile id', async () => { + const mockRequest = httpServerMock.createKibanaRequest(); + const mockResponse = httpServerMock.createLifecycleResponseFactory(); + const mockUser = mockAuthenticatedUser(); + const mockAuthHeaders = { authorization: 'Basic xxx' }; + const mockAuthResponseHeaders = { 'WWW-Authenticate': 'Negotiate' }; + + authenticate.mockResolvedValue( + AuthenticationResult.succeeded( + { ...mockUser, profile_uid: 'USER_PROFILE_ID' }, + { + authHeaders: mockAuthHeaders, + authResponseHeaders: mockAuthResponseHeaders, + } + ) + ); + + await authHandler(mockRequest, mockResponse, mockAuthToolkit); + + expect(mockAuthToolkit.authenticated).toHaveBeenCalledTimes(1); + expect(mockAuthToolkit.authenticated).toHaveBeenCalledWith({ + state: { ...mockUser, profile_uid: 'USER_PROFILE_ID' }, + requestHeaders: mockAuthHeaders, + responseHeaders: mockAuthResponseHeaders, + }); + }); + it('redirects user if redirection is requested by the authenticator preserving authentication response headers if any', async () => { const mockResponse = httpServerMock.createLifecycleResponseFactory(); authenticate.mockResolvedValue( diff --git a/x-pack/plugins/security/server/authentication/authenticator.test.ts b/x-pack/plugins/security/server/authentication/authenticator.test.ts index 1c62b5ae44dd9..1c160bb4dfa48 100644 --- a/x-pack/plugins/security/server/authentication/authenticator.test.ts +++ b/x-pack/plugins/security/server/authentication/authenticator.test.ts @@ -39,7 +39,7 @@ import type { UserProfileGrant } from '../user_profile'; import { userProfileServiceMock } from '../user_profile/user_profile_service.mock'; import { AuthenticationResult } from './authentication_result'; import type { AuthenticatorOptions } from './authenticator'; -import { Authenticator } from './authenticator'; +import { Authenticator, enrichWithUserProfileId } from './authenticator'; import { DeauthenticationResult } from './deauthentication_result'; import type { BasicAuthenticationProvider, SAMLAuthenticationProvider } from './providers'; @@ -379,6 +379,29 @@ describe('Authenticator', () => { expectAuditEvents({ action: 'user_login', outcome: 'success' }); }); + it('returns user enriched with user profile id.', async () => { + const request = httpServerMock.createKibanaRequest(); + const user = mockAuthenticatedUser({ profile_uid: undefined }); + mockOptions.session.create.mockResolvedValue( + sessionMock.createValue({ + userProfileId: 'PROFILE_ID', + }) + ); + + mockBasicAuthenticationProvider.login.mockResolvedValue( + AuthenticationResult.succeeded(user, { + state: {}, // to ensure a new session is created + }) + ); + + const result = await authenticator.login(request, { provider: { type: 'basic' }, value: {} }); + expect(result.user).toEqual( + expect.objectContaining({ + profile_uid: 'PROFILE_ID', + }) + ); + }); + describe('user_login audit events', () => { // Every other test case includes audit event assertions, but the user_login event is a bit special. // We have these separate, detailed test cases to ensure that the session ID is included for user_login success events. @@ -2560,3 +2583,65 @@ describe('Authenticator', () => { }); }); }); + +describe('enrichWithUserProfileId', () => { + it('should enrich succeeded authentication results with user profile id', () => { + const authenticationResult = AuthenticationResult.succeeded( + mockAuthenticatedUser({ profile_uid: undefined }) + ); + const sessionValue = sessionMock.createValue({ userProfileId: 'uid' }); + expect(enrichWithUserProfileId(authenticationResult, sessionValue)).toEqual( + expect.objectContaining({ + user: expect.objectContaining({ + profile_uid: 'uid', + }), + }) + ); + }); + + it('should enrich redirected authentication results with user profile id', () => { + const authenticationResult = AuthenticationResult.redirectTo('/redirect/to', { + user: mockAuthenticatedUser({ profile_uid: undefined }), + }); + const sessionValue = sessionMock.createValue({ userProfileId: 'uid' }); + expect(enrichWithUserProfileId(authenticationResult, sessionValue)).toEqual( + expect.objectContaining({ + user: expect.objectContaining({ + profile_uid: 'uid', + }), + }) + ); + }); + + it('should not change unhandled authentication results', () => { + const authenticationResult = AuthenticationResult.notHandled(); + const sessionValue = sessionMock.createValue(); + expect(enrichWithUserProfileId(authenticationResult, sessionValue)).toBe(authenticationResult); + }); + + it('should not change failed authentication results', () => { + const authenticationResult = AuthenticationResult.failed(new Error('Authentication error')); + const sessionValue = sessionMock.createValue(); + expect(enrichWithUserProfileId(authenticationResult, sessionValue)).toBe(authenticationResult); + }); + + it('should not change redirected authentication results without user', () => { + const authenticationResult = AuthenticationResult.redirectTo('/redirect/to'); + const sessionValue = sessionMock.createValue(); + expect(enrichWithUserProfileId(authenticationResult, sessionValue)).toBe(authenticationResult); + }); + + it('should not change succeeded authentication result if session has no user profile id', () => { + const authenticationResult = AuthenticationResult.succeeded(mockAuthenticatedUser()); + const sessionValue = sessionMock.createValue({ userProfileId: undefined }); + expect(enrichWithUserProfileId(authenticationResult, sessionValue)).toBe(authenticationResult); + }); + + it('should not change succeeded authentication result if user profile ids already match', () => { + const authenticationResult = AuthenticationResult.succeeded( + mockAuthenticatedUser({ profile_uid: 'uid' }) + ); + const sessionValue = sessionMock.createValue({ userProfileId: 'uid' }); + expect(enrichWithUserProfileId(authenticationResult, sessionValue)).toBe(authenticationResult); + }); +}); diff --git a/x-pack/plugins/security/server/authentication/authenticator.ts b/x-pack/plugins/security/server/authentication/authenticator.ts index 735224fd83720..0e925530d10a6 100644 --- a/x-pack/plugins/security/server/authentication/authenticator.ts +++ b/x-pack/plugins/security/server/authentication/authenticator.ts @@ -335,11 +335,14 @@ export class Authenticator { existingSessionValue, }); - return this.handlePreAccessRedirects( - request, - authenticationResult, - sessionUpdateResult, - attempt.redirectURL + return enrichWithUserProfileId( + this.handlePreAccessRedirects( + request, + authenticationResult, + sessionUpdateResult, + attempt.redirectURL + ), + sessionUpdateResult ? sessionUpdateResult.value : null ); } } @@ -351,7 +354,7 @@ export class Authenticator { * Performs request authentication using configured chain of authentication providers. * @param request Request instance. */ - async authenticate(request: KibanaRequest) { + async authenticate(request: KibanaRequest): Promise { assertRequest(request); const existingSessionValue = await this.getSessionValue(request); @@ -399,10 +402,12 @@ export class Authenticator { authenticationResult, existingSessionValue, }); - - return canRedirectRequest(request) - ? this.handlePreAccessRedirects(request, authenticationResult, sessionUpdateResult) - : authenticationResult; + return enrichWithUserProfileId( + canRedirectRequest(request) + ? this.handlePreAccessRedirects(request, authenticationResult, sessionUpdateResult) + : authenticationResult, + sessionUpdateResult ? sessionUpdateResult.value : null + ); } } @@ -427,11 +432,15 @@ export class Authenticator { const provider = this.providers.get(existingSessionValue.provider.name)!; const authenticationResult = await provider.authenticate(request, existingSessionValue.state); if (!authenticationResult.notHandled()) { - await this.updateSessionValue(request, { + const sessionUpdateResult = await this.updateSessionValue(request, { provider: existingSessionValue.provider, authenticationResult, existingSessionValue, }); + + if (sessionUpdateResult) { + return enrichWithUserProfileId(authenticationResult, sessionUpdateResult.value); + } } return authenticationResult; @@ -631,6 +640,7 @@ export class Authenticator { const auditLogger = this.options.audit.asScoped(request); auditLogger.log( userLoginEvent({ + userProfileId: existingSessionValue?.userProfileId, sessionId: existingSessionValue?.sid, authenticationResult, authenticationProvider: provider.name, @@ -737,7 +747,7 @@ export class Authenticator { } } - let newSessionValue; + let newSessionValue: Readonly | null; if (!existingSessionValue) { newSessionValue = await this.session.create(request, { username: authenticationResult.user?.username, @@ -756,6 +766,7 @@ export class Authenticator { const auditLogger = this.options.audit.asScoped(request); auditLogger.log( userLoginEvent({ + userProfileId, // We must explicitly specify the `userProfileId` here since we just created the session and it can't be inferred from the request context. sessionId: newSessionValue?.sid, // We must explicitly specify the `sessionId` here since we just created the session and it can't be inferred from the request context. authenticationResult, authenticationProvider: provider.name, @@ -796,12 +807,7 @@ export class Authenticator { }: InvalidateSessionValueParams) { if (isSessionAuthenticated(sessionValue) && !skipAuditEvent) { const auditLogger = this.options.audit.asScoped(request); - auditLogger.log( - userLogoutEvent({ - username: sessionValue.username, - provider: sessionValue.provider, - }) - ); + auditLogger.log(userLogoutEvent(sessionValue)); } await this.session.invalidate(request, { match: 'current' }); @@ -946,3 +952,37 @@ export class Authenticator { : `${this.options.basePath.serverBasePath}/security/logged_out?${searchParams.toString()}`; } } + +export function enrichWithUserProfileId( + authenticationResult: AuthenticationResult, + sessionValue: SessionValue | null +) { + if ( + !authenticationResult.user || + !sessionValue?.userProfileId || + authenticationResult.user.profile_uid === sessionValue.userProfileId + ) { + return authenticationResult; + } + + const enrichedUser: AuthenticatedUser = { + ...authenticationResult.user, + profile_uid: sessionValue.userProfileId, + }; + + if (authenticationResult.redirected()) { + return AuthenticationResult.redirectTo(authenticationResult.redirectURL!, { + user: enrichedUser, + userProfileGrant: authenticationResult.userProfileGrant, + authResponseHeaders: authenticationResult.authResponseHeaders, + state: authenticationResult.state, + }); + } + + return AuthenticationResult.succeeded(enrichedUser, { + userProfileGrant: authenticationResult.userProfileGrant, + authHeaders: authenticationResult.authHeaders, + authResponseHeaders: authenticationResult.authResponseHeaders, + state: authenticationResult.state, + }); +} diff --git a/x-pack/test/api_integration/apis/security/basic_login.js b/x-pack/test/api_integration/apis/security/basic_login.js index c81034b6fb824..6402945af74a6 100644 --- a/x-pack/test/api_integration/apis/security/basic_login.js +++ b/x-pack/test/api_integration/apis/security/basic_login.js @@ -135,7 +135,7 @@ export default function ({ getService }) { ) .expect(200); - expect(apiResponse.body).to.only.have.keys([ + expect(apiResponse.body).to.have.keys([ 'username', 'full_name', 'email', @@ -182,7 +182,7 @@ export default function ({ getService }) { .set('Cookie', sessionCookie.cookieString()) .expect(200); - expect(apiResponse.body).to.only.have.keys([ + expect(apiResponse.body).to.have.keys([ 'username', 'full_name', 'email', diff --git a/x-pack/test/security_api_integration/tests/kerberos/kerberos_login.ts b/x-pack/test/security_api_integration/tests/kerberos/kerberos_login.ts index f92f9d5a58b5b..10420d637afaf 100644 --- a/x-pack/test/security_api_integration/tests/kerberos/kerberos_login.ts +++ b/x-pack/test/security_api_integration/tests/kerberos/kerberos_login.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import jestExpect from 'expect'; import { parse as parseCookie, Cookie } from 'tough-cookie'; import { setTimeout as setTimeoutAsync } from 'timers/promises'; import { adminTestUser } from '@kbn/test'; @@ -142,26 +143,29 @@ export default function ({ getService }: FtrProviderContext) { ? ['kibana_admin', 'superuser_anonymous'] : ['kibana_admin']; - await supertest + const spnegoResponse = await supertest .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) - .expect(200, { - username: 'tester@TEST.ELASTIC.CO', - roles: expectedUserRoles, - full_name: null, - email: null, - metadata: { - kerberos_user_principal_name: 'tester@TEST.ELASTIC.CO', - kerberos_realm: 'TEST.ELASTIC.CO', - }, - enabled: true, - authentication_realm: { name: 'kerb1', type: 'kerberos' }, - lookup_realm: { name: 'kerb1', type: 'kerberos' }, - authentication_provider: { type: 'kerberos', name: 'kerberos' }, - authentication_type: 'token', - elastic_cloud_user: false, - }); + .expect(200); + + jestExpect(spnegoResponse.body).toEqual({ + username: 'tester@TEST.ELASTIC.CO', + roles: expectedUserRoles, + full_name: null, + email: null, + metadata: { + kerberos_user_principal_name: 'tester@TEST.ELASTIC.CO', + kerberos_realm: 'TEST.ELASTIC.CO', + }, + enabled: true, + authentication_realm: { name: 'kerb1', type: 'kerberos' }, + lookup_realm: { name: 'kerb1', type: 'kerberos' }, + authentication_provider: { type: 'kerberos', name: 'kerberos' }, + authentication_type: 'token', + elastic_cloud_user: false, + profile_uid: jestExpect.any(String), + }); }); it('should re-initiate SPNEGO handshake if token is rejected with 401', async () => { diff --git a/x-pack/test/security_api_integration/tests/login_selector/basic_functionality.ts b/x-pack/test/security_api_integration/tests/login_selector/basic_functionality.ts index df7d309261a38..b9f5aa96080e9 100644 --- a/x-pack/test/security_api_integration/tests/login_selector/basic_functionality.ts +++ b/x-pack/test/security_api_integration/tests/login_selector/basic_functionality.ts @@ -53,7 +53,7 @@ export default function ({ getService }: FtrProviderContext) { .set('Cookie', sessionCookie.cookieString()) .expect(200); - expect(apiResponse.body).to.only.have.keys([ + expect(apiResponse.body).to.have.keys([ 'username', 'full_name', 'email', diff --git a/x-pack/test/security_api_integration/tests/oidc/authorization_code_flow/oidc_auth.ts b/x-pack/test/security_api_integration/tests/oidc/authorization_code_flow/oidc_auth.ts index 9ea2e9b635522..4222f4f6a64f7 100644 --- a/x-pack/test/security_api_integration/tests/oidc/authorization_code_flow/oidc_auth.ts +++ b/x-pack/test/security_api_integration/tests/oidc/authorization_code_flow/oidc_auth.ts @@ -217,7 +217,7 @@ export default function ({ getService }: FtrProviderContext) { .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(200); - expect(apiResponse.body).to.only.have.keys([ + expect(apiResponse.body).to.have.keys([ 'username', 'full_name', 'email', @@ -271,7 +271,7 @@ export default function ({ getService }: FtrProviderContext) { .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(200); - expect(apiResponse.body).to.only.have.keys([ + expect(apiResponse.body).to.have.keys([ 'username', 'full_name', 'email', diff --git a/x-pack/test/security_api_integration/tests/oidc/implicit_flow/oidc_auth.ts b/x-pack/test/security_api_integration/tests/oidc/implicit_flow/oidc_auth.ts index 9a0483d5cebaa..8e7fe36fd689b 100644 --- a/x-pack/test/security_api_integration/tests/oidc/implicit_flow/oidc_auth.ts +++ b/x-pack/test/security_api_integration/tests/oidc/implicit_flow/oidc_auth.ts @@ -141,7 +141,7 @@ export default function ({ getService }: FtrProviderContext) { .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(200); - expect(apiResponse.body).to.only.have.keys([ + expect(apiResponse.body).to.have.keys([ 'username', 'full_name', 'email', diff --git a/x-pack/test/security_api_integration/tests/pki/pki_auth.ts b/x-pack/test/security_api_integration/tests/pki/pki_auth.ts index 6b8178ac938df..c286adcc7879b 100644 --- a/x-pack/test/security_api_integration/tests/pki/pki_auth.ts +++ b/x-pack/test/security_api_integration/tests/pki/pki_auth.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import jestExpect from 'expect'; import { parse as parseCookie, Cookie } from 'tough-cookie'; import { setTimeout as setTimeoutAsync } from 'timers/promises'; import { readFileSync } from 'fs'; @@ -123,7 +124,7 @@ export default function ({ getService }: FtrProviderContext) { }); it('should properly set cookie and authenticate user', async () => { - const response = await supertest + let response = await supertest .get('/security/account') .ca(CA_CERT) .pfx(FIRST_CLIENT_CERT) @@ -136,29 +137,32 @@ export default function ({ getService }: FtrProviderContext) { checkCookieIsSet(sessionCookie); // Cookie should be accepted. - await supertest + response = await supertest .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .ca(CA_CERT) .pfx(FIRST_CLIENT_CERT) .set('Cookie', sessionCookie.cookieString()) - .expect(200, { - username: 'first_client', - roles: ['kibana_admin'], - full_name: null, - email: null, - enabled: true, - metadata: { - pki_delegated_by_realm: 'reserved', - pki_delegated_by_user: 'kibana_system', - pki_dn: 'CN=first_client', - }, - authentication_realm: { name: 'pki1', type: 'pki' }, - lookup_realm: { name: 'pki1', type: 'pki' }, - authentication_provider: { name: 'pki', type: 'pki' }, - authentication_type: 'token', - elastic_cloud_user: false, - }); + .expect(200); + + jestExpect(response.body).toEqual({ + username: 'first_client', + roles: ['kibana_admin'], + full_name: null, + email: null, + enabled: true, + metadata: { + pki_delegated_by_realm: 'reserved', + pki_delegated_by_user: 'kibana_system', + pki_dn: 'CN=first_client', + }, + authentication_realm: { name: 'pki1', type: 'pki' }, + lookup_realm: { name: 'pki1', type: 'pki' }, + authentication_provider: { name: 'pki', type: 'pki' }, + authentication_type: 'token', + elastic_cloud_user: false, + profile_uid: jestExpect.any(String), + }); }); it('should update session if new certificate is provided', async () => { @@ -180,23 +184,26 @@ export default function ({ getService }: FtrProviderContext) { .pfx(SECOND_CLIENT_CERT) .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) - .expect(200, { - username: 'second_client', - roles: [], - full_name: null, - email: null, - enabled: true, - metadata: { - pki_delegated_by_realm: 'reserved', - pki_delegated_by_user: 'kibana_system', - pki_dn: 'CN=second_client', - }, - authentication_realm: { name: 'pki1', type: 'pki' }, - lookup_realm: { name: 'pki1', type: 'pki' }, - authentication_provider: { name: 'pki', type: 'pki' }, - authentication_type: 'realm', - elastic_cloud_user: false, - }); + .expect(200); + + jestExpect(response.body).toEqual({ + username: 'second_client', + roles: [], + full_name: null, + email: null, + enabled: true, + metadata: { + pki_delegated_by_realm: 'reserved', + pki_delegated_by_user: 'kibana_system', + pki_dn: 'CN=second_client', + }, + authentication_realm: { name: 'pki1', type: 'pki' }, + lookup_realm: { name: 'pki1', type: 'pki' }, + authentication_provider: { name: 'pki', type: 'pki' }, + authentication_type: 'realm', + elastic_cloud_user: false, + profile_uid: jestExpect.any(String), + }); checkCookieIsSet(parseCookie(response.headers['set-cookie'][0])!); }); diff --git a/x-pack/test/security_api_integration/tests/saml/saml_login.ts b/x-pack/test/security_api_integration/tests/saml/saml_login.ts index 474525eab4979..43d38a818c8ff 100644 --- a/x-pack/test/security_api_integration/tests/saml/saml_login.ts +++ b/x-pack/test/security_api_integration/tests/saml/saml_login.ts @@ -55,7 +55,7 @@ export default function ({ getService }: FtrProviderContext) { .set('Cookie', sessionCookie.cookieString()) .expect(200); - expect(apiResponse.body).to.only.have.keys([ + expect(apiResponse.body).to.have.keys([ 'username', 'full_name', 'email', diff --git a/x-pack/test/security_api_integration/tests/user_profiles/get_current.ts b/x-pack/test/security_api_integration/tests/user_profiles/get_current.ts index d7f23545aecd0..a56c5ac9004b8 100644 --- a/x-pack/test/security_api_integration/tests/user_profiles/get_current.ts +++ b/x-pack/test/security_api_integration/tests/user_profiles/get_current.ts @@ -6,6 +6,7 @@ */ import { parse as parseCookie } from 'tough-cookie'; +import expect from 'expect'; import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { @@ -64,6 +65,10 @@ export default function ({ getService }: FtrProviderContext) { .get('/internal/security/user_profile?dataPath=some') .set('Cookie', sessionCookie.cookieString()) .expect(200); + const { body: userWithProfileId } = await supertestWithoutAuth + .get('/internal/security/me') + .set('Cookie', sessionCookie.cookieString()) + .expect(200); // Profile UID is supposed to be stable. expectSnapshot(profileWithoutData).toMatchInline(` @@ -134,6 +139,7 @@ export default function ({ getService }: FtrProviderContext) { }, } `); + expect(userWithProfileId.profile_uid).toBe('u_K1WXIRQbRoHiuJylXp842IEhAO_OdqT7SDHrJSzUIjU_0'); }); }); } From 31a688049dc0fd724a1dd1b98c63e08cacce8b2b Mon Sep 17 00:00:00 2001 From: Shahzad Date: Mon, 3 Oct 2022 14:49:37 +0200 Subject: [PATCH 08/10] [Synthetics] Remove unused sync telemetry (#141349) --- .../telemetry/monitor_upgrade_sender.ts | 22 ------ .../synthetics_service/synthetics_service.ts | 71 ------------------- 2 files changed, 93 deletions(-) diff --git a/x-pack/plugins/synthetics/server/routes/telemetry/monitor_upgrade_sender.ts b/x-pack/plugins/synthetics/server/routes/telemetry/monitor_upgrade_sender.ts index 5d0d29a4c8ac5..1cb4659359f5e 100644 --- a/x-pack/plugins/synthetics/server/routes/telemetry/monitor_upgrade_sender.ts +++ b/x-pack/plugins/synthetics/server/routes/telemetry/monitor_upgrade_sender.ts @@ -22,11 +22,8 @@ import { MONITOR_UPDATE_CHANNEL, MONITOR_CURRENT_CHANNEL, MONITOR_ERROR_EVENTS_CHANNEL, - MONITOR_SYNC_STATE_CHANNEL, - MONITOR_SYNC_EVENTS_CHANNEL, } from '../../legacy_uptime/lib/telemetry/constants'; import { MonitorErrorEvent } from '../../legacy_uptime/lib/telemetry/types'; -import { MonitorSyncEvent } from '../../legacy_uptime/lib/telemetry/types'; export interface UpgradeError { key?: string; @@ -50,23 +47,6 @@ export function sendTelemetryEvents( } } -export function sendSyncTelemetryEvents( - logger: Logger, - eventsTelemetry: TelemetryEventsSender | undefined, - updateEvent: MonitorSyncEvent -) { - if (eventsTelemetry === undefined) { - return; - } - - try { - eventsTelemetry.queueTelemetryEvents(MONITOR_SYNC_STATE_CHANNEL, [updateEvent]); - eventsTelemetry.queueTelemetryEvents(MONITOR_SYNC_EVENTS_CHANNEL, [updateEvent]); - } catch (exc) { - logger.error(`queuing telemetry events failed ${exc}`); - } -} - export function sendErrorTelemetryEvents( logger: Logger, eventsTelemetry: TelemetryEventsSender | undefined, @@ -180,8 +160,6 @@ export function formatTelemetryDeleteEvent( }); } -export function formatTelemetrySyncEvent() {} - function getScriptType( attributes: Partial, isInlineScript: boolean diff --git a/x-pack/plugins/synthetics/server/synthetics_service/synthetics_service.ts b/x-pack/plugins/synthetics/server/synthetics_service/synthetics_service.ts index d0211800dc6c0..c0f977758f6da 100644 --- a/x-pack/plugins/synthetics/server/synthetics_service/synthetics_service.ts +++ b/x-pack/plugins/synthetics/server/synthetics_service/synthetics_service.ts @@ -16,8 +16,6 @@ import { TaskInstance, } from '@kbn/task-manager-plugin/server'; import { sendErrorTelemetryEvents } from '../routes/telemetry/monitor_upgrade_sender'; -import { MonitorSyncEvent } from '../legacy_uptime/lib/telemetry/types'; -import { sendSyncTelemetryEvents } from '../routes/telemetry/monitor_upgrade_sender'; import { UptimeServerSetup } from '../legacy_uptime/lib/adapters'; import { installSyntheticsIndexTemplates } from '../routes/synthetics_service/install_index_templates'; import { SyntheticsServiceApiKey } from '../../common/runtime_types/synthetics_service_api_key'; @@ -317,11 +315,6 @@ export class SyntheticsService { return null; } - if (!configs && monitorConfigs.length > 0) { - const telemetry = this.getSyncTelemetry(monitorConfigs); - sendSyncTelemetryEvents(this.logger, this.server.telemetry, telemetry); - } - this.apiKey = await this.getApiKey(); if (!this.apiKey) { @@ -490,70 +483,6 @@ export class SyntheticsService { formatMonitorConfig(Object.keys(config) as ConfigKey[], config as Partial) ); } - - getSyncTelemetry(monitors: SyntheticsMonitorWithId[]): MonitorSyncEvent { - let totalRuns = 0; - let browserTestRuns = 0; - let httpTestRuns = 0; - let icmpTestRuns = 0; - let tcpTestRuns = 0; - - const locationRuns: Record = {}; - const locationMonitors: Record = {}; - - const testRunsInDay = (schedule: string) => { - return (24 * 60) / Number(schedule); - }; - - const monitorsByType: Record = { - browser: 0, - http: 0, - tcp: 0, - icmp: 0, - }; - - monitors.forEach((monitor) => { - if (monitor.schedule.number) { - totalRuns += testRunsInDay(monitor.schedule.number); - } - switch (monitor.type) { - case 'browser': - browserTestRuns += testRunsInDay(monitor.schedule.number); - break; - case 'http': - httpTestRuns += testRunsInDay(monitor.schedule.number); - break; - case 'icmp': - icmpTestRuns += testRunsInDay(monitor.schedule.number); - break; - case 'tcp': - tcpTestRuns += testRunsInDay(monitor.schedule.number); - break; - default: - break; - } - - monitorsByType[monitor.type] = (monitorsByType[monitor.type] ?? 0) + 1; - - monitor.locations.forEach(({ id }) => { - locationRuns[id + 'Tests'] = - (locationRuns[id + 'Tests'] ?? 0) + testRunsInDay(monitor.schedule.number); - locationMonitors[id + 'Monitors'] = (locationMonitors[id + 'Monitors'] ?? 0) + 1; - }); - }); - - return { - total: monitors.length, - totalTests: totalRuns, - browserTests24h: browserTestRuns, - httpTests24h: httpTestRuns, - icmpTests24h: icmpTestRuns, - tcpTests24h: tcpTestRuns, - ...locationRuns, - ...locationMonitors, - ...monitorsByType, - }; - } } class IndexTemplateInstallationError extends Error { From f4184540be6c606f74ff5ccf973b0e0da69e2c74 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Mon, 3 Oct 2022 15:00:40 +0200 Subject: [PATCH 09/10] [Observability] Fix flaky test (#142210) --- .../series_editor/columns/series_actions.tsx | 1 + .../apps/observability/exploratory_view.ts | 28 +++++++++++++------ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/series_actions.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/series_actions.tsx index 129fdf1cf25e3..aab83cc511d9c 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/series_actions.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/series_actions.tsx @@ -89,6 +89,7 @@ export function SeriesActions({ seriesId, series, seriesConfig, onEditClick }: P aria-label={EDIT_SERIES_LABEL} size="s" onClick={onEditClick} + data-test-subj={`editSeries${seriesId}`} />
diff --git a/x-pack/test/observability_functional/apps/observability/exploratory_view.ts b/x-pack/test/observability_functional/apps/observability/exploratory_view.ts index 8f27f20ce30e6..b3adaa556dac3 100644 --- a/x-pack/test/observability_functional/apps/observability/exploratory_view.ts +++ b/x-pack/test/observability_functional/apps/observability/exploratory_view.ts @@ -19,8 +19,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const rangeFrom = '2021-01-17T16%3A46%3A15.338Z'; const rangeTo = '2021-01-19T17%3A01%3A32.309Z'; - // Failing: See https://github.com/elastic/kibana/issues/106934 - describe.skip('ExploratoryView', () => { + describe('ExploratoryView', () => { before(async () => { await esArchiver.loadIfNeeded( Path.join('x-pack/test/apm_api_integration/common/fixtures/es_archiver', '8.0.0') @@ -33,11 +32,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await esArchiver.loadIfNeeded( Path.join('x-pack/test/apm_api_integration/common/fixtures/es_archiver', 'rum_test_data') ); - - await PageObjects.common.navigateToApp('ux', { - search: `?rangeFrom=${rangeFrom}&rangeTo=${rangeTo}`, - }); - await PageObjects.header.waitUntilLoadingHasFinished(); }); after(async () => { @@ -48,16 +42,28 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await esArchiver.unload( Path.join('x-pack/test/apm_api_integration/common/fixtures/es_archiver', 'rum_8.0.0') ); + await esArchiver.unload( + Path.join('x-pack/test/apm_api_integration/common/fixtures/es_archiver', 'rum_test_data') + ); + }); + + it('should go to ux app', async function () { + await PageObjects.common.navigateToApp('ux', { + search: `?rangeFrom=${rangeFrom}&rangeTo=${rangeTo}`, + }); + + await PageObjects.header.waitUntilLoadingHasFinished(); }); it('should able to open exploratory view from ux app', async () => { await testSubjects.exists('uxAnalyzeBtn'); await testSubjects.click('uxAnalyzeBtn'); - expect(await find.existsByCssSelector('.euiBasicTable')).to.eql(true); + + await PageObjects.header.waitUntilLoadingHasFinished(); }); it('renders lens visualization', async () => { - expect(await testSubjects.exists('lnsVisualizationContainer')).to.eql(true); + expect(await testSubjects.exists('xyVisChart')).to.eql(true); expect( await find.existsByCssSelector('div[data-title="Prefilled from exploratory view app"]') @@ -67,12 +73,16 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('can do a breakdown per series', async () => { + await testSubjects.click('editSeries0'); + await testSubjects.click('seriesBreakdown'); expect(await find.existsByCssSelector('[id="user_agent.name"]')).to.eql(true); await find.clickByCssSelector('[id="user_agent.name"]'); + await testSubjects.click('seriesChangesApplyButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); expect(await find.existsByCssSelector('[title="Chrome Mobile iOS"]')).to.eql(true); From a8d54b3e3e9193fb7d2c12a872eaee7adbac651d Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Mon, 3 Oct 2022 16:19:06 +0300 Subject: [PATCH 10/10] [TSVB] [Annotations] Update label for Time field (#142452) * [TSVB] [Annotations] Update label for Time field Closes: #142226 * Update src/plugins/vis_types/timeseries/public/application/components/aggs/field_select/field_select.tsx Co-authored-by: Marco Liberati * [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix' Co-authored-by: Marco Liberati Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../components/aggs/field_select/field_select.tsx | 11 ++++++++--- .../public/application/components/annotation_row.tsx | 6 +++++- x-pack/plugins/translations/translations/fr-FR.json | 1 - x-pack/plugins/translations/translations/ja-JP.json | 1 - x-pack/plugins/translations/translations/zh-CN.json | 1 - 5 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/plugins/vis_types/timeseries/public/application/components/aggs/field_select/field_select.tsx b/src/plugins/vis_types/timeseries/public/application/components/aggs/field_select/field_select.tsx index 27f4d96381fda..df4d683d11ea9 100644 --- a/src/plugins/vis_types/timeseries/public/application/components/aggs/field_select/field_select.tsx +++ b/src/plugins/vis_types/timeseries/public/application/components/aggs/field_select/field_select.tsx @@ -47,10 +47,15 @@ interface FieldSelectProps { fullWidth?: boolean; } -const getPreselectedFields = ( +const getPlaceholderValue = ( placeholder?: string, options?: Array> -) => placeholder && findInGroupedOptions(options, placeholder)?.label; +) => { + if (!placeholder) { + return; + } + return findInGroupedOptions(options, placeholder)?.label || placeholder; +}; export function FieldSelect({ label, @@ -138,7 +143,7 @@ export function FieldSelect({ onNewItemAdd={onNewItemAdd.bind(undefined, props.index)} onDeleteItem={onDeleteItem.bind(undefined, props.index)} onChange={onFieldSelectItemChange.bind(undefined, props.index)} - placeholder={getPreselectedFields(placeholder, groupedOptions)} + placeholder={getPlaceholderValue(placeholder, groupedOptions)} disableAdd={!allowMultiSelect || selectedIds?.length >= MAX_MULTI_FIELDS_ITEMS} disableDelete={!allowMultiSelect || selectedIds?.length <= 1} /> diff --git a/src/plugins/vis_types/timeseries/public/application/components/annotation_row.tsx b/src/plugins/vis_types/timeseries/public/application/components/annotation_row.tsx index 49ae7ea348f5a..9d44ba5f95745 100644 --- a/src/plugins/vis_types/timeseries/public/application/components/annotation_row.tsx +++ b/src/plugins/vis_types/timeseries/public/application/components/annotation_row.tsx @@ -154,7 +154,7 @@ export const AnnotationRow = ({ label={ } restrict={RESTRICT_FIELDS} @@ -165,6 +165,10 @@ export const AnnotationRow = ({ }) } indexPattern={model.index_pattern} + placeholder={ + fetchedIndex?.indexPattern?.timeFieldName ?? + fetchedIndex?.defaultIndex?.timeFieldName + } fields={fields} /> diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 151159fa0980b..da2072ab3d605 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -5487,7 +5487,6 @@ "visTypeTimeseries.annotationsEditor.ignorePanelFiltersLabel": "Ignorer les filtres de panneau ?", "visTypeTimeseries.annotationsEditor.queryStringLabel": "Chaîne de requête", "visTypeTimeseries.annotationsEditor.rowTemplateLabel": "Modèle de ligne (requis)", - "visTypeTimeseries.annotationsEditor.timeFieldLabel": "Champ temporel (requis)", "visTypeTimeseries.calculateLabel.bucketScriptsLabel": "Script de compartiment", "visTypeTimeseries.calculateLabel.countLabel": "Décompte", "visTypeTimeseries.calculateLabel.filterRatioLabel": "Rapport de filtre", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 5465a9a7be7f5..0238b9e9add28 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -5481,7 +5481,6 @@ "visTypeTimeseries.annotationsEditor.ignorePanelFiltersLabel": "パネルフィルターを無視しますか?", "visTypeTimeseries.annotationsEditor.queryStringLabel": "クエリ文字列", "visTypeTimeseries.annotationsEditor.rowTemplateLabel": "行テンプレート(必須)", - "visTypeTimeseries.annotationsEditor.timeFieldLabel": "時間フィールド(必須)", "visTypeTimeseries.calculateLabel.bucketScriptsLabel": "バケットスクリプト", "visTypeTimeseries.calculateLabel.countLabel": "カウント", "visTypeTimeseries.calculateLabel.filterRatioLabel": "フィルターレート", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index e2de967852a88..d555235d7ad76 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -5488,7 +5488,6 @@ "visTypeTimeseries.annotationsEditor.ignorePanelFiltersLabel": "忽略面板筛选?", "visTypeTimeseries.annotationsEditor.queryStringLabel": "查询字符串", "visTypeTimeseries.annotationsEditor.rowTemplateLabel": "行模板(必需)", - "visTypeTimeseries.annotationsEditor.timeFieldLabel": "时间字段(必需)", "visTypeTimeseries.calculateLabel.bucketScriptsLabel": "存储桶脚本", "visTypeTimeseries.calculateLabel.countLabel": "计数", "visTypeTimeseries.calculateLabel.filterRatioLabel": "筛选比",