diff --git a/x-pack/legacy/plugins/security/common/model/builtin_es_privileges.ts b/x-pack/legacy/plugins/security/common/model/builtin_es_privileges.ts
new file mode 100644
index 0000000000000..373d5df31bcec
--- /dev/null
+++ b/x-pack/legacy/plugins/security/common/model/builtin_es_privileges.ts
@@ -0,0 +1,10 @@
+/*
+ * 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.
+ */
+
+export interface BuiltinESPrivileges {
+ cluster: string[];
+ index: string[];
+}
diff --git a/x-pack/legacy/plugins/security/common/model/index.ts b/x-pack/legacy/plugins/security/common/model/index.ts
index 83648cfb59a67..6557db90a6207 100644
--- a/x-pack/legacy/plugins/security/common/model/index.ts
+++ b/x-pack/legacy/plugins/security/common/model/index.ts
@@ -10,3 +10,4 @@ export { RawKibanaPrivileges, RawKibanaFeaturePrivileges } from './raw_kibana_pr
export { KibanaPrivileges } from './kibana_privileges';
export { User, EditUser, getUserDisplayName } from './user';
export { AuthenticatedUser, canUserChangePassword } from './authenticated_user';
+export { BuiltinESPrivileges } from './builtin_es_privileges';
diff --git a/x-pack/legacy/plugins/security/index.js b/x-pack/legacy/plugins/security/index.js
index 250c8729b5466..196cedfa8dc36 100644
--- a/x-pack/legacy/plugins/security/index.js
+++ b/x-pack/legacy/plugins/security/index.js
@@ -11,6 +11,7 @@ import { initUsersApi } from './server/routes/api/v1/users';
import { initExternalRolesApi } from './server/routes/api/external/roles';
import { initPrivilegesApi } from './server/routes/api/external/privileges';
import { initIndicesApi } from './server/routes/api/v1/indices';
+import { initGetBuiltinPrivilegesApi } from './server/routes/api/v1/builtin_privileges';
import { initOverwrittenSessionView } from './server/routes/views/overwritten_session';
import { initLoginView } from './server/routes/views/login';
import { initLogoutView } from './server/routes/views/logout';
@@ -212,6 +213,7 @@ export const security = (kibana) => new kibana.Plugin({
initExternalRolesApi(server);
initIndicesApi(server);
initPrivilegesApi(server);
+ initGetBuiltinPrivilegesApi(server);
initLoginView(server, xpackMainPlugin);
initLogoutView(server);
initLoggedOutView(server);
diff --git a/x-pack/legacy/plugins/security/public/services/application_privilege.js b/x-pack/legacy/plugins/security/public/services/application_privilege.js
deleted file mode 100644
index 00db6cccfb13e..0000000000000
--- a/x-pack/legacy/plugins/security/public/services/application_privilege.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * 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 'angular-resource';
-import { uiModules } from 'ui/modules';
-
-const module = uiModules.get('security', ['ngResource']);
-module.service('ApplicationPrivileges', ($resource, chrome) => {
- const baseUrl = chrome.addBasePath('/api/security/v1/privileges');
- return $resource(baseUrl, null, {
- query: {
- isArray: false,
- }
- });
-});
diff --git a/x-pack/legacy/plugins/security/public/services/role_privileges.js b/x-pack/legacy/plugins/security/public/services/role_privileges.js
deleted file mode 100644
index e9e3dbf729a2c..0000000000000
--- a/x-pack/legacy/plugins/security/public/services/role_privileges.js
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.
- */
-
-const clusterPrivileges = [
- 'all',
- 'monitor',
- 'manage',
- 'manage_security',
- 'manage_index_templates',
- 'manage_pipeline',
- 'manage_ingest_pipelines',
- 'transport_client',
- 'manage_ml',
- 'monitor_ml',
- 'manage_data_frame_transforms',
- 'monitor_data_frame_transforms',
- 'manage_watcher',
- 'monitor_watcher',
- 'read_ccr',
- 'manage_ccr',
- 'manage_ilm',
- 'read_ilm',
- 'monitor_rollup',
- 'manage_rollup',
- 'manage_token',
- 'manage_saml',
- 'create_snapshot',
- 'manage_oidc',
-];
-const indexPrivileges = [
- 'all',
- 'manage',
- 'monitor',
- 'read',
- 'index',
- 'create',
- 'delete',
- 'write',
- 'delete_index',
- 'create_index',
- 'view_index_metadata',
- 'read_cross_cluster',
- 'manage_follow_index',
- 'manage_ilm',
- 'manage_leader_index',
-];
-
-export function getClusterPrivileges() {
- return [...clusterPrivileges];
-}
-
-export function getIndexPrivileges() {
- return [...indexPrivileges];
-}
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/edit_role_page.test.tsx b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/edit_role_page.test.tsx
index 94206c99b5954..80c8c079b9001 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/edit_role_page.test.tsx
+++ b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/edit_role_page.test.tsx
@@ -65,6 +65,13 @@ const buildRawKibanaPrivileges = () => {
return privilegesFactory(actions, xpackMainPlugin as any).get();
};
+const buildBuiltinESPrivileges = () => {
+ return {
+ cluster: ['all', 'manage', 'monitor'],
+ index: ['all', 'read', 'write', 'index'],
+ };
+};
+
const buildUICapabilities = (canManageSpaces = true) => {
return {
catalogue: {},
@@ -132,7 +139,8 @@ describe('', () => {
const features: Feature[] = buildFeatures();
const mockHttpClient = jest.fn();
const indexPatterns: string[] = ['foo*', 'bar*'];
- const privileges: RawKibanaPrivileges = buildRawKibanaPrivileges();
+ const kibanaPrivileges: RawKibanaPrivileges = buildRawKibanaPrivileges();
+ const builtinESPrivileges = buildBuiltinESPrivileges();
const spaces: Space[] = buildSpaces();
const uiCapabilities: UICapabilities = buildUICapabilities();
@@ -146,7 +154,8 @@ describe('', () => {
features={features}
httpClient={mockHttpClient}
indexPatterns={indexPatterns}
- privileges={privileges}
+ kibanaPrivileges={kibanaPrivileges}
+ builtinESPrivileges={builtinESPrivileges}
spaces={spaces}
spacesEnabled={true}
uiCapabilities={uiCapabilities}
@@ -180,7 +189,8 @@ describe('', () => {
const features: Feature[] = buildFeatures();
const mockHttpClient = jest.fn();
const indexPatterns: string[] = ['foo*', 'bar*'];
- const privileges: RawKibanaPrivileges = buildRawKibanaPrivileges();
+ const kibanaPrivileges: RawKibanaPrivileges = buildRawKibanaPrivileges();
+ const builtinESPrivileges = buildBuiltinESPrivileges();
const spaces: Space[] = buildSpaces();
const uiCapabilities: UICapabilities = buildUICapabilities();
@@ -194,7 +204,8 @@ describe('', () => {
features={features}
httpClient={mockHttpClient}
indexPatterns={indexPatterns}
- privileges={privileges}
+ kibanaPrivileges={kibanaPrivileges}
+ builtinESPrivileges={builtinESPrivileges}
spaces={spaces}
spacesEnabled={true}
uiCapabilities={uiCapabilities}
@@ -222,7 +233,8 @@ describe('', () => {
const features: Feature[] = buildFeatures();
const mockHttpClient = jest.fn();
const indexPatterns: string[] = ['foo*', 'bar*'];
- const privileges: RawKibanaPrivileges = buildRawKibanaPrivileges();
+ const kibanaPrivileges: RawKibanaPrivileges = buildRawKibanaPrivileges();
+ const builtinESPrivileges = buildBuiltinESPrivileges();
const spaces: Space[] = buildSpaces();
const uiCapabilities: UICapabilities = buildUICapabilities();
@@ -236,7 +248,8 @@ describe('', () => {
features={features}
httpClient={mockHttpClient}
indexPatterns={indexPatterns}
- privileges={privileges}
+ kibanaPrivileges={kibanaPrivileges}
+ builtinESPrivileges={builtinESPrivileges}
spaces={spaces}
spacesEnabled={true}
uiCapabilities={uiCapabilities}
@@ -280,7 +293,8 @@ describe('', () => {
const features: Feature[] = buildFeatures();
const mockHttpClient = jest.fn();
const indexPatterns: string[] = ['foo*', 'bar*'];
- const privileges: RawKibanaPrivileges = buildRawKibanaPrivileges();
+ const kibanaPrivileges: RawKibanaPrivileges = buildRawKibanaPrivileges();
+ const builtinESPrivileges = buildBuiltinESPrivileges();
const spaces: Space[] = buildSpaces();
const uiCapabilities: UICapabilities = buildUICapabilities();
@@ -294,7 +308,8 @@ describe('', () => {
features={features}
httpClient={mockHttpClient}
indexPatterns={indexPatterns}
- privileges={privileges}
+ kibanaPrivileges={kibanaPrivileges}
+ builtinESPrivileges={builtinESPrivileges}
spaces={spaces}
spacesEnabled={true}
uiCapabilities={uiCapabilities}
@@ -327,7 +342,8 @@ describe('', () => {
const features: Feature[] = buildFeatures();
const mockHttpClient = jest.fn();
const indexPatterns: string[] = ['foo*', 'bar*'];
- const privileges: RawKibanaPrivileges = buildRawKibanaPrivileges();
+ const kibanaPrivileges: RawKibanaPrivileges = buildRawKibanaPrivileges();
+ const builtinESPrivileges = buildBuiltinESPrivileges();
const spaces: Space[] = buildSpaces();
const uiCapabilities: UICapabilities = buildUICapabilities(false);
@@ -341,7 +357,8 @@ describe('', () => {
features={features}
httpClient={mockHttpClient}
indexPatterns={indexPatterns}
- privileges={privileges}
+ kibanaPrivileges={kibanaPrivileges}
+ builtinESPrivileges={builtinESPrivileges}
spaces={spaces}
spacesEnabled={true}
uiCapabilities={uiCapabilities}
@@ -374,7 +391,8 @@ describe('', () => {
const features: Feature[] = buildFeatures();
const mockHttpClient = jest.fn();
const indexPatterns: string[] = ['foo*', 'bar*'];
- const privileges: RawKibanaPrivileges = buildRawKibanaPrivileges();
+ const kibanaPrivileges: RawKibanaPrivileges = buildRawKibanaPrivileges();
+ const builtinESPrivileges = buildBuiltinESPrivileges();
const spaces: Space[] = buildSpaces();
const uiCapabilities: UICapabilities = buildUICapabilities(false);
@@ -388,7 +406,8 @@ describe('', () => {
features={features}
httpClient={mockHttpClient}
indexPatterns={indexPatterns}
- privileges={privileges}
+ kibanaPrivileges={kibanaPrivileges}
+ builtinESPrivileges={builtinESPrivileges}
spaces={spaces}
spacesEnabled={true}
uiCapabilities={uiCapabilities}
@@ -424,7 +443,8 @@ describe('', () => {
const features: Feature[] = buildFeatures();
const mockHttpClient = jest.fn();
const indexPatterns: string[] = ['foo*', 'bar*'];
- const privileges: RawKibanaPrivileges = buildRawKibanaPrivileges();
+ const kibanaPrivileges: RawKibanaPrivileges = buildRawKibanaPrivileges();
+ const builtinESPrivileges = buildBuiltinESPrivileges();
const uiCapabilities: UICapabilities = buildUICapabilities();
const wrapper = mountWithIntl(
@@ -437,7 +457,8 @@ describe('', () => {
features={features}
httpClient={mockHttpClient}
indexPatterns={indexPatterns}
- privileges={privileges}
+ kibanaPrivileges={kibanaPrivileges}
+ builtinESPrivileges={builtinESPrivileges}
spaces={[]}
spacesEnabled={false}
uiCapabilities={uiCapabilities}
@@ -471,7 +492,8 @@ describe('', () => {
const features: Feature[] = buildFeatures();
const mockHttpClient = jest.fn();
const indexPatterns: string[] = ['foo*', 'bar*'];
- const privileges: RawKibanaPrivileges = buildRawKibanaPrivileges();
+ const kibanaPrivileges: RawKibanaPrivileges = buildRawKibanaPrivileges();
+ const builtinESPrivileges = buildBuiltinESPrivileges();
const uiCapabilities: UICapabilities = buildUICapabilities();
const wrapper = mountWithIntl(
@@ -484,7 +506,8 @@ describe('', () => {
features={features}
httpClient={mockHttpClient}
indexPatterns={indexPatterns}
- privileges={privileges}
+ kibanaPrivileges={kibanaPrivileges}
+ builtinESPrivileges={builtinESPrivileges}
spaces={[]}
spacesEnabled={false}
uiCapabilities={uiCapabilities}
@@ -512,7 +535,8 @@ describe('', () => {
const features: Feature[] = buildFeatures();
const mockHttpClient = jest.fn();
const indexPatterns: string[] = ['foo*', 'bar*'];
- const privileges: RawKibanaPrivileges = buildRawKibanaPrivileges();
+ const kibanaPrivileges: RawKibanaPrivileges = buildRawKibanaPrivileges();
+ const builtinESPrivileges = buildBuiltinESPrivileges();
const uiCapabilities: UICapabilities = buildUICapabilities();
const wrapper = mountWithIntl(
@@ -525,7 +549,8 @@ describe('', () => {
features={features}
httpClient={mockHttpClient}
indexPatterns={indexPatterns}
- privileges={privileges}
+ kibanaPrivileges={kibanaPrivileges}
+ builtinESPrivileges={builtinESPrivileges}
spaces={[]}
spacesEnabled={false}
uiCapabilities={uiCapabilities}
@@ -568,7 +593,8 @@ describe('', () => {
const features: Feature[] = buildFeatures();
const mockHttpClient = jest.fn();
const indexPatterns: string[] = ['foo*', 'bar*'];
- const privileges: RawKibanaPrivileges = buildRawKibanaPrivileges();
+ const kibanaPrivileges: RawKibanaPrivileges = buildRawKibanaPrivileges();
+ const builtinESPrivileges = buildBuiltinESPrivileges();
const uiCapabilities: UICapabilities = buildUICapabilities();
const wrapper = mountWithIntl(
@@ -581,7 +607,8 @@ describe('', () => {
features={features}
httpClient={mockHttpClient}
indexPatterns={indexPatterns}
- privileges={privileges}
+ kibanaPrivileges={kibanaPrivileges}
+ builtinESPrivileges={builtinESPrivileges}
spaces={[]}
spacesEnabled={false}
uiCapabilities={uiCapabilities}
@@ -613,7 +640,8 @@ describe('', () => {
const features: Feature[] = buildFeatures();
const mockHttpClient = jest.fn();
const indexPatterns: string[] = ['foo*', 'bar*'];
- const privileges: RawKibanaPrivileges = buildRawKibanaPrivileges();
+ const kibanaPrivileges: RawKibanaPrivileges = buildRawKibanaPrivileges();
+ const builtinESPrivileges = buildBuiltinESPrivileges();
const uiCapabilities: UICapabilities = buildUICapabilities(false);
const wrapper = mountWithIntl(
@@ -626,7 +654,8 @@ describe('', () => {
features={features}
httpClient={mockHttpClient}
indexPatterns={indexPatterns}
- privileges={privileges}
+ kibanaPrivileges={kibanaPrivileges}
+ builtinESPrivileges={builtinESPrivileges}
spaces={[]}
spacesEnabled={false}
uiCapabilities={uiCapabilities}
@@ -659,7 +688,8 @@ describe('', () => {
const features: Feature[] = buildFeatures();
const mockHttpClient = jest.fn();
const indexPatterns: string[] = ['foo*', 'bar*'];
- const privileges: RawKibanaPrivileges = buildRawKibanaPrivileges();
+ const kibanaPrivileges: RawKibanaPrivileges = buildRawKibanaPrivileges();
+ const builtinESPrivileges = buildBuiltinESPrivileges();
const uiCapabilities: UICapabilities = buildUICapabilities(false);
const wrapper = mountWithIntl(
@@ -672,7 +702,8 @@ describe('', () => {
features={features}
httpClient={mockHttpClient}
indexPatterns={indexPatterns}
- privileges={privileges}
+ kibanaPrivileges={kibanaPrivileges}
+ builtinESPrivileges={builtinESPrivileges}
spaces={[]}
spacesEnabled={false}
uiCapabilities={uiCapabilities}
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/edit_role_page.tsx b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/edit_role_page.tsx
index 2ff3aba2cae5b..9996427f59b24 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/edit_role_page.tsx
+++ b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/edit_role_page.tsx
@@ -24,7 +24,12 @@ import { UICapabilities } from 'ui/capabilities';
import { toastNotifications } from 'ui/notify';
import { Space } from '../../../../../../spaces/common/model/space';
import { Feature } from '../../../../../../xpack_main/types';
-import { KibanaPrivileges, RawKibanaPrivileges, Role } from '../../../../../common/model';
+import {
+ KibanaPrivileges,
+ RawKibanaPrivileges,
+ Role,
+ BuiltinESPrivileges,
+} from '../../../../../common/model';
import {
isReadOnlyRole,
isReservedRole,
@@ -46,7 +51,8 @@ interface Props {
httpClient: any;
allowDocumentLevelSecurity: boolean;
allowFieldLevelSecurity: boolean;
- privileges: RawKibanaPrivileges;
+ kibanaPrivileges: RawKibanaPrivileges;
+ builtinESPrivileges: BuiltinESPrivileges;
spaces?: Space[];
spacesEnabled: boolean;
intl: InjectedIntl;
@@ -246,6 +252,7 @@ class EditRolePageUI extends Component {
runAsUsers={this.props.runAsUsers}
validator={this.validator}
indexPatterns={this.props.indexPatterns}
+ builtinESPrivileges={this.props.builtinESPrivileges}
allowDocumentLevelSecurity={this.props.allowDocumentLevelSecurity}
allowFieldLevelSecurity={this.props.allowFieldLevelSecurity}
/>
@@ -264,7 +271,7 @@ class EditRolePageUI extends Component {
{
kibana: [],
};
- const wrapper = shallow();
+ const wrapper = shallow(
+
+ );
expect(wrapper).toMatchSnapshot();
});
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/cluster_privileges.tsx b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/cluster_privileges.tsx
index 7901fb9ff7fb4..b6bd1930a1d27 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/cluster_privileges.tsx
+++ b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/cluster_privileges.tsx
@@ -8,19 +8,16 @@ import { EuiComboBox, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import React, { Component } from 'react';
import { Role } from '../../../../../../../common/model';
import { isReadOnlyRole } from '../../../../../../lib/role_utils';
-// @ts-ignore
-import { getClusterPrivileges } from '../../../../../../services/role_privileges';
interface Props {
role: Role;
+ availableClusterPrivileges: string[];
onChange: (privs: string[]) => void;
}
export class ClusterPrivileges extends Component {
public render() {
- const clusterPrivileges = getClusterPrivileges();
-
- return {this.buildComboBox(clusterPrivileges)};
+ return {this.buildComboBox(this.props.availableClusterPrivileges)};
}
public buildComboBox = (items: string[]) => {
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/elasticsearch_privileges.test.tsx b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/elasticsearch_privileges.test.tsx
index ccdbf5a9f3555..5ba3d1daf61ac 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/elasticsearch_privileges.test.tsx
+++ b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/elasticsearch_privileges.test.tsx
@@ -30,6 +30,10 @@ test('it renders without crashing', () => {
allowDocumentLevelSecurity: true,
allowFieldLevelSecurity: true,
validator: new RoleValidator(),
+ builtinESPrivileges: {
+ cluster: ['all', 'manage', 'monitor'],
+ index: ['all', 'read', 'write', 'index'],
+ },
};
const wrapper = shallowWithIntl();
expect(wrapper).toMatchSnapshot();
@@ -54,6 +58,10 @@ test('it renders ClusterPrivileges', () => {
allowDocumentLevelSecurity: true,
allowFieldLevelSecurity: true,
validator: new RoleValidator(),
+ builtinESPrivileges: {
+ cluster: ['all', 'manage', 'monitor'],
+ index: ['all', 'read', 'write', 'index'],
+ },
};
const wrapper = mountWithIntl();
expect(wrapper.find(ClusterPrivileges)).toHaveLength(1);
@@ -78,6 +86,10 @@ test('it renders IndexPrivileges', () => {
allowDocumentLevelSecurity: true,
allowFieldLevelSecurity: true,
validator: new RoleValidator(),
+ builtinESPrivileges: {
+ cluster: ['all', 'manage', 'monitor'],
+ index: ['all', 'read', 'write', 'index'],
+ },
};
const wrapper = mountWithIntl();
expect(wrapper.find(IndexPrivileges)).toHaveLength(1);
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/elasticsearch_privileges.tsx b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/elasticsearch_privileges.tsx
index 1d450bd868b11..7540cf2cedab7 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/elasticsearch_privileges.tsx
+++ b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/elasticsearch_privileges.tsx
@@ -19,7 +19,7 @@ import {
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import React, { Component, Fragment } from 'react';
-import { Role } from '../../../../../../../common/model';
+import { Role, BuiltinESPrivileges } from '../../../../../../../common/model';
// @ts-ignore
import { documentationLinks } from '../../../../../../documentation_links';
import { RoleValidator } from '../../../lib/validate_role';
@@ -35,6 +35,7 @@ interface Props {
onChange: (role: Role) => void;
runAsUsers: string[];
validator: RoleValidator;
+ builtinESPrivileges: BuiltinESPrivileges;
indexPatterns: string[];
allowDocumentLevelSecurity: boolean;
allowFieldLevelSecurity: boolean;
@@ -59,6 +60,7 @@ export class ElasticsearchPrivileges extends Component {
indexPatterns,
allowDocumentLevelSecurity,
allowFieldLevelSecurity,
+ builtinESPrivileges,
} = this.props;
const indexProps = {
@@ -69,6 +71,7 @@ export class ElasticsearchPrivileges extends Component {
allowDocumentLevelSecurity,
allowFieldLevelSecurity,
onChange,
+ availableIndexPrivileges: builtinESPrivileges.index,
};
return (
@@ -93,7 +96,11 @@ export class ElasticsearchPrivileges extends Component {
}
>
-
+
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privilege_form.test.tsx b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privilege_form.test.tsx
index 136222e920362..6d386fd78a11b 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privilege_form.test.tsx
+++ b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privilege_form.test.tsx
@@ -22,6 +22,7 @@ test('it renders without crashing', () => {
formIndex: 0,
indexPatterns: [],
availableFields: [],
+ availableIndexPrivileges: ['all', 'read', 'write', 'index'],
isReadOnlyRole: false,
allowDocumentLevelSecurity: true,
allowFieldLevelSecurity: true,
@@ -48,6 +49,7 @@ describe('delete button', () => {
formIndex: 0,
indexPatterns: [],
availableFields: [],
+ availableIndexPrivileges: ['all', 'read', 'write', 'index'],
isReadOnlyRole: false,
allowDocumentLevelSecurity: true,
allowFieldLevelSecurity: true,
@@ -99,6 +101,7 @@ describe(`document level security`, () => {
formIndex: 0,
indexPatterns: [],
availableFields: [],
+ availableIndexPrivileges: ['all', 'read', 'write', 'index'],
isReadOnlyRole: false,
allowDocumentLevelSecurity: true,
allowFieldLevelSecurity: true,
@@ -157,6 +160,7 @@ describe('field level security', () => {
formIndex: 0,
indexPatterns: [],
availableFields: [],
+ availableIndexPrivileges: ['all', 'read', 'write', 'index'],
isReadOnlyRole: false,
allowDocumentLevelSecurity: true,
allowFieldLevelSecurity: true,
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privilege_form.tsx b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privilege_form.tsx
index 2a64227bba0e8..bafc56dc167ea 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privilege_form.tsx
+++ b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privilege_form.tsx
@@ -20,8 +20,6 @@ import { FormattedMessage } from '@kbn/i18n/react';
import _ from 'lodash';
import React, { ChangeEvent, Component, Fragment } from 'react';
import { RoleIndexPrivilege } from '../../../../../../../common/model';
-// @ts-ignore
-import { getIndexPrivileges } from '../../../../../../services/role_privileges';
import { RoleValidator } from '../../../lib/validate_role';
const fromOption = (option: any) => option.label;
@@ -31,6 +29,7 @@ interface Props {
formIndex: number;
indexPrivilege: RoleIndexPrivilege;
indexPatterns: string[];
+ availableIndexPrivileges: string[];
availableFields: string[];
onChange: (indexPrivilege: RoleIndexPrivilege) => void;
onDelete: () => void;
@@ -126,7 +125,7 @@ export class IndexPrivilegeForm extends Component {
>
{
allowFieldLevelSecurity: true,
editable: true,
validator: new RoleValidator(),
+ availableIndexPrivileges: ['all', 'read', 'write', 'index'],
};
const wrapper = shallowWithIntl();
expect(wrapper).toMatchSnapshot();
@@ -60,6 +61,7 @@ test('it renders a IndexPrivilegeForm for each privilege on the role', () => {
allowDocumentLevelSecurity: true,
allowFieldLevelSecurity: true,
validator: new RoleValidator(),
+ availableIndexPrivileges: ['all', 'read', 'write', 'index'],
};
const wrapper = mountWithIntl();
expect(wrapper.find(IndexPrivilegeForm)).toHaveLength(1);
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privileges.tsx b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privileges.tsx
index 7b7934fb3413a..1f54a5aacf948 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privileges.tsx
+++ b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privileges.tsx
@@ -14,6 +14,7 @@ import { IndexPrivilegeForm } from './index_privilege_form';
interface Props {
role: Role;
indexPatterns: string[];
+ availableIndexPrivileges: string[];
allowDocumentLevelSecurity: boolean;
allowFieldLevelSecurity: boolean;
httpClient: any;
@@ -42,7 +43,12 @@ export class IndexPrivileges extends Component {
public render() {
const { indices = [] } = this.props.role.elasticsearch;
- const { indexPatterns, allowDocumentLevelSecurity, allowFieldLevelSecurity } = this.props;
+ const {
+ indexPatterns,
+ allowDocumentLevelSecurity,
+ allowFieldLevelSecurity,
+ availableIndexPrivileges,
+ } = this.props;
const props = {
indexPatterns,
@@ -60,6 +66,7 @@ export class IndexPrivileges extends Component {
{...props}
formIndex={idx}
validator={this.props.validator}
+ availableIndexPrivileges={availableIndexPrivileges}
indexPrivilege={indexPrivilege}
availableFields={this.state.availableFields[indexPrivilege.names.join(',')]}
onChange={this.onIndexPrivilegeChange(idx)}
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/index.js b/x-pack/legacy/plugins/security/public/views/management/edit_role/index.js
index aa5bf65742895..952b86b9c8c29 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/index.js
+++ b/x-pack/legacy/plugins/security/public/views/management/edit_role/index.js
@@ -10,8 +10,6 @@ import { capabilities } from 'ui/capabilities';
import { kfetch } from 'ui/kfetch';
import { fatalError, toastNotifications } from 'ui/notify';
import template from 'plugins/security/views/management/edit_role/edit_role.html';
-import 'ui/angular_ui_select';
-import 'plugins/security/services/application_privilege';
import 'plugins/security/services/shield_user';
import 'plugins/security/services/shield_role';
import 'plugins/security/services/shield_indices';
@@ -87,9 +85,12 @@ const routeDefinition = (action) => ({
}
return [];
},
- privileges() {
+ kibanaPrivileges() {
return kfetch({ method: 'get', pathname: '/api/security/privileges', query: { includeActions: true } });
},
+ builtinESPrivileges() {
+ return kfetch({ method: 'get', pathname: '/api/security/v1/esPrivileges/builtin' });
+ },
features() {
return kfetch({ method: 'get', pathname: '/api/features/v1' }).catch(e => {
// TODO: This check can be removed once all of these `resolve` entries are moved out of Angular and into the React app.
@@ -132,7 +133,8 @@ const routeDefinition = (action) => ({
users,
indexPatterns,
spaces,
- privileges,
+ kibanaPrivileges,
+ builtinESPrivileges,
features,
} = $route.current.locals;
@@ -153,7 +155,8 @@ const routeDefinition = (action) => ({
spacesEnabled={enableSpaceAwarePrivileges}
uiCapabilities={capabilities.get()}
features={features}
- privileges={privileges}
+ kibanaPrivileges={kibanaPrivileges}
+ builtinESPrivileges={builtinESPrivileges}
/>
, domNode);
diff --git a/x-pack/legacy/plugins/security/server/routes/api/v1/builtin_privileges.ts b/x-pack/legacy/plugins/security/server/routes/api/v1/builtin_privileges.ts
new file mode 100644
index 0000000000000..991b57b11a8f8
--- /dev/null
+++ b/x-pack/legacy/plugins/security/server/routes/api/v1/builtin_privileges.ts
@@ -0,0 +1,29 @@
+/*
+ * 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 { Legacy } from 'kibana';
+import { BuiltinESPrivileges } from '../../../../common/model';
+import { getClient } from '../../../../../../server/lib/get_client_shield';
+
+export function initGetBuiltinPrivilegesApi(server: Legacy.Server) {
+ server.route({
+ method: 'GET',
+ path: '/api/security/v1/esPrivileges/builtin',
+ async handler(req: Legacy.Request) {
+ const callWithRequest = getClient(server).callWithRequest;
+ const privileges = await callWithRequest(
+ req,
+ 'shield.getBuiltinPrivileges'
+ );
+
+ // Exclude the `none` privilege, as it doesn't make sense as an option within the Kibana UI
+ privileges.cluster = privileges.cluster.filter(privilege => privilege !== 'none');
+ privileges.index = privileges.index.filter(privilege => privilege !== 'none');
+
+ return privileges;
+ },
+ });
+}
diff --git a/x-pack/legacy/server/lib/esjs_shield_plugin.js b/x-pack/legacy/server/lib/esjs_shield_plugin.js
index 51b22abdbfbd6..bdfc00d0230ae 100644
--- a/x-pack/legacy/server/lib/esjs_shield_plugin.js
+++ b/x-pack/legacy/server/lib/esjs_shield_plugin.js
@@ -488,5 +488,14 @@
fmt: '/_security/user/_has_privileges'
}
});
+
+ shield.getBuiltinPrivileges = ca({
+ params: {},
+ urls: [
+ {
+ fmt: '/_security/privilege/_builtin'
+ }
+ ]
+ });
};
}));
diff --git a/x-pack/test/api_integration/apis/security/builtin_es_privileges.ts b/x-pack/test/api_integration/apis/security/builtin_es_privileges.ts
new file mode 100644
index 0000000000000..2b0c8c5bc5996
--- /dev/null
+++ b/x-pack/test/api_integration/apis/security/builtin_es_privileges.ts
@@ -0,0 +1,43 @@
+/*
+ * 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 expect from '@kbn/expect/expect.js';
+import { KibanaFunctionalTestDefaultProviders } from '../../../types/providers';
+
+// eslint-disable-next-line import/no-default-export
+export default function({ getService }: KibanaFunctionalTestDefaultProviders) {
+ const supertest = getService('supertest');
+
+ describe('Builtin ES Privileges', () => {
+ describe('GET /api/security/v1/esPrivileges/builtin', () => {
+ it('should return a list of available builtin privileges', async () => {
+ await supertest
+ .get('/api/security/v1/esPrivileges/builtin')
+ .set('kbn-xsrf', 'xxx')
+ .send()
+ .expect(200)
+ .then((response: Record) => {
+ const sampleOfExpectedClusterPrivileges = ['all', 'manage', 'monitor'];
+ const sampleOfExpectedIndexPrivileges = ['create', 'index', 'delete'];
+
+ const payload = response.body;
+ expect(Object.keys(payload).sort()).to.eql(['cluster', 'index']);
+
+ sampleOfExpectedClusterPrivileges.forEach(privilege =>
+ expect(payload.cluster).to.contain(privilege)
+ );
+
+ sampleOfExpectedIndexPrivileges.forEach(privilege =>
+ expect(payload.index).to.contain(privilege)
+ );
+
+ expect(payload.cluster).not.to.contain('none');
+ expect(payload.index).not.to.contain('none');
+ });
+ });
+ });
+ });
+}
diff --git a/x-pack/test/api_integration/apis/security/index.js b/x-pack/test/api_integration/apis/security/index.js
index c2c39cb22f562..b272af4a35460 100644
--- a/x-pack/test/api_integration/apis/security/index.js
+++ b/x-pack/test/api_integration/apis/security/index.js
@@ -9,6 +9,7 @@ export default function ({ loadTestFile }) {
this.tags('ciGroup6');
loadTestFile(require.resolve('./basic_login'));
+ loadTestFile(require.resolve('./builtin_es_privileges'));
loadTestFile(require.resolve('./index_fields'));
loadTestFile(require.resolve('./roles'));
loadTestFile(require.resolve('./privileges'));