269 lines
8.9 KiB
Plaintext
269 lines
8.9 KiB
Plaintext
[[development-plugin-feature-registration]]
|
|
== Plugin feature registration
|
|
|
|
If your plugin will be used with {kib}'s default distribution, then you have the ability to register the features that your plugin provides. Features are typically apps in {kib}; once registered, you can toggle them via Spaces, and secure them via Roles when security is enabled.
|
|
|
|
=== UI Capabilities
|
|
|
|
Registering features also gives your plugin access to “UI Capabilities”. These capabilities are boolean flags that you can use to conditionally render your interface, based on the current user's permissions. For example, you can hide or disable a Save button if the current user is not authorized.
|
|
|
|
=== Registering a feature
|
|
|
|
Feature registration is controlled via the built-in `features` plugin. To register a feature, call `features`'s `registerKibanaFeature` function from your plugin's `setup` lifecycle function, and provide the appropriate details:
|
|
|
|
["source","javascript"]
|
|
-----------
|
|
setup(core, { features }) {
|
|
features.registerKibanaFeature({
|
|
// feature details here.
|
|
});
|
|
}
|
|
-----------
|
|
|
|
=== Feature details
|
|
Registering a feature consists of the following fields. For more information, consult the {kib-repo}blob/{branch}/x-pack/plugins/features/server/feature_registry.ts[feature registry interface].
|
|
|
|
|
|
[cols="1a, 1a, 1a, 1a"]
|
|
|===
|
|
|Field name |Data type |Example |Description
|
|
|
|
|`id` (required)
|
|
|`string`
|
|
|`"sample_feature"`
|
|
|A unique identifier for your feature. Usually, the ID of your plugin is sufficient.
|
|
|
|
|`name` (required)
|
|
|`string`
|
|
|`"Sample Feature"`
|
|
|A human readable name for your feature.
|
|
|
|
|`category` (required)
|
|
|{kib-repo}blob/{branch}/src/core/types/app_category.ts[`AppCategory`]
|
|
|`DEFAULT_APP_CATEGORIES.kibana`
|
|
|The `AppCategory` which best represents your feature. Used to organize the display
|
|
of features within the management screens.
|
|
|
|
|`app` (required)
|
|
|`string[]`
|
|
|`["sample_app", "kibana"]`
|
|
|An array of applications this feature enables. Typically, all of your plugin's apps (from `uiExports`) will be included here.
|
|
|
|
|`privileges` (required)
|
|
|{kib-repo}blob/{branch}/x-pack/plugins/features/common/feature.ts[`KibanaFeatureConfig`].
|
|
|See <<example-1-canvas,Example 1>> and <<example-2-dev-tools,Example 2>>
|
|
|The set of privileges this feature requires to function.
|
|
|
|
|`subFeatures` (optional)
|
|
|{kib-repo}blob/{branch}/x-pack/plugins/features/common/feature.ts[`KibanaFeatureConfig`].
|
|
|See <<example-3-discover,Example 3>>
|
|
|The set of subfeatures that enables finer access control than the `all` and `read` feature privileges. These options are only available in the Gold subscription level and higher.
|
|
|
|
|===
|
|
|
|
==== Privilege definition
|
|
The `privileges` section of feature registration allows plugins to implement read/write and read-only modes for their applications.
|
|
|
|
For a full explanation of fields and options, consult the {kib-repo}blob/{branch}/x-pack/plugins/features/server/feature_registry.ts[feature registry interface].
|
|
|
|
=== Using UI Capabilities
|
|
|
|
UI Capabilities are available to your public (client) plugin code. These capabilities are read-only, and are used to inform the UI. This object is namespaced by feature id. For example, if your feature id is “foo”, then your UI Capabilities are stored at `uiCapabilities.foo`.
|
|
Capabilities can be accessed from your plugin's `start` lifecycle from the `core.application` service:
|
|
|
|
["source","javascript"]
|
|
-----------
|
|
public start(core) {
|
|
const { capabilities } = core.application;
|
|
|
|
const canUserSave = capabilities.foo.save;
|
|
if (canUserSave) {
|
|
// show save button
|
|
}
|
|
}
|
|
-----------
|
|
|
|
[[example-1-canvas]]
|
|
=== Example 1: Canvas Application
|
|
["source","javascript"]
|
|
-----------
|
|
public setup(core, { features }) {
|
|
features.registerKibanaFeature({
|
|
id: 'canvas',
|
|
name: 'Canvas',
|
|
category: DEFAULT_APP_CATEGORIES.kibana,
|
|
app: ['canvas', 'kibana'],
|
|
catalogue: ['canvas'],
|
|
privileges: {
|
|
all: {
|
|
savedObject: {
|
|
all: ['canvas-workpad'],
|
|
read: ['index-pattern'],
|
|
},
|
|
ui: ['save'],
|
|
},
|
|
read: {
|
|
savedObject: {
|
|
all: [],
|
|
read: ['index-pattern', 'canvas-workpad'],
|
|
},
|
|
ui: [],
|
|
},
|
|
},
|
|
});
|
|
}
|
|
-----------
|
|
|
|
This shows how the Canvas application might register itself as a {kib} feature.
|
|
Note that it specifies different `savedObject` access levels for each privilege:
|
|
|
|
- Users with read/write access (`all` privilege) need to be able to read/write `canvas-workpad` saved objects, and they need read-only access to `index-pattern` saved objects.
|
|
- Users with read-only access (`read` privilege) do not need to have read/write access to any saved objects, but instead get read-only access to `index-pattern` and `canvas-workpad` saved objects.
|
|
|
|
Additionally, Canvas registers the `canvas` UI app and `canvas` catalogue entry. This tells {kib} that these entities are available for users with either the `read` or `all` privilege.
|
|
|
|
The `all` privilege defines a single “save” UI Capability. To access this in the UI, Canvas could:
|
|
|
|
["source","javascript"]
|
|
-----------
|
|
public start(core) {
|
|
const { capabilities } = core.application;
|
|
|
|
const canUserSave = capabilities.canvas.save;
|
|
if (canUserSave) {
|
|
// show save button
|
|
}
|
|
}
|
|
-----------
|
|
|
|
Because the `read` privilege does not define the `save` capability, users with read-only access will have their `uiCapabilities.canvas.save` flag set to `false`.
|
|
|
|
[[example-2-dev-tools]]
|
|
=== Example 2: Dev Tools
|
|
|
|
["source","javascript"]
|
|
-----------
|
|
public setup(core, { features }) {
|
|
features.registerKibanaFeature({
|
|
id: 'dev_tools',
|
|
name: i18n.translate('xpack.features.devToolsFeatureName', {
|
|
defaultMessage: 'Dev Tools',
|
|
}),
|
|
category: DEFAULT_APP_CATEGORIES.management,
|
|
app: ['kibana'],
|
|
catalogue: ['console', 'searchprofiler', 'grokdebugger'],
|
|
privileges: {
|
|
all: {
|
|
api: ['console'],
|
|
savedObject: {
|
|
all: [],
|
|
read: [],
|
|
},
|
|
ui: ['show'],
|
|
},
|
|
read: {
|
|
api: ['console'],
|
|
savedObject: {
|
|
all: [],
|
|
read: [],
|
|
},
|
|
ui: ['show'],
|
|
},
|
|
},
|
|
privilegesTooltip: i18n.translate('xpack.features.devToolsPrivilegesTooltip', {
|
|
defaultMessage:
|
|
'User should also be granted the appropriate {es} cluster and index privileges',
|
|
}),
|
|
});
|
|
}
|
|
-----------
|
|
|
|
Unlike the Canvas example, Dev Tools does not require access to any saved objects to function. Dev Tools does specify an API endpoint, however. When this is configured, the Security plugin will automatically authorize access to any server API route that is tagged with `access:console`, similar to the following:
|
|
|
|
["source","javascript"]
|
|
-----------
|
|
server.route({
|
|
path: '/api/console/proxy',
|
|
method: 'POST',
|
|
config: {
|
|
tags: ['access:console'],
|
|
handler: async (req, h) => {
|
|
// ...
|
|
}
|
|
}
|
|
});
|
|
-----------
|
|
|
|
[[example-3-discover]]
|
|
=== Example 3: Discover
|
|
|
|
Discover takes advantage of subfeature privileges to allow fine-grained access control. In this example,
|
|
a single "Create Short URLs" subfeature privilege is defined, which allows users to grant access to this feature without having to grant the `all` privilege to Discover. In other words, you can grant `read` access to Discover, and also grant the ability to create short URLs.
|
|
|
|
["source","javascript"]
|
|
-----------
|
|
public setup(core, { features }) {
|
|
features.registerKibanaFeature({
|
|
{
|
|
id: 'discover',
|
|
name: i18n.translate('xpack.features.discoverFeatureName', {
|
|
defaultMessage: 'Discover',
|
|
}),
|
|
order: 100,
|
|
category: DEFAULT_APP_CATEGORIES.kibana,
|
|
app: ['kibana'],
|
|
catalogue: ['discover'],
|
|
privileges: {
|
|
all: {
|
|
app: ['kibana'],
|
|
catalogue: ['discover'],
|
|
savedObject: {
|
|
all: ['search', 'query'],
|
|
read: ['index-pattern'],
|
|
},
|
|
ui: ['show', 'save', 'saveQuery'],
|
|
},
|
|
read: {
|
|
app: ['kibana'],
|
|
catalogue: ['discover'],
|
|
savedObject: {
|
|
all: [],
|
|
read: ['index-pattern', 'search', 'query'],
|
|
},
|
|
ui: ['show'],
|
|
},
|
|
},
|
|
subFeatures: [
|
|
{
|
|
name: i18n.translate('xpack.features.ossFeatures.discoverShortUrlSubFeatureName', {
|
|
defaultMessage: 'Short URLs',
|
|
}),
|
|
privilegeGroups: [
|
|
{
|
|
groupType: 'independent',
|
|
privileges: [
|
|
{
|
|
id: 'url_create',
|
|
name: i18n.translate(
|
|
'xpack.features.ossFeatures.discoverCreateShortUrlPrivilegeName',
|
|
{
|
|
defaultMessage: 'Create Short URLs',
|
|
}
|
|
),
|
|
includeIn: 'all',
|
|
savedObject: {
|
|
all: ['url'],
|
|
read: [],
|
|
},
|
|
ui: ['createShortUrl'],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
}
|
|
});
|
|
}
|
|
-----------
|