diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/delete_migration.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/delete_migration.ts index b99bc9720a40d..37bb19d429e84 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/delete_migration.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/delete_migration.ts @@ -20,6 +20,7 @@ import { updateMigrationSavedObject } from './update_migration_saved_object'; * @param soClient An {@link SavedObjectsClientContract} * @param migration the migration to be finalized {@link SignalsMigrationSO} * @param signalsAlias the alias for signals indices + * @param username name of the user initiating the deletion * * @returns the migration SavedObject {@link SignalsMigrationSO} * @throws if the migration is invalid or a client throws @@ -29,11 +30,13 @@ export const deleteMigration = async ({ migration, signalsAlias, soClient, + username, }: { esClient: ElasticsearchClient; migration: SignalsMigrationSO; signalsAlias: string; soClient: SavedObjectsClientContract; + username: string; }): Promise => { if (isMigrationPending(migration) || isMigrationDeleted(migration)) { return migration; @@ -59,7 +62,7 @@ export const deleteMigration = async ({ } const deletedMigration = await updateMigrationSavedObject({ - username: 'TODO', + username, soClient, id: migration.id, attributes: { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/finalize_migration.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/finalize_migration.ts index a78a0cc1abef5..6726f6c686330 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/finalize_migration.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/finalize_migration.ts @@ -23,6 +23,7 @@ import { updateMigrationSavedObject } from './update_migration_saved_object'; * @param soClient An {@link SavedObjectsClientContract} * @param migration the migration to be finalized {@link SignalsMigrationSO} * @param signalsAlias the alias for signals indices + * @param username name of the user initiating the finalization * * @returns the migration SavedObject {@link SignalsMigrationSO} * @throws if the migration is invalid or a client throws @@ -32,11 +33,13 @@ export const finalizeMigration = async ({ migration, signalsAlias, soClient, + username, }: { esClient: ElasticsearchClient; migration: SignalsMigrationSO; signalsAlias: string; soClient: SavedObjectsClientContract; + username: string; }): Promise => { if (isMigrationDeleted(migration) || !isMigrationPending(migration)) { return migration; @@ -53,7 +56,7 @@ export const finalizeMigration = async ({ const destinationCount = await getIndexCount({ esClient, index: destinationIndex }); if (sourceCount !== destinationCount) { const updatedMigration = await updateMigrationSavedObject({ - username: 'TODO', + username, soClient, id: migration.id, attributes: { @@ -85,7 +88,7 @@ export const finalizeMigration = async ({ await esClient.delete({ index: '.tasks', id: taskId }); const updatedMigration = await updateMigrationSavedObject({ - username: 'TODO', + username, soClient, id: migration.id, attributes: { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/migration_service.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/migration_service.ts index 78cfbde6bd1f8..72df98692a88b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/migration_service.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/migration_service.ts @@ -37,7 +37,7 @@ export interface SignalsMigrationService { export const signalsMigrationService = ({ esClient, soClient, - username = 'system', + username, }: { esClient: ElasticsearchClient; soClient: SavedObjectsClientContract; @@ -64,6 +64,7 @@ export const signalsMigrationService = ({ migration, signalsAlias, soClient, + username, }), delete: ({ migration, signalsAlias }) => deleteMigration({ @@ -71,6 +72,7 @@ export const signalsMigrationService = ({ migration, signalsAlias, soClient, + username, }), }; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.test.ts index b0498ffc05143..552a8accfa30c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.test.ts @@ -5,6 +5,7 @@ */ import { requestMock, serverMock } from '../__mocks__'; +import { SetupPlugins } from '../../../../plugin'; import { SignalsReindexOptions } from '../../../../../common/detection_engine/schemas/request/create_signals_migration_schema'; import { DETECTION_ENGINE_SIGNALS_MIGRATION_URL } from '../../../../../common/constants'; import { getCreateSignalsMigrationSchemaMock } from '../../../../../common/detection_engine/schemas/request/create_signals_migration_schema.mock'; @@ -35,7 +36,13 @@ describe('creating signals migrations route', () => { (getIndexVersionsByIndex as jest.Mock).mockResolvedValue({ 'my-signals-index': -1 }); (getSignalVersionsByIndex as jest.Mock).mockResolvedValue({ 'my-signals-index': [] }); - createSignalsMigrationRoute(server.router); + const securityMock = ({ + authc: { + getCurrentUser: jest.fn().mockReturnValue({ user: { username: 'my-username' } }), + }, + } as unknown) as SetupPlugins['security']; + + createSignalsMigrationRoute(server.router, securityMock); }); it('passes options to the createMigration', async () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.ts index 61bad5495213a..313cc37b20d88 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.ts @@ -5,6 +5,7 @@ */ import { IRouter } from 'src/core/server'; +import { SetupPlugins } from '../../../../plugin'; import { DETECTION_ENGINE_SIGNALS_MIGRATION_URL } from '../../../../../common/constants'; import { createSignalsMigrationSchema } from '../../../../../common/detection_engine/schemas/request/create_signals_migration_schema'; import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; @@ -18,7 +19,10 @@ import { getIndexVersionsByIndex } from '../../migrations/get_index_versions_by_ import { getSignalVersionsByIndex } from '../../migrations/get_signal_versions_by_index'; import { SIGNALS_TEMPLATE_VERSION } from '../index/get_signals_template'; -export const createSignalsMigrationRoute = (router: IRouter) => { +export const createSignalsMigrationRoute = ( + router: IRouter, + security: SetupPlugins['security'] +) => { router.post( { path: DETECTION_ENGINE_SIGNALS_MIGRATION_URL, @@ -36,11 +40,16 @@ export const createSignalsMigrationRoute = (router: IRouter) => { try { const esClient = context.core.elasticsearch.client.asCurrentUser; const soClient = context.core.savedObjects.client; - const migrationService = signalsMigrationService({ esClient, soClient, username: 'TODO' }); const appClient = context.securitySolution?.getAppClient(); if (!appClient) { return siemResponse.error({ statusCode: 404 }); } + const user = await security?.authc.getCurrentUser(request); + const migrationService = signalsMigrationService({ + esClient, + soClient, + username: user?.username ?? 'elastic', + }); const signalsAlias = appClient.getSignalsIndex(); const currentVersion = await getTemplateVersion({ @@ -50,7 +59,7 @@ export const createSignalsMigrationRoute = (router: IRouter) => { if (isOutdated({ current: currentVersion, target: SIGNALS_TEMPLATE_VERSION })) { throw new BadRequestError( - 'Cannot migrate due to the signals template being out of date. Please visit Detections to automatically update your template, then try again.' + `Cannot migrate due to the signals template being out of date. Latest version: [${SIGNALS_TEMPLATE_VERSION}], template version: [${currentVersion}]. Please visit Detections to automatically update your template, then try again.` ); } const signalsIndexAliases = await getIndexAliases({ esClient, alias: signalsAlias }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/delete_signals_migration_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/delete_signals_migration_route.ts index cbcd114175023..1ab14edeada4f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/delete_signals_migration_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/delete_signals_migration_route.ts @@ -5,6 +5,7 @@ */ import { IRouter } from 'src/core/server'; +import { SetupPlugins } from '../../../../plugin'; import { DETECTION_ENGINE_SIGNALS_MIGRATION_URL } from '../../../../../common/constants'; import { deleteSignalsMigrationSchema } from '../../../../../common/detection_engine/schemas/request/delete_signals_migration_schema'; import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; @@ -13,7 +14,10 @@ import { BadRequestError } from '../../errors/bad_request_error'; import { signalsMigrationService } from '../../migrations/migration_service'; import { getMigrationSavedObjectsByIndex } from '../../migrations/get_migration_saved_objects_by_index'; -export const deleteSignalsMigrationRoute = (router: IRouter) => { +export const deleteSignalsMigrationRoute = ( + router: IRouter, + security: SetupPlugins['security'] +) => { router.delete( { path: DETECTION_ENGINE_SIGNALS_MIGRATION_URL, @@ -31,12 +35,18 @@ export const deleteSignalsMigrationRoute = (router: IRouter) => { try { const esClient = context.core.elasticsearch.client.asCurrentUser; const soClient = context.core.savedObjects.client; - const migrationService = signalsMigrationService({ esClient, soClient, username: 'TODO' }); const appClient = context.securitySolution?.getAppClient(); if (!appClient) { return siemResponse.error({ statusCode: 404 }); } + const user = await security?.authc.getCurrentUser(request); + const migrationService = signalsMigrationService({ + esClient, + soClient, + username: user?.username ?? 'elastic', + }); + const signalsAlias = appClient.getSignalsIndex(); const migrationsByIndex = await getMigrationSavedObjectsByIndex({ index: indices, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/finalize_signals_migration_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/finalize_signals_migration_route.test.ts index ff34a2c290ce6..361425e7794da 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/finalize_signals_migration_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/finalize_signals_migration_route.test.ts @@ -5,6 +5,7 @@ */ import { serverMock } from '../__mocks__'; +import { SetupPlugins } from '../../../../plugin'; import { getFinalizeSignalsMigrationRequest } from '../__mocks__/request_responses'; import { getMigrationSavedObjectsByIndex } from '../../migrations/get_migration_saved_objects_by_index'; import { getSignalsMigrationSavedObjectMock } from '../../migrations/saved_objects_schema.mock'; @@ -18,7 +19,12 @@ describe('finalizing signals migrations', () => { beforeEach(() => { server = serverMock.create(); - finalizeSignalsMigrationRoute(server.router); + const securityMock = ({ + authc: { + getCurrentUser: jest.fn().mockReturnValue({ user: { username: 'my-username' } }), + }, + } as unknown) as SetupPlugins['security']; + finalizeSignalsMigrationRoute(server.router, securityMock); }); it('returns an inline error if no migration exists', async () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/finalize_signals_migration_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/finalize_signals_migration_route.ts index 49666737ceb34..fe67acc417964 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/finalize_signals_migration_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/finalize_signals_migration_route.ts @@ -5,6 +5,7 @@ */ import { IRouter } from 'src/core/server'; +import { SetupPlugins } from '../../../../plugin'; import { DETECTION_ENGINE_SIGNALS_FINALIZE_MIGRATION_URL } from '../../../../../common/constants'; import { finalizeSignalsMigrationSchema } from '../../../../../common/detection_engine/schemas/request/finalize_signals_migration_schema'; import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; @@ -14,7 +15,10 @@ import { signalsMigrationService } from '../../migrations/migration_service'; import { buildSiemResponse, transformError } from '../utils'; import { getMigrationSavedObjectsByIndex } from '../../migrations/get_migration_saved_objects_by_index'; -export const finalizeSignalsMigrationRoute = (router: IRouter) => { +export const finalizeSignalsMigrationRoute = ( + router: IRouter, + security: SetupPlugins['security'] +) => { router.post( { path: DETECTION_ENGINE_SIGNALS_FINALIZE_MIGRATION_URL, @@ -36,7 +40,12 @@ export const finalizeSignalsMigrationRoute = (router: IRouter) => { if (!appClient) { return siemResponse.error({ statusCode: 404 }); } - const migrationService = signalsMigrationService({ esClient, soClient, username: 'TODO' }); + const user = await security?.authc.getCurrentUser(request); + const migrationService = signalsMigrationService({ + esClient, + soClient, + username: user?.username ?? 'elastic', + }); const migrationsByIndex = await getMigrationSavedObjectsByIndex({ soClient, index: indices, diff --git a/x-pack/plugins/security_solution/server/routes/index.ts b/x-pack/plugins/security_solution/server/routes/index.ts index 16991abe82601..0204869904397 100644 --- a/x-pack/plugins/security_solution/server/routes/index.ts +++ b/x-pack/plugins/security_solution/server/routes/index.ts @@ -87,9 +87,9 @@ export const initRoutes = ( setSignalsStatusRoute(router); querySignalsRoute(router); getSignalsMigrationStatusRoute(router); - createSignalsMigrationRoute(router); - finalizeSignalsMigrationRoute(router); - deleteSignalsMigrationRoute(router); + createSignalsMigrationRoute(router, security); + finalizeSignalsMigrationRoute(router, security); + deleteSignalsMigrationRoute(router, security); // Detection Engine index routes that have the REST endpoints of /api/detection_engine/index // All REST index creation, policy management for spaces diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_signals_migrations.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_signals_migrations.ts index 8ac28c40db086..3271a75fcd1d1 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_signals_migrations.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_signals_migrations.ts @@ -179,7 +179,7 @@ export default ({ getService }: FtrProviderContext): void => { .set('kbn-xsrf', 'true') .auth(ROLES.t1_analyst, 'changeme') .send({ index: [legacySignalsIndexName] }) - .expect(403); + .expect(400); }); }); };