diff --git a/x-pack/plugins/ml/common/types/capabilities.ts b/x-pack/plugins/ml/common/types/capabilities.ts index 2a449c95faa5b..5f6cb32c45247 100644 --- a/x-pack/plugins/ml/common/types/capabilities.ts +++ b/x-pack/plugins/ml/common/types/capabilities.ts @@ -7,6 +7,7 @@ import { KibanaRequest } from 'kibana/server'; export const userMlCapabilities = { + canAccessML: false, // Anomaly Detection canGetJobs: false, canGetDatafeeds: false, @@ -38,8 +39,8 @@ export const adminMlCapabilities = { canCreateFilter: false, canDeleteFilter: false, // Data Frame Analytics - canDeleteDataFrameAnalytics: false, canCreateDataFrameAnalytics: false, + canDeleteDataFrameAnalytics: false, canStartStopDataFrameAnalytics: false, }; @@ -47,7 +48,9 @@ export type UserMlCapabilities = typeof userMlCapabilities; export type AdminMlCapabilities = typeof adminMlCapabilities; export type MlCapabilities = UserMlCapabilities & AdminMlCapabilities; -export const basicLicenseMlCapabilities = ['canFindFileStructure'] as Array; +export const basicLicenseMlCapabilities = ['canAccessML', 'canFindFileStructure'] as Array< + keyof MlCapabilities +>; export function getDefaultCapabilities(): MlCapabilities { return { @@ -56,6 +59,23 @@ export function getDefaultCapabilities(): MlCapabilities { }; } +export function getPluginPrivileges() { + const userMlCapabilitiesKeys = Object.keys(userMlCapabilities); + const adminMlCapabilitiesKeys = Object.keys(adminMlCapabilities); + const allMlCapabilities = [...adminMlCapabilitiesKeys, ...userMlCapabilitiesKeys]; + + return { + user: { + ui: userMlCapabilitiesKeys, + api: userMlCapabilitiesKeys.map(k => `ml:${k}`), + }, + admin: { + ui: allMlCapabilities, + api: allMlCapabilities.map(k => `ml:${k}`), + }, + }; +} + export interface MlCapabilitiesResponse { capabilities: MlCapabilities; upgradeInProgress: boolean; diff --git a/x-pack/plugins/ml/server/plugin.ts b/x-pack/plugins/ml/server/plugin.ts index 64f8eb4b0acd3..4fadb07d386e3 100644 --- a/x-pack/plugins/ml/server/plugin.ts +++ b/x-pack/plugins/ml/server/plugin.ts @@ -45,7 +45,7 @@ import { systemRoutes } from './routes/system'; import { MlLicense } from '../common/license'; import { MlServerLicense } from './lib/license'; import { createSharedServices, SharedServices } from './shared_services'; -import { userMlCapabilities, adminMlCapabilities } from '../common/types/capabilities'; +import { getPluginPrivileges } from '../common/types/capabilities'; import { setupCapabilitiesSwitcher } from './lib/capabilities'; import { registerKibanaSettings } from './lib/register_settings'; @@ -75,8 +75,7 @@ export class MlServerPlugin implements Plugin `access:${k}`)); registerKibanaSettings(coreSetup); this.mlLicense.setup(plugins.licensing.license$, [ @@ -168,7 +169,7 @@ export class MlServerPlugin implements Plugin { try { @@ -86,6 +89,9 @@ export function annotationRoutes( validate: { body: indexAnnotationSchema, }, + options: { + tags: ['access:ml:canCreateJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -130,6 +136,9 @@ export function annotationRoutes( validate: { params: deleteAnnotationSchema, }, + options: { + tags: ['access:ml:canCreateJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/anomaly_detectors.ts b/x-pack/plugins/ml/server/routes/anomaly_detectors.ts index ca63d69f403f6..63cd5498231af 100644 --- a/x-pack/plugins/ml/server/routes/anomaly_detectors.ts +++ b/x-pack/plugins/ml/server/routes/anomaly_detectors.ts @@ -37,6 +37,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { { path: '/api/ml/anomaly_detectors', validate: false, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -65,6 +68,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { validate: { params: jobIdSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -93,6 +99,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { { path: '/api/ml/anomaly_detectors/_stats', validate: false, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -121,6 +130,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { validate: { params: jobIdSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -154,6 +166,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { params: jobIdSchema, body: schema.object(anomalyDetectionJobSchema), }, + options: { + tags: ['access:ml:canCreateJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -188,6 +203,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { params: jobIdSchema, body: anomalyDetectionUpdateJobSchema, }, + options: { + tags: ['access:ml:canUpdateJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -220,6 +238,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { validate: { params: jobIdSchema, }, + options: { + tags: ['access:ml:canOpenJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -251,6 +272,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { validate: { params: jobIdSchema, }, + options: { + tags: ['access:ml:canCloseJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -286,6 +310,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { validate: { params: jobIdSchema, }, + options: { + tags: ['access:ml:canDeleteJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -319,6 +346,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { validate: { body: schema.any(), }, + options: { + tags: ['access:ml:canCreateJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -351,6 +381,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { params: jobIdSchema, body: forecastAnomalyDetector, }, + options: { + tags: ['access:ml:canForecastJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -389,6 +422,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { params: jobIdSchema, body: getRecordsSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -425,6 +461,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { params: getBucketParamsSchema, body: getBucketsSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -462,6 +501,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { params: jobIdSchema, body: getOverallBucketsSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -496,6 +538,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { validate: { params: getCategoriesSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/calendars.ts b/x-pack/plugins/ml/server/routes/calendars.ts index a17601f74ae93..9c80651a13999 100644 --- a/x-pack/plugins/ml/server/routes/calendars.ts +++ b/x-pack/plugins/ml/server/routes/calendars.ts @@ -52,6 +52,9 @@ export function calendars({ router, mlLicense }: RouteInitialization) { { path: '/api/ml/calendars', validate: false, + options: { + tags: ['access:ml:canGetCalendars'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -81,6 +84,9 @@ export function calendars({ router, mlLicense }: RouteInitialization) { validate: { params: calendarIdsSchema, }, + options: { + tags: ['access:ml:canGetCalendars'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { let returnValue; @@ -117,6 +123,9 @@ export function calendars({ router, mlLicense }: RouteInitialization) { validate: { body: calendarSchema, }, + options: { + tags: ['access:ml:canCreateCalendar'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -149,6 +158,9 @@ export function calendars({ router, mlLicense }: RouteInitialization) { params: calendarIdSchema, body: calendarSchema, }, + options: { + tags: ['access:ml:canCreateCalendar'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -180,6 +192,9 @@ export function calendars({ router, mlLicense }: RouteInitialization) { validate: { params: calendarIdSchema, }, + options: { + tags: ['access:ml:canDeleteCalendar'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/data_frame_analytics.ts b/x-pack/plugins/ml/server/routes/data_frame_analytics.ts index dd9e0ea66aa9d..32cb2b343f876 100644 --- a/x-pack/plugins/ml/server/routes/data_frame_analytics.ts +++ b/x-pack/plugins/ml/server/routes/data_frame_analytics.ts @@ -33,6 +33,9 @@ export function dataFrameAnalyticsRoutes({ router, mlLicense }: RouteInitializat { path: '/api/ml/data_frame/analytics', validate: false, + options: { + tags: ['access:ml:canGetDataFrameAnalytics'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -61,6 +64,9 @@ export function dataFrameAnalyticsRoutes({ router, mlLicense }: RouteInitializat validate: { params: analyticsIdSchema, }, + options: { + tags: ['access:ml:canGetDataFrameAnalytics'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -88,6 +94,9 @@ export function dataFrameAnalyticsRoutes({ router, mlLicense }: RouteInitializat { path: '/api/ml/data_frame/analytics/_stats', validate: false, + options: { + tags: ['access:ml:canGetDataFrameAnalytics'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -118,6 +127,9 @@ export function dataFrameAnalyticsRoutes({ router, mlLicense }: RouteInitializat validate: { params: analyticsIdSchema, }, + options: { + tags: ['access:ml:canGetDataFrameAnalytics'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -155,6 +167,9 @@ export function dataFrameAnalyticsRoutes({ router, mlLicense }: RouteInitializat params: analyticsIdSchema, body: dataAnalyticsJobConfigSchema, }, + options: { + tags: ['access:ml:canCreateDataFrameAnalytics'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -190,6 +205,9 @@ export function dataFrameAnalyticsRoutes({ router, mlLicense }: RouteInitializat validate: { body: dataAnalyticsEvaluateSchema, }, + options: { + tags: ['access:ml:canCreateDataFrameAnalytics'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -224,6 +242,9 @@ export function dataFrameAnalyticsRoutes({ router, mlLicense }: RouteInitializat validate: { body: dataAnalyticsExplainSchema, }, + options: { + tags: ['access:ml:canCreateDataFrameAnalytics'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -257,6 +278,9 @@ export function dataFrameAnalyticsRoutes({ router, mlLicense }: RouteInitializat validate: { params: analyticsIdSchema, }, + options: { + tags: ['access:ml:canDeleteDataFrameAnalytics'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -291,6 +315,9 @@ export function dataFrameAnalyticsRoutes({ router, mlLicense }: RouteInitializat validate: { params: analyticsIdSchema, }, + options: { + tags: ['access:ml:canStartStopDataFrameAnalytics'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -324,6 +351,9 @@ export function dataFrameAnalyticsRoutes({ router, mlLicense }: RouteInitializat params: analyticsIdSchema, query: stopsDataFrameAnalyticsJobQuerySchema, }, + options: { + tags: ['access:ml:canStartStopDataFrameAnalytics'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -364,6 +394,9 @@ export function dataFrameAnalyticsRoutes({ router, mlLicense }: RouteInitializat validate: { params: analyticsIdSchema, }, + options: { + tags: ['access:ml:canGetDataFrameAnalytics'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/data_visualizer.ts b/x-pack/plugins/ml/server/routes/data_visualizer.ts index 20029fbd8d1a6..04008a896a1a2 100644 --- a/x-pack/plugins/ml/server/routes/data_visualizer.ts +++ b/x-pack/plugins/ml/server/routes/data_visualizer.ts @@ -88,6 +88,9 @@ export function dataVisualizerRoutes({ router, mlLicense }: RouteInitialization) params: indexPatternTitleSchema, body: dataVisualizerFieldStatsSchema, }, + options: { + tags: ['access:ml:canAccessML'], + }, }, mlLicense.basicLicenseAPIGuard(async (context, request, response) => { try { @@ -150,6 +153,9 @@ export function dataVisualizerRoutes({ router, mlLicense }: RouteInitialization) params: indexPatternTitleSchema, body: dataVisualizerOverallStatsSchema, }, + options: { + tags: ['access:ml:canAccessML'], + }, }, mlLicense.basicLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/datafeeds.ts b/x-pack/plugins/ml/server/routes/datafeeds.ts index ec667e1d305f5..50f64161c29eb 100644 --- a/x-pack/plugins/ml/server/routes/datafeeds.ts +++ b/x-pack/plugins/ml/server/routes/datafeeds.ts @@ -28,6 +28,9 @@ export function dataFeedRoutes({ router, mlLicense }: RouteInitialization) { { path: '/api/ml/datafeeds', validate: false, + options: { + tags: ['access:ml:canGetDatafeeds'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -57,6 +60,9 @@ export function dataFeedRoutes({ router, mlLicense }: RouteInitialization) { validate: { params: datafeedIdSchema, }, + options: { + tags: ['access:ml:canGetDatafeeds'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -83,6 +89,9 @@ export function dataFeedRoutes({ router, mlLicense }: RouteInitialization) { { path: '/api/ml/datafeeds/_stats', validate: false, + options: { + tags: ['access:ml:canGetDatafeeds'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -112,6 +121,9 @@ export function dataFeedRoutes({ router, mlLicense }: RouteInitialization) { validate: { params: datafeedIdSchema, }, + options: { + tags: ['access:ml:canGetDatafeeds'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -146,6 +158,9 @@ export function dataFeedRoutes({ router, mlLicense }: RouteInitialization) { params: datafeedIdSchema, body: datafeedConfigSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -181,6 +196,9 @@ export function dataFeedRoutes({ router, mlLicense }: RouteInitialization) { params: datafeedIdSchema, body: datafeedConfigSchema, }, + options: { + tags: ['access:ml:canUpdateDatafeed'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -216,6 +234,9 @@ export function dataFeedRoutes({ router, mlLicense }: RouteInitialization) { params: datafeedIdSchema, query: deleteDatafeedQuerySchema, }, + options: { + tags: ['access:ml:canDeleteJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -255,6 +276,9 @@ export function dataFeedRoutes({ router, mlLicense }: RouteInitialization) { params: datafeedIdSchema, body: startDatafeedSchema, }, + options: { + tags: ['access:ml:canStartStopDatafeed'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -291,6 +315,9 @@ export function dataFeedRoutes({ router, mlLicense }: RouteInitialization) { validate: { params: datafeedIdSchema, }, + options: { + tags: ['access:ml:canStartStopDatafeed'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -324,6 +351,9 @@ export function dataFeedRoutes({ router, mlLicense }: RouteInitialization) { validate: { params: datafeedIdSchema, }, + options: { + tags: ['access:ml:canPreviewDatafeed'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/fields_service.ts b/x-pack/plugins/ml/server/routes/fields_service.ts index 577e8e0161342..b0f13df294145 100644 --- a/x-pack/plugins/ml/server/routes/fields_service.ts +++ b/x-pack/plugins/ml/server/routes/fields_service.ts @@ -46,8 +46,10 @@ export function fieldsService({ router, mlLicense }: RouteInitialization) { validate: { body: getCardinalityOfFieldsSchema, }, + options: { + tags: ['access:ml:canAccessML'], + }, }, - mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { const resp = await getCardinalityOfFields(context, request.body); @@ -79,6 +81,9 @@ export function fieldsService({ router, mlLicense }: RouteInitialization) { validate: { body: getTimeFieldRangeSchema, }, + options: { + tags: ['access:ml:canAccessML'], + }, }, mlLicense.basicLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/file_data_visualizer.ts b/x-pack/plugins/ml/server/routes/file_data_visualizer.ts index 3f3fc3f547b6a..0f389f9505943 100644 --- a/x-pack/plugins/ml/server/routes/file_data_visualizer.ts +++ b/x-pack/plugins/ml/server/routes/file_data_visualizer.ts @@ -71,6 +71,7 @@ export function fileDataVisualizerRoutes({ router, mlLicense }: RouteInitializat accepts: ['text/*', 'application/json'], maxBytes: MAX_FILE_SIZE_BYTES, }, + tags: ['access:ml:canFindFileStructure'], }, }, mlLicense.basicLicenseAPIGuard(async (context, request, response) => { @@ -105,6 +106,7 @@ export function fileDataVisualizerRoutes({ router, mlLicense }: RouteInitializat accepts: ['application/json'], maxBytes: MAX_FILE_SIZE_BYTES, }, + tags: ['access:ml:canFindFileStructure'], }, }, mlLicense.basicLicenseAPIGuard(async (context, request, response) => { diff --git a/x-pack/plugins/ml/server/routes/filters.ts b/x-pack/plugins/ml/server/routes/filters.ts index 738c25070358d..d5287c349a8fc 100644 --- a/x-pack/plugins/ml/server/routes/filters.ts +++ b/x-pack/plugins/ml/server/routes/filters.ts @@ -57,6 +57,9 @@ export function filtersRoutes({ router, mlLicense }: RouteInitialization) { { path: '/api/ml/filters', validate: false, + options: { + tags: ['access:ml:canGetFilters'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -89,6 +92,9 @@ export function filtersRoutes({ router, mlLicense }: RouteInitialization) { validate: { params: filterIdSchema, }, + options: { + tags: ['access:ml:canGetFilters'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -120,6 +126,9 @@ export function filtersRoutes({ router, mlLicense }: RouteInitialization) { validate: { body: createFilterSchema, }, + options: { + tags: ['access:ml:canCreateFilter'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -155,6 +164,9 @@ export function filtersRoutes({ router, mlLicense }: RouteInitialization) { params: filterIdSchema, body: updateFilterSchema, }, + options: { + tags: ['access:ml:canCreateFilter'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -186,6 +198,9 @@ export function filtersRoutes({ router, mlLicense }: RouteInitialization) { validate: { params: filterIdSchema, }, + options: { + tags: ['access:ml:canDeleteFilter'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -216,6 +231,9 @@ export function filtersRoutes({ router, mlLicense }: RouteInitialization) { { path: '/api/ml/filters/_stats', validate: false, + options: { + tags: ['access:ml:canGetFilters'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/job_audit_messages.ts b/x-pack/plugins/ml/server/routes/job_audit_messages.ts index 1fe5a7af95d4f..5acc89e7d13be 100644 --- a/x-pack/plugins/ml/server/routes/job_audit_messages.ts +++ b/x-pack/plugins/ml/server/routes/job_audit_messages.ts @@ -33,6 +33,9 @@ export function jobAuditMessagesRoutes({ router, mlLicense }: RouteInitializatio params: jobAuditMessagesJobIdSchema, query: jobAuditMessagesQuerySchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -67,6 +70,9 @@ export function jobAuditMessagesRoutes({ router, mlLicense }: RouteInitializatio validate: { query: jobAuditMessagesQuerySchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/job_service.ts b/x-pack/plugins/ml/server/routes/job_service.ts index 149ca2591fd76..8f806dc4d98ab 100644 --- a/x-pack/plugins/ml/server/routes/job_service.ts +++ b/x-pack/plugins/ml/server/routes/job_service.ts @@ -4,11 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import Boom from 'boom'; import { schema } from '@kbn/config-schema'; -import { KibanaRequest } from 'kibana/server'; import { wrapError } from '../client/error_wrapper'; -import { RouteInitialization, JobServiceRouteDeps } from '../types'; +import { RouteInitialization } from '../types'; import { categorizationFieldExamplesSchema, chartSchema, @@ -27,19 +25,7 @@ import { categorizationExamplesProvider } from '../models/job_service/new_job'; /** * Routes for job service */ -export function jobServiceRoutes( - { router, mlLicense }: RouteInitialization, - { resolveMlCapabilities }: JobServiceRouteDeps -) { - async function hasPermissionToCreateJobs(request: KibanaRequest) { - const mlCapabilities = await resolveMlCapabilities(request); - if (mlCapabilities === null) { - throw new Error('resolveMlCapabilities is not defined'); - } - - return mlCapabilities.canCreateJob; - } - +export function jobServiceRoutes({ router, mlLicense }: RouteInitialization) { /** * @apiGroup JobService * @@ -55,6 +41,9 @@ export function jobServiceRoutes( validate: { body: forceStartDatafeedSchema, }, + options: { + tags: ['access:ml:canStartStopDatafeed'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -86,6 +75,9 @@ export function jobServiceRoutes( validate: { body: datafeedIdsSchema, }, + options: { + tags: ['access:ml:canStartStopDatafeed'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -117,6 +109,9 @@ export function jobServiceRoutes( validate: { body: jobIdsSchema, }, + options: { + tags: ['access:ml:canDeleteJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -148,6 +143,9 @@ export function jobServiceRoutes( validate: { body: jobIdsSchema, }, + options: { + tags: ['access:ml:canCloseJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -184,6 +182,9 @@ export function jobServiceRoutes( validate: { body: jobIdsSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -215,6 +216,9 @@ export function jobServiceRoutes( validate: { body: schema.object(jobsWithTimerangeSchema), }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -245,6 +249,9 @@ export function jobServiceRoutes( validate: { body: jobIdsSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -272,6 +279,9 @@ export function jobServiceRoutes( { path: '/api/ml/jobs/groups', validate: false, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -302,6 +312,9 @@ export function jobServiceRoutes( validate: { body: schema.object(updateGroupsSchema), }, + options: { + tags: ['access:ml:canUpdateJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -329,6 +342,9 @@ export function jobServiceRoutes( { path: '/api/ml/jobs/deleting_jobs_tasks', validate: false, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -359,6 +375,9 @@ export function jobServiceRoutes( validate: { body: jobIdsSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -389,6 +408,9 @@ export function jobServiceRoutes( params: schema.object({ indexPattern: schema.string() }), query: schema.maybe(schema.object({ rollup: schema.maybe(schema.string()) })), }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -422,6 +444,9 @@ export function jobServiceRoutes( validate: { body: schema.object(chartSchema), }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -474,6 +499,9 @@ export function jobServiceRoutes( validate: { body: schema.object(chartSchema), }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -522,6 +550,9 @@ export function jobServiceRoutes( { path: '/api/ml/jobs/all_jobs_and_group_ids', validate: false, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -552,6 +583,9 @@ export function jobServiceRoutes( validate: { body: schema.object(lookBackProgressSchema), }, + options: { + tags: ['access:ml:canCreateJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -583,17 +617,12 @@ export function jobServiceRoutes( validate: { body: schema.object(categorizationFieldExamplesSchema), }, + options: { + tags: ['access:ml:canCreateJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { - // due to the use of the _analyze endpoint which is called by the kibana user, - // basic job creation privileges are required to use this endpoint - if ((await hasPermissionToCreateJobs(request)) === false) { - throw Boom.forbidden( - 'Insufficient privileges, the machine_learning_admin role is required.' - ); - } - const { validateCategoryExamples } = categorizationExamplesProvider( context.ml!.mlClient.callAsCurrentUser, context.ml!.mlClient.callAsInternalUser @@ -644,6 +673,9 @@ export function jobServiceRoutes( validate: { body: schema.object(topCategoriesSchema), }, + options: { + tags: ['access:ml:canCreateJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/job_validation.ts b/x-pack/plugins/ml/server/routes/job_validation.ts index dd2bd9deadf43..632166d6d5fb8 100644 --- a/x-pack/plugins/ml/server/routes/job_validation.ts +++ b/x-pack/plugins/ml/server/routes/job_validation.ts @@ -57,6 +57,9 @@ export function jobValidationRoutes({ router, mlLicense }: RouteInitialization, validate: { body: estimateBucketSpanSchema, }, + options: { + tags: ['access:ml:canCreateJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -106,6 +109,9 @@ export function jobValidationRoutes({ router, mlLicense }: RouteInitialization, validate: { body: modelMemoryLimitSchema, }, + options: { + tags: ['access:ml:canCreateJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -135,6 +141,9 @@ export function jobValidationRoutes({ router, mlLicense }: RouteInitialization, validate: { body: validateCardinalitySchema, }, + options: { + tags: ['access:ml:canCreateJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -167,6 +176,9 @@ export function jobValidationRoutes({ router, mlLicense }: RouteInitialization, validate: { body: validateJobSchema, }, + options: { + tags: ['access:ml:canCreateJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/modules.ts b/x-pack/plugins/ml/server/routes/modules.ts index 2891144fc4574..d8474efcf122d 100644 --- a/x-pack/plugins/ml/server/routes/modules.ts +++ b/x-pack/plugins/ml/server/routes/modules.ts @@ -97,6 +97,9 @@ export function dataRecognizer({ router, mlLicense }: RouteInitialization) { indexPatternTitle: schema.string(), }), }, + options: { + tags: ['access:ml:'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -127,6 +130,9 @@ export function dataRecognizer({ router, mlLicense }: RouteInitialization) { ...getModuleIdParamSchema(true), }), }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -161,6 +167,9 @@ export function dataRecognizer({ router, mlLicense }: RouteInitialization) { params: schema.object(getModuleIdParamSchema()), body: setupModuleBodySchema, }, + options: { + tags: ['access:ml:canCreateJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -218,6 +227,9 @@ export function dataRecognizer({ router, mlLicense }: RouteInitialization) { validate: { params: schema.object(getModuleIdParamSchema()), }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/notification_settings.ts b/x-pack/plugins/ml/server/routes/notification_settings.ts index 59458b1e486db..e4a9abb0784be 100644 --- a/x-pack/plugins/ml/server/routes/notification_settings.ts +++ b/x-pack/plugins/ml/server/routes/notification_settings.ts @@ -22,6 +22,9 @@ export function notificationRoutes({ router, mlLicense }: RouteInitialization) { { path: '/api/ml/notification_settings', validate: false, + options: { + tags: ['access:ml:canAccessML'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/results_service.ts b/x-pack/plugins/ml/server/routes/results_service.ts index 89c267340fe52..94ca0827ccfa5 100644 --- a/x-pack/plugins/ml/server/routes/results_service.ts +++ b/x-pack/plugins/ml/server/routes/results_service.ts @@ -88,6 +88,9 @@ export function resultsServiceRoutes({ router, mlLicense }: RouteInitialization) validate: { body: anomaliesTableDataSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -117,6 +120,9 @@ export function resultsServiceRoutes({ router, mlLicense }: RouteInitialization) validate: { body: categoryDefinitionSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -146,6 +152,9 @@ export function resultsServiceRoutes({ router, mlLicense }: RouteInitialization) validate: { body: maxAnomalyScoreSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -175,6 +184,9 @@ export function resultsServiceRoutes({ router, mlLicense }: RouteInitialization) validate: { body: categoryExamplesSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -204,6 +216,9 @@ export function resultsServiceRoutes({ router, mlLicense }: RouteInitialization) validate: { body: partitionFieldValuesSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/system.ts b/x-pack/plugins/ml/server/routes/system.ts index d5fe45728c56c..3bfc2dcc04772 100644 --- a/x-pack/plugins/ml/server/routes/system.ts +++ b/x-pack/plugins/ml/server/routes/system.ts @@ -110,6 +110,9 @@ export function systemRoutes( { path: '/api/ml/ml_capabilities', validate: false, + options: { + tags: ['access:ml:canAccessML'], + }, }, mlLicense.basicLicenseAPIGuard(async (context, request, response) => { try { @@ -150,7 +153,11 @@ export function systemRoutes( { path: '/api/ml/ml_node_count', validate: false, + options: { + tags: ['access:ml:canGetJobs'], + }, }, + mlLicense.basicLicenseAPIGuard(async (context, request, response) => { try { // check for basic license first for consistency with other @@ -201,6 +208,9 @@ export function systemRoutes( { path: '/api/ml/info', validate: false, + options: { + tags: ['access:ml:canAccessML'], + }, }, mlLicense.basicLicenseAPIGuard(async (context, request, response) => { try { @@ -229,6 +239,9 @@ export function systemRoutes( validate: { body: schema.maybe(schema.any()), }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/types.ts b/x-pack/plugins/ml/server/types.ts index d4cd61a7fa4f7..678e81d3526ac 100644 --- a/x-pack/plugins/ml/server/types.ts +++ b/x-pack/plugins/ml/server/types.ts @@ -30,10 +30,6 @@ export interface SystemRouteDeps { resolveMlCapabilities: ResolveMlCapabilities; } -export interface JobServiceRouteDeps { - resolveMlCapabilities: ResolveMlCapabilities; -} - export interface PluginsSetup { cloud: CloudSetup; features: FeaturesPluginSetup;