Skip to content

Commit

Permalink
Support for sub-feature privileges (#60563)
Browse files Browse the repository at this point in the history
* initial server-side support for sub-feature privileges (#57507)

* initial server-side support for sub-feature privileges

* start addressing PR feedback

* renaming interfaces

* move privilege id collision check to security plugin

* additional testing

* change featurePrivilegeIterator import location

* fix link assertions following rebase from master

* Initial UI support for sub-feature privileges (#59198)

* Initial UI support for sub-feature privileges

* Address PR feedback

* display deleted spaces correctly in the privilege summary

* additional testing

* update snapshot

* Enables sub-feature privileges for gold+ licenses (#59750)

* enables sub-feature privileges for gold+ licenses

* Address PR feedback

* address platform review feedback
  • Loading branch information
legrego committed Mar 24, 2020
1 parent f371acf commit b82cc6e
Show file tree
Hide file tree
Showing 180 changed files with 12,447 additions and 7,069 deletions.
Expand Up @@ -890,7 +890,8 @@ export class DashboardAppController {
share.toggleShareContextMenu({
anchorElement,
allowEmbed: true,
allowShortUrl: !dashboardConfig.getHideWriteControls(),
allowShortUrl:
!dashboardConfig.getHideWriteControls() || dashboardCapabilities.createShortUrl,
shareableUrl: unhashUrl(window.location.href),
objectId: dash.id,
objectType: 'dashboard',
Expand Down
3 changes: 3 additions & 0 deletions x-pack/legacy/plugins/apm/index.ts
Expand Up @@ -96,13 +96,15 @@ export const apm: LegacyPluginInitializer = kibana => {
name: i18n.translate('xpack.apm.featureRegistry.apmFeatureName', {
defaultMessage: 'APM'
}),
order: 900,
icon: 'apmApp',
navLinkId: 'apm',
app: ['apm', 'kibana'],
catalogue: ['apm'],
// see x-pack/plugins/features/common/feature_kibana_privileges.ts
privileges: {
all: {
app: ['apm', 'kibana'],
api: ['apm', 'apm_write', 'actions-read', 'alerting-read'],
catalogue: ['apm'],
savedObject: {
Expand All @@ -121,6 +123,7 @@ export const apm: LegacyPluginInitializer = kibana => {
]
},
read: {
app: ['apm', 'kibana'],
api: ['apm', 'actions-read', 'alerting-read'],
catalogue: ['apm'],
savedObject: {
Expand Down
5 changes: 5 additions & 0 deletions x-pack/legacy/plugins/graph/index.ts
Expand Up @@ -37,20 +37,25 @@ export const graph: LegacyPluginInitializer = kibana => {
name: i18n.translate('xpack.graph.featureRegistry.graphFeatureName', {
defaultMessage: 'Graph',
}),
order: 1200,
icon: 'graphApp',
navLinkId: 'graph',
app: ['graph', 'kibana'],
catalogue: ['graph'],
validLicenses: ['platinum', 'enterprise', 'trial'],
privileges: {
all: {
app: ['graph', 'kibana'],
catalogue: ['graph'],
savedObject: {
all: ['graph-workspace'],
read: ['index-pattern'],
},
ui: ['save', 'delete'],
},
read: {
app: ['graph', 'kibana'],
catalogue: ['graph'],
savedObject: {
all: [],
read: ['index-pattern', 'graph-workspace'],
Expand Down
5 changes: 5 additions & 0 deletions x-pack/legacy/plugins/maps/server/plugin.js
Expand Up @@ -23,19 +23,24 @@ export class MapPlugin {
name: i18n.translate('xpack.maps.featureRegistry.mapsFeatureName', {
defaultMessage: 'Maps',
}),
order: 600,
icon: APP_ICON,
navLinkId: APP_ID,
app: [APP_ID, 'kibana'],
catalogue: [APP_ID],
privileges: {
all: {
app: [APP_ID, 'kibana'],
catalogue: [APP_ID],
savedObject: {
all: [MAP_SAVED_OBJECT_TYPE, 'query'],
read: ['index-pattern'],
},
ui: ['save', 'show', 'saveQuery'],
},
read: {
app: [APP_ID, 'kibana'],
catalogue: [APP_ID],
savedObject: {
all: [],
read: [MAP_SAVED_OBJECT_TYPE, 'index-pattern', 'query'],
Expand Down
5 changes: 5 additions & 0 deletions x-pack/legacy/plugins/siem/server/plugin.ts
Expand Up @@ -97,12 +97,15 @@ export class Plugin {
name: i18n.translate('xpack.siem.featureRegistry.linkSiemTitle', {
defaultMessage: 'SIEM',
}),
order: 1100,
icon: 'securityAnalyticsApp',
navLinkId: 'siem',
app: ['siem', 'kibana'],
catalogue: ['siem'],
privileges: {
all: {
app: ['siem', 'kibana'],
catalogue: ['siem'],
api: ['siem', 'actions-read', 'actions-all', 'alerting-read', 'alerting-all'],
savedObject: {
all: [
Expand All @@ -128,6 +131,8 @@ export class Plugin {
],
},
read: {
app: ['siem', 'kibana'],
catalogue: ['siem'],
api: ['siem', 'actions-read', 'actions-all', 'alerting-read', 'alerting-all'],
savedObject: {
all: ['alert', 'action', 'action_task_params'],
Expand Down
4 changes: 2 additions & 2 deletions x-pack/legacy/plugins/xpack_main/server/xpack_main.d.ts
Expand Up @@ -5,12 +5,12 @@
*/

import KbnServer from 'src/legacy/server/kbn_server';
import { Feature, FeatureWithAllOrReadPrivileges } from '../../../../plugins/features/server';
import { Feature, FeatureConfig } from '../../../../plugins/features/server';
import { XPackInfo, XPackInfoOptions } from './lib/xpack_info';
export { XPackFeature } from './lib/xpack_info';

export interface XPackMainPlugin {
info: XPackInfo;
getFeatures(): Feature[];
registerFeature(feature: FeatureWithAllOrReadPrivileges): void;
registerFeature(feature: FeatureConfig): void;
}
5 changes: 5 additions & 0 deletions x-pack/plugins/canvas/server/plugin.ts
Expand Up @@ -32,19 +32,24 @@ export class CanvasPlugin implements Plugin {
plugins.features.registerFeature({
id: 'canvas',
name: 'Canvas',
order: 400,
icon: 'canvasApp',
navLinkId: 'canvas',
app: ['canvas', 'kibana'],
catalogue: ['canvas'],
privileges: {
all: {
app: ['canvas', 'kibana'],
catalogue: ['canvas'],
savedObject: {
all: ['canvas-workpad', 'canvas-element'],
read: ['index-pattern'],
},
ui: ['save', 'show'],
},
read: {
app: ['canvas', 'kibana'],
catalogue: ['canvas'],
savedObject: {
all: [],
read: ['index-pattern', 'canvas-workpad', 'canvas-element'],
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/endpoint/server/plugin.ts
Expand Up @@ -43,6 +43,7 @@ export class EndpointPlugin
app: ['endpoint', 'kibana'],
privileges: {
all: {
app: ['endpoint', 'kibana'],
api: ['resolver'],
savedObject: {
all: [],
Expand All @@ -51,6 +52,7 @@ export class EndpointPlugin
ui: ['save'],
},
read: {
app: ['endpoint', 'kibana'],
api: [],
savedObject: {
all: [],
Expand Down
88 changes: 79 additions & 9 deletions x-pack/plugins/features/common/feature.ts
Expand Up @@ -4,16 +4,16 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { FeatureKibanaPrivileges, FeatureKibanaPrivilegesSet } from './feature_kibana_privileges';
import { RecursiveReadonly } from '@kbn/utility-types';
import { FeatureKibanaPrivileges } from './feature_kibana_privileges';
import { SubFeatureConfig, SubFeature } from './sub_feature';

/**
* Interface for registering a feature.
* Feature registration allows plugins to hide their applications with spaces,
* and secure access when configured for security.
*/
export interface Feature<
TPrivileges extends Partial<FeatureKibanaPrivilegesSet> = FeatureKibanaPrivilegesSet
> {
export interface FeatureConfig {
/**
* Unique identifier for this feature.
* This identifier is also used when generating UI Capabilities.
Expand All @@ -28,6 +28,11 @@ export interface Feature<
*/
name: string;

/**
* An ordinal used to sort features relative to one another for display.
*/
order?: number;

/**
* Whether or not this feature should be excluded from the base privileges.
* This is primarily helpful when migrating applications with a "legacy" privileges model
Expand Down Expand Up @@ -98,7 +103,15 @@ export interface Feature<
* ```
* @see FeatureKibanaPrivileges
*/
privileges: TPrivileges;
privileges: {
all: FeatureKibanaPrivileges;
read: FeatureKibanaPrivileges;
} | null;

/**
* Optional sub-feature privilege definitions. This can only be specified if `privileges` are are also defined.
*/
subFeatures?: SubFeatureConfig[];

/**
* Optional message to display on the Role Management screen when configuring permissions for this feature.
Expand All @@ -114,7 +127,64 @@ export interface Feature<
};
}

export type FeatureWithAllOrReadPrivileges = Feature<{
all?: FeatureKibanaPrivileges;
read?: FeatureKibanaPrivileges;
}>;
export class Feature {
public readonly subFeatures: SubFeature[];

constructor(protected readonly config: RecursiveReadonly<FeatureConfig>) {
this.subFeatures = (config.subFeatures ?? []).map(
subFeatureConfig => new SubFeature(subFeatureConfig)
);
}

public get id() {
return this.config.id;
}

public get name() {
return this.config.name;
}

public get order() {
return this.config.order;
}

public get navLinkId() {
return this.config.navLinkId;
}

public get app() {
return this.config.app;
}

public get catalogue() {
return this.config.catalogue;
}

public get management() {
return this.config.management;
}

public get icon() {
return this.config.icon;
}

public get validLicenses() {
return this.config.validLicenses;
}

public get privileges() {
return this.config.privileges;
}

public get excludeFromBasePrivileges() {
return this.config.excludeFromBasePrivileges ?? false;
}

public get reserved() {
return this.config.reserved;
}

public toRaw() {
return { ...this.config } as FeatureConfig;
}
}
2 changes: 0 additions & 2 deletions x-pack/plugins/features/common/feature_kibana_privileges.ts
Expand Up @@ -123,5 +123,3 @@ export interface FeatureKibanaPrivileges {
*/
ui: string[];
}

export type FeatureKibanaPrivilegesSet = Record<string, FeatureKibanaPrivileges>;
9 changes: 8 additions & 1 deletion x-pack/plugins/features/common/index.ts
Expand Up @@ -5,4 +5,11 @@
*/

export { FeatureKibanaPrivileges } from './feature_kibana_privileges';
export * from './feature';
export { Feature, FeatureConfig } from './feature';
export {
SubFeature,
SubFeatureConfig,
SubFeaturePrivilegeConfig,
SubFeaturePrivilegeGroupConfig,
SubFeaturePrivilegeGroupType,
} from './sub_feature';
87 changes: 87 additions & 0 deletions x-pack/plugins/features/common/sub_feature.ts
@@ -0,0 +1,87 @@
/*
* 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 { RecursiveReadonly } from '@kbn/utility-types';
import { FeatureKibanaPrivileges } from './feature_kibana_privileges';

/**
* Configuration for a sub-feature.
*/
export interface SubFeatureConfig {
/** Display name for this sub-feature */
name: string;

/** Collection of privilege groups */
privilegeGroups: SubFeaturePrivilegeGroupConfig[];
}

/**
* The type of privilege group.
* - `mutually_exclusive`::
* Users will be able to select at most one privilege within this group.
* Privileges must be specified in descending order of permissiveness (e.g. `All`, `Read`, not `Read`, `All)
* - `independent`::
* Users will be able to select any combination of privileges within this group.
*/
export type SubFeaturePrivilegeGroupType = 'mutually_exclusive' | 'independent';

/**
* Configuration for a sub-feature privilege group.
*/
export interface SubFeaturePrivilegeGroupConfig {
/**
* The type of privilege group.
* - `mutually_exclusive`::
* Users will be able to select at most one privilege within this group.
* Privileges must be specified in descending order of permissiveness (e.g. `All`, `Read`, not `Read`, `All)
* - `independent`::
* Users will be able to select any combination of privileges within this group.
*/
groupType: SubFeaturePrivilegeGroupType;

/**
* The privileges which belong to this group.
*/
privileges: SubFeaturePrivilegeConfig[];
}

/**
* Configuration for a sub-feature privilege.
*/
export interface SubFeaturePrivilegeConfig
extends Omit<FeatureKibanaPrivileges, 'excludeFromBasePrivileges'> {
/**
* Identifier for this privilege. Must be unique across all other privileges within a feature.
*/
id: string;

/**
* The display name for this privilege.
*/
name: string;

/**
* Denotes which Primary Feature Privilege this sub-feature privilege should be included in.
* `read` is also included in `all` automatically.
*/
includeIn: 'all' | 'read' | 'none';
}

export class SubFeature {
constructor(protected readonly config: RecursiveReadonly<SubFeatureConfig>) {}

public get name() {
return this.config.name;
}

public get privilegeGroups() {
return this.config.privilegeGroups;
}

public toRaw() {
return { ...this.config };
}
}
2 changes: 1 addition & 1 deletion x-pack/plugins/features/kibana.json
Expand Up @@ -4,5 +4,5 @@
"kibanaVersion": "kibana",
"optionalPlugins": ["timelion"],
"server": true,
"ui": false
"ui": true
}

0 comments on commit b82cc6e

Please sign in to comment.