diff --git a/x-pack/plugins/entity_manager/server/lib/auth/privileges.ts b/x-pack/plugins/entity_manager/server/lib/auth/privileges.ts index 674e870c898bc..2a8fd057eb270 100644 --- a/x-pack/plugins/entity_manager/server/lib/auth/privileges.ts +++ b/x-pack/plugins/entity_manager/server/lib/auth/privileges.ts @@ -10,15 +10,18 @@ import { ENTITY_INTERNAL_INDICES_PATTERN } from '../../../common/constants_entit import { SO_ENTITY_DEFINITION_TYPE, SO_ENTITY_DISCOVERY_API_KEY_TYPE } from '../../saved_objects'; import { BUILT_IN_ALLOWED_INDICES } from '../entities/built_in/constants'; -export const canManageEntityDefinition = async (client: ElasticsearchClient) => { +export const canManageEntityDefinition = async ( + client: ElasticsearchClient, + sourceIndices: string[] +) => { const { has_all_requested: hasAllRequested } = await client.security.hasPrivileges({ - body: entityDefinitionRuntimePrivileges, + body: entityDefinitionRuntimePrivileges(sourceIndices), }); return hasAllRequested; }; -const canDeleteEntityDefinition = async (client: ElasticsearchClient) => { +export const canDeleteEntityDefinition = async (client: ElasticsearchClient) => { const { has_all_requested: hasAllRequested } = await client.security.hasPrivileges({ body: entityDefinitionDeletionPrivileges, }); @@ -43,9 +46,10 @@ const canDeleteAPIKey = async (client: ElasticsearchClient) => { }; export const canEnableEntityDiscovery = async (client: ElasticsearchClient) => { - return Promise.all([canManageAPIKey(client), canManageEntityDefinition(client)]).then((results) => - results.every(Boolean) - ); + return Promise.all([ + canManageAPIKey(client), + canManageEntityDefinition(client, BUILT_IN_ALLOWED_INDICES), + ]).then((results) => results.every(Boolean)); }; export const canDisableEntityDiscovery = async (client: ElasticsearchClient) => { @@ -54,7 +58,7 @@ export const canDisableEntityDiscovery = async (client: ElasticsearchClient) => ); }; -export const entityDefinitionRuntimePrivileges = { +export const entityDefinitionRuntimePrivileges = (sourceIndices: string[]) => ({ cluster: ['manage_transform', 'manage_ingest_pipelines', 'manage_index_templates'], index: [ { @@ -73,7 +77,7 @@ export const entityDefinitionRuntimePrivileges = { resources: ['*'], }, ], -}; +}); export const entityDefinitionDeletionPrivileges = { cluster: ['manage_transform', 'manage_ingest_pipelines', 'manage_index_templates'], diff --git a/x-pack/plugins/entity_manager/server/routes/entities/create.ts b/x-pack/plugins/entity_manager/server/routes/entities/create.ts index 04bc75568d240..a22916f3e69f7 100644 --- a/x-pack/plugins/entity_manager/server/routes/entities/create.ts +++ b/x-pack/plugins/entity_manager/server/routes/entities/create.ts @@ -12,6 +12,7 @@ import { EntityIdConflict } from '../../lib/entities/errors/entity_id_conflict_e import { EntitySecurityException } from '../../lib/entities/errors/entity_security_exception'; import { InvalidTransformError } from '../../lib/entities/errors/invalid_transform_error'; import { createEntityManagerServerRoute } from '../create_entity_manager_server_route'; +import { canManageEntityDefinition } from '../../lib/auth'; /** * @openapi @@ -62,8 +63,22 @@ export const createEntityDefinitionRoute = createEntityManagerServerRoute({ query: createEntityDefinitionQuerySchema, body: entityDefinitionSchema, }), - handler: async ({ request, response, params, logger, getScopedClient }) => { + handler: async ({ context, request, response, params, logger, getScopedClient }) => { try { + const currentUserClient = (await context.core).elasticsearch.client.asCurrentUser; + const isAuthorized = await canManageEntityDefinition( + currentUserClient, + params.body.indexPatterns + ); + if (!isAuthorized) { + return response.forbidden({ + body: { + message: + 'Current Kibana user does not have the required permissions to create the entity definition', + }, + }); + } + const client = await getScopedClient({ request }); const definition = await client.createEntityDefinition({ definition: params.body, diff --git a/x-pack/plugins/entity_manager/server/routes/entities/delete.ts b/x-pack/plugins/entity_manager/server/routes/entities/delete.ts index abc9ed4782428..ff5b9624dbb3c 100644 --- a/x-pack/plugins/entity_manager/server/routes/entities/delete.ts +++ b/x-pack/plugins/entity_manager/server/routes/entities/delete.ts @@ -14,6 +14,7 @@ import { EntityDefinitionNotFound } from '../../lib/entities/errors/entity_not_f import { EntitySecurityException } from '../../lib/entities/errors/entity_security_exception'; import { InvalidTransformError } from '../../lib/entities/errors/invalid_transform_error'; import { createEntityManagerServerRoute } from '../create_entity_manager_server_route'; +import { canDeleteEntityDefinition } from '../../lib/auth/privileges'; /** * @openapi @@ -64,8 +65,19 @@ export const deleteEntityDefinitionRoute = createEntityManagerServerRoute({ path: deleteEntityDefinitionParamsSchema, query: deleteEntityDefinitionQuerySchema, }), - handler: async ({ request, response, params, logger, getScopedClient }) => { + handler: async ({ context, request, response, params, logger, getScopedClient }) => { try { + const currentUserClient = (await context.core).elasticsearch.client.asCurrentUser; + const isAuthorized = await canDeleteEntityDefinition(currentUserClient); + if (!isAuthorized) { + return response.forbidden({ + body: { + message: + 'Current Kibana user does not have the required permissions to delete the entity definition', + }, + }); + } + const client = await getScopedClient({ request }); await client.deleteEntityDefinition({ id: params.path.id, diff --git a/x-pack/plugins/entity_manager/server/routes/entities/update.ts b/x-pack/plugins/entity_manager/server/routes/entities/update.ts index e9cf4341bae99..f1118028cda93 100644 --- a/x-pack/plugins/entity_manager/server/routes/entities/update.ts +++ b/x-pack/plugins/entity_manager/server/routes/entities/update.ts @@ -12,6 +12,8 @@ import { InvalidTransformError } from '../../lib/entities/errors/invalid_transfo import { createEntityManagerServerRoute } from '../create_entity_manager_server_route'; import { EntityDefinitionNotFound } from '../../lib/entities/errors/entity_not_found'; import { EntityDefinitionUpdateConflict } from '../../lib/entities/errors/entity_definition_update_conflict'; +import { findEntityDefinitionById } from '../../lib/entities/find_entity_definition'; +import { canManageEntityDefinition } from '../../lib/auth'; /** * @openapi @@ -65,10 +67,32 @@ export const updateEntityDefinitionRoute = createEntityManagerServerRoute({ path: z.object({ id: z.string() }), body: entityDefinitionUpdateSchema, }), - handler: async ({ request, response, params, logger, getScopedClient }) => { - const entityClient = await getScopedClient({ request }); - + handler: async ({ context, request, response, params, logger, getScopedClient }) => { try { + const core = await context.core; + const definition = await findEntityDefinitionById({ + id: params.path.id, + esClient: core.elasticsearch.client.asCurrentUser, + soClient: core.savedObjects.client, + }); + if (!definition) { + throw new EntityDefinitionNotFound(`Unable to find entity definition [${params.path.id}]`); + } + + const isAuthorized = await canManageEntityDefinition( + core.elasticsearch.client.asCurrentUser, + params.body.indexPatterns ?? definition.indexPatterns + ); + if (!isAuthorized) { + return response.forbidden({ + body: { + message: + 'Current Kibana user does not have the required permissions to update the entity definition', + }, + }); + } + + const entityClient = await getScopedClient({ request }); const updatedDefinition = await entityClient.updateEntityDefinition({ id: params.path.id, definitionUpdate: params.body,