[Security into Core] expose authc.getCurrentUser from core.security (#177976)

## Summary

First part of https://github.com/elastic/kibana/issues/174578

- Introduce the new `security` core service, both on the browser and
server-side.
- In this first stage, this service only has a single API:
`authc.getCurrentUser`
- Have the security plugin register its API to Core for ex-exposition

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Pierre Gayvallet 2024-03-14 13:31:18 +01:00 committed by GitHub
parent e46ddb1a5f
commit b816af44a4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
141 changed files with 1901 additions and 124 deletions

7
.github/CODEOWNERS vendored
View file

@ -277,6 +277,13 @@ packages/core/saved-objects/core-saved-objects-server @elastic/kibana-core
packages/core/saved-objects/core-saved-objects-server-internal @elastic/kibana-core
packages/core/saved-objects/core-saved-objects-server-mocks @elastic/kibana-core
packages/core/saved-objects/core-saved-objects-utils-server @elastic/kibana-core
packages/core/security/core-security-browser @elastic/kibana-core
packages/core/security/core-security-browser-internal @elastic/kibana-core
packages/core/security/core-security-browser-mocks @elastic/kibana-core
packages/core/security/core-security-common @elastic/kibana-core @elastic/kibana-security
packages/core/security/core-security-server @elastic/kibana-core
packages/core/security/core-security-server-internal @elastic/kibana-core
packages/core/security/core-security-server-mocks @elastic/kibana-core
packages/core/status/core-status-common @elastic/kibana-core
packages/core/status/core-status-common-internal @elastic/kibana-core
packages/core/status/core-status-server @elastic/kibana-core

View file

@ -338,6 +338,13 @@
"@kbn/core-saved-objects-server": "link:packages/core/saved-objects/core-saved-objects-server",
"@kbn/core-saved-objects-server-internal": "link:packages/core/saved-objects/core-saved-objects-server-internal",
"@kbn/core-saved-objects-utils-server": "link:packages/core/saved-objects/core-saved-objects-utils-server",
"@kbn/core-security-browser": "link:packages/core/security/core-security-browser",
"@kbn/core-security-browser-internal": "link:packages/core/security/core-security-browser-internal",
"@kbn/core-security-browser-mocks": "link:packages/core/security/core-security-browser-mocks",
"@kbn/core-security-common": "link:packages/core/security/core-security-common",
"@kbn/core-security-server": "link:packages/core/security/core-security-server",
"@kbn/core-security-server-internal": "link:packages/core/security/core-security-server-internal",
"@kbn/core-security-server-mocks": "link:packages/core/security/core-security-server-mocks",
"@kbn/core-status-common": "link:packages/core/status/core-status-common",
"@kbn/core-status-common-internal": "link:packages/core/status/core-status-common-internal",
"@kbn/core-status-server": "link:packages/core/status/core-status-server",

View file

@ -6,10 +6,12 @@
* Side Public License, v 1.
*/
import { loggerMock } from '@kbn/logging-mocks';
import { loggerMock, MockedLogger } from '@kbn/logging-mocks';
import type { CoreContext } from '@kbn/core-base-browser-internal';
function createCoreContext({ production = false }: { production?: boolean } = {}): CoreContext {
function createCoreContext({ production = false }: { production?: boolean } = {}): CoreContext & {
logger: MockedLogger;
} {
return {
coreId: Symbol('core context mock'),
logger: loggerMock.create(),

View file

@ -193,3 +193,42 @@ describe('#deprecations', () => {
});
});
});
describe('#security', () => {
describe('#authc', () => {
test('only creates one instance', () => {
const request = httpServerMock.createKibanaRequest();
const coreStart = createCoreRouteHandlerContextParamsMock();
const context = new CoreRouteHandlerContext(coreStart, request);
const authc1 = context.security.authc;
const authc2 = context.security.authc;
expect(authc1).toBe(authc2);
});
describe('getCurrentUser', () => {
test('calls coreStart.security.authc.getCurrentUser with the correct parameters', () => {
const request = httpServerMock.createKibanaRequest();
const coreStart = createCoreRouteHandlerContextParamsMock();
const context = new CoreRouteHandlerContext(coreStart, request);
context.security.authc.getCurrentUser();
expect(coreStart.security.authc.getCurrentUser).toHaveBeenCalledTimes(1);
expect(coreStart.security.authc.getCurrentUser).toHaveBeenCalledWith(request);
});
test('returns the result of coreStart.security.authc.getCurrentUser', () => {
const request = httpServerMock.createKibanaRequest();
const coreStart = createCoreRouteHandlerContextParamsMock();
const context = new CoreRouteHandlerContext(coreStart, request);
const stubUser: any = Symbol.for('stubUser');
coreStart.security.authc.getCurrentUser.mockReturnValue(stubUser);
const user = context.security.authc.getCurrentUser();
expect(user).toBe(stubUser);
});
});
});
});

View file

@ -24,6 +24,10 @@ import {
CoreUiSettingsRouteHandlerContext,
type InternalUiSettingsServiceStart,
} from '@kbn/core-ui-settings-server-internal';
import {
CoreSecurityRouteHandlerContext,
type InternalSecurityServiceStart,
} from '@kbn/core-security-server-internal';
/**
* Subset of `InternalCoreStart` used by {@link CoreRouteHandlerContext}
@ -34,6 +38,7 @@ export interface CoreRouteHandlerContextParams {
savedObjects: InternalSavedObjectsServiceStart;
uiSettings: InternalUiSettingsServiceStart;
deprecations: InternalDeprecationsServiceStart;
security: InternalSecurityServiceStart;
}
/**
@ -42,22 +47,62 @@ export interface CoreRouteHandlerContextParams {
* @internal
*/
export class CoreRouteHandlerContext implements CoreRequestHandlerContext {
readonly elasticsearch: CoreElasticsearchRouteHandlerContext;
readonly savedObjects: CoreSavedObjectsRouteHandlerContext;
readonly uiSettings: CoreUiSettingsRouteHandlerContext;
readonly deprecations: CoreDeprecationsRouteHandlerContext;
#elasticsearch?: CoreElasticsearchRouteHandlerContext;
#savedObjects?: CoreSavedObjectsRouteHandlerContext;
#uiSettings?: CoreUiSettingsRouteHandlerContext;
#deprecations?: CoreDeprecationsRouteHandlerContext;
#security?: CoreSecurityRouteHandlerContext;
constructor(coreStart: CoreRouteHandlerContextParams, request: KibanaRequest) {
this.elasticsearch = new CoreElasticsearchRouteHandlerContext(coreStart.elasticsearch, request);
this.savedObjects = new CoreSavedObjectsRouteHandlerContext(coreStart.savedObjects, request);
this.uiSettings = new CoreUiSettingsRouteHandlerContext(
coreStart.uiSettings,
this.savedObjects
);
this.deprecations = new CoreDeprecationsRouteHandlerContext(
coreStart.deprecations,
this.elasticsearch,
this.savedObjects
);
constructor(
private readonly coreStart: CoreRouteHandlerContextParams,
private readonly request: KibanaRequest
) {}
public get elasticsearch() {
if (!this.#elasticsearch) {
this.#elasticsearch = new CoreElasticsearchRouteHandlerContext(
this.coreStart.elasticsearch,
this.request
);
}
return this.#elasticsearch;
}
public get savedObjects() {
if (!this.#savedObjects) {
this.#savedObjects = new CoreSavedObjectsRouteHandlerContext(
this.coreStart.savedObjects,
this.request
);
}
return this.#savedObjects;
}
public get uiSettings() {
if (!this.#uiSettings) {
this.#uiSettings = new CoreUiSettingsRouteHandlerContext(
this.coreStart.uiSettings,
this.savedObjects
);
}
return this.#uiSettings;
}
public get deprecations() {
if (!this.#deprecations) {
this.#deprecations = new CoreDeprecationsRouteHandlerContext(
this.coreStart.deprecations,
this.elasticsearch,
this.savedObjects
);
}
return this.#deprecations;
}
public get security() {
if (!this.#security) {
this.#security = new CoreSecurityRouteHandlerContext(this.coreStart.security, this.request);
}
return this.#security;
}
}

View file

@ -10,6 +10,7 @@ import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks';
import { savedObjectsServiceMock } from '@kbn/core-saved-objects-server-mocks';
import { uiSettingsServiceMock } from '@kbn/core-ui-settings-server-mocks';
import { deprecationsServiceMock } from '@kbn/core-deprecations-server-mocks';
import { securityServiceMock } from '@kbn/core-security-server-mocks';
export const createCoreRouteHandlerContextParamsMock = () => {
return {
@ -17,5 +18,6 @@ export const createCoreRouteHandlerContextParamsMock = () => {
savedObjects: savedObjectsServiceMock.createInternalStartContract(),
uiSettings: uiSettingsServiceMock.createStartContract(),
deprecations: deprecationsServiceMock.createInternalStartContract(),
security: securityServiceMock.createInternalStart(),
};
};

View file

@ -23,6 +23,8 @@
"@kbn/core-saved-objects-server-mocks",
"@kbn/core-ui-settings-server-mocks",
"@kbn/core-deprecations-server-mocks",
"@kbn/core-security-server-internal",
"@kbn/core-security-server-mocks",
],
"exclude": [
"target/**/*",

View file

@ -11,6 +11,7 @@ import type { ElasticsearchRequestHandlerContext } from '@kbn/core-elasticsearch
import type { SavedObjectsRequestHandlerContext } from '@kbn/core-saved-objects-server';
import type { DeprecationsRequestHandlerContext } from '@kbn/core-deprecations-server';
import type { UiSettingsRequestHandlerContext } from '@kbn/core-ui-settings-server';
import type { SecurityRequestHandlerContext } from '@kbn/core-security-server';
/**
* The `core` context provided to route handler.
@ -31,6 +32,7 @@ export interface CoreRequestHandlerContext {
elasticsearch: ElasticsearchRequestHandlerContext;
uiSettings: UiSettingsRequestHandlerContext;
deprecations: DeprecationsRequestHandlerContext;
security: SecurityRequestHandlerContext;
}
/**

View file

@ -15,7 +15,8 @@
"@kbn/core-elasticsearch-server",
"@kbn/core-saved-objects-server",
"@kbn/core-deprecations-server",
"@kbn/core-ui-settings-server"
"@kbn/core-ui-settings-server",
"@kbn/core-security-server"
],
"exclude": [
"target/**/*",

View file

@ -10,11 +10,13 @@ import type { CoreSetup } from '@kbn/core-lifecycle-browser';
import type { InternalApplicationSetup } from '@kbn/core-application-browser-internal';
import type { InternalInjectedMetadataSetup } from '@kbn/core-injected-metadata-browser-internal';
import type { InternalHttpSetup } from '@kbn/core-http-browser-internal';
import type { InternalSecurityServiceSetup } from '@kbn/core-security-browser-internal';
/** @internal */
export interface InternalCoreSetup
extends Omit<CoreSetup, 'application' | 'plugins' | 'getStartServices' | 'http'> {
extends Omit<CoreSetup, 'application' | 'plugins' | 'getStartServices' | 'http' | 'security'> {
application: InternalApplicationSetup;
injectedMetadata: InternalInjectedMetadataSetup;
http: InternalHttpSetup;
security: InternalSecurityServiceSetup;
}

View file

@ -10,10 +10,13 @@ import type { CoreStart } from '@kbn/core-lifecycle-browser';
import type { InternalApplicationStart } from '@kbn/core-application-browser-internal';
import type { InternalInjectedMetadataStart } from '@kbn/core-injected-metadata-browser-internal';
import type { InternalHttpStart } from '@kbn/core-http-browser-internal';
import type { InternalSecurityServiceStart } from '@kbn/core-security-browser-internal';
/** @internal */
export interface InternalCoreStart extends Omit<CoreStart, 'application' | 'plugins' | 'http'> {
export interface InternalCoreStart
extends Omit<CoreStart, 'application' | 'plugins' | 'http' | 'security'> {
application: InternalApplicationStart;
injectedMetadata: InternalInjectedMetadataStart;
http: InternalHttpStart;
security: InternalSecurityServiceStart;
}

View file

@ -15,7 +15,8 @@
"@kbn/core-lifecycle-browser",
"@kbn/core-application-browser-internal",
"@kbn/core-injected-metadata-browser-internal",
"@kbn/core-http-browser-internal"
"@kbn/core-http-browser-internal",
"@kbn/core-security-browser-internal"
],
"exclude": [
"target/**/*",

View file

@ -17,6 +17,7 @@ import { deprecationsServiceMock } from '@kbn/core-deprecations-browser-mocks';
import { notificationServiceMock } from '@kbn/core-notifications-browser-mocks';
import { applicationServiceMock } from '@kbn/core-application-browser-mocks';
import { customBrandingServiceMock } from '@kbn/core-custom-branding-browser-mocks';
import { securityServiceMock } from '@kbn/core-security-browser-mocks';
import { createCoreStartMock } from './core_start.mock';
export function createCoreSetupMock({
@ -44,6 +45,7 @@ export function createCoreSetupMock({
settings: settingsServiceMock.createSetupContract(),
deprecations: deprecationsServiceMock.createSetupContract(),
theme: themeServiceMock.createSetupContract(),
security: securityServiceMock.createSetup(),
plugins: {
onSetup: jest.fn(),
onStart: jest.fn(),

View file

@ -21,6 +21,7 @@ import { notificationServiceMock } from '@kbn/core-notifications-browser-mocks';
import { applicationServiceMock } from '@kbn/core-application-browser-mocks';
import { chromeServiceMock } from '@kbn/core-chrome-browser-mocks';
import { customBrandingServiceMock } from '@kbn/core-custom-branding-browser-mocks';
import { securityServiceMock } from '@kbn/core-security-browser-mocks';
export function createCoreStartMock({ basePath = '' } = {}) {
const mock = {
@ -40,6 +41,7 @@ export function createCoreStartMock({ basePath = '' } = {}) {
deprecations: deprecationsServiceMock.createStartContract(),
theme: themeServiceMock.createStartContract(),
fatalErrors: fatalErrorsServiceMock.createStartContract(),
security: securityServiceMock.createStart(),
plugins: {
onStart: jest.fn(),
},

View file

@ -26,7 +26,8 @@
"@kbn/core-notifications-browser-mocks",
"@kbn/core-application-browser-mocks",
"@kbn/core-chrome-browser-mocks",
"@kbn/core-custom-branding-browser-mocks"
"@kbn/core-custom-branding-browser-mocks",
"@kbn/core-security-browser-mocks"
],
"exclude": [
"target/**/*",

View file

@ -16,6 +16,7 @@ import type { NotificationsSetup } from '@kbn/core-notifications-browser';
import type { ApplicationSetup } from '@kbn/core-application-browser';
import type { CustomBrandingSetup } from '@kbn/core-custom-branding-browser';
import type { PluginsServiceSetup } from '@kbn/core-plugins-contracts-browser';
import type { SecurityServiceSetup } from '@kbn/core-security-browser';
import type { CoreStart } from './core_start';
/**
@ -56,6 +57,8 @@ export interface CoreSetup<TPluginsStart extends object = object, TStart = unkno
theme: ThemeServiceSetup;
/** {@link PluginsServiceSetup} */
plugins: PluginsServiceSetup;
/** {@link SecurityServiceSetup} */
security: SecurityServiceSetup;
/** {@link StartServicesAccessor} */
getStartServices: StartServicesAccessor<TPluginsStart, TStart>;
}

View file

@ -22,6 +22,7 @@ import type { ApplicationStart } from '@kbn/core-application-browser';
import type { ChromeStart } from '@kbn/core-chrome-browser';
import type { CustomBrandingStart } from '@kbn/core-custom-branding-browser';
import type { PluginsServiceStart } from '@kbn/core-plugins-contracts-browser';
import type { SecurityServiceStart } from '@kbn/core-security-browser';
/**
* Core services exposed to the `Plugin` start lifecycle
@ -71,4 +72,6 @@ export interface CoreStart {
theme: ThemeServiceStart;
/** {@link PluginsServiceStart} */
plugins: PluginsServiceStart;
/** {@link SecurityServiceStart} */
security: SecurityServiceStart;
}

View file

@ -27,7 +27,8 @@
"@kbn/core-saved-objects-browser",
"@kbn/core-chrome-browser",
"@kbn/core-custom-branding-browser",
"@kbn/core-plugins-contracts-browser"
"@kbn/core-plugins-contracts-browser",
"@kbn/core-security-browser"
],
"exclude": [
"target/**/*",

View file

@ -26,6 +26,7 @@ import type { InternalUiSettingsServiceSetup } from '@kbn/core-ui-settings-serve
import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal';
import type { InternalCustomBrandingSetup } from '@kbn/core-custom-branding-server-internal';
import type { InternalUserSettingsServiceSetup } from '@kbn/core-user-settings-server-internal';
import type { InternalSecurityServiceSetup } from '@kbn/core-security-server-internal';
/** @internal */
export interface InternalCoreSetup {
@ -49,4 +50,5 @@ export interface InternalCoreSetup {
coreUsageData: InternalCoreUsageDataSetup;
customBranding: InternalCustomBrandingSetup;
userSettings: InternalUserSettingsServiceSetup;
security: InternalSecurityServiceSetup;
}

View file

@ -18,6 +18,7 @@ import type { InternalSavedObjectsServiceStart } from '@kbn/core-saved-objects-s
import type { InternalUiSettingsServiceStart } from '@kbn/core-ui-settings-server-internal';
import type { CoreUsageDataStart } from '@kbn/core-usage-data-server';
import type { CustomBrandingStart } from '@kbn/core-custom-branding-server';
import type { InternalSecurityServiceStart } from '@kbn/core-security-server-internal';
/**
* @internal
@ -35,4 +36,5 @@ export interface InternalCoreStart {
executionContext: InternalExecutionContextStart;
deprecations: InternalDeprecationsServiceStart;
customBranding: CustomBrandingStart;
security: InternalSecurityServiceStart;
}

View file

@ -33,7 +33,8 @@
"@kbn/core-usage-data-server",
"@kbn/core-custom-branding-server-internal",
"@kbn/core-custom-branding-server",
"@kbn/core-user-settings-server-internal"
"@kbn/core-user-settings-server-internal",
"@kbn/core-security-server-internal"
],
"exclude": [
"target/**/*",

View file

@ -6,13 +6,13 @@
* Side Public License, v 1.
*/
import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks';
import type { RequestHandlerContext } from '@kbn/core-http-request-handler-context-server';
import type { CoreSetup, StartServicesAccessor } from '@kbn/core-lifecycle-server';
import type { MockedKeys } from '@kbn/utility-types-jest';
import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks';
import { httpServiceMock } from '@kbn/core-http-server-mocks';
import { httpResourcesMock } from '@kbn/core-http-resources-server-mocks';
import { uiSettingsServiceMock } from '@kbn/core-ui-settings-server-mocks';
import type { CoreSetup, StartServicesAccessor } from '@kbn/core-lifecycle-server';
import type { MockedKeys } from '@kbn/utility-types-jest';
import { analyticsServiceMock } from '@kbn/core-analytics-server-mocks';
import { capabilitiesServiceMock } from '@kbn/core-capabilities-server-mocks';
import { docLinksServiceMock } from '@kbn/core-doc-links-server-mocks';
@ -25,8 +25,9 @@ import { deprecationsServiceMock } from '@kbn/core-deprecations-server-mocks';
import { executionContextServiceMock } from '@kbn/core-execution-context-server-mocks';
import { coreUsageDataServiceMock } from '@kbn/core-usage-data-server-mocks';
import { customBrandingServiceMock } from '@kbn/core-custom-branding-server-mocks';
import { createCoreStartMock } from './core_start.mock';
import { userSettingsServiceMock } from '@kbn/core-user-settings-server-mocks';
import { securityServiceMock } from '@kbn/core-security-server-mocks';
import { createCoreStartMock } from './core_start.mock';
type CoreSetupMockType = MockedKeys<CoreSetup> & {
elasticsearch: ReturnType<typeof elasticsearchServiceMock.createSetup>;
@ -67,6 +68,7 @@ export function createCoreSetupMock({
metrics: metricsServiceMock.createSetupContract(),
deprecations: deprecationsServiceMock.createSetupContract(),
executionContext: executionContextServiceMock.createInternalSetupContract(),
security: securityServiceMock.createSetup(),
coreUsageData: {
registerUsageCounter: coreUsageDataServiceMock.createSetupContract().registerUsageCounter,
},

View file

@ -6,19 +6,20 @@
* Side Public License, v 1.
*/
import type { CoreStart } from '@kbn/core-lifecycle-server';
import type { MockedKeys } from '@kbn/utility-types-jest';
import { analyticsServiceMock } from '@kbn/core-analytics-server-mocks';
import { capabilitiesServiceMock } from '@kbn/core-capabilities-server-mocks';
import { docLinksServiceMock } from '@kbn/core-doc-links-server-mocks';
import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks';
import { executionContextServiceMock } from '@kbn/core-execution-context-server-mocks';
import { httpServiceMock } from '@kbn/core-http-server-mocks';
import type { CoreStart } from '@kbn/core-lifecycle-server';
import { metricsServiceMock } from '@kbn/core-metrics-server-mocks';
import { savedObjectsServiceMock } from '@kbn/core-saved-objects-server-mocks';
import { uiSettingsServiceMock } from '@kbn/core-ui-settings-server-mocks';
import { coreUsageDataServiceMock } from '@kbn/core-usage-data-server-mocks';
import type { MockedKeys } from '@kbn/utility-types-jest';
import { customBrandingServiceMock } from '@kbn/core-custom-branding-server-mocks';
import { securityServiceMock } from '@kbn/core-security-server-mocks';
export function createCoreStartMock() {
const mock: MockedKeys<CoreStart> = {
@ -33,6 +34,7 @@ export function createCoreStartMock() {
coreUsageData: coreUsageDataServiceMock.createStartContract(),
executionContext: executionContextServiceMock.createInternalStartContract(),
customBranding: customBrandingServiceMock.createStartContract(),
security: securityServiceMock.createStart(),
plugins: {
onStart: jest.fn(),
},

View file

@ -26,6 +26,7 @@ import { uiSettingsServiceMock } from '@kbn/core-ui-settings-server-mocks';
import { coreUsageDataServiceMock } from '@kbn/core-usage-data-server-mocks';
import { customBrandingServiceMock } from '@kbn/core-custom-branding-server-mocks';
import { userSettingsServiceMock } from '@kbn/core-user-settings-server-mocks';
import { securityServiceMock } from '@kbn/core-security-server-mocks';
export function createInternalCoreSetupMock() {
const setupDeps = {
@ -49,6 +50,7 @@ export function createInternalCoreSetupMock() {
coreUsageData: coreUsageDataServiceMock.createSetupContract(),
customBranding: customBrandingServiceMock.createSetupContract(),
userSettings: userSettingsServiceMock.createSetupContract(),
security: securityServiceMock.createInternalSetup(),
};
return setupDeps;
}

View file

@ -18,6 +18,7 @@ import { savedObjectsServiceMock } from '@kbn/core-saved-objects-server-mocks';
import { uiSettingsServiceMock } from '@kbn/core-ui-settings-server-mocks';
import { coreUsageDataServiceMock } from '@kbn/core-usage-data-server-mocks';
import { customBrandingServiceMock } from '@kbn/core-custom-branding-server-mocks';
import { securityServiceMock } from '@kbn/core-security-server-mocks';
export function createInternalCoreStartMock() {
const startDeps = {
@ -33,6 +34,7 @@ export function createInternalCoreStartMock() {
executionContext: executionContextServiceMock.createInternalStartContract(),
deprecations: deprecationsServiceMock.createInternalStartContract(),
customBranding: customBrandingServiceMock.createStartContract(),
security: securityServiceMock.createInternalStart(),
};
return startDeps;
}

View file

@ -35,6 +35,7 @@
"@kbn/core-logging-server-mocks",
"@kbn/core-custom-branding-server-mocks",
"@kbn/core-user-settings-server-mocks",
"@kbn/core-security-server-mocks",
],
"exclude": [
"target/**/*",

View file

@ -6,26 +6,27 @@
* Side Public License, v 1.
*/
import { AnalyticsServiceSetup } from '@kbn/core-analytics-server';
import { CapabilitiesSetup } from '@kbn/core-capabilities-server';
import { DeprecationsServiceSetup } from '@kbn/core-deprecations-server';
import { DocLinksServiceSetup } from '@kbn/core-doc-links-server';
import { ElasticsearchServiceSetup } from '@kbn/core-elasticsearch-server';
import { ExecutionContextSetup } from '@kbn/core-execution-context-server';
import { RequestHandlerContext } from '@kbn/core-http-request-handler-context-server';
import { HttpResources } from '@kbn/core-http-resources-server';
import { HttpServiceSetup } from '@kbn/core-http-server';
import { I18nServiceSetup } from '@kbn/core-i18n-server';
import { LoggingServiceSetup } from '@kbn/core-logging-server';
import { MetricsServiceSetup } from '@kbn/core-metrics-server';
import { SavedObjectsServiceSetup } from '@kbn/core-saved-objects-server';
import { StatusServiceSetup } from '@kbn/core-status-server';
import { UiSettingsServiceSetup } from '@kbn/core-ui-settings-server';
import { CoreUsageDataSetup } from '@kbn/core-usage-data-server';
import { CustomBrandingSetup } from '@kbn/core-custom-branding-server';
import { UserSettingsServiceSetup } from '@kbn/core-user-settings-server';
import { PluginsServiceSetup } from '@kbn/core-plugins-contracts-server';
import { CoreStart } from './core_start';
import type { AnalyticsServiceSetup } from '@kbn/core-analytics-server';
import type { CapabilitiesSetup } from '@kbn/core-capabilities-server';
import type { DeprecationsServiceSetup } from '@kbn/core-deprecations-server';
import type { DocLinksServiceSetup } from '@kbn/core-doc-links-server';
import type { ElasticsearchServiceSetup } from '@kbn/core-elasticsearch-server';
import type { ExecutionContextSetup } from '@kbn/core-execution-context-server';
import type { RequestHandlerContext } from '@kbn/core-http-request-handler-context-server';
import type { HttpResources } from '@kbn/core-http-resources-server';
import type { HttpServiceSetup } from '@kbn/core-http-server';
import type { I18nServiceSetup } from '@kbn/core-i18n-server';
import type { LoggingServiceSetup } from '@kbn/core-logging-server';
import type { MetricsServiceSetup } from '@kbn/core-metrics-server';
import type { SavedObjectsServiceSetup } from '@kbn/core-saved-objects-server';
import type { StatusServiceSetup } from '@kbn/core-status-server';
import type { UiSettingsServiceSetup } from '@kbn/core-ui-settings-server';
import type { CoreUsageDataSetup } from '@kbn/core-usage-data-server';
import type { CustomBrandingSetup } from '@kbn/core-custom-branding-server';
import type { UserSettingsServiceSetup } from '@kbn/core-user-settings-server';
import type { PluginsServiceSetup } from '@kbn/core-plugins-contracts-server';
import type { SecurityServiceSetup } from '@kbn/core-security-server';
import type { CoreStart } from './core_start';
/**
* Context passed to the `setup` method of `standard` plugins.
@ -76,6 +77,8 @@ export interface CoreSetup<TPluginsStart extends object = object, TStart = unkno
coreUsageData: CoreUsageDataSetup;
/** {@link PluginsServiceSetup} */
plugins: PluginsServiceSetup;
/** {@link SecurityServiceSetup} */
security: SecurityServiceSetup;
}
/**

View file

@ -6,18 +6,19 @@
* Side Public License, v 1.
*/
import { AnalyticsServiceStart } from '@kbn/core-analytics-server';
import { CapabilitiesStart } from '@kbn/core-capabilities-server';
import { DocLinksServiceStart } from '@kbn/core-doc-links-server';
import { ElasticsearchServiceStart } from '@kbn/core-elasticsearch-server';
import { ExecutionContextStart } from '@kbn/core-execution-context-server';
import { HttpServiceStart } from '@kbn/core-http-server';
import { MetricsServiceStart } from '@kbn/core-metrics-server';
import { SavedObjectsServiceStart } from '@kbn/core-saved-objects-server';
import { UiSettingsServiceStart } from '@kbn/core-ui-settings-server';
import { CoreUsageDataStart } from '@kbn/core-usage-data-server';
import { CustomBrandingStart } from '@kbn/core-custom-branding-server';
import { PluginsServiceStart } from '@kbn/core-plugins-contracts-server';
import type { AnalyticsServiceStart } from '@kbn/core-analytics-server';
import type { CapabilitiesStart } from '@kbn/core-capabilities-server';
import type { DocLinksServiceStart } from '@kbn/core-doc-links-server';
import type { ElasticsearchServiceStart } from '@kbn/core-elasticsearch-server';
import type { ExecutionContextStart } from '@kbn/core-execution-context-server';
import type { HttpServiceStart } from '@kbn/core-http-server';
import type { MetricsServiceStart } from '@kbn/core-metrics-server';
import type { SavedObjectsServiceStart } from '@kbn/core-saved-objects-server';
import type { UiSettingsServiceStart } from '@kbn/core-ui-settings-server';
import type { CoreUsageDataStart } from '@kbn/core-usage-data-server';
import type { CustomBrandingStart } from '@kbn/core-custom-branding-server';
import type { PluginsServiceStart } from '@kbn/core-plugins-contracts-server';
import type { SecurityServiceStart } from '@kbn/core-security-server';
/**
* Context passed to the plugins `start` method.
@ -49,4 +50,6 @@ export interface CoreStart {
coreUsageData: CoreUsageDataStart;
/** {@link PluginsServiceStart} */
plugins: PluginsServiceStart;
/** {@link SecurityServiceStart} */
security: SecurityServiceStart;
}

View file

@ -30,7 +30,8 @@
"@kbn/core-usage-data-server",
"@kbn/core-custom-branding-server",
"@kbn/core-user-settings-server",
"@kbn/core-plugins-contracts-server"
"@kbn/core-plugins-contracts-server",
"@kbn/core-security-server"
],
"exclude": [
"target/**/*",

View file

@ -93,6 +93,9 @@ export function createPluginSetupContext<
uiSettings: deps.uiSettings,
settings: deps.settings,
theme: deps.theme,
security: {
registerSecurityApi: (api) => deps.security.registerSecurityApi(api),
},
plugins: {
onSetup: (...dependencyNames) => runtimeResolver.onSetup(plugin.name, dependencyNames),
onStart: (...dependencyNames) => runtimeResolver.onStart(plugin.name, dependencyNames),
@ -156,6 +159,9 @@ export function createPluginStartContext<
fatalErrors: deps.fatalErrors,
deprecations: deps.deprecations,
theme: deps.theme,
security: {
authc: deps.security.authc,
},
plugins: {
onStart: (...dependencyNames) => runtimeResolver.onStart(plugin.name, dependencyNames),
},

View file

@ -41,6 +41,7 @@ import type { PluginInitializerContext } from '@kbn/core-plugins-browser';
import type { CoreSetup, CoreStart } from '@kbn/core-lifecycle-browser';
import { savedObjectsServiceMock } from '@kbn/core-saved-objects-browser-mocks';
import { deprecationsServiceMock } from '@kbn/core-deprecations-browser-mocks';
import { securityServiceMock } from '@kbn/core-security-browser-mocks';
export let mockPluginInitializers: Map<PluginName, MockedPluginInitializer>;
@ -98,12 +99,14 @@ describe('PluginsService', () => {
notifications: notificationServiceMock.createSetupContract(),
uiSettings: uiSettingsServiceMock.createSetupContract(),
theme: themeServiceMock.createSetupContract(),
security: securityServiceMock.createInternalSetup(),
};
mockSetupContext = {
...omit(mockSetupDeps, 'injectedMetadata'),
application: expect.any(Object),
plugins: expect.any(Object),
getStartServices: expect.any(Function),
security: expect.any(Object),
http: {
...mockSetupDeps.http,
staticAssets: expect.any(Object),
@ -126,12 +129,14 @@ describe('PluginsService', () => {
fatalErrors: fatalErrorsServiceMock.createStartContract(),
deprecations: deprecationsServiceMock.createStartContract(),
theme: themeServiceMock.createStartContract(),
security: securityServiceMock.createInternalStart(),
};
mockStartContext = {
...omit(mockStartDeps, 'injectedMetadata'),
application: expect.any(Object),
plugins: expect.any(Object),
chrome: omit(mockStartDeps.chrome, 'getComponent'),
security: expect.any(Object),
http: {
...mockStartDeps.http,
staticAssets: expect.any(Object),

View file

@ -37,6 +37,7 @@
"@kbn/core-deprecations-browser-mocks",
"@kbn/utility-types",
"@kbn/core-plugins-contracts-browser",
"@kbn/core-security-browser-mocks",
],
"exclude": [
"target/**/*",

View file

@ -284,6 +284,9 @@ export function createPluginSetupContext<TPlugin, TPluginDependencies>({
onSetup: (...dependencyNames) => runtimeResolver.onSetup(plugin.name, dependencyNames),
onStart: (...dependencyNames) => runtimeResolver.onStart(plugin.name, dependencyNames),
},
security: {
registerSecurityApi: (api) => deps.security.registerSecurityApi(api),
},
};
}
@ -360,5 +363,8 @@ export function createPluginStartContext<TPlugin, TPluginDependencies>({
plugins: {
onStart: (...dependencyNames) => runtimeResolver.onStart(plugin.name, dependencyNames),
},
security: {
authc: deps.security.authc,
},
};
}

View file

@ -25,6 +25,7 @@ import { integrationsServiceMock } from '@kbn/core-integrations-browser-mocks';
import { coreAppsMock } from '@kbn/core-apps-browser-mocks';
import { loggingSystemMock } from '@kbn/core-logging-browser-mocks';
import { customBrandingServiceMock } from '@kbn/core-custom-branding-browser-mocks';
import { securityServiceMock } from '@kbn/core-security-browser-mocks';
export const analyticsServiceStartMock = analyticsServiceMock.createAnalyticsServiceStart();
export const MockAnalyticsService = analyticsServiceMock.create();
@ -156,3 +157,9 @@ export const LoggingSystemConstructor = jest.fn().mockImplementation(() => MockL
jest.doMock('@kbn/core-logging-browser-internal', () => ({
BrowserLoggingSystem: LoggingSystemConstructor,
}));
export const MockSecurityService = securityServiceMock.create();
export const SecurityServiceConstructor = jest.fn().mockImplementation(() => MockSecurityService);
jest.doMock('@kbn/core-security-browser-internal', () => ({
SecurityService: SecurityServiceConstructor,
}));

View file

@ -44,6 +44,8 @@ import {
MockSettingsService,
MockCustomBrandingService,
CustomBrandingServiceConstructor,
MockSecurityService,
SecurityServiceConstructor,
} from './core_system.test.mocks';
import type { EnvironmentMode } from '@kbn/config';
import { CoreSystem } from './core_system';
@ -150,6 +152,7 @@ describe('constructor', () => {
expect(AnalyticsServiceConstructor).toHaveBeenCalledTimes(1);
expect(LoggingSystemConstructor).toHaveBeenCalledTimes(1);
expect(CustomBrandingServiceConstructor).toHaveBeenCalledTimes(1);
expect(SecurityServiceConstructor).toHaveBeenCalledTimes(1);
});
it('passes injectedMetadata param to InjectedMetadataService', () => {
@ -309,6 +312,11 @@ describe('#setup()', () => {
await setupCore();
expect(MockChromeService.setup).toHaveBeenCalledTimes(1);
});
it('calls security#setup()', async () => {
await setupCore();
expect(MockSecurityService.setup).toHaveBeenCalledTimes(1);
});
});
describe('#start()', () => {
@ -495,6 +503,11 @@ describe('#start()', () => {
await startCore();
expect(MockThemeService.start).toHaveBeenCalledTimes(1);
});
it('calls security#start()', async () => {
await startCore();
expect(MockSecurityService.start).toHaveBeenCalledTimes(1);
});
});
describe('#stop()', () => {

View file

@ -36,9 +36,9 @@ import { CoreAppsService } from '@kbn/core-apps-browser-internal';
import type { InternalCoreSetup, InternalCoreStart } from '@kbn/core-lifecycle-browser-internal';
import { PluginsService } from '@kbn/core-plugins-browser-internal';
import { CustomBrandingService } from '@kbn/core-custom-branding-browser-internal';
import { SecurityService } from '@kbn/core-security-browser-internal';
import { KBN_LOAD_MARKS } from './events';
import { fetchOptionalMemoryInfo } from './fetch_optional_memory_info';
import {
LOAD_SETUP_DONE,
LOAD_START_DONE,
@ -104,6 +104,7 @@ export class CoreSystem {
private readonly coreContext: CoreContext;
private readonly executionContext: ExecutionContextService;
private readonly customBranding: CustomBrandingService;
private readonly security: SecurityService;
private fatalErrorsSetup: FatalErrorsSetup | null = null;
constructor(params: CoreSystemParams) {
@ -128,6 +129,7 @@ export class CoreSystem {
// Stop Core before rendering any fatal errors into the DOM
this.stop();
});
this.security = new SecurityService(this.coreContext);
this.theme = new ThemeService();
this.notifications = new NotificationsService();
this.http = new HttpService();
@ -235,6 +237,7 @@ export class CoreSystem {
fatalErrors: this.fatalErrorsSetup,
executionContext,
});
const security = this.security.setup();
this.chrome.setup({ analytics });
const uiSettings = this.uiSettings.setup({ http, injectedMetadata });
const settings = this.settings.setup({ http, injectedMetadata });
@ -256,6 +259,7 @@ export class CoreSystem {
settings,
executionContext,
customBranding,
security,
};
// Services that do not expose contracts at setup
@ -280,6 +284,7 @@ export class CoreSystem {
public async start() {
try {
const analytics = this.analytics.start();
const security = this.security.start();
const injectedMetadata = await this.injectedMetadata.start();
const uiSettings = await this.uiSettings.start();
const settings = await this.settings.start();
@ -354,6 +359,7 @@ export class CoreSystem {
fatalErrors,
deprecations,
customBranding,
security,
};
await this.plugins.start(core);
@ -416,6 +422,7 @@ export class CoreSystem {
this.deprecations.stop();
this.theme.stop();
this.analytics.stop();
this.security.stop();
this.rootDomElement.textContent = '';
}

View file

@ -62,6 +62,8 @@
"@kbn/config",
"@kbn/core-custom-branding-browser-internal",
"@kbn/core-custom-branding-browser-mocks",
"@kbn/core-security-browser-mocks",
"@kbn/core-security-browser-internal",
],
"exclude": [
"target/**/*",

View file

@ -7,37 +7,46 @@
*/
import { httpServiceMock } from '@kbn/core-http-server-mocks';
import { pluginServiceMock } from '@kbn/core-plugins-server-mocks';
import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks';
import { configServiceMock } from '@kbn/config-mocks';
import { savedObjectsServiceMock } from '@kbn/core-saved-objects-server-mocks';
import { renderingServiceMock } from '@kbn/core-rendering-server-mocks';
import { environmentServiceMock } from '@kbn/core-environment-server-mocks';
import { nodeServiceMock } from '@kbn/core-node-server-mocks';
import { metricsServiceMock } from '@kbn/core-metrics-server-mocks';
import { statusServiceMock } from '@kbn/core-status-server-mocks';
import { loggingServiceMock } from '@kbn/core-logging-server-mocks';
import { i18nServiceMock } from '@kbn/core-i18n-server-mocks';
import { prebootServiceMock } from '@kbn/core-preboot-server-mocks';
import { deprecationsServiceMock } from '@kbn/core-deprecations-server-mocks';
import { docLinksServiceMock } from '@kbn/core-doc-links-server-mocks';
import { userSettingsServiceMock } from '@kbn/core-user-settings-server-mocks';
import { securityServiceMock } from '@kbn/core-security-server-mocks';
export const mockHttpService = httpServiceMock.create();
jest.doMock('@kbn/core-http-server-internal', () => ({
HttpService: jest.fn(() => mockHttpService),
}));
import { pluginServiceMock } from '@kbn/core-plugins-server-mocks';
export const mockPluginsService = pluginServiceMock.create();
jest.doMock('@kbn/core-plugins-server-internal', () => ({
PluginsService: jest.fn(() => mockPluginsService),
}));
import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks';
export const mockElasticsearchService = elasticsearchServiceMock.create();
jest.doMock('@kbn/core-elasticsearch-server-internal', () => ({
ElasticsearchService: jest.fn(() => mockElasticsearchService),
}));
const realKbnConfig = jest.requireActual('@kbn/config');
import { configServiceMock } from '@kbn/config-mocks';
export const mockConfigService = configServiceMock.create();
jest.doMock('@kbn/config', () => ({
...realKbnConfig,
ConfigService: jest.fn(() => mockConfigService),
}));
import { savedObjectsServiceMock } from '@kbn/core-saved-objects-server-mocks';
jest.doMock('@kbn/config', () => {
const realKbnConfig = jest.requireActual('@kbn/config');
return {
...realKbnConfig,
ConfigService: jest.fn(() => mockConfigService),
};
});
export const mockSavedObjectsService = savedObjectsServiceMock.create();
jest.doMock('@kbn/core-saved-objects-server-internal', () => ({
@ -75,73 +84,57 @@ jest.doMock('@kbn/core-config-server-internal', () => ({
ensureValidConfiguration: mockEnsureValidConfiguration,
}));
import { renderingServiceMock } from '@kbn/core-rendering-server-mocks';
export const mockRenderingService = renderingServiceMock.create();
jest.doMock('@kbn/core-rendering-server-internal', () => ({
RenderingService: jest.fn(() => mockRenderingService),
}));
import { environmentServiceMock } from '@kbn/core-environment-server-mocks';
export const mockEnvironmentService = environmentServiceMock.create();
jest.doMock('@kbn/core-environment-server-internal', () => ({
EnvironmentService: jest.fn(() => mockEnvironmentService),
}));
import { nodeServiceMock } from '@kbn/core-node-server-mocks';
export const mockNodeService = nodeServiceMock.create();
jest.doMock('@kbn/core-node-server-internal', () => ({
NodeService: jest.fn(() => mockNodeService),
}));
import { metricsServiceMock } from '@kbn/core-metrics-server-mocks';
export const mockMetricsService = metricsServiceMock.create();
jest.doMock('@kbn/core-metrics-server-internal', () => ({
MetricsService: jest.fn(() => mockMetricsService),
}));
import { statusServiceMock } from '@kbn/core-status-server-mocks';
export const mockStatusService = statusServiceMock.create();
jest.doMock('@kbn/core-status-server-internal', () => ({
StatusService: jest.fn(() => mockStatusService),
}));
import { loggingServiceMock } from '@kbn/core-logging-server-mocks';
export const mockLoggingService = loggingServiceMock.create();
jest.doMock('@kbn/core-logging-server-internal', () => ({
LoggingService: jest.fn(() => mockLoggingService),
}));
import { i18nServiceMock } from '@kbn/core-i18n-server-mocks';
export const mockI18nService = i18nServiceMock.create();
jest.doMock('@kbn/core-i18n-server-internal', () => ({
I18nService: jest.fn(() => mockI18nService),
}));
import { prebootServiceMock } from '@kbn/core-preboot-server-mocks';
export const mockPrebootService = prebootServiceMock.create();
jest.doMock('@kbn/core-preboot-server-internal', () => ({
PrebootService: jest.fn(() => mockPrebootService),
}));
import { deprecationsServiceMock } from '@kbn/core-deprecations-server-mocks';
export const mockDeprecationService = deprecationsServiceMock.create();
jest.doMock('@kbn/core-deprecations-server-internal', () => ({
DeprecationsService: jest.fn(() => mockDeprecationService),
}));
import { docLinksServiceMock } from '@kbn/core-doc-links-server-mocks';
import { userSettingsServiceMock } from '@kbn/core-user-settings-server-mocks';
export const mockDocLinksService = docLinksServiceMock.create();
jest.doMock('@kbn/core-doc-links-server-internal', () => ({
DocLinksService: jest.fn(() => mockDocLinksService),
}));
export const mockSecurityService = securityServiceMock.create();
jest.doMock('@kbn/core-security-server-internal', () => ({
SecurityService: jest.fn(() => mockSecurityService),
}));

View file

@ -27,6 +27,7 @@ import {
mockDocLinksService,
mockCustomBrandingService,
mockUserSettingsService,
mockSecurityService,
} from './server.test.mocks';
import { BehaviorSubject } from 'rxjs';
@ -117,6 +118,7 @@ test('sets up services on "setup"', async () => {
expect(mockDocLinksService.setup).not.toHaveBeenCalled();
expect(mockCustomBrandingService.setup).not.toHaveBeenCalled();
expect(mockUserSettingsService.setup).not.toHaveBeenCalled();
expect(mockSecurityService.setup).not.toHaveBeenCalled();
await server.setup();
@ -135,6 +137,7 @@ test('sets up services on "setup"', async () => {
expect(mockDocLinksService.setup).toHaveBeenCalledTimes(1);
expect(mockCustomBrandingService.setup).toHaveBeenCalledTimes(1);
expect(mockUserSettingsService.setup).toHaveBeenCalledTimes(1);
expect(mockSecurityService.setup).toHaveBeenCalledTimes(1);
});
test('injects legacy dependency to context#setup()', async () => {
@ -187,6 +190,7 @@ test('runs services on "start"', async () => {
expect(mockDeprecationService.start).not.toHaveBeenCalled();
expect(mockDocLinksService.start).not.toHaveBeenCalled();
expect(mockCustomBrandingService.start).not.toHaveBeenCalled();
expect(mockSecurityService.start).not.toHaveBeenCalled();
await server.start();
@ -198,6 +202,7 @@ test('runs services on "start"', async () => {
expect(mockDeprecationService.start).toHaveBeenCalledTimes(1);
expect(mockDocLinksService.start).toHaveBeenCalledTimes(1);
expect(mockCustomBrandingService.start).toHaveBeenCalledTimes(1);
expect(mockSecurityService.start).toHaveBeenCalledTimes(1);
});
test('does not fail on "setup" if there are unused paths detected', async () => {
@ -225,6 +230,7 @@ test('stops services on "stop"', async () => {
expect(mockStatusService.stop).not.toHaveBeenCalled();
expect(mockLoggingService.stop).not.toHaveBeenCalled();
expect(mockCustomBrandingService.stop).not.toHaveBeenCalled();
expect(mockSecurityService.stop).not.toHaveBeenCalled();
await server.stop();
@ -238,6 +244,7 @@ test('stops services on "stop"', async () => {
expect(mockStatusService.stop).toHaveBeenCalledTimes(1);
expect(mockLoggingService.stop).toHaveBeenCalledTimes(1);
expect(mockCustomBrandingService.stop).toHaveBeenCalledTimes(1);
expect(mockSecurityService.stop).toHaveBeenCalledTimes(1);
});
test(`doesn't preboot core services if config validation fails`, async () => {

View file

@ -44,7 +44,6 @@ import type {
PrebootRequestHandlerContext,
} from '@kbn/core-http-request-handler-context-server';
import { RenderingService } from '@kbn/core-rendering-server-internal';
import { HttpResourcesService } from '@kbn/core-http-resources-server-internal';
import type {
InternalCorePreboot,
@ -53,6 +52,7 @@ import type {
} from '@kbn/core-lifecycle-server-internal';
import { DiscoveredPlugins, PluginsService } from '@kbn/core-plugins-server-internal';
import { CoreAppsService } from '@kbn/core-apps-server-internal';
import { SecurityService } from '@kbn/core-security-server-internal';
import { registerServiceConfig } from './register_service_config';
import { MIGRATION_EXCEPTION_CODE } from './constants';
@ -100,6 +100,7 @@ export class Server {
private readonly docLinks: DocLinksService;
private readonly customBranding: CustomBrandingService;
private readonly userSettingsService: UserSettingsService;
private readonly security: SecurityService;
private readonly savedObjectsStartPromise: Promise<SavedObjectsServiceStart>;
private resolveSavedObjectsStartPromise?: (value: SavedObjectsServiceStart) => void;
@ -148,6 +149,7 @@ export class Server {
this.docLinks = new DocLinksService(core);
this.customBranding = new CustomBrandingService(core);
this.userSettingsService = new UserSettingsService(core);
this.security = new SecurityService(core);
this.savedObjectsStartPromise = new Promise((resolve) => {
this.resolveSavedObjectsStartPromise = resolve;
@ -248,6 +250,7 @@ export class Server {
});
const executionContextSetup = this.executionContext.setup();
const docLinksSetup = this.docLinks.setup();
const securitySetup = this.security.setup();
const httpSetup = await this.http.setup({
context: contextServiceSetup,
@ -344,6 +347,7 @@ export class Server {
deprecations: deprecationsSetup,
coreUsageData: coreUsageDataSetup,
userSettings: userSettingsServiceSetup,
security: securitySetup,
};
const pluginsSetup = await this.plugins.setup(coreSetup);
@ -363,6 +367,7 @@ export class Server {
const startTransaction = apm.startTransaction('server-start', 'kibana-platform');
const analyticsStart = this.analytics.start();
const securityStart = this.security.start();
const executionContextStart = this.executionContext.start();
const docLinkStart = this.docLinks.start();
const elasticsearchStart = await this.elasticsearch.start();
@ -414,6 +419,7 @@ export class Server {
uiSettings: uiSettingsStart,
coreUsageData: coreUsageDataStart,
deprecations: deprecationsStart,
security: securityStart,
};
await this.plugins.start(this.coreStart);
@ -444,6 +450,7 @@ export class Server {
await this.customBranding.stop();
this.node.stop();
this.deprecations.stop();
this.security.stop();
}
private registerCoreContext(coreSetup: InternalCoreSetup) {

View file

@ -71,6 +71,8 @@
"@kbn/core-node-server",
"@kbn/core-user-settings-server-internal",
"@kbn/core-user-settings-server-mocks",
"@kbn/core-security-server-mocks",
"@kbn/core-security-server-internal",
],
"exclude": [
"target/**/*",

View file

@ -0,0 +1,4 @@
# @kbn/core-security-browser-internal
This package contains the internal types and implementation for Core's browser-side `security` service.

View file

@ -0,0 +1,12 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
export { SecurityService } from './src/security_service';
export type {
InternalSecurityServiceSetup,
InternalSecurityServiceStart,
} from './src/internal_contracts';

View file

@ -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
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
module.exports = {
preset: '@kbn/test',
rootDir: '../../../..',
roots: ['<rootDir>/packages/core/security/core-security-browser-internal'],
};

View file

@ -0,0 +1,5 @@
{
"type": "shared-common",
"id": "@kbn/core-security-browser-internal",
"owner": "@elastic/kibana-core"
}

View file

@ -0,0 +1,6 @@
{
"name": "@kbn/core-security-browser-internal",
"private": true,
"version": "1.0.0",
"license": "SSPL-1.0 OR Elastic License 2.0"
}

View file

@ -0,0 +1,12 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { SecurityServiceSetup, SecurityServiceStart } from '@kbn/core-security-browser';
export type InternalSecurityServiceSetup = SecurityServiceSetup;
export type InternalSecurityServiceStart = SecurityServiceStart;

View file

@ -0,0 +1,19 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
export const getDefaultSecurityImplementationMock = jest.fn();
export const convertSecurityApiMock = jest.fn();
jest.doMock('./utils', () => {
const actual = jest.requireActual('./utils');
return {
...actual,
getDefaultSecurityImplementation: getDefaultSecurityImplementationMock,
convertSecurityApi: convertSecurityApiMock,
};
});

View file

@ -0,0 +1,97 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import {
convertSecurityApiMock,
getDefaultSecurityImplementationMock,
} from './security_service.test.mocks';
import { loggerMock } from '@kbn/logging-mocks';
import { coreContextMock } from '@kbn/core-base-browser-mocks';
import type { CoreSecurityContract } from '@kbn/core-security-browser';
import { SecurityService } from './security_service';
const createStubInternalContract = (): CoreSecurityContract => {
return Symbol('stubContract') as unknown as CoreSecurityContract;
};
describe('SecurityService', () => {
let coreContext: ReturnType<typeof coreContextMock.create>;
let service: SecurityService;
beforeEach(() => {
coreContext = coreContextMock.create();
service = new SecurityService(coreContext);
convertSecurityApiMock.mockReset();
getDefaultSecurityImplementationMock.mockReset();
});
describe('#setup', () => {
describe('#registerSecurityApi', () => {
it('throws if called more than once', () => {
const { registerSecurityApi } = service.setup();
const contract = createStubInternalContract();
registerSecurityApi(contract);
expect(() => registerSecurityApi(contract)).toThrowErrorMatchingInlineSnapshot(
`"security API can only be registered once"`
);
});
});
});
describe('#start', () => {
it('logs a warning if the security API was not registered', () => {
service.setup();
service.start();
expect(loggerMock.collect(coreContext.logger).warn).toMatchInlineSnapshot(`
Array [
Array [
"Security API was not registered, using default implementation",
],
]
`);
});
it('calls convertSecurityApi with the registered API', () => {
const { registerSecurityApi } = service.setup();
const contract = createStubInternalContract();
registerSecurityApi(contract);
service.start();
expect(convertSecurityApiMock).toHaveBeenCalledTimes(1);
expect(convertSecurityApiMock).toHaveBeenCalledWith(contract);
});
it('calls convertSecurityApi with the default implementation when no API was registered', () => {
const contract = createStubInternalContract();
getDefaultSecurityImplementationMock.mockReturnValue(contract);
service.setup();
service.start();
expect(convertSecurityApiMock).toHaveBeenCalledTimes(1);
expect(convertSecurityApiMock).toHaveBeenCalledWith(contract);
});
it('returns the result of convertSecurityApi as contract', () => {
const convertedContract = { stub: true };
convertSecurityApiMock.mockReturnValue(convertedContract);
service.setup();
const startContract = service.start();
expect(startContract).toEqual(convertedContract);
});
});
});

View file

@ -0,0 +1,48 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { Logger } from '@kbn/logging';
import type { CoreContext, CoreService } from '@kbn/core-base-browser-internal';
import type { CoreSecurityContract } from '@kbn/core-security-browser';
import type {
InternalSecurityServiceSetup,
InternalSecurityServiceStart,
} from './internal_contracts';
import { getDefaultSecurityImplementation, convertSecurityApi } from './utils';
export class SecurityService
implements CoreService<InternalSecurityServiceSetup, InternalSecurityServiceStart>
{
private readonly log: Logger;
private securityApi?: CoreSecurityContract;
constructor(coreContext: CoreContext) {
this.log = coreContext.logger.get('security-service');
}
public setup(): InternalSecurityServiceSetup {
return {
registerSecurityApi: (api) => {
if (this.securityApi) {
throw new Error('security API can only be registered once');
}
this.securityApi = api;
},
};
}
public start(): InternalSecurityServiceStart {
if (!this.securityApi) {
this.log.warn('Security API was not registered, using default implementation');
}
const apiContract = this.securityApi ?? getDefaultSecurityImplementation();
return convertSecurityApi(apiContract);
}
public stop() {}
}

View file

@ -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
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { CoreSecurityContract } from '@kbn/core-security-browser';
import { convertSecurityApi } from './convert_security_api';
describe('convertSecurityApi', () => {
it('returns the API from the source', () => {
const source: CoreSecurityContract = { authc: { getCurrentUser: jest.fn() } };
const output = convertSecurityApi(source);
expect(output.authc.getCurrentUser).toBe(source.authc.getCurrentUser);
});
});

View file

@ -0,0 +1,17 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { CoreSecurityContract } from '@kbn/core-security-browser';
import type { InternalSecurityServiceStart } from '../internal_contracts';
export const convertSecurityApi = (
privateApi: CoreSecurityContract
): InternalSecurityServiceStart => {
// shapes are the same for now given we only have one API exposed.
return privateApi;
};

View file

@ -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
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { CoreSecurityContract } from '@kbn/core-security-browser';
import { getDefaultSecurityImplementation } from './default_implementation';
describe('getDefaultSecurityImplementation', () => {
let implementation: CoreSecurityContract;
beforeEach(() => {
implementation = getDefaultSecurityImplementation();
});
describe('authc.getCurrentUser', () => {
it('rejects with an error', async () => {
await expect(() =>
implementation.authc.getCurrentUser()
).rejects.toThrowErrorMatchingInlineSnapshot(`"No authenticated user"`);
});
});
});

View file

@ -0,0 +1,19 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { CoreSecurityContract } from '@kbn/core-security-browser';
export const getDefaultSecurityImplementation = (): CoreSecurityContract => {
return {
authc: {
getCurrentUser: () => {
return Promise.reject(new Error('No authenticated user'));
},
},
};
};

View file

@ -0,0 +1,10 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
export { convertSecurityApi } from './convert_security_api';
export { getDefaultSecurityImplementation } from './default_implementation';

View file

@ -0,0 +1,25 @@
{
"extends": "../../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "target/types",
"types": [
"jest",
"node",
"react"
]
},
"include": [
"**/*.ts",
"**/*.tsx",
],
"exclude": [
"target/**/*"
],
"kbn_references": [
"@kbn/core-security-browser",
"@kbn/logging",
"@kbn/core-base-browser-internal",
"@kbn/logging-mocks",
"@kbn/core-base-browser-mocks",
]
}

View file

@ -0,0 +1,3 @@
# @kbn/core-security-browser-mocks
This package contains mocks types for Core's browser-side `security` service.

View file

@ -0,0 +1,9 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
export { securityServiceMock } from './src/security_service.mock';

View file

@ -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
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
module.exports = {
preset: '@kbn/test',
rootDir: '../../../..',
roots: ['<rootDir>/packages/core/security/core-security-browser-mocks'],
};

View file

@ -0,0 +1,5 @@
{
"type": "shared-common",
"id": "@kbn/core-security-browser-mocks",
"owner": "@elastic/kibana-core"
}

View file

@ -0,0 +1,6 @@
{
"name": "@kbn/core-security-browser-mocks",
"private": true,
"version": "1.0.0",
"license": "SSPL-1.0 OR Elastic License 2.0"
}

View file

@ -0,0 +1,67 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { SecurityServiceSetup, SecurityServiceStart } from '@kbn/core-security-browser';
import type {
InternalSecurityServiceSetup,
InternalSecurityServiceStart,
} from '@kbn/core-security-browser-internal';
const createSetupMock = () => {
const mock: jest.Mocked<SecurityServiceSetup> = {
registerSecurityApi: jest.fn(),
};
return mock;
};
const createStartMock = () => {
const mock: jest.MockedObjectDeep<SecurityServiceStart> = {
authc: {
getCurrentUser: jest.fn(),
},
};
return mock;
};
const createInternalSetupMock = () => {
const mock: jest.Mocked<InternalSecurityServiceSetup> = {
registerSecurityApi: jest.fn(),
};
return mock;
};
const createInternalStartMock = () => {
const mock: jest.MockedObjectDeep<InternalSecurityServiceStart> = {
authc: {
getCurrentUser: jest.fn(),
},
};
return mock;
};
const createServiceMock = () => {
const mock = {
setup: jest.fn().mockReturnValue(createSetupMock()),
start: jest.fn().mockReturnValue(createStartMock()),
stop: jest.fn(),
};
return mock;
};
export const securityServiceMock = {
create: createServiceMock,
createSetup: createSetupMock,
createStart: createStartMock,
createInternalSetup: createInternalSetupMock,
createInternalStart: createInternalStartMock,
};

View file

@ -0,0 +1,22 @@
{
"extends": "../../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "target/types",
"types": [
"jest",
"node",
"react"
]
},
"include": [
"**/*.ts",
"**/*.tsx",
],
"exclude": [
"target/**/*"
],
"kbn_references": [
"@kbn/core-security-browser",
"@kbn/core-security-browser-internal",
]
}

View file

@ -0,0 +1,3 @@
# @kbn/core-security-browser
This package contains the public types for Core's browser-side `security` service.

View file

@ -0,0 +1,11 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
export type { SecurityServiceSetup, SecurityServiceStart } from './src/contracts';
export type { CoreAuthenticationService } from './src/authc';
export type { CoreSecurityContract, AuthenticationServiceContract } from './src/api_provider';

View file

@ -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
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
module.exports = {
preset: '@kbn/test',
rootDir: '../../../..',
roots: ['<rootDir>/packages/core/security/core-security-browser'],
};

View file

@ -0,0 +1,5 @@
{
"type": "shared-common",
"id": "@kbn/core-security-browser",
"owner": "@elastic/kibana-core"
}

View file

@ -0,0 +1,6 @@
{
"name": "@kbn/core-security-browser",
"private": true,
"version": "1.0.0",
"license": "SSPL-1.0 OR Elastic License 2.0"
}

View file

@ -0,0 +1,24 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { CoreAuthenticationService } from './authc';
/**
* The contract exposed by the security provider for Core to
* consume and re-expose via its security service.
*
* @public
*/
export interface CoreSecurityContract {
authc: AuthenticationServiceContract;
}
/**
* @public
*/
export type AuthenticationServiceContract = CoreAuthenticationService;

View file

@ -0,0 +1,22 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { AuthenticatedUser } from '@kbn/core-security-common';
/**
* Core's authentication service
*
* @public
*/
export interface CoreAuthenticationService {
/**
* Returns currently authenticated user
* and throws if current user isn't authenticated.
*/
getCurrentUser(): Promise<AuthenticatedUser>;
}

View file

@ -0,0 +1,36 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { CoreAuthenticationService } from './authc';
import type { CoreSecurityContract } from './api_provider';
/**
* Setup contract for Core's security service.
*
* @public
*/
export interface SecurityServiceSetup {
/**
* Register the security implementation that then will be used and re-exposed by Core.
*
* @remark this should **exclusively** be used by the security plugin.
*/
registerSecurityApi(api: CoreSecurityContract): void;
}
/**
* Start contract for Core's security service.
*
* @public
*/
export interface SecurityServiceStart {
/**
* The {@link CoreAuthenticationService | authentication service}
*/
authc: CoreAuthenticationService;
}

View file

@ -0,0 +1,21 @@
{
"extends": "../../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "target/types",
"types": [
"jest",
"node",
"react"
]
},
"include": [
"**/*.ts",
"**/*.tsx",
],
"exclude": [
"target/**/*"
],
"kbn_references": [
"@kbn/core-security-common",
]
}

View file

@ -0,0 +1,3 @@
# @kbn/core-security-common
This package contains the common public types for Core's `security` domain.

View file

@ -0,0 +1,14 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
export type {
User,
UserRealm,
AuthenticatedUser,
AuthenticationProvider,
} from './src/authentication';

View file

@ -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
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
module.exports = {
preset: '@kbn/test',
rootDir: '../../../..',
roots: ['<rootDir>/packages/core/security/core-security-common'],
};

View file

@ -0,0 +1,5 @@
{
"type": "shared-common",
"id": "@kbn/core-security-common",
"owner": ["@elastic/kibana-core", "@elastic/kibana-security"]
}

View file

@ -0,0 +1,6 @@
{
"name": "@kbn/core-security-common",
"private": true,
"version": "1.0.0",
"license": "SSPL-1.0 OR Elastic License 2.0"
}

View file

@ -1,8 +1,9 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { AuthenticationProvider } from './authentication_provider';

View file

@ -1,8 +1,9 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
/**

View file

@ -0,0 +1,11 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
export type { AuthenticatedUser, UserRealm } from './authenticated_user';
export type { User } from './user';
export type { AuthenticationProvider } from './authentication_provider';

View file

@ -1,8 +1,9 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
/**

View file

@ -0,0 +1,19 @@
{
"extends": "../../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "target/types",
"types": [
"jest",
"node",
"react"
]
},
"include": [
"**/*.ts",
"**/*.tsx",
],
"exclude": [
"target/**/*"
],
"kbn_references": []
}

View file

@ -0,0 +1,4 @@
# @kbn/core-security-server-internal
This package contains the internal types and implementation for Core's server-side `security` service.

View file

@ -0,0 +1,14 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
export { SecurityService } from './src/security_service';
export { CoreSecurityRouteHandlerContext } from './src/security_route_handler_context';
export type {
InternalSecurityServiceSetup,
InternalSecurityServiceStart,
} from './src/internal_contracts';

View file

@ -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
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
module.exports = {
preset: '@kbn/test/jest_node',
rootDir: '../../../..',
roots: ['<rootDir>/packages/core/security/core-security-server-internal'],
};

View file

@ -0,0 +1,5 @@
{
"type": "shared-common",
"id": "@kbn/core-security-server-internal",
"owner": "@elastic/kibana-core"
}

View file

@ -0,0 +1,6 @@
{
"name": "@kbn/core-security-server-internal",
"private": true,
"version": "1.0.0",
"license": "SSPL-1.0 OR Elastic License 2.0"
}

View file

@ -0,0 +1,12 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { SecurityServiceSetup, SecurityServiceStart } from '@kbn/core-security-server';
export type InternalSecurityServiceSetup = SecurityServiceSetup;
export type InternalSecurityServiceStart = SecurityServiceStart;

View file

@ -0,0 +1,32 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { KibanaRequest } from '@kbn/core-http-server';
import type {
SecurityRequestHandlerContext,
AuthcRequestHandlerContext,
} from '@kbn/core-security-server';
import type { InternalSecurityServiceStart } from './internal_contracts';
export class CoreSecurityRouteHandlerContext implements SecurityRequestHandlerContext {
#authc?: AuthcRequestHandlerContext;
constructor(
private readonly securityStart: InternalSecurityServiceStart,
private readonly request: KibanaRequest
) {}
public get authc() {
if (this.#authc == null) {
this.#authc = {
getCurrentUser: () => this.securityStart.authc.getCurrentUser(this.request),
};
}
return this.#authc;
}
}

View file

@ -0,0 +1,19 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
export const getDefaultSecurityImplementationMock = jest.fn();
export const convertSecurityApiMock = jest.fn();
jest.doMock('./utils', () => {
const actual = jest.requireActual('./utils');
return {
...actual,
getDefaultSecurityImplementation: getDefaultSecurityImplementationMock,
convertSecurityApi: convertSecurityApiMock,
};
});

View file

@ -0,0 +1,97 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import {
convertSecurityApiMock,
getDefaultSecurityImplementationMock,
} from './security_service.test.mocks';
import { loggerMock, MockedLogger } from '@kbn/logging-mocks';
import { mockCoreContext } from '@kbn/core-base-server-mocks';
import type { CoreSecurityContract } from '@kbn/core-security-server';
import { SecurityService } from './security_service';
const createStubInternalContract = (): CoreSecurityContract => {
return Symbol('stubContract') as unknown as CoreSecurityContract;
};
describe('SecurityService', () => {
let coreContext: ReturnType<typeof mockCoreContext.create>;
let service: SecurityService;
beforeEach(() => {
coreContext = mockCoreContext.create();
service = new SecurityService(coreContext);
convertSecurityApiMock.mockReset();
getDefaultSecurityImplementationMock.mockReset();
});
describe('#setup', () => {
describe('#registerSecurityApi', () => {
it('throws if called more than once', () => {
const { registerSecurityApi } = service.setup();
const contract = createStubInternalContract();
registerSecurityApi(contract);
expect(() => registerSecurityApi(contract)).toThrowErrorMatchingInlineSnapshot(
`"security API can only be registered once"`
);
});
});
});
describe('#start', () => {
it('logs a warning if the security API was not registered', () => {
service.setup();
service.start();
expect(loggerMock.collect(coreContext.logger as MockedLogger).warn).toMatchInlineSnapshot(`
Array [
Array [
"Security API was not registered, using default implementation",
],
]
`);
});
it('calls convertSecurityApi with the registered API', () => {
const { registerSecurityApi } = service.setup();
const contract = createStubInternalContract();
registerSecurityApi(contract);
service.start();
expect(convertSecurityApiMock).toHaveBeenCalledTimes(1);
expect(convertSecurityApiMock).toHaveBeenCalledWith(contract);
});
it('calls convertSecurityApi with the default implementation when no API was registered', () => {
const contract = createStubInternalContract();
getDefaultSecurityImplementationMock.mockReturnValue(contract);
service.setup();
service.start();
expect(convertSecurityApiMock).toHaveBeenCalledTimes(1);
expect(convertSecurityApiMock).toHaveBeenCalledWith(contract);
});
it('returns the result of convertSecurityApi as contract', () => {
const convertedContract = { stub: true };
convertSecurityApiMock.mockReturnValue(convertedContract);
service.setup();
const startContract = service.start();
expect(startContract).toEqual(convertedContract);
});
});
});

View file

@ -0,0 +1,48 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { Logger } from '@kbn/logging';
import type { CoreContext, CoreService } from '@kbn/core-base-server-internal';
import type { CoreSecurityContract } from '@kbn/core-security-server';
import type {
InternalSecurityServiceSetup,
InternalSecurityServiceStart,
} from './internal_contracts';
import { getDefaultSecurityImplementation, convertSecurityApi } from './utils';
export class SecurityService
implements CoreService<InternalSecurityServiceSetup, InternalSecurityServiceStart>
{
private readonly log: Logger;
private securityApi?: CoreSecurityContract;
constructor(coreContext: CoreContext) {
this.log = coreContext.logger.get('security-service');
}
public setup(): InternalSecurityServiceSetup {
return {
registerSecurityApi: (api) => {
if (this.securityApi) {
throw new Error('security API can only be registered once');
}
this.securityApi = api;
},
};
}
public start(): InternalSecurityServiceStart {
if (!this.securityApi) {
this.log.warn('Security API was not registered, using default implementation');
}
const apiContract = this.securityApi ?? getDefaultSecurityImplementation();
return convertSecurityApi(apiContract);
}
public stop() {}
}

View file

@ -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
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { CoreSecurityContract } from '@kbn/core-security-server';
import { convertSecurityApi } from './convert_security_api';
describe('convertSecurityApi', () => {
it('returns the API from the source', () => {
const source: CoreSecurityContract = { authc: { getCurrentUser: jest.fn() } };
const output = convertSecurityApi(source);
expect(output.authc.getCurrentUser).toBe(source.authc.getCurrentUser);
});
});

View file

@ -0,0 +1,17 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { CoreSecurityContract } from '@kbn/core-security-server';
import type { InternalSecurityServiceStart } from '../internal_contracts';
export const convertSecurityApi = (
privateApi: CoreSecurityContract
): InternalSecurityServiceStart => {
// shapes are the same for now given we only have one API exposed.
return privateApi;
};

View file

@ -0,0 +1,25 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { CoreSecurityContract } from '@kbn/core-security-server';
import { getDefaultSecurityImplementation } from './default_implementation';
describe('getDefaultSecurityImplementation', () => {
let implementation: CoreSecurityContract;
beforeEach(() => {
implementation = getDefaultSecurityImplementation();
});
describe('authc.getCurrentUser', () => {
it('returns null', async () => {
const user = implementation.authc.getCurrentUser({} as any);
expect(user).toBeNull();
});
});
});

View file

@ -0,0 +1,17 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { CoreSecurityContract } from '@kbn/core-security-server';
export const getDefaultSecurityImplementation = (): CoreSecurityContract => {
return {
authc: {
getCurrentUser: () => null,
},
};
};

View file

@ -0,0 +1,10 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
export { convertSecurityApi } from './convert_security_api';
export { getDefaultSecurityImplementation } from './default_implementation';

View file

@ -0,0 +1,24 @@
{
"extends": "../../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "target/types",
"types": [
"jest",
"node"
]
},
"include": [
"**/*.ts",
],
"exclude": [
"target/**/*"
],
"kbn_references": [
"@kbn/core-security-server",
"@kbn/logging",
"@kbn/core-base-server-internal",
"@kbn/core-http-server",
"@kbn/logging-mocks",
"@kbn/core-base-server-mocks",
]
}

View file

@ -0,0 +1,3 @@
# @kbn/core-security-server-mocks
This package contains mocks types for Core's server-side `security` service.

View file

@ -0,0 +1,9 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
export { securityServiceMock } from './src/security_service.mock';

Some files were not shown because too many files have changed in this diff Show more