diff --git a/x-pack/plugins/ingest_pipelines/common/constants.ts b/x-pack/plugins/ingest_pipelines/common/constants.ts
index 13cece33838df..edf681c276a84 100644
--- a/x-pack/plugins/ingest_pipelines/common/constants.ts
+++ b/x-pack/plugins/ingest_pipelines/common/constants.ts
@@ -14,3 +14,5 @@ export const PLUGIN_MIN_LICENSE_TYPE = basicLicense;
export const BASE_PATH = '/management/elasticsearch/ingest_pipelines';
export const API_BASE_PATH = '/api/ingest_pipelines';
+
+export const APP_CLUSTER_REQUIRED_PRIVILEGES = ['manage_pipeline', 'cluster:monitor/nodes/info'];
diff --git a/x-pack/plugins/ingest_pipelines/public/application/app.tsx b/x-pack/plugins/ingest_pipelines/public/application/app.tsx
index 1027d08c133db..2ec72267701d7 100644
--- a/x-pack/plugins/ingest_pipelines/public/application/app.tsx
+++ b/x-pack/plugins/ingest_pipelines/public/application/app.tsx
@@ -3,19 +3,22 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
-
-import React from 'react';
+import { FormattedMessage } from '@kbn/i18n/react';
+import { EuiPageContent } from '@elastic/eui';
+import React, { FunctionComponent } from 'react';
import { HashRouter, Switch, Route } from 'react-router-dom';
-import { BASE_PATH } from '../../common/constants';
-import { PipelinesList, PipelinesCreate, PipelinesEdit, PipelinesClone } from './sections';
-export const App = () => {
- return (
-
-
-
- );
-};
+import { BASE_PATH, APP_CLUSTER_REQUIRED_PRIVILEGES } from '../../common/constants';
+
+import {
+ SectionError,
+ useAuthorizationContext,
+ WithPrivileges,
+ SectionLoading,
+ NotAuthorizedSection,
+} from '../shared_imports';
+
+import { PipelinesList, PipelinesCreate, PipelinesEdit, PipelinesClone } from './sections';
export const AppWithoutRouter = () => (
@@ -25,3 +28,72 @@ export const AppWithoutRouter = () => (
);
+
+export const App: FunctionComponent = () => {
+ const { apiError } = useAuthorizationContext();
+
+ if (apiError) {
+ return (
+
+ }
+ error={apiError}
+ />
+ );
+ }
+
+ return (
+ `cluster.${privilege}`)}
+ >
+ {({ isLoading, hasPrivileges, privilegesMissing }) => {
+ if (isLoading) {
+ return (
+
+
+
+ );
+ }
+
+ if (!hasPrivileges) {
+ return (
+
+
+ }
+ message={
+
+ }
+ />
+
+ );
+ }
+
+ return (
+
+
+
+ );
+ }}
+
+ );
+};
diff --git a/x-pack/plugins/ingest_pipelines/public/application/index.tsx b/x-pack/plugins/ingest_pipelines/public/application/index.tsx
index 778ce0c873e66..e43dba4689b44 100644
--- a/x-pack/plugins/ingest_pipelines/public/application/index.tsx
+++ b/x-pack/plugins/ingest_pipelines/public/application/index.tsx
@@ -4,11 +4,16 @@
* you may not use this file except in compliance with the Elastic License.
*/
+import { HttpSetup } from 'kibana/public';
import React, { ReactNode } from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { NotificationsSetup } from 'kibana/public';
import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/public';
+import { API_BASE_PATH } from '../../common/constants';
+
+import { AuthorizationProvider } from '../shared_imports';
+
import { App } from './app';
import { DocumentationService, UiMetricService, ApiService, BreadcrumbService } from './services';
@@ -20,17 +25,27 @@ export interface AppServices {
notifications: NotificationsSetup;
}
+export interface CoreServices {
+ http: HttpSetup;
+}
+
export const renderApp = (
element: HTMLElement,
I18nContext: ({ children }: { children: ReactNode }) => JSX.Element,
- services: AppServices
+ services: AppServices,
+ coreServices: CoreServices
) => {
render(
-
-
-
-
- ,
+
+
+
+
+
+
+ ,
element
);
diff --git a/x-pack/plugins/ingest_pipelines/public/application/mount_management_section.ts b/x-pack/plugins/ingest_pipelines/public/application/mount_management_section.ts
index 9b950a54096c3..e36f27cbf5f62 100644
--- a/x-pack/plugins/ingest_pipelines/public/application/mount_management_section.ts
+++ b/x-pack/plugins/ingest_pipelines/public/application/mount_management_section.ts
@@ -10,11 +10,11 @@ import { documentationService, uiMetricService, apiService, breadcrumbService }
import { renderApp } from '.';
export async function mountManagementSection(
- coreSetup: CoreSetup,
+ { http, getStartServices, notifications }: CoreSetup,
params: ManagementAppMountParams
) {
const { element, setBreadcrumbs } = params;
- const [coreStart] = await coreSetup.getStartServices();
+ const [coreStart] = await getStartServices();
const {
docLinks,
i18n: { Context: I18nContext },
@@ -28,8 +28,8 @@ export async function mountManagementSection(
metric: uiMetricService,
documentation: documentationService,
api: apiService,
- notifications: coreSetup.notifications,
+ notifications,
};
- return renderApp(element, I18nContext, services);
+ return renderApp(element, I18nContext, services, { http });
}
diff --git a/x-pack/plugins/ingest_pipelines/public/shared_imports.ts b/x-pack/plugins/ingest_pipelines/public/shared_imports.ts
index 1035a1d8fc864..5127821f3820c 100644
--- a/x-pack/plugins/ingest_pipelines/public/shared_imports.ts
+++ b/x-pack/plugins/ingest_pipelines/public/shared_imports.ts
@@ -45,6 +45,15 @@ export {
isJSON,
isEmptyString,
} from '../../../../src/plugins/es_ui_shared/static/validators/string';
-export { SectionLoading } from '../../../../src/plugins/es_ui_shared/public';
+
+export {
+ SectionLoading,
+ WithPrivileges,
+ AuthorizationProvider,
+ SectionError,
+ Error,
+ useAuthorizationContext,
+ NotAuthorizedSection,
+} from '../../../../src/plugins/es_ui_shared/public';
export const useKibana = () => _useKibana();
diff --git a/x-pack/plugins/ingest_pipelines/server/routes/api/index.ts b/x-pack/plugins/ingest_pipelines/server/routes/api/index.ts
index 9992f56512c01..37819b9bf6889 100644
--- a/x-pack/plugins/ingest_pipelines/server/routes/api/index.ts
+++ b/x-pack/plugins/ingest_pipelines/server/routes/api/index.ts
@@ -10,4 +10,6 @@ export { registerCreateRoute } from './create';
export { registerUpdateRoute } from './update';
+export { registerPrivilegesRoute } from './privileges';
+
export { registerDeleteRoute } from './delete';
diff --git a/x-pack/plugins/ingest_pipelines/server/routes/api/privileges.ts b/x-pack/plugins/ingest_pipelines/server/routes/api/privileges.ts
new file mode 100644
index 0000000000000..2e1c11928959f
--- /dev/null
+++ b/x-pack/plugins/ingest_pipelines/server/routes/api/privileges.ts
@@ -0,0 +1,62 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+import { RouteDependencies } from '../../types';
+import { API_BASE_PATH, APP_CLUSTER_REQUIRED_PRIVILEGES } from '../../../common/constants';
+import { Privileges } from '../../../../../../src/plugins/es_ui_shared/public';
+
+const extractMissingPrivileges = (privilegesObject: { [key: string]: boolean } = {}): string[] =>
+ Object.keys(privilegesObject).reduce((privileges: string[], privilegeName: string): string[] => {
+ if (!privilegesObject[privilegeName]) {
+ privileges.push(privilegeName);
+ }
+ return privileges;
+ }, []);
+
+export const registerPrivilegesRoute = ({ license, router }: RouteDependencies) => {
+ router.get(
+ {
+ path: `${API_BASE_PATH}/privileges`,
+ validate: false,
+ },
+ license.guardApiRoute(async (ctx, req, res) => {
+ const {
+ core: {
+ elasticsearch: { dataClient },
+ },
+ } = ctx;
+
+ const privilegesResult: Privileges = {
+ hasAllPrivileges: true,
+ missingPrivileges: {
+ cluster: [],
+ },
+ };
+
+ try {
+ const { has_all_requested: hasAllPrivileges, cluster } = await dataClient.callAsCurrentUser(
+ 'transport.request',
+ {
+ path: '/_security/user/_has_privileges',
+ method: 'POST',
+ body: {
+ cluster: APP_CLUSTER_REQUIRED_PRIVILEGES,
+ },
+ }
+ );
+
+ if (!hasAllPrivileges) {
+ privilegesResult.missingPrivileges.cluster = extractMissingPrivileges(cluster);
+ }
+
+ privilegesResult.hasAllPrivileges = hasAllPrivileges;
+
+ return res.ok({ body: privilegesResult });
+ } catch (e) {
+ return res.internalError(e);
+ }
+ })
+ );
+};
diff --git a/x-pack/plugins/ingest_pipelines/server/routes/index.ts b/x-pack/plugins/ingest_pipelines/server/routes/index.ts
index 419525816f217..8cfcc1054ca4e 100644
--- a/x-pack/plugins/ingest_pipelines/server/routes/index.ts
+++ b/x-pack/plugins/ingest_pipelines/server/routes/index.ts
@@ -10,6 +10,7 @@ import {
registerGetRoutes,
registerCreateRoute,
registerUpdateRoute,
+ registerPrivilegesRoute,
registerDeleteRoute,
} from './api';
@@ -18,6 +19,7 @@ export class ApiRoutes {
registerGetRoutes(dependencies);
registerCreateRoute(dependencies);
registerUpdateRoute(dependencies);
+ registerPrivilegesRoute(dependencies);
registerDeleteRoute(dependencies);
}
}