From 2087423aea0db15e399d3ef78cc547a07fbc3c8b Mon Sep 17 00:00:00 2001 From: Aleh Zasypkin Date: Wed, 30 Oct 2019 15:14:22 +0100 Subject: [PATCH 1/7] Move files. --- x-pack/{legacy => }/plugins/encrypted_saved_objects/README.md | 0 .../server}/__snapshots__/index.test.ts.snap | 0 .../encrypted_saved_objects/server/audit/audit_logger.test.ts} | 0 .../encrypted_saved_objects/server/audit/audit_logger.ts} | 0 .../server/crypto}/encrypted_saved_objects_service.test.ts | 0 .../server/crypto}/encrypted_saved_objects_service.ts | 0 .../server/crypto}/encryption_error.test.ts | 0 .../encrypted_saved_objects/server/crypto}/encryption_error.ts | 0 .../encrypted_saved_objects/server/crypto/index.mock.ts} | 0 .../encrypted_saved_objects/server}/index.test.ts | 0 .../plugins/encrypted_saved_objects/server/plugin.mock.ts | 0 .../{legacy => }/plugins/encrypted_saved_objects/server/plugin.ts | 0 .../saved_objects}/encrypted_saved_objects_client_wrapper.test.ts | 0 .../saved_objects}/encrypted_saved_objects_client_wrapper.ts | 0 .../encrypted_saved_objects/server/saved_objects}/index.ts | 0 15 files changed, 0 insertions(+), 0 deletions(-) rename x-pack/{legacy => }/plugins/encrypted_saved_objects/README.md (100%) rename x-pack/{legacy/plugins/encrypted_saved_objects => plugins/encrypted_saved_objects/server}/__snapshots__/index.test.ts.snap (100%) rename x-pack/{legacy/plugins/encrypted_saved_objects/server/lib/encrypted_saved_objects_audit_logger.test.ts => plugins/encrypted_saved_objects/server/audit/audit_logger.test.ts} (100%) rename x-pack/{legacy/plugins/encrypted_saved_objects/server/lib/encrypted_saved_objects_audit_logger.ts => plugins/encrypted_saved_objects/server/audit/audit_logger.ts} (100%) rename x-pack/{legacy/plugins/encrypted_saved_objects/server/lib => plugins/encrypted_saved_objects/server/crypto}/encrypted_saved_objects_service.test.ts (100%) rename x-pack/{legacy/plugins/encrypted_saved_objects/server/lib => plugins/encrypted_saved_objects/server/crypto}/encrypted_saved_objects_service.ts (100%) rename x-pack/{legacy/plugins/encrypted_saved_objects/server/lib => plugins/encrypted_saved_objects/server/crypto}/encryption_error.test.ts (100%) rename x-pack/{legacy/plugins/encrypted_saved_objects/server/lib => plugins/encrypted_saved_objects/server/crypto}/encryption_error.ts (100%) rename x-pack/{legacy/plugins/encrypted_saved_objects/server/lib/encrypted_saved_objects_service.mock.ts => plugins/encrypted_saved_objects/server/crypto/index.mock.ts} (100%) rename x-pack/{legacy/plugins/encrypted_saved_objects => plugins/encrypted_saved_objects/server}/index.test.ts (100%) rename x-pack/{legacy => }/plugins/encrypted_saved_objects/server/plugin.mock.ts (100%) rename x-pack/{legacy => }/plugins/encrypted_saved_objects/server/plugin.ts (100%) rename x-pack/{legacy/plugins/encrypted_saved_objects/server/lib => plugins/encrypted_saved_objects/server/saved_objects}/encrypted_saved_objects_client_wrapper.test.ts (100%) rename x-pack/{legacy/plugins/encrypted_saved_objects/server/lib => plugins/encrypted_saved_objects/server/saved_objects}/encrypted_saved_objects_client_wrapper.ts (100%) rename x-pack/{legacy/plugins/encrypted_saved_objects/server/lib => plugins/encrypted_saved_objects/server/saved_objects}/index.ts (100%) diff --git a/x-pack/legacy/plugins/encrypted_saved_objects/README.md b/x-pack/plugins/encrypted_saved_objects/README.md similarity index 100% rename from x-pack/legacy/plugins/encrypted_saved_objects/README.md rename to x-pack/plugins/encrypted_saved_objects/README.md diff --git a/x-pack/legacy/plugins/encrypted_saved_objects/__snapshots__/index.test.ts.snap b/x-pack/plugins/encrypted_saved_objects/server/__snapshots__/index.test.ts.snap similarity index 100% rename from x-pack/legacy/plugins/encrypted_saved_objects/__snapshots__/index.test.ts.snap rename to x-pack/plugins/encrypted_saved_objects/server/__snapshots__/index.test.ts.snap diff --git a/x-pack/legacy/plugins/encrypted_saved_objects/server/lib/encrypted_saved_objects_audit_logger.test.ts b/x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.test.ts similarity index 100% rename from x-pack/legacy/plugins/encrypted_saved_objects/server/lib/encrypted_saved_objects_audit_logger.test.ts rename to x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.test.ts diff --git a/x-pack/legacy/plugins/encrypted_saved_objects/server/lib/encrypted_saved_objects_audit_logger.ts b/x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.ts similarity index 100% rename from x-pack/legacy/plugins/encrypted_saved_objects/server/lib/encrypted_saved_objects_audit_logger.ts rename to x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.ts diff --git a/x-pack/legacy/plugins/encrypted_saved_objects/server/lib/encrypted_saved_objects_service.test.ts b/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.test.ts similarity index 100% rename from x-pack/legacy/plugins/encrypted_saved_objects/server/lib/encrypted_saved_objects_service.test.ts rename to x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.test.ts diff --git a/x-pack/legacy/plugins/encrypted_saved_objects/server/lib/encrypted_saved_objects_service.ts b/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.ts similarity index 100% rename from x-pack/legacy/plugins/encrypted_saved_objects/server/lib/encrypted_saved_objects_service.ts rename to x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.ts diff --git a/x-pack/legacy/plugins/encrypted_saved_objects/server/lib/encryption_error.test.ts b/x-pack/plugins/encrypted_saved_objects/server/crypto/encryption_error.test.ts similarity index 100% rename from x-pack/legacy/plugins/encrypted_saved_objects/server/lib/encryption_error.test.ts rename to x-pack/plugins/encrypted_saved_objects/server/crypto/encryption_error.test.ts diff --git a/x-pack/legacy/plugins/encrypted_saved_objects/server/lib/encryption_error.ts b/x-pack/plugins/encrypted_saved_objects/server/crypto/encryption_error.ts similarity index 100% rename from x-pack/legacy/plugins/encrypted_saved_objects/server/lib/encryption_error.ts rename to x-pack/plugins/encrypted_saved_objects/server/crypto/encryption_error.ts diff --git a/x-pack/legacy/plugins/encrypted_saved_objects/server/lib/encrypted_saved_objects_service.mock.ts b/x-pack/plugins/encrypted_saved_objects/server/crypto/index.mock.ts similarity index 100% rename from x-pack/legacy/plugins/encrypted_saved_objects/server/lib/encrypted_saved_objects_service.mock.ts rename to x-pack/plugins/encrypted_saved_objects/server/crypto/index.mock.ts diff --git a/x-pack/legacy/plugins/encrypted_saved_objects/index.test.ts b/x-pack/plugins/encrypted_saved_objects/server/index.test.ts similarity index 100% rename from x-pack/legacy/plugins/encrypted_saved_objects/index.test.ts rename to x-pack/plugins/encrypted_saved_objects/server/index.test.ts diff --git a/x-pack/legacy/plugins/encrypted_saved_objects/server/plugin.mock.ts b/x-pack/plugins/encrypted_saved_objects/server/plugin.mock.ts similarity index 100% rename from x-pack/legacy/plugins/encrypted_saved_objects/server/plugin.mock.ts rename to x-pack/plugins/encrypted_saved_objects/server/plugin.mock.ts diff --git a/x-pack/legacy/plugins/encrypted_saved_objects/server/plugin.ts b/x-pack/plugins/encrypted_saved_objects/server/plugin.ts similarity index 100% rename from x-pack/legacy/plugins/encrypted_saved_objects/server/plugin.ts rename to x-pack/plugins/encrypted_saved_objects/server/plugin.ts diff --git a/x-pack/legacy/plugins/encrypted_saved_objects/server/lib/encrypted_saved_objects_client_wrapper.test.ts b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.test.ts similarity index 100% rename from x-pack/legacy/plugins/encrypted_saved_objects/server/lib/encrypted_saved_objects_client_wrapper.test.ts rename to x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.test.ts diff --git a/x-pack/legacy/plugins/encrypted_saved_objects/server/lib/encrypted_saved_objects_client_wrapper.ts b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.ts similarity index 100% rename from x-pack/legacy/plugins/encrypted_saved_objects/server/lib/encrypted_saved_objects_client_wrapper.ts rename to x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.ts diff --git a/x-pack/legacy/plugins/encrypted_saved_objects/server/lib/index.ts b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts similarity index 100% rename from x-pack/legacy/plugins/encrypted_saved_objects/server/lib/index.ts rename to x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts From 8c91d8188332319045f14475b45d61ca4b8f2aea Mon Sep 17 00:00:00 2001 From: Aleh Zasypkin Date: Thu, 31 Oct 2019 17:14:56 +0100 Subject: [PATCH 2/7] Changes in EncryptedSavedObjects plugin. --- .../plugins/encrypted_saved_objects/index.ts | 83 ++++------- .../plugins/encrypted_saved_objects/README.md | 45 +++--- .../encrypted_saved_objects/kibana.json | 8 + .../server/__snapshots__/index.test.ts.snap | 14 -- .../server/audit/audit_logger.test.ts | 4 +- .../server/audit/audit_logger.ts | 13 +- .../server/audit/index.mock.ts | 18 +++ .../server/audit/index.ts | 7 + .../server/config.test.ts | 70 +++++++++ .../encrypted_saved_objects/server/config.ts | 46 ++++++ .../encrypted_saved_objects_service.test.ts | 27 +--- .../crypto/encrypted_saved_objects_service.ts | 26 ++-- .../server/crypto/index.mock.ts | 88 +++++------ .../server/crypto/index.ts | 13 ++ .../server/index.test.ts | 17 --- .../encrypted_saved_objects/server/index.ts | 16 ++ .../encrypted_saved_objects/server/mocks.ts | 26 ++++ .../server/plugin.mock.ts | 21 --- .../server/plugin.test.ts | 38 +++++ .../encrypted_saved_objects/server/plugin.ts | 139 ++++++++++-------- ...ypted_saved_objects_client_wrapper.test.ts | 49 +++--- .../encrypted_saved_objects_client_wrapper.ts | 2 +- .../server/saved_objects/index.ts | 68 ++++++++- .../plugins/encrypted_saved_objects/index.ts | 13 +- x-pack/test/typings/hapi.d.ts | 2 - x-pack/typings/hapi.d.ts | 2 - 26 files changed, 550 insertions(+), 305 deletions(-) create mode 100644 x-pack/plugins/encrypted_saved_objects/kibana.json delete mode 100644 x-pack/plugins/encrypted_saved_objects/server/__snapshots__/index.test.ts.snap create mode 100644 x-pack/plugins/encrypted_saved_objects/server/audit/index.mock.ts create mode 100644 x-pack/plugins/encrypted_saved_objects/server/audit/index.ts create mode 100644 x-pack/plugins/encrypted_saved_objects/server/config.test.ts create mode 100644 x-pack/plugins/encrypted_saved_objects/server/config.ts create mode 100644 x-pack/plugins/encrypted_saved_objects/server/crypto/index.ts delete mode 100644 x-pack/plugins/encrypted_saved_objects/server/index.test.ts create mode 100644 x-pack/plugins/encrypted_saved_objects/server/index.ts create mode 100644 x-pack/plugins/encrypted_saved_objects/server/mocks.ts delete mode 100644 x-pack/plugins/encrypted_saved_objects/server/plugin.mock.ts create mode 100644 x-pack/plugins/encrypted_saved_objects/server/plugin.test.ts diff --git a/x-pack/legacy/plugins/encrypted_saved_objects/index.ts b/x-pack/legacy/plugins/encrypted_saved_objects/index.ts index a5f28631f3d52..eff049f3b3d8d 100644 --- a/x-pack/legacy/plugins/encrypted_saved_objects/index.ts +++ b/x-pack/legacy/plugins/encrypted_saved_objects/index.ts @@ -5,62 +5,41 @@ */ import { Root } from 'joi'; -import { Legacy, Server } from 'kibana'; - +import { Legacy } from 'kibana'; +import { PluginSetupContract } from '../../../plugins/encrypted_saved_objects/server'; // @ts-ignore import { AuditLogger } from '../../server/lib/audit_logger'; -import { CONFIG_PREFIX, PLUGIN_ID, Plugin } from './server/plugin'; - -/** - * Public interface of the security plugin for the legacy plugin system. - */ -export type EncryptedSavedObjectsPlugin = ReturnType; - -export const encryptedSavedObjects = (kibana: any) => +export const encryptedSavedObjects = (kibana: { + Plugin: new (options: Legacy.PluginSpecOptions & { configPrefix?: string }) => unknown; +}) => new kibana.Plugin({ - id: PLUGIN_ID, - configPrefix: CONFIG_PREFIX, - require: ['kibana', 'elasticsearch', 'xpack_main'], - - config(Joi: Root) { - return Joi.object({ - enabled: Joi.boolean().default(true), - encryptionKey: Joi.when(Joi.ref('$dist'), { - is: true, - then: Joi.string().min(32), - otherwise: Joi.string() - .min(32) - .default('a'.repeat(32)), - }), - }).default(); - }, - - async init(server: Legacy.Server) { - const loggerFacade = { - fatal: (errorOrMessage: string | Error) => server.log(['fatal', PLUGIN_ID], errorOrMessage), - trace: (message: string) => server.log(['debug', PLUGIN_ID], message), - error: (message: string) => server.log(['error', PLUGIN_ID], message), - warn: (message: string) => server.log(['warning', PLUGIN_ID], message), - debug: (message: string) => server.log(['debug', PLUGIN_ID], message), - info: (message: string) => server.log(['info', PLUGIN_ID], message), - } as Server.Logger; - - const config = server.config(); - const encryptedSavedObjectsSetup = new Plugin(loggerFacade).setup( - { - config: { - encryptionKey: config.get(`${CONFIG_PREFIX}.encryptionKey`), - }, - savedObjects: server.savedObjects, - elasticsearch: server.plugins.elasticsearch, - }, - { audit: new AuditLogger(server, PLUGIN_ID, config, server.plugins.xpack_main.info) } - ); - - // Re-expose plugin setup contract through legacy mechanism. - for (const [setupMethodName, setupMethod] of Object.entries(encryptedSavedObjectsSetup)) { - server.expose(setupMethodName, setupMethod); + id: 'encrypted_saved_objects', + configPrefix: 'xpack.encrypted_saved_objects', + require: ['xpack_main'], + + // Some legacy plugins still use `enabled` config key, so we keep it here, but the rest of the + // keys is handled by the New Platform plugin. + config: (Joi: Root) => + Joi.object({ enabled: Joi.boolean().default(true) }) + .unknown(true) + .default(), + + init(server: Legacy.Server) { + const encryptedSavedObjectsPlugin = (server.newPlatform.setup.plugins + .encrypted_saved_objects as unknown) as PluginSetupContract; + if (!encryptedSavedObjectsPlugin) { + throw new Error('New Platform XPack EncryptedSavedObjects plugin is not available.'); } + + encryptedSavedObjectsPlugin.__legacyCompat.registerLegacyAPI({ + savedObjects: server.savedObjects, + auditLogger: new AuditLogger( + server, + 'encrypted_saved_objects', + server.config(), + server.plugins.xpack_main.info + ), + }); }, }); diff --git a/x-pack/plugins/encrypted_saved_objects/README.md b/x-pack/plugins/encrypted_saved_objects/README.md index f63c558d323e8..32caa347cdac4 100644 --- a/x-pack/plugins/encrypted_saved_objects/README.md +++ b/x-pack/plugins/encrypted_saved_objects/README.md @@ -11,15 +11,14 @@ security and spaces filtering as well as performing audit logging. Follow these steps to use `encrypted_saved_objects` in your plugin: -1. Declare `encrypted_saved_objects` as a dependency: +1. Declare `encrypted_saved_objects` as a dependency in `kibana.json`: -```typescript -... -new kibana.Plugin({ +```json +{ ... - require: ['encrypted_saved_objects'], + "requiredPlugins": ["encrypted_saved_objects"], ... -}); +} ``` 2. Add attributes to be encrypted in `mappings.json` file for the respective Saved Object type. These attributes should @@ -37,13 +36,17 @@ searchable or analyzed: } ``` -3. Register Saved Object type using the provided API: +3. Register Saved Object type using the provided API at the `setup` stage: ```typescript -server.plugins.encrypted_saved_objects.registerType({ - type: 'my-saved-object-type', - attributesToEncrypt: new Set(['mySecret']), -}); +... +public setup(core: CoreSetup, { encryptedSavedObjects }: PluginSetupDependencies) { + encrypted_saved_objects.registerType({ + type: 'my-saved-object-type', + attributesToEncrypt: new Set(['mySecret']), + }); +} +... ``` 4. For any Saved Object operation that does not require retrieval of decrypted content, use standard REST or @@ -51,11 +54,17 @@ programmatic Saved Object API, e.g.: ```typescript ... -async handler(request: Request) { - return await server.savedObjects - .getScopedSavedObjectsClient(request) - .create('my-saved-object-type', { name: 'some name', mySecret: 'non encrypted secret' }); -} +router.get( + { path: '/some-path', validate: false }, + async (context, req, res) => { + return res.ok({ + body: await context.core.savedObjects.client.create( + 'my-saved-object-type', + { name: 'some name', mySecret: 'non encrypted secret' } + ), + }); + } +); ... ``` @@ -63,12 +72,12 @@ async handler(request: Request) { **Note:** As name suggests the method will retrieve the encrypted values and decrypt them on behalf of the internal Kibana user to make it possible to use this method even when user request context is not available (e.g. in background tasks). -Hence this method should only be used wherever consumers would otherwise feel comfortable using `callWithInternalUser` +Hence this method should only be used wherever consumers would otherwise feel comfortable using `callAsInternalUser` and preferably only as a part of the Kibana server routines that are outside of the lifecycle of a HTTP request that a user has control over. ```typescript -const savedObjectWithDecryptedContent = await server.plugins.encrypted_saved_objects.getDecryptedAsInternalUser( +const savedObjectWithDecryptedContent = await encrypted_saved_objects.getDecryptedAsInternalUser( 'my-saved-object-type', 'saved-object-id' ); diff --git a/x-pack/plugins/encrypted_saved_objects/kibana.json b/x-pack/plugins/encrypted_saved_objects/kibana.json new file mode 100644 index 0000000000000..00dc1eebddeb7 --- /dev/null +++ b/x-pack/plugins/encrypted_saved_objects/kibana.json @@ -0,0 +1,8 @@ +{ + "id": "encrypted_saved_objects", + "version": "8.0.0", + "kibanaVersion": "kibana", + "configPath": ["xpack", "encrypted_saved_objects"], + "server": true, + "ui": false +} diff --git a/x-pack/plugins/encrypted_saved_objects/server/__snapshots__/index.test.ts.snap b/x-pack/plugins/encrypted_saved_objects/server/__snapshots__/index.test.ts.snap deleted file mode 100644 index e3c069069bf14..0000000000000 --- a/x-pack/plugins/encrypted_saved_objects/server/__snapshots__/index.test.ts.snap +++ /dev/null @@ -1,14 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`config schema with context {"dist":false} produces correct config 1`] = ` -Object { - "enabled": true, - "encryptionKey": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", -} -`; - -exports[`config schema with context {"dist":true} produces correct config 1`] = ` -Object { - "enabled": true, -} -`; diff --git a/x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.test.ts b/x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.test.ts index 8c286da8308f2..3553a3bc34779 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.test.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.test.ts @@ -4,11 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EncryptedSavedObjectsAuditLogger } from './encrypted_saved_objects_audit_logger'; +import { EncryptedSavedObjectsAuditLogger } from './audit_logger'; test('properly logs audit events', () => { const mockInternalAuditLogger = { log: jest.fn() }; - const audit = new EncryptedSavedObjectsAuditLogger(mockInternalAuditLogger); + const audit = new EncryptedSavedObjectsAuditLogger(() => mockInternalAuditLogger); audit.encryptAttributesSuccess(['one', 'two'], { type: 'known-type', diff --git a/x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.ts b/x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.ts index e6a832a074e03..9eb0a1e0872c2 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.ts @@ -4,16 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SavedObjectDescriptor, descriptorToArray } from './encrypted_saved_objects_service'; +import { SavedObjectDescriptor, descriptorToArray } from '../crypto'; +import { LegacyAPI } from '../plugin'; /** * Represents all audit events the plugin can log. */ export class EncryptedSavedObjectsAuditLogger { - constructor(private readonly auditLogger: any) {} + constructor(private readonly getAuditLogger: () => LegacyAPI['auditLogger']) {} public encryptAttributeFailure(attributeName: string, descriptor: SavedObjectDescriptor) { - this.auditLogger.log( + this.getAuditLogger().log( 'encrypt_failure', `Failed to encrypt attribute "${attributeName}" for saved object "[${descriptorToArray( descriptor @@ -23,7 +24,7 @@ export class EncryptedSavedObjectsAuditLogger { } public decryptAttributeFailure(attributeName: string, descriptor: SavedObjectDescriptor) { - this.auditLogger.log( + this.getAuditLogger().log( 'decrypt_failure', `Failed to decrypt attribute "${attributeName}" for saved object "[${descriptorToArray( descriptor @@ -36,7 +37,7 @@ export class EncryptedSavedObjectsAuditLogger { attributesNames: readonly string[], descriptor: SavedObjectDescriptor ) { - this.auditLogger.log( + this.getAuditLogger().log( 'encrypt_success', `Successfully encrypted attributes "[${attributesNames}]" for saved object "[${descriptorToArray( descriptor @@ -49,7 +50,7 @@ export class EncryptedSavedObjectsAuditLogger { attributesNames: readonly string[], descriptor: SavedObjectDescriptor ) { - this.auditLogger.log( + this.getAuditLogger().log( 'decrypt_success', `Successfully decrypted attributes "[${attributesNames}]" for saved object "[${descriptorToArray( descriptor diff --git a/x-pack/plugins/encrypted_saved_objects/server/audit/index.mock.ts b/x-pack/plugins/encrypted_saved_objects/server/audit/index.mock.ts new file mode 100644 index 0000000000000..41f1c9dac7d18 --- /dev/null +++ b/x-pack/plugins/encrypted_saved_objects/server/audit/index.mock.ts @@ -0,0 +1,18 @@ +/* + * 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 { EncryptedSavedObjectsAuditLogger } from './audit_logger'; + +export const encryptedSavedObjectsAuditLoggerMock = { + create() { + return ({ + encryptAttributesSuccess: jest.fn(), + encryptAttributeFailure: jest.fn(), + decryptAttributesSuccess: jest.fn(), + decryptAttributeFailure: jest.fn(), + } as unknown) as jest.Mocked; + }, +}; diff --git a/x-pack/plugins/encrypted_saved_objects/server/audit/index.ts b/x-pack/plugins/encrypted_saved_objects/server/audit/index.ts new file mode 100644 index 0000000000000..97f684ec841fe --- /dev/null +++ b/x-pack/plugins/encrypted_saved_objects/server/audit/index.ts @@ -0,0 +1,7 @@ +/* + * 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 { EncryptedSavedObjectsAuditLogger } from './audit_logger'; diff --git a/x-pack/plugins/encrypted_saved_objects/server/config.test.ts b/x-pack/plugins/encrypted_saved_objects/server/config.test.ts new file mode 100644 index 0000000000000..1e4b109ebf4ef --- /dev/null +++ b/x-pack/plugins/encrypted_saved_objects/server/config.test.ts @@ -0,0 +1,70 @@ +/* + * 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. + */ + +jest.mock('crypto', () => ({ randomBytes: jest.fn() })); + +import { first } from 'rxjs/operators'; +import { loggingServiceMock, coreMock } from 'src/core/server/mocks'; +import { createConfig$, ConfigSchema } from './config'; + +describe('config schema', () => { + it('generates proper defaults', () => { + expect(ConfigSchema.validate({})).toMatchInlineSnapshot(` + Object { + "enabled": true, + "encryptionKey": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + } + `); + + expect(ConfigSchema.validate({}, { dist: false })).toMatchInlineSnapshot(` + Object { + "enabled": true, + "encryptionKey": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + } + `); + + expect(ConfigSchema.validate({}, { dist: true })).toMatchInlineSnapshot(` + Object { + "enabled": true, + } + `); + }); + + it('should throw error if xpack.encrypted_saved_objects.encryptionKey is less than 32 characters', () => { + expect(() => + ConfigSchema.validate({ encryptionKey: 'foo' }) + ).toThrowErrorMatchingInlineSnapshot( + `"[encryptionKey]: value is [foo] but it must have a minimum length of [32]."` + ); + + expect(() => + ConfigSchema.validate({ encryptionKey: 'foo' }, { dist: true }) + ).toThrowErrorMatchingInlineSnapshot( + `"[encryptionKey]: value is [foo] but it must have a minimum length of [32]."` + ); + }); +}); + +describe('createConfig$()', () => { + it('should log a warning and set xpack.encrypted_saved_objects.encryptionKey if not set', async () => { + const mockRandomBytes = jest.requireMock('crypto').randomBytes; + mockRandomBytes.mockReturnValue('ab'.repeat(16)); + + const contextMock = coreMock.createPluginInitializerContext({}); + const config = await createConfig$(contextMock) + .pipe(first()) + .toPromise(); + expect(config).toEqual({ encryptionKey: 'ab'.repeat(16) }); + + expect(loggingServiceMock.collect(contextMock.logger).warn).toMatchInlineSnapshot(` + Array [ + Array [ + "Generating a random key for xpack.encrypted_saved_objects.encryptionKey. To be able to decrypt encrypted saved objects attributes after restart, please set xpack.encrypted_saved_objects.encryptionKey in kibana.yml", + ], + ] + `); + }); +}); diff --git a/x-pack/plugins/encrypted_saved_objects/server/config.ts b/x-pack/plugins/encrypted_saved_objects/server/config.ts new file mode 100644 index 0000000000000..dfc5e7493cae0 --- /dev/null +++ b/x-pack/plugins/encrypted_saved_objects/server/config.ts @@ -0,0 +1,46 @@ +/* + * 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 crypto from 'crypto'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { schema, TypeOf } from '@kbn/config-schema'; +import { PluginInitializerContext } from 'src/core/server'; + +export type ConfigType = ReturnType extends Observable + ? P + : ReturnType; + +export const ConfigSchema = schema.object({ + enabled: schema.boolean({ defaultValue: true }), + encryptionKey: schema.conditional( + schema.contextRef('dist'), + true, + schema.maybe(schema.string({ minLength: 32 })), + schema.string({ minLength: 32, defaultValue: 'a'.repeat(32) }) + ), +}); + +export function createConfig$(context: PluginInitializerContext) { + return context.config.create>().pipe( + map(config => { + const logger = context.logger.get('config'); + + let encryptionKey = config.encryptionKey; + if (encryptionKey === undefined) { + logger.warn( + 'Generating a random key for xpack.encrypted_saved_objects.encryptionKey. ' + + 'To be able to decrypt encrypted saved objects attributes after restart, ' + + 'please set xpack.encrypted_saved_objects.encryptionKey in kibana.yml' + ); + + encryptionKey = crypto.randomBytes(16).toString('hex'); + } + + return { ...config, encryptionKey }; + }) + ); +} diff --git a/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.test.ts b/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.test.ts index 2f38bcf96c583..e1e1a8224aa7b 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.test.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.test.ts @@ -6,19 +6,17 @@ jest.mock('@elastic/node-crypto', () => jest.fn()); -import { EncryptedSavedObjectsAuditLogger } from './encrypted_saved_objects_audit_logger'; +import { EncryptedSavedObjectsAuditLogger } from '../audit'; import { EncryptedSavedObjectsService } from './encrypted_saved_objects_service'; import { EncryptionError } from './encryption_error'; +import { loggingServiceMock } from 'src/core/server/mocks'; +import { encryptedSavedObjectsAuditLoggerMock } from '../audit/index.mock'; + let service: EncryptedSavedObjectsService; let mockAuditLogger: jest.Mocked; beforeEach(() => { - mockAuditLogger = { - encryptAttributesSuccess: jest.fn(), - encryptAttributeFailure: jest.fn(), - decryptAttributesSuccess: jest.fn(), - decryptAttributeFailure: jest.fn(), - } as any; + mockAuditLogger = encryptedSavedObjectsAuditLoggerMock.create(); // Call actual `@elastic/node-crypto` by default, but allow to override implementation in tests. jest @@ -27,8 +25,7 @@ beforeEach(() => { service = new EncryptedSavedObjectsService( 'encryption-key-abc', - ['known-type-1', 'known-type-2'], - { debug: jest.fn(), error: jest.fn() } as any, + loggingServiceMock.create().get(), mockAuditLogger ); }); @@ -54,12 +51,6 @@ describe('#registerType', () => { service.registerType({ type: 'known-type-1', attributesToEncrypt: new Set(['attr']) }) ).toThrowError('The "known-type-1" saved object type is already registered.'); }); - - it('throws if `type` references to the unknown type', () => { - expect(() => - service.registerType({ type: 'unknown-type', attributesToEncrypt: new Set(['attr']) }) - ).toThrowError('The type "unknown-type" is not known saved object type.'); - }); }); describe('#isRegistered', () => { @@ -137,8 +128,7 @@ describe('#encryptAttributes', () => { service = new EncryptedSavedObjectsService( 'encryption-key-abc', - ['known-type-1', 'known-type-2'], - { debug: jest.fn(), error: jest.fn() } as any, + loggingServiceMock.create().get(), mockAuditLogger ); }); @@ -773,8 +763,7 @@ describe('#decryptAttributes', () => { it('fails if encrypted with another encryption key', async () => { service = new EncryptedSavedObjectsService( 'encryption-key-abc*', - ['known-type-1'], - { debug: jest.fn(), error: jest.fn() } as any, + loggingServiceMock.create().get(), mockAuditLogger ); diff --git a/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.ts b/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.ts index 558f9127c4273..7fc2e24ffd260 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.ts @@ -8,8 +8,8 @@ import nodeCrypto from '@elastic/node-crypto'; import stringify from 'json-stable-stringify'; import typeDetect from 'type-detect'; -import { Server } from 'kibana'; -import { EncryptedSavedObjectsAuditLogger } from './encrypted_saved_objects_audit_logger'; +import { Logger } from 'src/core/server'; +import { EncryptedSavedObjectsAuditLogger } from '../audit'; import { EncryptionError } from './encryption_error'; /** @@ -62,14 +62,12 @@ export class EncryptedSavedObjectsService { /** * @param encryptionKey The key used to encrypt and decrypt saved objects attributes. - * @param knownTypes The list of all known saved object types. - * @param log Ordinary logger instance. + * @param logger Ordinary logger instance. * @param audit Audit logger instance. */ constructor( encryptionKey: string, - private readonly knownTypes: readonly string[], - private readonly log: Server.Logger, + private readonly logger: Logger, private readonly audit: EncryptedSavedObjectsAuditLogger ) { this.crypto = nodeCrypto({ encryptionKey }); @@ -91,10 +89,6 @@ export class EncryptedSavedObjectsService { throw new Error(`The "${typeRegistration.type}" saved object type is already registered.`); } - if (!this.knownTypes.includes(typeRegistration.type)) { - throw new Error(`The type "${typeRegistration.type}" is not known saved object type.`); - } - this.typeRegistrations.set(typeRegistration.type, typeRegistration); } @@ -160,7 +154,9 @@ export class EncryptedSavedObjectsService { encryptionAAD ); } catch (err) { - this.log.error(`Failed to encrypt "${attributeName}" attribute: ${err.message || err}`); + this.logger.error( + `Failed to encrypt "${attributeName}" attribute: ${err.message || err}` + ); this.audit.encryptAttributeFailure(attributeName, descriptor); throw new EncryptionError( @@ -176,7 +172,7 @@ export class EncryptedSavedObjectsService { // not the case we should collect and log them to make troubleshooting easier. const encryptedAttributesKeys = Object.keys(encryptedAttributes); if (encryptedAttributesKeys.length !== typeRegistration.attributesToEncrypt.size) { - this.log.debug( + this.logger.debug( `The following attributes of saved object "${descriptorToArray( descriptor )}" should have been encrypted: ${Array.from( @@ -238,7 +234,7 @@ export class EncryptedSavedObjectsService { encryptionAAD ); } catch (err) { - this.log.error(`Failed to decrypt "${attributeName}" attribute: ${err.message || err}`); + this.logger.error(`Failed to decrypt "${attributeName}" attribute: ${err.message || err}`); this.audit.decryptAttributeFailure(attributeName, descriptor); throw new EncryptionError( @@ -253,7 +249,7 @@ export class EncryptedSavedObjectsService { // not the case we should collect and log them to make troubleshooting easier. const decryptedAttributesKeys = Object.keys(decryptedAttributes); if (decryptedAttributesKeys.length !== typeRegistration.attributesToEncrypt.size) { - this.log.debug( + this.logger.debug( `The following attributes of saved object "${descriptorToArray( descriptor )}" should have been decrypted: ${Array.from( @@ -299,7 +295,7 @@ export class EncryptedSavedObjectsService { } if (Object.keys(attributesAAD).length) { - this.log.debug( + this.logger.debug( `The AAD for saved object "${descriptorToArray( descriptor )}" does not include any attributes.` diff --git a/x-pack/plugins/encrypted_saved_objects/server/crypto/index.mock.ts b/x-pack/plugins/encrypted_saved_objects/server/crypto/index.mock.ts index 235d64cc348c9..b1795b9439808 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/crypto/index.mock.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/crypto/index.mock.ts @@ -8,53 +8,55 @@ import { EncryptedSavedObjectsService, EncryptedSavedObjectTypeRegistration, SavedObjectDescriptor, -} from './encrypted_saved_objects_service'; +} from '.'; -export function createEncryptedSavedObjectsServiceMock( - registrations: EncryptedSavedObjectTypeRegistration[] = [] -) { - const mock: jest.Mocked = new (jest.requireMock( - './encrypted_saved_objects_service' - )).EncryptedSavedObjectsService(); +export const encryptedSavedObjectsServiceMock = { + create(registrations: EncryptedSavedObjectTypeRegistration[] = []) { + const mock: jest.Mocked = new (jest.requireMock( + './encrypted_saved_objects_service' + )).EncryptedSavedObjectsService(); - function processAttributes>( - descriptor: Pick, - attrs: T, - action: (attrs: T, attrName: string) => void - ) { - const registration = registrations.find(r => r.type === descriptor.type); - if (!registration) { - return attrs; - } + function processAttributes>( + descriptor: Pick, + attrs: T, + action: (attrs: T, attrName: string) => void + ) { + const registration = registrations.find(r => r.type === descriptor.type); + if (!registration) { + return attrs; + } - const clonedAttrs = { ...attrs }; - for (const attrName of registration.attributesToEncrypt) { - if (attrName in clonedAttrs) { - action(clonedAttrs, attrName); + const clonedAttrs = { ...attrs }; + for (const attrName of registration.attributesToEncrypt) { + if (attrName in clonedAttrs) { + action(clonedAttrs, attrName); + } } + return clonedAttrs; } - return clonedAttrs; - } - mock.isRegistered.mockImplementation(type => registrations.findIndex(r => r.type === type) >= 0); - mock.encryptAttributes.mockImplementation(async (descriptor, attrs) => - processAttributes( - descriptor, - attrs, - (clonedAttrs, attrName) => (clonedAttrs[attrName] = `*${clonedAttrs[attrName]}*`) - ) - ); - mock.decryptAttributes.mockImplementation(async (descriptor, attrs) => - processAttributes( - descriptor, - attrs, - (clonedAttrs, attrName) => - (clonedAttrs[attrName] = (clonedAttrs[attrName] as string).slice(1, -1)) - ) - ); - mock.stripEncryptedAttributes.mockImplementation((type, attrs) => - processAttributes({ type }, attrs, (clonedAttrs, attrName) => delete clonedAttrs[attrName]) - ); + mock.isRegistered.mockImplementation( + type => registrations.findIndex(r => r.type === type) >= 0 + ); + mock.encryptAttributes.mockImplementation(async (descriptor, attrs) => + processAttributes( + descriptor, + attrs, + (clonedAttrs, attrName) => (clonedAttrs[attrName] = `*${clonedAttrs[attrName]}*`) + ) + ); + mock.decryptAttributes.mockImplementation(async (descriptor, attrs) => + processAttributes( + descriptor, + attrs, + (clonedAttrs, attrName) => + (clonedAttrs[attrName] = (clonedAttrs[attrName] as string).slice(1, -1)) + ) + ); + mock.stripEncryptedAttributes.mockImplementation((type, attrs) => + processAttributes({ type }, attrs, (clonedAttrs, attrName) => delete clonedAttrs[attrName]) + ); - return mock; -} + return mock; + }, +}; diff --git a/x-pack/plugins/encrypted_saved_objects/server/crypto/index.ts b/x-pack/plugins/encrypted_saved_objects/server/crypto/index.ts new file mode 100644 index 0000000000000..0849f0eb320dd --- /dev/null +++ b/x-pack/plugins/encrypted_saved_objects/server/crypto/index.ts @@ -0,0 +1,13 @@ +/* + * 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 { + EncryptedSavedObjectsService, + EncryptedSavedObjectTypeRegistration, + descriptorToArray, + SavedObjectDescriptor, +} from './encrypted_saved_objects_service'; +export { EncryptionError } from './encryption_error'; diff --git a/x-pack/plugins/encrypted_saved_objects/server/index.test.ts b/x-pack/plugins/encrypted_saved_objects/server/index.test.ts deleted file mode 100644 index 26c0166186c4c..0000000000000 --- a/x-pack/plugins/encrypted_saved_objects/server/index.test.ts +++ /dev/null @@ -1,17 +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 { encryptedSavedObjects } from './index'; -import { getConfigSchema } from '../../../test_utils'; - -const describeWithContext = describe.each([[{ dist: false }], [{ dist: true }]]); - -describeWithContext('config schema with context %j', context => { - it('produces correct config', async () => { - const schema = await getConfigSchema(encryptedSavedObjects); - await expect(schema.validate({}, { context })).resolves.toMatchSnapshot(); - }); -}); diff --git a/x-pack/plugins/encrypted_saved_objects/server/index.ts b/x-pack/plugins/encrypted_saved_objects/server/index.ts new file mode 100644 index 0000000000000..5e6edb95ec37a --- /dev/null +++ b/x-pack/plugins/encrypted_saved_objects/server/index.ts @@ -0,0 +1,16 @@ +/* + * 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 { PluginInitializerContext } from 'src/core/server'; +import { ConfigSchema } from './config'; +import { Plugin } from './plugin'; + +export { EncryptedSavedObjectTypeRegistration, EncryptionError } from './crypto'; +export { PluginSetupContract, PluginStartContract } from './plugin'; + +export const config = { schema: ConfigSchema }; +export const plugin = (initializerContext: PluginInitializerContext) => + new Plugin(initializerContext); diff --git a/x-pack/plugins/encrypted_saved_objects/server/mocks.ts b/x-pack/plugins/encrypted_saved_objects/server/mocks.ts new file mode 100644 index 0000000000000..87c36381a841a --- /dev/null +++ b/x-pack/plugins/encrypted_saved_objects/server/mocks.ts @@ -0,0 +1,26 @@ +/* + * 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 { PluginSetupContract, PluginStartContract } from './plugin'; + +function createEncryptedSavedObjectsSetupMock() { + return { + registerType: jest.fn(), + __legacyCompat: { registerLegacyAPI: jest.fn() }, + } as jest.Mocked; +} + +function createEncryptedSavedObjectsStartMock() { + return { + isEncryptionError: jest.fn(), + getDecryptedAsInternalUser: jest.fn(), + } as jest.Mocked; +} + +export const encryptedSavedObjectsMock = { + createSetup: createEncryptedSavedObjectsSetupMock, + createStart: createEncryptedSavedObjectsStartMock, +}; diff --git a/x-pack/plugins/encrypted_saved_objects/server/plugin.mock.ts b/x-pack/plugins/encrypted_saved_objects/server/plugin.mock.ts deleted file mode 100644 index 7c6e37c7e5d4c..0000000000000 --- a/x-pack/plugins/encrypted_saved_objects/server/plugin.mock.ts +++ /dev/null @@ -1,21 +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 { Plugin } from './plugin'; -type EncryptedSavedObjectsPlugin = ReturnType; - -const createEncryptedSavedObjectsMock = () => { - const mocked: jest.Mocked = { - isEncryptionError: jest.fn(), - registerType: jest.fn(), - getDecryptedAsInternalUser: jest.fn(), - }; - return mocked; -}; - -export const encryptedSavedObjectsMock = { - create: createEncryptedSavedObjectsMock, -}; diff --git a/x-pack/plugins/encrypted_saved_objects/server/plugin.test.ts b/x-pack/plugins/encrypted_saved_objects/server/plugin.test.ts new file mode 100644 index 0000000000000..534ed13ba0acb --- /dev/null +++ b/x-pack/plugins/encrypted_saved_objects/server/plugin.test.ts @@ -0,0 +1,38 @@ +/* + * 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 { Plugin } from './plugin'; + +import { coreMock } from 'src/core/server/mocks'; + +describe('EncryptedSavedObjects Plugin', () => { + describe('setup()', () => { + it('exposes proper contract', async () => { + const plugin = new Plugin(coreMock.createPluginInitializerContext()); + await expect(plugin.setup(coreMock.createSetup())).resolves.toMatchInlineSnapshot(` + Object { + "__legacyCompat": Object { + "registerLegacyAPI": [Function], + }, + "registerType": [Function], + } + `); + }); + }); + + describe('start()', () => { + it('exposes proper contract', async () => { + const plugin = new Plugin(coreMock.createPluginInitializerContext()); + await plugin.setup(coreMock.createSetup()); + await expect(plugin.start()).toMatchInlineSnapshot(` + Object { + "getDecryptedAsInternalUser": [Function], + "isEncryptionError": [Function], + } + `); + }); + }); +}); diff --git a/x-pack/plugins/encrypted_saved_objects/server/plugin.ts b/x-pack/plugins/encrypted_saved_objects/server/plugin.ts index ad38ca0f7a881..73c2439f777cc 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/plugin.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/plugin.ts @@ -4,89 +4,110 @@ * you may not use this file except in compliance with the Elastic License. */ -import crypto from 'crypto'; -import { Legacy, Server } from 'kibana'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { SavedObjectsRepository } from 'src/core/server/saved_objects/service'; -import { SavedObjectsBaseOptions, SavedObject, SavedObjectAttributes } from 'src/core/server'; +import { + Logger, + SavedObjectsBaseOptions, + PluginInitializerContext, + CoreSetup, + SavedObjectsLegacyService, + KibanaRequest, + LegacyRequest, +} from 'src/core/server'; +import { first } from 'rxjs/operators'; +import { createConfig$ } from './config'; import { EncryptedSavedObjectsService, EncryptedSavedObjectTypeRegistration, EncryptionError, - EncryptedSavedObjectsAuditLogger, - EncryptedSavedObjectsClientWrapper, -} from './lib'; +} from './crypto'; +import { EncryptedSavedObjectsAuditLogger } from './audit'; +import { SavedObjectsSetup, setupSavedObjects } from './saved_objects'; -export const PLUGIN_ID = 'encrypted_saved_objects'; -export const CONFIG_PREFIX = `xpack.${PLUGIN_ID}`; +export interface PluginSetupContract { + registerType: (typeRegistration: EncryptedSavedObjectTypeRegistration) => void; + __legacyCompat: { registerLegacyAPI: (legacyAPI: LegacyAPI) => void }; +} -interface CoreSetup { - config: { encryptionKey?: string }; - elasticsearch: Legacy.Plugins.elasticsearch.Plugin; - savedObjects: Legacy.SavedObjectsService; +export interface PluginStartContract extends SavedObjectsSetup { + isEncryptionError: (error: Error) => boolean; } -interface PluginsSetup { - audit: unknown; +/** + * Describes a set of APIs that is available in the legacy platform only and required by this plugin + * to function properly. + */ +export interface LegacyAPI { + savedObjects: SavedObjectsLegacyService; + auditLogger: { + log: (eventType: string, message: string, data?: Record) => void; + }; } +/** + * Represents EncryptedSavedObjects Plugin instance that will be managed by the Kibana plugin system. + */ export class Plugin { - constructor(private readonly log: Server.Logger) {} - - public setup(core: CoreSetup, plugins: PluginsSetup) { - let encryptionKey = core.config.encryptionKey; - if (encryptionKey == null) { - this.log.warn( - `Generating a random key for ${CONFIG_PREFIX}.encryptionKey. To be able ` + - 'to decrypt encrypted saved objects attributes after restart, please set ' + - `${CONFIG_PREFIX}.encryptionKey in kibana.yml` - ); + private readonly logger: Logger; + private savedObjectsSetup?: ReturnType; - encryptionKey = crypto.randomBytes(16).toString('hex'); + private legacyAPI?: LegacyAPI; + private readonly getLegacyAPI = () => { + if (!this.legacyAPI) { + throw new Error('Legacy API is not registered!'); } + return this.legacyAPI; + }; + + constructor(private readonly initializerContext: PluginInitializerContext) { + this.logger = this.initializerContext.logger.get(); + } + + public async setup(core: CoreSetup): Promise { + const config = await createConfig$(this.initializerContext) + .pipe(first()) + .toPromise(); + const adminClusterClient = await core.elasticsearch.adminClient$.pipe(first()).toPromise(); const service = Object.freeze( new EncryptedSavedObjectsService( - encryptionKey, - core.savedObjects.types, - this.log, - new EncryptedSavedObjectsAuditLogger(plugins.audit) + config.encryptionKey, + this.logger, + new EncryptedSavedObjectsAuditLogger(() => this.getLegacyAPI().auditLogger) ) ); - // Register custom saved object client that will encrypt, decrypt and strip saved object - // attributes where appropriate for any saved object repository request. We choose max possible - // priority for this wrapper to allow all other wrappers to set proper `namespace` for the Saved - // Object (e.g. wrapper registered by the Spaces plugin) before we encrypt attributes since - // `namespace` is included into AAD. - core.savedObjects.addScopedSavedObjectsClientWrapperFactory( - Number.MAX_SAFE_INTEGER, - 'encrypted_saved_objects', - ({ client: baseClient }) => new EncryptedSavedObjectsClientWrapper({ baseClient, service }) - ); + return { + registerType: (typeRegistration: EncryptedSavedObjectTypeRegistration) => + service.registerType(typeRegistration), + __legacyCompat: { + registerLegacyAPI: (legacyAPI: LegacyAPI) => { + this.legacyAPI = legacyAPI; + this.savedObjectsSetup = setupSavedObjects({ + adminClusterClient, + service, + savedObjects: legacyAPI.savedObjects, + }); + }, + }, + }; + } - const internalRepository: SavedObjectsRepository = core.savedObjects.getSavedObjectsRepository( - core.elasticsearch.getCluster('admin').callWithInternalUser - ); + public start() { + this.logger.debug('Starting plugin'); return { isEncryptionError: (error: Error) => error instanceof EncryptionError, - registerType: (typeRegistration: EncryptedSavedObjectTypeRegistration) => - service.registerType(typeRegistration), - getDecryptedAsInternalUser: async ( - type: string, - id: string, - options?: SavedObjectsBaseOptions - ): Promise> => { - const savedObject = await internalRepository.get(type, id, options); - return { - ...savedObject, - attributes: await service.decryptAttributes( - { type, id, namespace: options && options.namespace }, - savedObject.attributes - ), - }; + getDecryptedAsInternalUser: (type: string, id: string, options?: SavedObjectsBaseOptions) => { + if (!this.savedObjectsSetup) { + throw new Error('Legacy SavedObjects API is not registered!'); + } + + return this.savedObjectsSetup.getDecryptedAsInternalUser(type, id, options); }, }; } + + public stop() { + this.logger.debug('Stopping plugin'); + } } diff --git a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.test.ts b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.test.ts index a9f41513fbf14..8574293e3e6a6 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.test.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.test.ts @@ -6,18 +6,19 @@ jest.mock('uuid', () => ({ v4: jest.fn().mockReturnValue('uuid-v4-id') })); -import { EncryptedSavedObjectsClientWrapper } from './encrypted_saved_objects_client_wrapper'; -import { EncryptedSavedObjectsService } from './encrypted_saved_objects_service'; -import { createEncryptedSavedObjectsServiceMock } from './encrypted_saved_objects_service.mock'; -import { savedObjectsClientMock } from 'src/core/server/saved_objects/service/saved_objects_client.mock'; import { SavedObjectsClientContract } from 'src/core/server'; +import { EncryptedSavedObjectsService } from '../crypto'; +import { EncryptedSavedObjectsClientWrapper } from './encrypted_saved_objects_client_wrapper'; + +import { savedObjectsClientMock } from 'src/core/server/mocks'; +import { encryptedSavedObjectsServiceMock } from '../crypto/index.mock'; let wrapper: EncryptedSavedObjectsClientWrapper; let mockBaseClient: jest.Mocked; -let encryptedSavedObjectsServiceMock: jest.Mocked; +let encryptedSavedObjectsServiceMockInstance: jest.Mocked; beforeEach(() => { mockBaseClient = savedObjectsClientMock.create(); - encryptedSavedObjectsServiceMock = createEncryptedSavedObjectsServiceMock([ + encryptedSavedObjectsServiceMockInstance = encryptedSavedObjectsServiceMock.create([ { type: 'known-type', attributesToEncrypt: new Set(['attrSecret']), @@ -25,7 +26,7 @@ beforeEach(() => { ]); wrapper = new EncryptedSavedObjectsClientWrapper({ - service: encryptedSavedObjectsServiceMock, + service: encryptedSavedObjectsServiceMockInstance, baseClient: mockBaseClient, } as any); }); @@ -76,8 +77,8 @@ describe('#create', () => { attributes: { attrOne: 'one', attrThree: 'three' }, }); - expect(encryptedSavedObjectsServiceMock.encryptAttributes).toHaveBeenCalledTimes(1); - expect(encryptedSavedObjectsServiceMock.encryptAttributes).toHaveBeenCalledWith( + expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledTimes(1); + expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledWith( { type: 'known-type', id: 'uuid-v4-id' }, { attrOne: 'one', attrSecret: 'secret', attrThree: 'three' } ); @@ -107,8 +108,8 @@ describe('#create', () => { attributes: { attrOne: 'one', attrThree: 'three' }, }); - expect(encryptedSavedObjectsServiceMock.encryptAttributes).toHaveBeenCalledTimes(1); - expect(encryptedSavedObjectsServiceMock.encryptAttributes).toHaveBeenCalledWith( + expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledTimes(1); + expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledWith( { type: 'known-type', id: 'uuid-v4-id', namespace: 'some-namespace' }, { attrOne: 'one', attrSecret: 'secret', attrThree: 'three' } ); @@ -236,8 +237,8 @@ describe('#bulkCreate', () => { ], }); - expect(encryptedSavedObjectsServiceMock.encryptAttributes).toHaveBeenCalledTimes(1); - expect(encryptedSavedObjectsServiceMock.encryptAttributes).toHaveBeenCalledWith( + expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledTimes(1); + expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledWith( { type: 'known-type', id: 'uuid-v4-id' }, { attrOne: 'one', attrSecret: 'secret', attrThree: 'three' } ); @@ -272,8 +273,8 @@ describe('#bulkCreate', () => { ], }); - expect(encryptedSavedObjectsServiceMock.encryptAttributes).toHaveBeenCalledTimes(1); - expect(encryptedSavedObjectsServiceMock.encryptAttributes).toHaveBeenCalledWith( + expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledTimes(1); + expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledWith( { type: 'known-type', id: 'uuid-v4-id', namespace: 'some-namespace' }, { attrOne: 'one', attrSecret: 'secret', attrThree: 'three' } ); @@ -390,12 +391,12 @@ describe('#bulkUpdate', () => { ], }); - expect(encryptedSavedObjectsServiceMock.encryptAttributes).toHaveBeenCalledTimes(2); - expect(encryptedSavedObjectsServiceMock.encryptAttributes).toHaveBeenCalledWith( + expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledTimes(2); + expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledWith( { type: 'known-type', id: 'some-id' }, { attrOne: 'one', attrSecret: 'secret', attrThree: 'three' } ); - expect(encryptedSavedObjectsServiceMock.encryptAttributes).toHaveBeenCalledWith( + expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledWith( { type: 'known-type', id: 'some-id-2' }, { attrOne: 'one 2', attrSecret: 'secret 2', attrThree: 'three 2' } ); @@ -459,8 +460,8 @@ describe('#bulkUpdate', () => { ], }); - expect(encryptedSavedObjectsServiceMock.encryptAttributes).toHaveBeenCalledTimes(1); - expect(encryptedSavedObjectsServiceMock.encryptAttributes).toHaveBeenCalledWith( + expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledTimes(1); + expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledWith( { type: 'known-type', id: 'some-id', namespace: 'some-namespace' }, { attrOne: 'one', attrSecret: 'secret', attrThree: 'three' } ); @@ -822,8 +823,8 @@ describe('#update', () => { attributes: { attrOne: 'one', attrThree: 'three' }, }); - expect(encryptedSavedObjectsServiceMock.encryptAttributes).toHaveBeenCalledTimes(1); - expect(encryptedSavedObjectsServiceMock.encryptAttributes).toHaveBeenCalledWith( + expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledTimes(1); + expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledWith( { type: 'known-type', id: 'some-id' }, { attrOne: 'one', attrSecret: 'secret', attrThree: 'three' } ); @@ -849,8 +850,8 @@ describe('#update', () => { attributes: { attrOne: 'one', attrThree: 'three' }, }); - expect(encryptedSavedObjectsServiceMock.encryptAttributes).toHaveBeenCalledTimes(1); - expect(encryptedSavedObjectsServiceMock.encryptAttributes).toHaveBeenCalledWith( + expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledTimes(1); + expect(encryptedSavedObjectsServiceMockInstance.encryptAttributes).toHaveBeenCalledWith( { type: 'known-type', id: 'some-id', namespace: 'some-namespace' }, { attrOne: 'one', attrSecret: 'secret', attrThree: 'three' } ); diff --git a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.ts b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.ts index 7fa066aa3355c..1e439b68f8c30 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.ts @@ -21,7 +21,7 @@ import { SavedObjectsUpdateOptions, SavedObjectsUpdateResponse, } from 'src/core/server'; -import { EncryptedSavedObjectsService } from './encrypted_saved_objects_service'; +import { EncryptedSavedObjectsService } from '../crypto'; interface EncryptedSavedObjectsClientOptions { baseClient: SavedObjectsClientContract; diff --git a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts index e60342ebca54d..c12358b124215 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts @@ -4,10 +4,64 @@ * you may not use this file except in compliance with the Elastic License. */ -export { - EncryptedSavedObjectsService, - EncryptedSavedObjectTypeRegistration, -} from './encrypted_saved_objects_service'; -export { EncryptionError } from './encryption_error'; -export { EncryptedSavedObjectsAuditLogger } from './encrypted_saved_objects_audit_logger'; -export { EncryptedSavedObjectsClientWrapper } from './encrypted_saved_objects_client_wrapper'; +import { + IClusterClient, + SavedObject, + SavedObjectAttributes, + SavedObjectsBaseOptions, +} from 'src/core/server'; +import { LegacyAPI } from '../plugin'; +import { EncryptedSavedObjectsService } from '../crypto'; +import { EncryptedSavedObjectsClientWrapper } from './encrypted_saved_objects_client_wrapper'; + +interface SetupSavedObjectsParams { + adminClusterClient: IClusterClient; + service: PublicMethodsOf; + savedObjects: LegacyAPI['savedObjects']; +} + +export interface SavedObjectsSetup { + getDecryptedAsInternalUser: ( + type: string, + id: string, + options?: SavedObjectsBaseOptions + ) => Promise>; +} + +export function setupSavedObjects({ + adminClusterClient, + service, + savedObjects, +}: SetupSavedObjectsParams): SavedObjectsSetup { + // Register custom saved object client that will encrypt, decrypt and strip saved object + // attributes where appropriate for any saved object repository request. We choose max possible + // priority for this wrapper to allow all other wrappers to set proper `namespace` for the Saved + // Object (e.g. wrapper registered by the Spaces plugin) before we encrypt attributes since + // `namespace` is included into AAD. + savedObjects.addScopedSavedObjectsClientWrapperFactory( + Number.MAX_SAFE_INTEGER, + 'encrypted_saved_objects', + ({ client: baseClient }) => new EncryptedSavedObjectsClientWrapper({ baseClient, service }) + ); + + const internalRepository = savedObjects.getSavedObjectsRepository( + adminClusterClient.callAsInternalUser + ); + + return { + getDecryptedAsInternalUser: async ( + type: string, + id: string, + options?: SavedObjectsBaseOptions + ): Promise> => { + const savedObject = await internalRepository.get(type, id, options); + return { + ...savedObject, + attributes: await service.decryptAttributes( + { type, id, namespace: options && options.namespace }, + savedObject.attributes + ), + }; + }, + }; +} diff --git a/x-pack/test/plugin_api_integration/plugins/encrypted_saved_objects/index.ts b/x-pack/test/plugin_api_integration/plugins/encrypted_saved_objects/index.ts index 7b39c236ec543..b20ae5963fcac 100644 --- a/x-pack/test/plugin_api_integration/plugins/encrypted_saved_objects/index.ts +++ b/x-pack/test/plugin_api_integration/plugins/encrypted_saved_objects/index.ts @@ -7,6 +7,10 @@ import { Request } from 'hapi'; import { boomify, badRequest } from 'boom'; import { Legacy } from 'kibana'; +import { + PluginSetupContract, + PluginStartContract, +} from '../../../../plugins/encrypted_saved_objects/server'; const SAVED_OBJECT_WITH_SECRET_TYPE = 'saved-object-with-secret'; @@ -21,15 +25,17 @@ export default function esoPlugin(kibana: any) { method: 'GET', path: '/api/saved_objects/get-decrypted-as-internal-user/{id}', async handler(request: Request) { + const encryptedSavedObjectsStart = server.newPlatform.start.plugins + .encrypted_saved_objects as PluginStartContract; const namespace = server.plugins.spaces && server.plugins.spaces.getSpaceId(request); try { - return await (server.plugins as any).encrypted_saved_objects.getDecryptedAsInternalUser( + return await encryptedSavedObjectsStart.getDecryptedAsInternalUser( SAVED_OBJECT_WITH_SECRET_TYPE, request.params.id, { namespace: namespace === 'default' ? undefined : namespace } ); } catch (err) { - if ((server.plugins as any).encrypted_saved_objects.isEncryptionError(err)) { + if (encryptedSavedObjectsStart.isEncryptionError(err)) { return badRequest('Failed to encrypt attributes'); } @@ -38,7 +44,8 @@ export default function esoPlugin(kibana: any) { }, }); - (server.plugins as any).encrypted_saved_objects.registerType({ + (server.newPlatform.setup.plugins + .encrypted_saved_objects as PluginSetupContract).registerType({ type: SAVED_OBJECT_WITH_SECRET_TYPE, attributesToEncrypt: new Set(['privateProperty']), attributesToExcludeFromAAD: new Set(['publicPropertyExcludedFromAAD']), diff --git a/x-pack/test/typings/hapi.d.ts b/x-pack/test/typings/hapi.d.ts index f12e3c0c1c763..339819798b480 100644 --- a/x-pack/test/typings/hapi.d.ts +++ b/x-pack/test/typings/hapi.d.ts @@ -7,7 +7,6 @@ import 'hapi'; import { CloudPlugin } from '../../legacy/plugins/cloud'; -import { EncryptedSavedObjectsPlugin } from '../../legacy/plugins/encrypted_saved_objects'; import { XPackMainPlugin } from '../../legacy/plugins/xpack_main/xpack_main'; import { SecurityPlugin } from '../../legacy/plugins/security'; import { ActionsPlugin, ActionsClient } from '../../legacy/plugins/actions'; @@ -23,7 +22,6 @@ declare module 'hapi' { cloud?: CloudPlugin; xpack_main: XPackMainPlugin; security?: SecurityPlugin; - encrypted_saved_objects?: EncryptedSavedObjectsPlugin; actions?: ActionsPlugin; alerting?: AlertingPlugin; task_manager?: TaskManager; diff --git a/x-pack/typings/hapi.d.ts b/x-pack/typings/hapi.d.ts index c5c02ef3765a7..1c6ad3a55cb2c 100644 --- a/x-pack/typings/hapi.d.ts +++ b/x-pack/typings/hapi.d.ts @@ -7,7 +7,6 @@ import 'hapi'; import { CloudPlugin } from '../legacy/plugins/cloud'; -import { EncryptedSavedObjectsPlugin } from '../legacy/plugins/encrypted_saved_objects'; import { XPackMainPlugin } from '../legacy/plugins/xpack_main/xpack_main'; import { SecurityPlugin } from '../legacy/plugins/security'; import { ActionsPlugin, ActionsClient } from '../legacy/plugins/actions'; @@ -23,7 +22,6 @@ declare module 'hapi' { cloud?: CloudPlugin; xpack_main: XPackMainPlugin; security?: SecurityPlugin; - encrypted_saved_objects?: EncryptedSavedObjectsPlugin; actions?: ActionsPlugin; alerting?: AlertingPlugin; task_manager?: TaskManager; From cfc031cd56a2cafe77c7a9fb3d388e9d9be57b45 Mon Sep 17 00:00:00 2001 From: Aleh Zasypkin Date: Thu, 31 Oct 2019 17:15:17 +0100 Subject: [PATCH 3/7] Changes in other plugins. --- .../server/lib/action_executor.test.ts | 4 ++-- .../actions/server/lib/action_executor.ts | 2 +- .../server/lib/task_runner_factory.test.ts | 4 ++-- .../actions/server/lib/task_runner_factory.ts | 2 +- .../actions/server/routes/_mock_server.ts | 20 +++++++++++++------ x-pack/legacy/plugins/actions/server/shim.ts | 17 ++++++++-------- .../server/lib/task_runner_factory.test.ts | 4 ++-- .../server/lib/task_runner_factory.ts | 2 +- x-pack/legacy/plugins/alerting/server/shim.ts | 17 ++++++++-------- 9 files changed, 39 insertions(+), 33 deletions(-) diff --git a/x-pack/legacy/plugins/actions/server/lib/action_executor.test.ts b/x-pack/legacy/plugins/actions/server/lib/action_executor.test.ts index c724717bef9eb..5ed67ae82b0ce 100644 --- a/x-pack/legacy/plugins/actions/server/lib/action_executor.test.ts +++ b/x-pack/legacy/plugins/actions/server/lib/action_executor.test.ts @@ -8,7 +8,7 @@ import Hapi from 'hapi'; import { schema } from '@kbn/config-schema'; import { ActionExecutor } from './action_executor'; import { actionTypeRegistryMock } from '../action_type_registry.mock'; -import { encryptedSavedObjectsMock } from '../../../encrypted_saved_objects/server/plugin.mock'; +import { encryptedSavedObjectsMock } from '../../../../../plugins/encrypted_saved_objects/server/mocks'; import { savedObjectsClientMock, loggingServiceMock, @@ -24,7 +24,7 @@ function getServices() { callCluster: jest.fn(), }; } -const encryptedSavedObjectsPlugin = encryptedSavedObjectsMock.create(); +const encryptedSavedObjectsPlugin = encryptedSavedObjectsMock.createStart(); const actionTypeRegistry = actionTypeRegistryMock.create(); const executeParams = { diff --git a/x-pack/legacy/plugins/actions/server/lib/action_executor.ts b/x-pack/legacy/plugins/actions/server/lib/action_executor.ts index aef389262f884..b7d4ea96ea0f8 100644 --- a/x-pack/legacy/plugins/actions/server/lib/action_executor.ts +++ b/x-pack/legacy/plugins/actions/server/lib/action_executor.ts @@ -5,7 +5,7 @@ */ import Hapi from 'hapi'; -import { EncryptedSavedObjectsStartContract } from '../shim'; +import { PluginStartContract as EncryptedSavedObjectsStartContract } from '../../../../../plugins/encrypted_saved_objects/server'; import { LegacySpacesPlugin as SpacesPluginStartContract } from '../../../spaces'; import { Logger } from '../../../../../../src/core/server'; import { validateParams, validateConfig, validateSecrets } from './validate_with_schema'; diff --git a/x-pack/legacy/plugins/actions/server/lib/task_runner_factory.test.ts b/x-pack/legacy/plugins/actions/server/lib/task_runner_factory.test.ts index 6411bc7462c9f..3e71725713070 100644 --- a/x-pack/legacy/plugins/actions/server/lib/task_runner_factory.test.ts +++ b/x-pack/legacy/plugins/actions/server/lib/task_runner_factory.test.ts @@ -11,7 +11,7 @@ import { ConcreteTaskInstance, TaskStatus } from '../../../task_manager'; import { TaskRunnerFactory } from './task_runner_factory'; import { actionTypeRegistryMock } from '../action_type_registry.mock'; import { actionExecutorMock } from './action_executor.mock'; -import { encryptedSavedObjectsMock } from '../../../encrypted_saved_objects/server/plugin.mock'; +import { encryptedSavedObjectsMock } from '../../../../../plugins/encrypted_saved_objects/server/mocks'; import { savedObjectsClientMock, loggingServiceMock, @@ -19,7 +19,7 @@ import { const spaceIdToNamespace = jest.fn(); const actionTypeRegistry = actionTypeRegistryMock.create(); -const mockedEncryptedSavedObjectsPlugin = encryptedSavedObjectsMock.create(); +const mockedEncryptedSavedObjectsPlugin = encryptedSavedObjectsMock.createStart(); const mockedActionExecutor = actionExecutorMock.create(); let fakeTimer: sinon.SinonFakeTimers; diff --git a/x-pack/legacy/plugins/actions/server/lib/task_runner_factory.ts b/x-pack/legacy/plugins/actions/server/lib/task_runner_factory.ts index efe9ce7fa8be5..c0cca22b2c3eb 100644 --- a/x-pack/legacy/plugins/actions/server/lib/task_runner_factory.ts +++ b/x-pack/legacy/plugins/actions/server/lib/task_runner_factory.ts @@ -7,7 +7,7 @@ import { ActionExecutorContract } from './action_executor'; import { ExecutorError } from './executor_error'; import { RunContext } from '../../../task_manager'; -import { EncryptedSavedObjectsStartContract } from '../shim'; +import { PluginStartContract as EncryptedSavedObjectsStartContract } from '../../../../../plugins/encrypted_saved_objects/server'; import { ActionTaskParams, GetBasePathFunction, SpaceIdToNamespaceFunction } from '../types'; export interface TaskRunnerContext { diff --git a/x-pack/legacy/plugins/actions/server/routes/_mock_server.ts b/x-pack/legacy/plugins/actions/server/routes/_mock_server.ts index 7f2341c1aa010..e08c5060eb74d 100644 --- a/x-pack/legacy/plugins/actions/server/routes/_mock_server.ts +++ b/x-pack/legacy/plugins/actions/server/routes/_mock_server.ts @@ -8,7 +8,7 @@ import Hapi from 'hapi'; import { savedObjectsClientMock } from '../../../../../../src/core/server/mocks'; import { actionsClientMock } from '../actions_client.mock'; import { actionTypeRegistryMock } from '../action_type_registry.mock'; -import { encryptedSavedObjectsMock } from '../../../encrypted_saved_objects/server/plugin.mock'; +import { encryptedSavedObjectsMock } from '../../../../../plugins/encrypted_saved_objects/server/mocks'; const defaultConfig = { 'kibana.index': '.kibana', @@ -22,7 +22,8 @@ export function createMockServer(config: Record = defaultConfig) { const actionsClient = actionsClientMock.create(); const actionTypeRegistry = actionTypeRegistryMock.create(); const savedObjectsClient = savedObjectsClientMock.create(); - const encryptedSavedObjects = encryptedSavedObjectsMock.create(); + const encryptedSavedObjectsSetup = encryptedSavedObjectsMock.createSetup(); + const encryptedSavedObjectsStart = encryptedSavedObjectsMock.createStart(); server.config = () => { return { @@ -52,11 +53,11 @@ export function createMockServer(config: Record = defaultConfig) { server.register({ name: 'encrypted_saved_objects', register(pluginServer: Hapi.Server) { - pluginServer.expose('isEncryptionError', encryptedSavedObjects.isEncryptionError); - pluginServer.expose('registerType', encryptedSavedObjects.registerType); + pluginServer.expose('isEncryptionError', encryptedSavedObjectsStart.isEncryptionError); + pluginServer.expose('registerType', encryptedSavedObjectsSetup.registerType); pluginServer.expose( 'getDecryptedAsInternalUser', - encryptedSavedObjects.getDecryptedAsInternalUser + encryptedSavedObjectsStart.getDecryptedAsInternalUser ); }, }); @@ -65,5 +66,12 @@ export function createMockServer(config: Record = defaultConfig) { server.decorate('request', 'getActionsClient', () => actionsClient); server.decorate('request', 'getBasePath', () => '/s/my-space'); - return { server, savedObjectsClient, actionsClient, actionTypeRegistry, encryptedSavedObjects }; + return { + server, + savedObjectsClient, + actionsClient, + actionTypeRegistry, + encryptedSavedObjectsSetup, + encryptedSavedObjectsStart, + }; } diff --git a/x-pack/legacy/plugins/actions/server/shim.ts b/x-pack/legacy/plugins/actions/server/shim.ts index c457a40a78b67..623b6c5330bd1 100644 --- a/x-pack/legacy/plugins/actions/server/shim.ts +++ b/x-pack/legacy/plugins/actions/server/shim.ts @@ -12,7 +12,10 @@ import { TaskManager } from '../../task_manager'; import { XPackMainPlugin } from '../../xpack_main/xpack_main'; import KbnServer from '../../../../../src/legacy/server/kbn_server'; import { LegacySpacesPlugin as SpacesPluginStartContract } from '../../spaces'; -import { EncryptedSavedObjectsPlugin } from '../../encrypted_saved_objects'; +import { + PluginSetupContract as EncryptedSavedObjectsSetupContract, + PluginStartContract as EncryptedSavedObjectsStartContract, +} from '../../../../plugins/encrypted_saved_objects/server'; import { PluginSetupContract as SecurityPlugin } from '../../../../plugins/security/server'; import { CoreSetup, @@ -24,7 +27,6 @@ import { // due to being marked as dependencies interface Plugins extends Hapi.PluginProperties { task_manager: TaskManager; - encrypted_saved_objects: EncryptedSavedObjectsPlugin; } export interface Server extends Legacy.Server { @@ -38,15 +40,10 @@ export type TaskManagerStartContract = Pick; export type SecurityPluginSetupContract = Pick; export type SecurityPluginStartContract = Pick; -export type EncryptedSavedObjectsSetupContract = Pick; export type TaskManagerSetupContract = Pick< TaskManager, 'addMiddleware' | 'registerTaskDefinitions' >; -export type EncryptedSavedObjectsStartContract = Pick< - EncryptedSavedObjectsPlugin, - 'isEncryptionError' | 'getDecryptedAsInternalUser' ->; /** * New platform interfaces @@ -126,7 +123,8 @@ export function shim( security: newPlatform.setup.plugins.security as SecurityPluginSetupContract | undefined, task_manager: server.plugins.task_manager, xpack_main: server.plugins.xpack_main, - encrypted_saved_objects: server.plugins.encrypted_saved_objects, + encrypted_saved_objects: newPlatform.setup.plugins + .encrypted_saved_objects as EncryptedSavedObjectsSetupContract, }; const pluginsStart: ActionsPluginsStart = { @@ -134,7 +132,8 @@ export function shim( // TODO: Currently a function because it's an optional dependency that // initializes after this function is called spaces: () => server.plugins.spaces, - encrypted_saved_objects: server.plugins.encrypted_saved_objects, + encrypted_saved_objects: newPlatform.start.plugins + .encrypted_saved_objects as EncryptedSavedObjectsStartContract, task_manager: server.plugins.task_manager, }; diff --git a/x-pack/legacy/plugins/alerting/server/lib/task_runner_factory.test.ts b/x-pack/legacy/plugins/alerting/server/lib/task_runner_factory.test.ts index 23591692bca1f..dcc74ed9488ce 100644 --- a/x-pack/legacy/plugins/alerting/server/lib/task_runner_factory.test.ts +++ b/x-pack/legacy/plugins/alerting/server/lib/task_runner_factory.test.ts @@ -9,7 +9,7 @@ import { schema } from '@kbn/config-schema'; import { AlertExecutorOptions } from '../types'; import { ConcreteTaskInstance } from '../../../task_manager'; import { TaskRunnerContext, TaskRunnerFactory } from './task_runner_factory'; -import { encryptedSavedObjectsMock } from '../../../encrypted_saved_objects/server/plugin.mock'; +import { encryptedSavedObjectsMock } from '../../../../../plugins/encrypted_saved_objects/server/mocks'; import { savedObjectsClientMock, loggingServiceMock, @@ -52,7 +52,7 @@ beforeAll(() => { afterAll(() => fakeTimer.restore()); const savedObjectsClient = savedObjectsClientMock.create(); -const encryptedSavedObjectsPlugin = encryptedSavedObjectsMock.create(); +const encryptedSavedObjectsPlugin = encryptedSavedObjectsMock.createStart(); const services = { log: jest.fn(), callCluster: jest.fn(), diff --git a/x-pack/legacy/plugins/alerting/server/lib/task_runner_factory.ts b/x-pack/legacy/plugins/alerting/server/lib/task_runner_factory.ts index ca11dc8533996..0c6bd1b4a777a 100644 --- a/x-pack/legacy/plugins/alerting/server/lib/task_runner_factory.ts +++ b/x-pack/legacy/plugins/alerting/server/lib/task_runner_factory.ts @@ -11,7 +11,7 @@ import { createAlertInstanceFactory } from './create_alert_instance_factory'; import { AlertInstance } from './alert_instance'; import { getNextRunAt } from './get_next_run_at'; import { validateAlertTypeParams } from './validate_alert_type_params'; -import { EncryptedSavedObjectsStartContract } from '../shim'; +import { PluginStartContract as EncryptedSavedObjectsStartContract } from '../../../../../plugins/encrypted_saved_objects/server'; import { PluginStartContract as ActionsPluginStartContract } from '../../../actions'; import { AlertType, diff --git a/x-pack/legacy/plugins/alerting/server/shim.ts b/x-pack/legacy/plugins/alerting/server/shim.ts index c977fda451df1..a18c1e86b0adc 100644 --- a/x-pack/legacy/plugins/alerting/server/shim.ts +++ b/x-pack/legacy/plugins/alerting/server/shim.ts @@ -10,7 +10,10 @@ import { LegacySpacesPlugin as SpacesPluginStartContract } from '../../spaces'; import { TaskManager } from '../../task_manager'; import { XPackMainPlugin } from '../../xpack_main/xpack_main'; import KbnServer from '../../../../../src/legacy/server/kbn_server'; -import { EncryptedSavedObjectsPlugin } from '../../encrypted_saved_objects'; +import { + PluginSetupContract as EncryptedSavedObjectsSetupContract, + PluginStartContract as EncryptedSavedObjectsStartContract, +} from '../../../../plugins/encrypted_saved_objects/server'; import { PluginSetupContract as SecurityPlugin } from '../../../../plugins/security/server'; import { CoreSetup, @@ -28,7 +31,6 @@ import { interface Plugins extends Hapi.PluginProperties { actions: ActionsPlugin; task_manager: TaskManager; - encrypted_saved_objects: EncryptedSavedObjectsPlugin; } export interface Server extends Legacy.Server { @@ -41,16 +43,11 @@ export interface Server extends Legacy.Server { export type TaskManagerStartContract = Pick; export type SecurityPluginSetupContract = Pick; export type SecurityPluginStartContract = Pick; -export type EncryptedSavedObjectsSetupContract = Pick; export type XPackMainPluginSetupContract = Pick; export type TaskManagerSetupContract = Pick< TaskManager, 'addMiddleware' | 'registerTaskDefinitions' >; -export type EncryptedSavedObjectsStartContract = Pick< - EncryptedSavedObjectsPlugin, - 'isEncryptionError' | 'getDecryptedAsInternalUser' ->; /** * New platform interfaces @@ -122,7 +119,8 @@ export function shim( task_manager: server.plugins.task_manager, actions: server.plugins.actions.setup, xpack_main: server.plugins.xpack_main, - encrypted_saved_objects: server.plugins.encrypted_saved_objects, + encrypted_saved_objects: newPlatform.setup.plugins + .encrypted_saved_objects as EncryptedSavedObjectsSetupContract, }; const pluginsStart: AlertingPluginsStart = { @@ -131,7 +129,8 @@ export function shim( // TODO: Currently a function because it's an optional dependency that // initializes after this function is called spaces: () => server.plugins.spaces, - encrypted_saved_objects: server.plugins.encrypted_saved_objects, + encrypted_saved_objects: newPlatform.start.plugins + .encrypted_saved_objects as EncryptedSavedObjectsStartContract, task_manager: server.plugins.task_manager, }; From 7d1b8d6d10c3e031f4d18424a8434bd12aaa783e Mon Sep 17 00:00:00 2001 From: Aleh Zasypkin Date: Fri, 1 Nov 2019 16:03:49 +0100 Subject: [PATCH 4/7] Review#1: Add code owner for new plugin. --- .github/CODEOWNERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 267691fde8197..67cc181ba93d7 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -44,7 +44,7 @@ /x-pack/test/functional/services/ml.ts @elastic/ml-ui # ML team owns the transform plugin, ES team added here for visibility # because the plugin lives in Kibana's Elasticsearch management section. -/x-pack/legacy/plugins/transform/ @elastic/ml-ui @elastic/es-ui +/x-pack/legacy/plugins/transform/ @elastic/ml-ui @elastic/es-ui # Operations /renovate.json5 @elastic/kibana-operations @@ -69,6 +69,7 @@ /x-pack/legacy/plugins/security/ @elastic/kibana-security /x-pack/legacy/plugins/spaces/ @elastic/kibana-security /x-pack/legacy/plugins/encrypted_saved_objects/ @elastic/kibana-security +/x-pack/plugins/encrypted_saved_objects/ @elastic/kibana-security /src/legacy/server/csp/ @elastic/kibana-security /x-pack/plugins/security/ @elastic/kibana-security /x-pack/test/api_integration/apis/security/ @elastic/kibana-security From bed212cbdd9255f25f67cd46304c1e73cb0aa2c0 Mon Sep 17 00:00:00 2001 From: Aleh Zasypkin Date: Fri, 1 Nov 2019 16:54:12 +0100 Subject: [PATCH 5/7] Review#1: Chnage config prefix and plugin ID to `encryptedSavedObjects`. --- x-pack/legacy/plugins/actions/index.ts | 4 ++-- x-pack/legacy/plugins/actions/server/plugin.ts | 8 ++++---- .../plugins/actions/server/routes/_mock_server.ts | 12 ------------ x-pack/legacy/plugins/actions/server/shim.ts | 12 ++++++------ x-pack/legacy/plugins/alerting/index.ts | 4 ++-- x-pack/legacy/plugins/alerting/server/plugin.ts | 4 ++-- x-pack/legacy/plugins/alerting/server/shim.ts | 12 ++++++------ .../legacy/plugins/encrypted_saved_objects/index.ts | 8 ++++---- x-pack/plugins/encrypted_saved_objects/README.md | 10 +++++----- x-pack/plugins/encrypted_saved_objects/kibana.json | 4 ++-- .../encrypted_saved_objects/server/config.test.ts | 6 +++--- .../plugins/encrypted_saved_objects/server/config.ts | 4 ++-- .../server/saved_objects/index.ts | 2 +- x-pack/test/functional/config.js | 2 +- .../plugins/encrypted_saved_objects/index.ts | 7 +++---- .../test_suites/encrypted_saved_objects/index.ts | 2 +- 16 files changed, 44 insertions(+), 57 deletions(-) diff --git a/x-pack/legacy/plugins/actions/index.ts b/x-pack/legacy/plugins/actions/index.ts index 7c4dd9f73c11f..a58c936c63749 100644 --- a/x-pack/legacy/plugins/actions/index.ts +++ b/x-pack/legacy/plugins/actions/index.ts @@ -22,10 +22,10 @@ export function actions(kibana: any) { return new kibana.Plugin({ id: 'actions', configPrefix: 'xpack.actions', - require: ['kibana', 'elasticsearch', 'task_manager', 'encrypted_saved_objects'], + require: ['kibana', 'elasticsearch', 'task_manager', 'encryptedSavedObjects'], isEnabled(config: Legacy.KibanaConfig) { return ( - config.get('xpack.encrypted_saved_objects.enabled') === true && + config.get('xpack.encryptedSavedObjects.enabled') === true && config.get('xpack.actions.enabled') === true && config.get('xpack.task_manager.enabled') === true ); diff --git a/x-pack/legacy/plugins/actions/server/plugin.ts b/x-pack/legacy/plugins/actions/server/plugin.ts index 618c1d120c37a..574113858d35c 100644 --- a/x-pack/legacy/plugins/actions/server/plugin.ts +++ b/x-pack/legacy/plugins/actions/server/plugin.ts @@ -92,12 +92,12 @@ export class Plugin { // - `secrets` properties will be encrypted // - `config` will be included in AAD // - everything else excluded from AAD - plugins.encrypted_saved_objects.registerType({ + plugins.encryptedSavedObjects.registerType({ type: 'action', attributesToEncrypt: new Set(['secrets']), attributesToExcludeFromAAD: new Set(['description']), }); - plugins.encrypted_saved_objects.registerType({ + plugins.encryptedSavedObjects.registerType({ type: 'action_task_params', attributesToEncrypt: new Set(['apiKey']), }); @@ -163,11 +163,11 @@ export class Plugin { logger, spaces: plugins.spaces, getServices, - encryptedSavedObjectsPlugin: plugins.encrypted_saved_objects, + encryptedSavedObjectsPlugin: plugins.encryptedSavedObjects, actionTypeRegistry: actionTypeRegistry!, }); taskRunnerFactory!.initialize({ - encryptedSavedObjectsPlugin: plugins.encrypted_saved_objects, + encryptedSavedObjectsPlugin: plugins.encryptedSavedObjects, getBasePath, spaceIdToNamespace, }); diff --git a/x-pack/legacy/plugins/actions/server/routes/_mock_server.ts b/x-pack/legacy/plugins/actions/server/routes/_mock_server.ts index e08c5060eb74d..23356cedb3ab8 100644 --- a/x-pack/legacy/plugins/actions/server/routes/_mock_server.ts +++ b/x-pack/legacy/plugins/actions/server/routes/_mock_server.ts @@ -50,18 +50,6 @@ export function createMockServer(config: Record = defaultConfig) { }, }); - server.register({ - name: 'encrypted_saved_objects', - register(pluginServer: Hapi.Server) { - pluginServer.expose('isEncryptionError', encryptedSavedObjectsStart.isEncryptionError); - pluginServer.expose('registerType', encryptedSavedObjectsSetup.registerType); - pluginServer.expose( - 'getDecryptedAsInternalUser', - encryptedSavedObjectsStart.getDecryptedAsInternalUser - ); - }, - }); - server.decorate('request', 'getSavedObjectsClient', () => savedObjectsClient); server.decorate('request', 'getActionsClient', () => actionsClient); server.decorate('request', 'getBasePath', () => '/s/my-space'); diff --git a/x-pack/legacy/plugins/actions/server/shim.ts b/x-pack/legacy/plugins/actions/server/shim.ts index 623b6c5330bd1..ee32face2ceb4 100644 --- a/x-pack/legacy/plugins/actions/server/shim.ts +++ b/x-pack/legacy/plugins/actions/server/shim.ts @@ -70,12 +70,12 @@ export interface ActionsPluginsSetup { security?: SecurityPluginSetupContract; task_manager: TaskManagerSetupContract; xpack_main: XPackMainPluginSetupContract; - encrypted_saved_objects: EncryptedSavedObjectsSetupContract; + encryptedSavedObjects: EncryptedSavedObjectsSetupContract; } export interface ActionsPluginsStart { security?: SecurityPluginStartContract; spaces: () => SpacesPluginStartContract | undefined; - encrypted_saved_objects: EncryptedSavedObjectsStartContract; + encryptedSavedObjects: EncryptedSavedObjectsStartContract; task_manager: TaskManagerStartContract; } @@ -123,8 +123,8 @@ export function shim( security: newPlatform.setup.plugins.security as SecurityPluginSetupContract | undefined, task_manager: server.plugins.task_manager, xpack_main: server.plugins.xpack_main, - encrypted_saved_objects: newPlatform.setup.plugins - .encrypted_saved_objects as EncryptedSavedObjectsSetupContract, + encryptedSavedObjects: newPlatform.setup.plugins + .encryptedSavedObjects as EncryptedSavedObjectsSetupContract, }; const pluginsStart: ActionsPluginsStart = { @@ -132,8 +132,8 @@ export function shim( // TODO: Currently a function because it's an optional dependency that // initializes after this function is called spaces: () => server.plugins.spaces, - encrypted_saved_objects: newPlatform.start.plugins - .encrypted_saved_objects as EncryptedSavedObjectsStartContract, + encryptedSavedObjects: newPlatform.start.plugins + .encryptedSavedObjects as EncryptedSavedObjectsStartContract, task_manager: server.plugins.task_manager, }; diff --git a/x-pack/legacy/plugins/alerting/index.ts b/x-pack/legacy/plugins/alerting/index.ts index 22db92baa8d28..b3e33f782688c 100644 --- a/x-pack/legacy/plugins/alerting/index.ts +++ b/x-pack/legacy/plugins/alerting/index.ts @@ -22,12 +22,12 @@ export function alerting(kibana: any) { return new kibana.Plugin({ id: 'alerting', configPrefix: 'xpack.alerting', - require: ['kibana', 'elasticsearch', 'actions', 'task_manager', 'encrypted_saved_objects'], + require: ['kibana', 'elasticsearch', 'actions', 'task_manager', 'encryptedSavedObjects'], isEnabled(config: Legacy.KibanaConfig) { return ( config.get('xpack.alerting.enabled') === true && config.get('xpack.actions.enabled') === true && - config.get('xpack.encrypted_saved_objects.enabled') === true && + config.get('xpack.encryptedSavedObjects.enabled') === true && config.get('xpack.task_manager.enabled') === true ); }, diff --git a/x-pack/legacy/plugins/alerting/server/plugin.ts b/x-pack/legacy/plugins/alerting/server/plugin.ts index d6c6d5907e7ac..c50bc795757f3 100644 --- a/x-pack/legacy/plugins/alerting/server/plugin.ts +++ b/x-pack/legacy/plugins/alerting/server/plugin.ts @@ -85,7 +85,7 @@ export class Plugin { }); // Encrypted attributes - plugins.encrypted_saved_objects.registerType({ + plugins.encryptedSavedObjects.registerType({ type: 'alert', attributesToEncrypt: new Set(['apiKey']), attributesToExcludeFromAAD: new Set([ @@ -147,7 +147,7 @@ export class Plugin { }; }, executeAction: plugins.actions.execute, - encryptedSavedObjectsPlugin: plugins.encrypted_saved_objects, + encryptedSavedObjectsPlugin: plugins.encryptedSavedObjects, spaceIdToNamespace(spaceId?: string): string | undefined { const spacesPlugin = plugins.spaces(); return spacesPlugin && spaceId ? spacesPlugin.spaceIdToNamespace(spaceId) : undefined; diff --git a/x-pack/legacy/plugins/alerting/server/shim.ts b/x-pack/legacy/plugins/alerting/server/shim.ts index a18c1e86b0adc..d86eab2038095 100644 --- a/x-pack/legacy/plugins/alerting/server/shim.ts +++ b/x-pack/legacy/plugins/alerting/server/shim.ts @@ -72,13 +72,13 @@ export interface AlertingPluginsSetup { task_manager: TaskManagerSetupContract; actions: ActionsPluginSetupContract; xpack_main: XPackMainPluginSetupContract; - encrypted_saved_objects: EncryptedSavedObjectsSetupContract; + encryptedSavedObjects: EncryptedSavedObjectsSetupContract; } export interface AlertingPluginsStart { actions: ActionsPluginStartContract; security?: SecurityPluginStartContract; spaces: () => SpacesPluginStartContract | undefined; - encrypted_saved_objects: EncryptedSavedObjectsStartContract; + encryptedSavedObjects: EncryptedSavedObjectsStartContract; task_manager: TaskManagerStartContract; } @@ -119,8 +119,8 @@ export function shim( task_manager: server.plugins.task_manager, actions: server.plugins.actions.setup, xpack_main: server.plugins.xpack_main, - encrypted_saved_objects: newPlatform.setup.plugins - .encrypted_saved_objects as EncryptedSavedObjectsSetupContract, + encryptedSavedObjects: newPlatform.setup.plugins + .encryptedSavedObjects as EncryptedSavedObjectsSetupContract, }; const pluginsStart: AlertingPluginsStart = { @@ -129,8 +129,8 @@ export function shim( // TODO: Currently a function because it's an optional dependency that // initializes after this function is called spaces: () => server.plugins.spaces, - encrypted_saved_objects: newPlatform.start.plugins - .encrypted_saved_objects as EncryptedSavedObjectsStartContract, + encryptedSavedObjects: newPlatform.start.plugins + .encryptedSavedObjects as EncryptedSavedObjectsStartContract, task_manager: server.plugins.task_manager, }; diff --git a/x-pack/legacy/plugins/encrypted_saved_objects/index.ts b/x-pack/legacy/plugins/encrypted_saved_objects/index.ts index eff049f3b3d8d..3969959d03cff 100644 --- a/x-pack/legacy/plugins/encrypted_saved_objects/index.ts +++ b/x-pack/legacy/plugins/encrypted_saved_objects/index.ts @@ -14,8 +14,8 @@ export const encryptedSavedObjects = (kibana: { Plugin: new (options: Legacy.PluginSpecOptions & { configPrefix?: string }) => unknown; }) => new kibana.Plugin({ - id: 'encrypted_saved_objects', - configPrefix: 'xpack.encrypted_saved_objects', + id: 'encryptedSavedObjects', + configPrefix: 'xpack.encryptedSavedObjects', require: ['xpack_main'], // Some legacy plugins still use `enabled` config key, so we keep it here, but the rest of the @@ -27,7 +27,7 @@ export const encryptedSavedObjects = (kibana: { init(server: Legacy.Server) { const encryptedSavedObjectsPlugin = (server.newPlatform.setup.plugins - .encrypted_saved_objects as unknown) as PluginSetupContract; + .encryptedSavedObjects as unknown) as PluginSetupContract; if (!encryptedSavedObjectsPlugin) { throw new Error('New Platform XPack EncryptedSavedObjects plugin is not available.'); } @@ -36,7 +36,7 @@ export const encryptedSavedObjects = (kibana: { savedObjects: server.savedObjects, auditLogger: new AuditLogger( server, - 'encrypted_saved_objects', + 'encryptedSavedObjects', server.config(), server.plugins.xpack_main.info ), diff --git a/x-pack/plugins/encrypted_saved_objects/README.md b/x-pack/plugins/encrypted_saved_objects/README.md index 32caa347cdac4..1dc7f99b7cd0c 100644 --- a/x-pack/plugins/encrypted_saved_objects/README.md +++ b/x-pack/plugins/encrypted_saved_objects/README.md @@ -9,14 +9,14 @@ security and spaces filtering as well as performing audit logging. ## Usage -Follow these steps to use `encrypted_saved_objects` in your plugin: +Follow these steps to use `encryptedSavedObjects` in your plugin: -1. Declare `encrypted_saved_objects` as a dependency in `kibana.json`: +1. Declare `encryptedSavedObjects` as a dependency in `kibana.json`: ```json { ... - "requiredPlugins": ["encrypted_saved_objects"], + "requiredPlugins": [encryptedSavedObjects], ... } ``` @@ -41,7 +41,7 @@ searchable or analyzed: ```typescript ... public setup(core: CoreSetup, { encryptedSavedObjects }: PluginSetupDependencies) { - encrypted_saved_objects.registerType({ + encryptedSavedObjects.registerType({ type: 'my-saved-object-type', attributesToEncrypt: new Set(['mySecret']), }); @@ -77,7 +77,7 @@ and preferably only as a part of the Kibana server routines that are outside of user has control over. ```typescript -const savedObjectWithDecryptedContent = await encrypted_saved_objects.getDecryptedAsInternalUser( +const savedObjectWithDecryptedContent = await encryptedSavedObjects.getDecryptedAsInternalUser( 'my-saved-object-type', 'saved-object-id' ); diff --git a/x-pack/plugins/encrypted_saved_objects/kibana.json b/x-pack/plugins/encrypted_saved_objects/kibana.json index 00dc1eebddeb7..8bf214a4d7c3f 100644 --- a/x-pack/plugins/encrypted_saved_objects/kibana.json +++ b/x-pack/plugins/encrypted_saved_objects/kibana.json @@ -1,8 +1,8 @@ { - "id": "encrypted_saved_objects", + "id": "encryptedSavedObjects", "version": "8.0.0", "kibanaVersion": "kibana", - "configPath": ["xpack", "encrypted_saved_objects"], + "configPath": ["xpack", "encryptedSavedObjects"], "server": true, "ui": false } diff --git a/x-pack/plugins/encrypted_saved_objects/server/config.test.ts b/x-pack/plugins/encrypted_saved_objects/server/config.test.ts index 1e4b109ebf4ef..7d6632aa56cb1 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/config.test.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/config.test.ts @@ -33,7 +33,7 @@ describe('config schema', () => { `); }); - it('should throw error if xpack.encrypted_saved_objects.encryptionKey is less than 32 characters', () => { + it('should throw error if xpack.encryptedSavedObjects.encryptionKey is less than 32 characters', () => { expect(() => ConfigSchema.validate({ encryptionKey: 'foo' }) ).toThrowErrorMatchingInlineSnapshot( @@ -49,7 +49,7 @@ describe('config schema', () => { }); describe('createConfig$()', () => { - it('should log a warning and set xpack.encrypted_saved_objects.encryptionKey if not set', async () => { + it('should log a warning and set xpack.encryptedSavedObjects.encryptionKey if not set', async () => { const mockRandomBytes = jest.requireMock('crypto').randomBytes; mockRandomBytes.mockReturnValue('ab'.repeat(16)); @@ -62,7 +62,7 @@ describe('createConfig$()', () => { expect(loggingServiceMock.collect(contextMock.logger).warn).toMatchInlineSnapshot(` Array [ Array [ - "Generating a random key for xpack.encrypted_saved_objects.encryptionKey. To be able to decrypt encrypted saved objects attributes after restart, please set xpack.encrypted_saved_objects.encryptionKey in kibana.yml", + "Generating a random key for xpack.encryptedSavedObjects.encryptionKey. To be able to decrypt encrypted saved objects attributes after restart, please set xpack.encryptedSavedObjects.encryptionKey in kibana.yml", ], ] `); diff --git a/x-pack/plugins/encrypted_saved_objects/server/config.ts b/x-pack/plugins/encrypted_saved_objects/server/config.ts index dfc5e7493cae0..c755b7dd9f205 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/config.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/config.ts @@ -32,9 +32,9 @@ export function createConfig$(context: PluginInitializerContext) { let encryptionKey = config.encryptionKey; if (encryptionKey === undefined) { logger.warn( - 'Generating a random key for xpack.encrypted_saved_objects.encryptionKey. ' + + 'Generating a random key for xpack.encryptedSavedObjects.encryptionKey. ' + 'To be able to decrypt encrypted saved objects attributes after restart, ' + - 'please set xpack.encrypted_saved_objects.encryptionKey in kibana.yml' + 'please set xpack.encryptedSavedObjects.encryptionKey in kibana.yml' ); encryptionKey = crypto.randomBytes(16).toString('hex'); diff --git a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts index c12358b124215..e5445e187e2cc 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts @@ -40,7 +40,7 @@ export function setupSavedObjects({ // `namespace` is included into AAD. savedObjects.addScopedSavedObjectsClientWrapperFactory( Number.MAX_SAFE_INTEGER, - 'encrypted_saved_objects', + 'encryptedSavedObjects', ({ client: baseClient }) => new EncryptedSavedObjectsClientWrapper({ baseClient, service }) ); diff --git a/x-pack/test/functional/config.js b/x-pack/test/functional/config.js index f8cedc03865bb..d1f03f2c136ff 100644 --- a/x-pack/test/functional/config.js +++ b/x-pack/test/functional/config.js @@ -82,7 +82,7 @@ export default async function ({ readConfigFile }) { '--xpack.reporting.csv.maxSizeBytes=2850', // small-ish limit for cutting off a 1999 byte report '--stats.maximumWaitTimeForAllCollectorsInS=1', '--xpack.security.encryptionKey="wuGNaIhoMpk5sO4UBxgr3NyW1sFcLgIf"', // server restarts should not invalidate active sessions - '--xpack.encrypted_saved_objects.encryptionKey="DkdXazszSCYexXqz4YktBGHCRkV6hyNK"', + '--xpack.encryptedSavedObjects.encryptionKey="DkdXazszSCYexXqz4YktBGHCRkV6hyNK"', '--telemetry.banner=false', '--timelion.ui.enabled=true', ], diff --git a/x-pack/test/plugin_api_integration/plugins/encrypted_saved_objects/index.ts b/x-pack/test/plugin_api_integration/plugins/encrypted_saved_objects/index.ts index b20ae5963fcac..a194e477da755 100644 --- a/x-pack/test/plugin_api_integration/plugins/encrypted_saved_objects/index.ts +++ b/x-pack/test/plugin_api_integration/plugins/encrypted_saved_objects/index.ts @@ -18,7 +18,7 @@ const SAVED_OBJECT_WITH_SECRET_TYPE = 'saved-object-with-secret'; export default function esoPlugin(kibana: any) { return new kibana.Plugin({ id: 'eso', - require: ['encrypted_saved_objects'], + require: ['encryptedSavedObjects'], uiExports: { mappings: require('./mappings.json') }, init(server: Legacy.Server) { server.route({ @@ -26,7 +26,7 @@ export default function esoPlugin(kibana: any) { path: '/api/saved_objects/get-decrypted-as-internal-user/{id}', async handler(request: Request) { const encryptedSavedObjectsStart = server.newPlatform.start.plugins - .encrypted_saved_objects as PluginStartContract; + .encryptedSavedObjects as PluginStartContract; const namespace = server.plugins.spaces && server.plugins.spaces.getSpaceId(request); try { return await encryptedSavedObjectsStart.getDecryptedAsInternalUser( @@ -44,8 +44,7 @@ export default function esoPlugin(kibana: any) { }, }); - (server.newPlatform.setup.plugins - .encrypted_saved_objects as PluginSetupContract).registerType({ + (server.newPlatform.setup.plugins.encryptedSavedObjects as PluginSetupContract).registerType({ type: SAVED_OBJECT_WITH_SECRET_TYPE, attributesToEncrypt: new Set(['privateProperty']), attributesToExcludeFromAAD: new Set(['publicPropertyExcludedFromAAD']), diff --git a/x-pack/test/plugin_api_integration/test_suites/encrypted_saved_objects/index.ts b/x-pack/test/plugin_api_integration/test_suites/encrypted_saved_objects/index.ts index 834e0225d0fb6..424160e84495e 100644 --- a/x-pack/test/plugin_api_integration/test_suites/encrypted_saved_objects/index.ts +++ b/x-pack/test/plugin_api_integration/test_suites/encrypted_saved_objects/index.ts @@ -7,7 +7,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function({ loadTestFile }: FtrProviderContext) { - describe('encrypted_saved_objects', function encryptedSavedObjectsSuite() { + describe('encryptedSavedObjects', function encryptedSavedObjectsSuite() { this.tags('ciGroup2'); loadTestFile(require.resolve('./encrypted_saved_objects_api')); }); From dccd3bda98c3a2ef246e2495acbfc87cc3c92e37 Mon Sep 17 00:00:00 2001 From: Aleh Zasypkin Date: Fri, 1 Nov 2019 17:09:42 +0100 Subject: [PATCH 6/7] Review#1: Fix the wrong check for the absence of AAD attributes. --- .../server/crypto/encrypted_saved_objects_service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.ts b/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.ts index 7fc2e24ffd260..94c1684529577 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.ts @@ -294,7 +294,7 @@ export class EncryptedSavedObjectsService { } } - if (Object.keys(attributesAAD).length) { + if (Object.keys(attributesAAD).length === 0) { this.logger.debug( `The AAD for saved object "${descriptorToArray( descriptor From 345681d9be0f459b93ab1b4e7b0260bae14239ed Mon Sep 17 00:00:00 2001 From: Aleh Zasypkin Date: Fri, 1 Nov 2019 21:13:10 +0100 Subject: [PATCH 7/7] Update x-pack/plugins/encrypted_saved_objects/README.md Co-Authored-By: Larry Gregory --- x-pack/plugins/encrypted_saved_objects/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/encrypted_saved_objects/README.md b/x-pack/plugins/encrypted_saved_objects/README.md index 1dc7f99b7cd0c..a352989870079 100644 --- a/x-pack/plugins/encrypted_saved_objects/README.md +++ b/x-pack/plugins/encrypted_saved_objects/README.md @@ -16,7 +16,7 @@ Follow these steps to use `encryptedSavedObjects` in your plugin: ```json { ... - "requiredPlugins": [encryptedSavedObjects], + "requiredPlugins": ["encryptedSavedObjects"], ... } ```