[8.x] Harden API Actions Definition standards (#193140) (#199470)

# Backport

This will backport the following commits from `main` to `8.x`:
- [Harden API Actions Definition standards
(#193140)](https://github.com/elastic/kibana/pull/193140)

<!--- Backport version: 8.9.8 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT
[{"author":{"name":"Sid","email":"siddharthmantri1@gmail.com"},"sourceCommit":{"committedDate":"2024-10-15T14:03:07Z","message":"Harden
API Actions Definition standards (#193140)\n\nCloses
https://github.com/elastic/kibana/issues/191716\r\n\r\n##
Summary\r\n\r\nThis PR introduces a new signature for the API Actions
`get` function\r\nthat validates standard API operations as part of the
name of the API\r\naction.\r\n\r\n\r\n### Changes\r\n- Added a new Enum
for a standard set of operations we expect all API\r\nactions to move
to\r\n- Old function signature based on a single subject marked as
deprecated.\r\n\r\n### Release Notes\r\nEnforce standard on API Actions
definitions by separating operations
and\r\nsubjects.\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>\r\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>\r\nCo-authored-by: Elena
Shostak
<elena.shostak@elastic.co>","sha":"343a33a637dfc2b2f68a3e35cc69bcc4f0566ced","branchLabelMapping":{"^v9.0.0$":"main","^v8.16.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:enhancement","Team:Security","Feature:Security/Authorization","Feature:Hardening","v9.0.0","backport:prev-minor"],"number":193140,"url":"https://github.com/elastic/kibana/pull/193140","mergeCommit":{"message":"Harden
API Actions Definition standards (#193140)\n\nCloses
https://github.com/elastic/kibana/issues/191716\r\n\r\n##
Summary\r\n\r\nThis PR introduces a new signature for the API Actions
`get` function\r\nthat validates standard API operations as part of the
name of the API\r\naction.\r\n\r\n\r\n### Changes\r\n- Added a new Enum
for a standard set of operations we expect all API\r\nactions to move
to\r\n- Old function signature based on a single subject marked as
deprecated.\r\n\r\n### Release Notes\r\nEnforce standard on API Actions
definitions by separating operations
and\r\nsubjects.\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>\r\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>\r\nCo-authored-by: Elena
Shostak
<elena.shostak@elastic.co>","sha":"343a33a637dfc2b2f68a3e35cc69bcc4f0566ced"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","labelRegex":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/193140","number":193140,"mergeCommit":{"message":"Harden
API Actions Definition standards (#193140)\n\nCloses
https://github.com/elastic/kibana/issues/191716\r\n\r\n##
Summary\r\n\r\nThis PR introduces a new signature for the API Actions
`get` function\r\nthat validates standard API operations as part of the
name of the API\r\naction.\r\n\r\n\r\n### Changes\r\n- Added a new Enum
for a standard set of operations we expect all API\r\nactions to move
to\r\n- Old function signature based on a single subject marked as
deprecated.\r\n\r\n### Release Notes\r\nEnforce standard on API Actions
definitions by separating operations
and\r\nsubjects.\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>\r\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>\r\nCo-authored-by: Elena
Shostak
<elena.shostak@elastic.co>","sha":"343a33a637dfc2b2f68a3e35cc69bcc4f0566ced"}}]}]
BACKPORT-->
This commit is contained in:
Sid 2024-11-08 15:36:16 +01:00 committed by GitHub
parent 8a81c046f7
commit f132d6bb49
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 164 additions and 92 deletions

View file

@ -14,6 +14,7 @@ import type {
StatsGetterConfig,
} from '@kbn/telemetry-collection-manager-plugin/server';
import type { SecurityPluginStart } from '@kbn/security-plugin/server';
import { ApiOperation } from '@kbn/security-plugin-types-server';
import { RequestHandler } from '@kbn/core-http-server';
import { FetchSnapshotTelemetry } from '../../common/routes';
import { UsageStatsBody, v2 } from '../../common/types';
@ -50,7 +51,7 @@ export function registerTelemetryUsageStatsRoutes(
// security API directly to check privileges for this action. Note that the 'decryptedTelemetry' API privilege string is only
// granted to users that have "Global All" or "Global Read" privileges in Kibana.
const { checkPrivilegesWithRequest, actions } = security.authz;
const privileges = { kibana: actions.api.get('decryptedTelemetry') };
const privileges = { kibana: actions.api.get(ApiOperation.Read, 'decryptedTelemetry') };
const { hasAllRequested } = await checkPrivilegesWithRequest(req).globally(privileges);
if (!hasAllRequested) {
return res.forbidden();

View file

@ -36,6 +36,7 @@
"@kbn/analytics-collection-utils",
"@kbn/react-kibana-mount",
"@kbn/core-node-server",
"@kbn/security-plugin-types-server",
],
"exclude": [
"target/**/*",

View file

@ -8,6 +8,7 @@
import { isString } from 'lodash';
import type { ApiActions as ApiActionsType } from '@kbn/security-plugin-types-server';
import { ApiOperation } from '@kbn/security-plugin-types-server';
export class ApiActions implements ApiActionsType {
private readonly prefix: string;
@ -16,11 +17,33 @@ export class ApiActions implements ApiActionsType {
this.prefix = `api:`;
}
public get(operation: string) {
if (!operation || !isString(operation)) {
throw new Error('operation is required and must be a string');
private isValidOperation(operation: string): operation is ApiOperation {
return Object.values(ApiOperation).includes(operation as ApiOperation);
}
public actionFromRouteTag(routeTag: string) {
const [operation, subject] = routeTag.split('_');
if (!this.isValidOperation(operation)) {
throw new Error('operation is required and must be a valid ApiOperation');
}
return this.get(operation, subject);
}
public get(operation: string | ApiOperation, subject?: string) {
if (arguments.length === 1) {
if (!isString(operation) || !operation) {
throw new Error('operation is required and must be a string');
}
return `${this.prefix}${operation}`;
}
return `${this.prefix}${operation}`;
if (!isString(subject) || !subject) {
throw new Error('subject is required and must be a string');
}
if (!this.isValidOperation(operation)) {
throw new Error('operation is required and must be a valid ApiOperation');
}
return `${this.prefix}${operation}_${subject}`;
}
}

View file

@ -7,6 +7,7 @@
import { KibanaFeature } from '@kbn/features-plugin/server';
import { featuresPluginMock } from '@kbn/features-plugin/server/mocks';
import { ApiOperation } from '@kbn/security-plugin-types-server';
import { getReplacedByForPrivilege, privilegesFactory } from './privileges';
import { licenseMock } from '../__fixtures__/licensing.mock';
@ -793,10 +794,12 @@ describe('features', () => {
const actual = privileges.get();
expect(actual).toHaveProperty(`${group}.all`, [
actions.login,
...(expectDecryptedTelemetry ? [actions.api.get('decryptedTelemetry')] : []),
...(expectGetFeatures ? [actions.api.get('features')] : []),
...(expectGetFeatures ? [actions.api.get('taskManager')] : []),
...(expectGetFeatures ? [actions.api.get('manageSpaces')] : []),
...(expectDecryptedTelemetry
? [actions.api.get(ApiOperation.Read, 'decryptedTelemetry')]
: []),
...(expectGetFeatures ? [actions.api.get(ApiOperation.Read, 'features')] : []),
...(expectGetFeatures ? [actions.api.get(ApiOperation.Manage, 'taskManager')] : []),
...(expectGetFeatures ? [actions.api.get(ApiOperation.Manage, 'spaces')] : []),
...(expectManageSpaces
? [
actions.space.manage,
@ -965,10 +968,12 @@ describe('features', () => {
const expectedActions = [
actions.login,
...(expectDecryptedTelemetry ? [actions.api.get('decryptedTelemetry')] : []),
...(expectGetFeatures ? [actions.api.get('features')] : []),
...(expectGetFeatures ? [actions.api.get('taskManager')] : []),
...(expectGetFeatures ? [actions.api.get('manageSpaces')] : []),
...(expectDecryptedTelemetry
? [actions.api.get(ApiOperation.Read, 'decryptedTelemetry')]
: []),
...(expectGetFeatures ? [actions.api.get(ApiOperation.Read, 'features')] : []),
...(expectGetFeatures ? [actions.api.get(ApiOperation.Manage, 'taskManager')] : []),
...(expectGetFeatures ? [actions.api.get(ApiOperation.Manage, 'spaces')] : []),
...(expectManageSpaces
? [
actions.space.manage,
@ -1124,7 +1129,9 @@ describe('features', () => {
const actual = privileges.get();
expect(actual).toHaveProperty(`${group}.read`, [
actions.login,
...(expectDecryptedTelemetry ? [actions.api.get('decryptedTelemetry')] : []),
...(expectDecryptedTelemetry
? [actions.api.get(ApiOperation.Read, 'decryptedTelemetry')]
: []),
...(expectGlobalSettings ? [actions.ui.get('globalSettings', 'show')] : []),
actions.ui.get('catalogue', 'read-catalogue-1'),
actions.ui.get('catalogue', 'read-catalogue-2'),
@ -1243,7 +1250,9 @@ describe('features', () => {
const expectedActions = [
actions.login,
...(expectDecryptedTelemetry ? [actions.api.get('decryptedTelemetry')] : []),
...(expectDecryptedTelemetry
? [actions.api.get(ApiOperation.Read, 'decryptedTelemetry')]
: []),
...(expectGlobalSettings ? [actions.ui.get('globalSettings', 'show')] : []),
actions.ui.get('catalogue', 'read-catalogue-2'),
actions.ui.get('management', 'read-management', 'read-management-2'),
@ -1341,10 +1350,12 @@ describe('features', () => {
const actual = privileges.get();
expect(actual).toHaveProperty(`${group}.all`, [
actions.login,
...(expectDecryptedTelemetry ? [actions.api.get('decryptedTelemetry')] : []),
...(expectGetFeatures ? [actions.api.get('features')] : []),
...(expectGetFeatures ? [actions.api.get('taskManager')] : []),
...(expectGetFeatures ? [actions.api.get('manageSpaces')] : []),
...(expectDecryptedTelemetry
? [actions.api.get(ApiOperation.Read, 'decryptedTelemetry')]
: []),
...(expectGetFeatures ? [actions.api.get(ApiOperation.Read, 'features')] : []),
...(expectGetFeatures ? [actions.api.get(ApiOperation.Manage, 'taskManager')] : []),
...(expectGetFeatures ? [actions.api.get(ApiOperation.Manage, 'spaces')] : []),
...(expectManageSpaces
? [
actions.space.manage,
@ -1359,7 +1370,9 @@ describe('features', () => {
]);
expect(actual).toHaveProperty(`${group}.read`, [
actions.login,
...(expectDecryptedTelemetry ? [actions.api.get('decryptedTelemetry')] : []),
...(expectDecryptedTelemetry
? [actions.api.get(ApiOperation.Read, 'decryptedTelemetry')]
: []),
...(expectGlobalSettings ? [actions.ui.get('globalSettings', 'show')] : []),
]);
});
@ -1410,10 +1423,12 @@ describe('features', () => {
const actual = privileges.get();
expect(actual).toHaveProperty(`${group}.all`, [
actions.login,
...(expectDecryptedTelemetry ? [actions.api.get('decryptedTelemetry')] : []),
...(expectGetFeatures ? [actions.api.get('features')] : []),
...(expectGetFeatures ? [actions.api.get('taskManager')] : []),
...(expectGetFeatures ? [actions.api.get('manageSpaces')] : []),
...(expectDecryptedTelemetry
? [actions.api.get(ApiOperation.Read, 'decryptedTelemetry')]
: []),
...(expectGetFeatures ? [actions.api.get(ApiOperation.Read, 'features')] : []),
...(expectGetFeatures ? [actions.api.get(ApiOperation.Manage, 'taskManager')] : []),
...(expectGetFeatures ? [actions.api.get(ApiOperation.Manage, 'spaces')] : []),
...(expectManageSpaces
? [
actions.space.manage,
@ -1428,7 +1443,9 @@ describe('features', () => {
]);
expect(actual).toHaveProperty(`${group}.read`, [
actions.login,
...(expectDecryptedTelemetry ? [actions.api.get('decryptedTelemetry')] : []),
...(expectDecryptedTelemetry
? [actions.api.get(ApiOperation.Read, 'decryptedTelemetry')]
: []),
...(expectGlobalSettings ? [actions.ui.get('globalSettings', 'show')] : []),
]);
});
@ -1508,10 +1525,12 @@ describe('features', () => {
const actual = privileges.get();
expect(actual).toHaveProperty(`${group}.all`, [
actions.login,
...(expectDecryptedTelemetry ? [actions.api.get('decryptedTelemetry')] : []),
...(expectGetFeatures ? [actions.api.get('features')] : []),
...(expectGetFeatures ? [actions.api.get('taskManager')] : []),
...(expectGetFeatures ? [actions.api.get('manageSpaces')] : []),
...(expectDecryptedTelemetry
? [actions.api.get(ApiOperation.Read, 'decryptedTelemetry')]
: []),
...(expectGetFeatures ? [actions.api.get(ApiOperation.Read, 'features')] : []),
...(expectGetFeatures ? [actions.api.get(ApiOperation.Manage, 'taskManager')] : []),
...(expectGetFeatures ? [actions.api.get(ApiOperation.Manage, 'spaces')] : []),
...(expectManageSpaces
? [
actions.space.manage,
@ -1526,7 +1545,9 @@ describe('features', () => {
]);
expect(actual).toHaveProperty(`${group}.read`, [
actions.login,
...(expectDecryptedTelemetry ? [actions.api.get('decryptedTelemetry')] : []),
...(expectDecryptedTelemetry
? [actions.api.get(ApiOperation.Read, 'decryptedTelemetry')]
: []),
...(expectGlobalSettings ? [actions.ui.get('globalSettings', 'show')] : []),
]);
});
@ -1578,10 +1599,12 @@ describe('features', () => {
const actual = privileges.get();
expect(actual).toHaveProperty(`${group}.all`, [
actions.login,
...(expectDecryptedTelemetry ? [actions.api.get('decryptedTelemetry')] : []),
...(expectGetFeatures ? [actions.api.get('features')] : []),
...(expectGetFeatures ? [actions.api.get('taskManager')] : []),
...(expectGetFeatures ? [actions.api.get('manageSpaces')] : []),
...(expectDecryptedTelemetry
? [actions.api.get(ApiOperation.Read, 'decryptedTelemetry')]
: []),
...(expectGetFeatures ? [actions.api.get(ApiOperation.Read, 'features')] : []),
...(expectGetFeatures ? [actions.api.get(ApiOperation.Manage, 'taskManager')] : []),
...(expectGetFeatures ? [actions.api.get(ApiOperation.Manage, 'spaces')] : []),
...(expectManageSpaces
? [
actions.space.manage,
@ -1596,7 +1619,9 @@ describe('features', () => {
]);
expect(actual).toHaveProperty(`${group}.read`, [
actions.login,
...(expectDecryptedTelemetry ? [actions.api.get('decryptedTelemetry')] : []),
...(expectDecryptedTelemetry
? [actions.api.get(ApiOperation.Read, 'decryptedTelemetry')]
: []),
...(expectGlobalSettings ? [actions.ui.get('globalSettings', 'show')] : []),
]);
});
@ -1677,10 +1702,12 @@ describe('features', () => {
const actual = privileges.get();
expect(actual).toHaveProperty(`${group}.all`, [
actions.login,
...(expectDecryptedTelemetry ? [actions.api.get('decryptedTelemetry')] : []),
...(expectGetFeatures ? [actions.api.get('features')] : []),
...(expectGetFeatures ? [actions.api.get('taskManager')] : []),
...(expectGetFeatures ? [actions.api.get('manageSpaces')] : []),
...(expectDecryptedTelemetry
? [actions.api.get(ApiOperation.Read, 'decryptedTelemetry')]
: []),
...(expectGetFeatures ? [actions.api.get(ApiOperation.Read, 'features')] : []),
...(expectGetFeatures ? [actions.api.get(ApiOperation.Manage, 'taskManager')] : []),
...(expectGetFeatures ? [actions.api.get(ApiOperation.Manage, 'spaces')] : []),
...(expectManageSpaces
? [
actions.space.manage,
@ -1695,7 +1722,9 @@ describe('features', () => {
]);
expect(actual).toHaveProperty(`${group}.read`, [
actions.login,
...(expectDecryptedTelemetry ? [actions.api.get('decryptedTelemetry')] : []),
...(expectDecryptedTelemetry
? [actions.api.get(ApiOperation.Read, 'decryptedTelemetry')]
: []),
...(expectGlobalSettings ? [actions.ui.get('globalSettings', 'show')] : []),
]);
});
@ -1945,10 +1974,10 @@ describe('subFeatures', () => {
expect(actual).toHaveProperty('global.all', [
actions.login,
actions.api.get('decryptedTelemetry'),
actions.api.get('features'),
actions.api.get('taskManager'),
actions.api.get('manageSpaces'),
actions.api.get(ApiOperation.Read, 'decryptedTelemetry'),
actions.api.get(ApiOperation.Read, 'features'),
actions.api.get(ApiOperation.Manage, 'taskManager'),
actions.api.get(ApiOperation.Manage, 'spaces'),
actions.space.manage,
actions.ui.get('spaces', 'manage'),
actions.ui.get('management', 'kibana', 'spaces'),
@ -1960,7 +1989,7 @@ describe('subFeatures', () => {
]);
expect(actual).toHaveProperty('global.read', [
actions.login,
actions.api.get('decryptedTelemetry'),
actions.api.get(ApiOperation.Read, 'decryptedTelemetry'),
actions.ui.get('globalSettings', 'show'),
actions.ui.get('foo', 'foo'),
]);
@ -2104,10 +2133,10 @@ describe('subFeatures', () => {
expect(actual).toHaveProperty('global.all', [
actions.login,
actions.api.get('decryptedTelemetry'),
actions.api.get('features'),
actions.api.get('taskManager'),
actions.api.get('manageSpaces'),
actions.api.get(ApiOperation.Read, 'decryptedTelemetry'),
actions.api.get(ApiOperation.Read, 'features'),
actions.api.get(ApiOperation.Manage, 'taskManager'),
actions.api.get(ApiOperation.Manage, 'spaces'),
actions.space.manage,
actions.ui.get('spaces', 'manage'),
actions.ui.get('management', 'kibana', 'spaces'),
@ -2137,7 +2166,7 @@ describe('subFeatures', () => {
]);
expect(actual).toHaveProperty('global.read', [
actions.login,
actions.api.get('decryptedTelemetry'),
actions.api.get(ApiOperation.Read, 'decryptedTelemetry'),
actions.ui.get('globalSettings', 'show'),
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
actions.savedObject.get('all-sub-feature-type', 'get'),
@ -2340,10 +2369,10 @@ describe('subFeatures', () => {
expect(actual).toHaveProperty('global.all', [
actions.login,
actions.api.get('decryptedTelemetry'),
actions.api.get('features'),
actions.api.get('taskManager'),
actions.api.get('manageSpaces'),
actions.api.get(ApiOperation.Read, 'decryptedTelemetry'),
actions.api.get(ApiOperation.Read, 'features'),
actions.api.get(ApiOperation.Manage, 'taskManager'),
actions.api.get(ApiOperation.Manage, 'spaces'),
actions.space.manage,
actions.ui.get('spaces', 'manage'),
actions.ui.get('management', 'kibana', 'spaces'),
@ -2354,7 +2383,7 @@ describe('subFeatures', () => {
]);
expect(actual).toHaveProperty('global.read', [
actions.login,
actions.api.get('decryptedTelemetry'),
actions.api.get(ApiOperation.Read, 'decryptedTelemetry'),
actions.ui.get('globalSettings', 'show'),
]);
@ -2479,10 +2508,10 @@ describe('subFeatures', () => {
expect(actual).toHaveProperty('global.all', [
actions.login,
actions.api.get('decryptedTelemetry'),
actions.api.get('features'),
actions.api.get('taskManager'),
actions.api.get('manageSpaces'),
actions.api.get(ApiOperation.Read, 'decryptedTelemetry'),
actions.api.get(ApiOperation.Read, 'features'),
actions.api.get(ApiOperation.Manage, 'taskManager'),
actions.api.get(ApiOperation.Manage, 'spaces'),
actions.space.manage,
actions.ui.get('spaces', 'manage'),
actions.ui.get('management', 'kibana', 'spaces'),
@ -2512,7 +2541,7 @@ describe('subFeatures', () => {
]);
expect(actual).toHaveProperty('global.read', [
actions.login,
actions.api.get('decryptedTelemetry'),
actions.api.get(ApiOperation.Read, 'decryptedTelemetry'),
actions.ui.get('globalSettings', 'show'),
actions.ui.get('foo', 'foo'),
]);
@ -2658,10 +2687,10 @@ describe('subFeatures', () => {
expect(actual).toHaveProperty('global.all', [
actions.login,
actions.api.get('decryptedTelemetry'),
actions.api.get('features'),
actions.api.get('taskManager'),
actions.api.get('manageSpaces'),
actions.api.get(ApiOperation.Read, 'decryptedTelemetry'),
actions.api.get(ApiOperation.Read, 'features'),
actions.api.get(ApiOperation.Manage, 'taskManager'),
actions.api.get(ApiOperation.Manage, 'spaces'),
actions.space.manage,
actions.ui.get('spaces', 'manage'),
actions.ui.get('management', 'kibana', 'spaces'),
@ -2672,7 +2701,7 @@ describe('subFeatures', () => {
]);
expect(actual).toHaveProperty('global.read', [
actions.login,
actions.api.get('decryptedTelemetry'),
actions.api.get(ApiOperation.Read, 'decryptedTelemetry'),
actions.ui.get('globalSettings', 'show'),
]);
@ -2795,10 +2824,10 @@ describe('subFeatures', () => {
expect(actual).toHaveProperty('global.all', [
actions.login,
actions.api.get('decryptedTelemetry'),
actions.api.get('features'),
actions.api.get('taskManager'),
actions.api.get('manageSpaces'),
actions.api.get(ApiOperation.Read, 'decryptedTelemetry'),
actions.api.get(ApiOperation.Read, 'features'),
actions.api.get(ApiOperation.Manage, 'taskManager'),
actions.api.get(ApiOperation.Manage, 'spaces'),
actions.space.manage,
actions.ui.get('spaces', 'manage'),
actions.ui.get('management', 'kibana', 'spaces'),
@ -2828,7 +2857,7 @@ describe('subFeatures', () => {
]);
expect(actual).toHaveProperty('global.read', [
actions.login,
actions.api.get('decryptedTelemetry'),
actions.api.get(ApiOperation.Read, 'decryptedTelemetry'),
actions.ui.get('globalSettings', 'show'),
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
actions.savedObject.get('all-sub-feature-type', 'get'),
@ -3010,10 +3039,10 @@ describe('subFeatures', () => {
expect(actual).toHaveProperty('global.all', [
actions.login,
actions.api.get('decryptedTelemetry'),
actions.api.get('features'),
actions.api.get('taskManager'),
actions.api.get('manageSpaces'),
actions.api.get(ApiOperation.Read, 'decryptedTelemetry'),
actions.api.get(ApiOperation.Read, 'features'),
actions.api.get(ApiOperation.Manage, 'taskManager'),
actions.api.get(ApiOperation.Manage, 'spaces'),
actions.space.manage,
actions.ui.get('spaces', 'manage'),
actions.ui.get('management', 'kibana', 'spaces'),
@ -3043,7 +3072,7 @@ describe('subFeatures', () => {
]);
expect(actual).toHaveProperty('global.read', [
actions.login,
actions.api.get('decryptedTelemetry'),
actions.api.get(ApiOperation.Read, 'decryptedTelemetry'),
actions.ui.get('globalSettings', 'show'),
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
actions.savedObject.get('all-sub-feature-type', 'get'),
@ -3244,10 +3273,10 @@ describe('subFeatures', () => {
expect(actual).toHaveProperty('global.all', [
actions.login,
actions.api.get('decryptedTelemetry'),
actions.api.get('features'),
actions.api.get('taskManager'),
actions.api.get('manageSpaces'),
actions.api.get(ApiOperation.Read, 'decryptedTelemetry'),
actions.api.get(ApiOperation.Read, 'features'),
actions.api.get(ApiOperation.Manage, 'taskManager'),
actions.api.get(ApiOperation.Manage, 'spaces'),
actions.space.manage,
actions.ui.get('spaces', 'manage'),
actions.ui.get('management', 'kibana', 'spaces'),
@ -3277,7 +3306,7 @@ describe('subFeatures', () => {
]);
expect(actual).toHaveProperty('global.read', [
actions.login,
actions.api.get('decryptedTelemetry'),
actions.api.get(ApiOperation.Read, 'decryptedTelemetry'),
actions.ui.get('globalSettings', 'show'),
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
actions.savedObject.get('all-sub-feature-type', 'get'),
@ -3514,10 +3543,10 @@ describe('subFeatures', () => {
expect(actual).toHaveProperty('global.all', [
actions.login,
actions.api.get('decryptedTelemetry'),
actions.api.get('features'),
actions.api.get('taskManager'),
actions.api.get('manageSpaces'),
actions.api.get(ApiOperation.Read, 'decryptedTelemetry'),
actions.api.get(ApiOperation.Read, 'features'),
actions.api.get(ApiOperation.Manage, 'taskManager'),
actions.api.get(ApiOperation.Manage, 'spaces'),
actions.space.manage,
actions.ui.get('spaces', 'manage'),
actions.ui.get('management', 'kibana', 'spaces'),
@ -3565,7 +3594,7 @@ describe('subFeatures', () => {
]);
expect(actual).toHaveProperty('global.read', [
actions.login,
actions.api.get('decryptedTelemetry'),
actions.api.get(ApiOperation.Read, 'decryptedTelemetry'),
actions.ui.get('globalSettings', 'show'),
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
actions.savedObject.get('all-sub-feature-type', 'get'),

View file

@ -17,6 +17,7 @@ import {
isMinimalPrivilegeId,
} from '@kbn/security-authorization-core-common';
import type { RawKibanaPrivileges, SecurityLicense } from '@kbn/security-plugin-types-common';
import { ApiOperation } from '@kbn/security-plugin-types-server';
import { featurePrivilegeBuilderFactory } from './feature_privilege_builder';
import type { Actions } from '../actions';
@ -210,10 +211,10 @@ export function privilegesFactory(
global: {
all: [
actions.login,
actions.api.get('decryptedTelemetry'),
actions.api.get('features'),
actions.api.get('taskManager'),
actions.api.get('manageSpaces'),
actions.api.get(ApiOperation.Read, 'decryptedTelemetry'),
actions.api.get(ApiOperation.Read, 'features'),
actions.api.get(ApiOperation.Manage, 'taskManager'),
actions.api.get(ApiOperation.Manage, 'spaces'),
actions.space.manage,
actions.ui.get('spaces', 'manage'),
actions.ui.get('management', 'kibana', 'spaces'),
@ -225,7 +226,7 @@ export function privilegesFactory(
],
read: [
actions.login,
actions.api.get('decryptedTelemetry'),
actions.api.get(ApiOperation.Read, 'decryptedTelemetry'),
actions.ui.get('globalSettings', 'show'),
...readActions,
],

View file

@ -88,3 +88,4 @@ export {
getRestApiKeyWithKibanaPrivilegesSchema,
} from './src/authentication';
export { getKibanaRoleSchema, elasticsearchRoleSchema, GLOBAL_RESOURCE } from './src/authorization';
export { ApiOperation } from './src/authorization';

View file

@ -6,5 +6,19 @@
*/
export interface ApiActions {
get(operation: string): string;
get(operation: ApiOperation, subject: string): string;
/**
* @deprecated use `get(operation: ApiOperation, subject: string)` instead
*/
get(subject: string): string;
actionFromRouteTag(routeTag: string): string;
}
export enum ApiOperation {
Read = 'read',
Create = 'create',
Update = 'update',
Delete = 'delete',
Manage = 'manage',
}

View file

@ -8,6 +8,7 @@
export type { Actions } from './actions';
export type { AlertingActions } from './alerting';
export type { ApiActions } from './api';
export { ApiOperation } from './api';
export type { AppActions } from './app';
export type { CasesActions } from './cases';
export type { SavedObjectActions } from './saved_object';

View file

@ -15,6 +15,7 @@ export type {
SpaceActions,
UIActions,
} from './actions';
export { ApiOperation } from './actions';
export type { AuthorizationServiceSetup } from './authorization_service';
export type {
CheckPrivilegesOptions,

View file

@ -22,7 +22,7 @@ export function defineRoutes({ router, featureRegistry }: RouteDefinitionParams)
{
path: '/api/features',
options: {
tags: ['access:features'],
tags: ['access:read_features'],
access: 'public',
summary: `Get features`,
},