From a5d1dfdeb2a19c3705ff06e4286bbba30d2eec31 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Wed, 24 Apr 2024 11:58:40 +0200 Subject: [PATCH 1/5] [security-in-core] change `userSettings` service to no longer depends on the `security` plugin --- .../src/plugin_context.ts | 4 +- .../core-root-server-internal/src/server.ts | 1 + .../index.ts | 4 +- .../src/user_settings_service.test.ts | 98 ++++++++++++ .../src/user_settings_service.ts | 73 +++++++++ .../user_settings_service.test.ts | 82 ---------- .../user_settings_service.ts | 65 -------- .../core-user-settings-server/index.ts | 2 +- .../core-user-settings-server/types.ts | 11 +- x-pack/plugins/security/server/plugin.ts | 17 --- .../user_profile_settings_client.test.ts | 46 ------ .../user_profile_settings_client.ts | 45 ------ .../user_profile/user_setting_service.ts | 55 ------- .../user_settings_service.test.ts | 143 ------------------ 14 files changed, 179 insertions(+), 467 deletions(-) create mode 100644 packages/core/user-settings/core-user-settings-server-internal/src/user_settings_service.test.ts create mode 100644 packages/core/user-settings/core-user-settings-server-internal/src/user_settings_service.ts delete mode 100644 packages/core/user-settings/core-user-settings-server-internal/user_settings_service.test.ts delete mode 100644 packages/core/user-settings/core-user-settings-server-internal/user_settings_service.ts delete mode 100644 x-pack/plugins/security/server/user_profile/user_profile_settings_client.test.ts delete mode 100644 x-pack/plugins/security/server/user_profile/user_profile_settings_client.ts delete mode 100644 x-pack/plugins/security/server/user_profile/user_setting_service.ts delete mode 100644 x-pack/plugins/security/server/user_profile/user_settings_service.test.ts diff --git a/packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts b/packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts index 830df5c94e008..7844319de1df9 100644 --- a/packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts +++ b/packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts @@ -272,9 +272,7 @@ export function createPluginSetupContext({ registerGlobal: deps.uiSettings.registerGlobal, setAllowlist: deps.uiSettings.setAllowlist, }, - userSettings: { - setUserProfileSettings: deps.userSettings.setUserProfileSettings, - }, + userSettings: {}, getStartServices: () => plugin.startDependencies, deprecations: deps.deprecations.getRegistry(plugin.name), coreUsageData: { diff --git a/packages/core/root/core-root-server-internal/src/server.ts b/packages/core/root/core-root-server-internal/src/server.ts index 1439fa19cb64d..ec375fd1a956a 100644 --- a/packages/core/root/core-root-server-internal/src/server.ts +++ b/packages/core/root/core-root-server-internal/src/server.ts @@ -381,6 +381,7 @@ export class Server { const analyticsStart = this.analytics.start(); const securityStart = this.security.start(); const userProfileStart = this.userProfile.start(); + this.userSettingsService.start({ userProfile: userProfileStart }); const executionContextStart = this.executionContext.start(); const docLinkStart = this.docLinks.start(); diff --git a/packages/core/user-settings/core-user-settings-server-internal/index.ts b/packages/core/user-settings/core-user-settings-server-internal/index.ts index e4cd3e0e42f30..f226321af6d64 100644 --- a/packages/core/user-settings/core-user-settings-server-internal/index.ts +++ b/packages/core/user-settings/core-user-settings-server-internal/index.ts @@ -6,5 +6,5 @@ * Side Public License, v 1. */ -export { UserSettingsService } from './user_settings_service'; -export type { InternalUserSettingsServiceSetup } from './user_settings_service'; +export { UserSettingsService } from './src/user_settings_service'; +export type { InternalUserSettingsServiceSetup } from './src/user_settings_service'; diff --git a/packages/core/user-settings/core-user-settings-server-internal/src/user_settings_service.test.ts b/packages/core/user-settings/core-user-settings-server-internal/src/user_settings_service.test.ts new file mode 100644 index 0000000000000..79feda9e23a98 --- /dev/null +++ b/packages/core/user-settings/core-user-settings-server-internal/src/user_settings_service.test.ts @@ -0,0 +1,98 @@ +/* + * 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 { mockCoreContext } from '@kbn/core-base-server-mocks'; +import { httpServerMock } from '@kbn/core-http-server-mocks'; +import { userProfileServiceMock } from '@kbn/core-user-profile-server-mocks'; +import type { UserProfileWithSecurity } from '@kbn/core-user-profile-common'; +import { UserSettingsService } from './user_settings_service'; + +describe('#setup', () => { + let coreContext: ReturnType; + let service: UserSettingsService; + let startDeps: { userProfile: ReturnType }; + + beforeEach(() => { + coreContext = mockCoreContext.create(); + service = new UserSettingsService(coreContext); + startDeps = { + userProfile: userProfileServiceMock.createInternalStart(), + }; + }); + + const createUserProfile = (darkMode: string | undefined): UserProfileWithSecurity => { + return { + data: { + userSettings: { + darkMode, + }, + }, + } as unknown as UserProfileWithSecurity; + }; + + it('fetches userSettings when client is set and returns `true` when `darkMode` is set to `dark`', async () => { + startDeps.userProfile.getCurrent.mockResolvedValue(createUserProfile('dark')); + + const { getUserSettingDarkMode } = service.setup(); + service.start(startDeps); + + const kibanaRequest = httpServerMock.createKibanaRequest(); + const darkMode = await getUserSettingDarkMode(kibanaRequest); + + expect(darkMode).toEqual(true); + expect(startDeps.userProfile.getCurrent).toHaveBeenCalledTimes(1); + expect(startDeps.userProfile.getCurrent).toHaveBeenCalledWith({ + request: kibanaRequest, + dataPath: 'userSettings', + }); + }); + + it('fetches userSettings when client is set and returns `false` when `darkMode` is set to `light`', async () => { + startDeps.userProfile.getCurrent.mockResolvedValue(createUserProfile('light')); + + const { getUserSettingDarkMode } = service.setup(); + service.start(startDeps); + + const kibanaRequest = httpServerMock.createKibanaRequest(); + const darkMode = await getUserSettingDarkMode(kibanaRequest); + + expect(darkMode).toEqual(false); + expect(startDeps.userProfile.getCurrent).toHaveBeenCalledTimes(1); + expect(startDeps.userProfile.getCurrent).toHaveBeenCalledWith({ + request: kibanaRequest, + dataPath: 'userSettings', + }); + }); + + it('fetches userSettings when client is set and returns `undefined` when `darkMode` is set to `` (the default value)', async () => { + startDeps.userProfile.getCurrent.mockResolvedValue(createUserProfile('')); + + const { getUserSettingDarkMode } = service.setup(); + service.start(startDeps); + + const kibanaRequest = httpServerMock.createKibanaRequest(); + const darkMode = await getUserSettingDarkMode(kibanaRequest); + + expect(darkMode).toEqual(undefined); + expect(startDeps.userProfile.getCurrent).toHaveBeenCalledTimes(1); + expect(startDeps.userProfile.getCurrent).toHaveBeenCalledWith({ + request: kibanaRequest, + dataPath: 'userSettings', + }); + }); + + it('does not fetch userSettings when client is not set, returns `undefined`, and logs a debug statement', async () => { + const { getUserSettingDarkMode } = service.setup(); + + const kibanaRequest = httpServerMock.createKibanaRequest(); + const darkMode = await getUserSettingDarkMode(kibanaRequest); + + expect(darkMode).toEqual(undefined); + expect(coreContext.logger.get().debug).toHaveBeenCalledWith('userProfile not set'); + }); +}); diff --git a/packages/core/user-settings/core-user-settings-server-internal/src/user_settings_service.ts b/packages/core/user-settings/core-user-settings-server-internal/src/user_settings_service.ts new file mode 100644 index 0000000000000..feb7877a795ad --- /dev/null +++ b/packages/core/user-settings/core-user-settings-server-internal/src/user_settings_service.ts @@ -0,0 +1,73 @@ +/* + * 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 { CoreContext } from '@kbn/core-base-server-internal'; +import type { Logger } from '@kbn/logging'; +import type { KibanaRequest } from '@kbn/core-http-server'; +import type { DarkModeValue } from '@kbn/core-ui-settings-common'; +import type { InternalUserProfileServiceStart } from '@kbn/core-user-profile-server-internal'; + +export interface UserSettingsServiceStartDeps { + userProfile: InternalUserProfileServiceStart; +} + +const userSettingsDataPath = 'userSettings'; + +/** + * @internal + */ +export interface InternalUserSettingsServiceSetup { + getUserSettingDarkMode: (request: KibanaRequest) => Promise; +} + +/** + * @internal + */ +export class UserSettingsService { + private logger: Logger; + private userProfile?: InternalUserProfileServiceStart; + + constructor(coreContext: CoreContext) { + this.logger = coreContext.logger.get('user-settings-service'); + } + + public setup(): InternalUserSettingsServiceSetup { + return { + getUserSettingDarkMode: async (request: KibanaRequest) => { + const userSettings = await this.getSettings(request); + return getUserSettingDarkMode(userSettings); + }, + }; + } + + public start(deps: UserSettingsServiceStartDeps) { + this.userProfile = deps.userProfile; + } + + private async getSettings(request: KibanaRequest): Promise> { + if (this.userProfile) { + const userProfile = await this.userProfile.getCurrent({ + request, + dataPath: userSettingsDataPath, + }); + return (userProfile?.data?.[userSettingsDataPath] ?? {}) as Record; + } else { + this.logger.debug('userProfile not set'); + return {}; + } + } +} + +const getUserSettingDarkMode = ( + userSettings: Record +): DarkModeValue | undefined => { + if (userSettings?.darkMode) { + return userSettings.darkMode.toUpperCase() === 'DARK'; + } + return undefined; +}; diff --git a/packages/core/user-settings/core-user-settings-server-internal/user_settings_service.test.ts b/packages/core/user-settings/core-user-settings-server-internal/user_settings_service.test.ts deleted file mode 100644 index 15715e62823d2..0000000000000 --- a/packages/core/user-settings/core-user-settings-server-internal/user_settings_service.test.ts +++ /dev/null @@ -1,82 +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 - * 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 { mockCoreContext } from '@kbn/core-base-server-mocks'; -import { UserSettingsService } from './user_settings_service'; -import { httpServerMock } from '@kbn/core-http-server-mocks'; - -describe('#setup', () => { - const coreContext: ReturnType = mockCoreContext.create(); - const { createKibanaRequest } = httpServerMock; - - it('fetches userSettings when client is set and returns `true` when `darkMode` is set to `dark`', async () => { - const service = new UserSettingsService(coreContext); - const { setUserProfileSettings, getUserSettingDarkMode } = service.setup(); - - const userProfileContract = { - get: jest.fn().mockReturnValueOnce(Promise.resolve({ darkMode: 'dark' })), - }; - - setUserProfileSettings(userProfileContract); - - const kibanaRequest = createKibanaRequest(); - const darkMode = await getUserSettingDarkMode(kibanaRequest); - - expect(darkMode).toEqual(true); - expect(userProfileContract.get).toHaveBeenCalledTimes(1); - expect(userProfileContract.get).toHaveBeenCalledWith(kibanaRequest); - }); - - it('fetches userSettings when client is set and returns `false` when `darkMode` is set to `light`', async () => { - const service = new UserSettingsService(coreContext); - const { setUserProfileSettings, getUserSettingDarkMode } = service.setup(); - - const userProfileContract = { - get: jest.fn().mockReturnValueOnce(Promise.resolve({ darkMode: 'light' })), - }; - - setUserProfileSettings(userProfileContract); - - const kibanaRequest = createKibanaRequest(); - const darkMode = await getUserSettingDarkMode(kibanaRequest); - - expect(darkMode).toEqual(false); - expect(userProfileContract.get).toHaveBeenCalledTimes(1); - expect(userProfileContract.get).toHaveBeenCalledWith(kibanaRequest); - }); - - it('fetches userSettings when client is set and returns `undefined` when `darkMode` is set to `` (the default value)', async () => { - const service = new UserSettingsService(coreContext); - const { setUserProfileSettings, getUserSettingDarkMode } = service.setup(); - - const userProfileContract = { - get: jest.fn().mockReturnValueOnce(Promise.resolve({ darkMode: '' })), - }; - - setUserProfileSettings(userProfileContract); - - const kibanaRequest = createKibanaRequest(); - const darkMode = await getUserSettingDarkMode(kibanaRequest); - - expect(darkMode).toEqual(undefined); - expect(userProfileContract.get).toHaveBeenCalledTimes(1); - expect(userProfileContract.get).toHaveBeenCalledWith(kibanaRequest); - }); - - it('does not fetch userSettings when client is not set, returns `undefined`, and logs a debug statement', async () => { - const service = new UserSettingsService(coreContext); - const { getUserSettingDarkMode } = service.setup(); - const kibanaRequest = createKibanaRequest(); - const darkMode = await getUserSettingDarkMode(kibanaRequest); - - expect(darkMode).toEqual(undefined); - expect(coreContext.logger.get().debug).toHaveBeenCalledWith( - 'UserProfileSettingsClient not set' - ); - }); -}); diff --git a/packages/core/user-settings/core-user-settings-server-internal/user_settings_service.ts b/packages/core/user-settings/core-user-settings-server-internal/user_settings_service.ts deleted file mode 100644 index 309f0defd22e2..0000000000000 --- a/packages/core/user-settings/core-user-settings-server-internal/user_settings_service.ts +++ /dev/null @@ -1,65 +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 - * 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 { CoreContext } from '@kbn/core-base-server-internal'; -import { Logger } from '@kbn/logging'; -import { KibanaRequest } from '@kbn/core-http-server'; -import { DarkModeValue } from '@kbn/core-ui-settings-common'; -import { UserProfileSettingsClientContract } from '@kbn/core-user-settings-server'; - -/** - * @internal - */ -export interface InternalUserSettingsServiceSetup { - setUserProfileSettings: (client: UserProfileSettingsClientContract) => void; - getUserSettingDarkMode: (request: KibanaRequest) => Promise; -} - -export class UserSettingsService { - private logger: Logger; - private client?: UserProfileSettingsClientContract; - - constructor(coreContext: CoreContext) { - this.logger = coreContext.logger.get('user-settings-service'); - } - - public setup(): InternalUserSettingsServiceSetup { - return { - setUserProfileSettings: (client: UserProfileSettingsClientContract) => { - this.client = client; - }, - getUserSettingDarkMode: async (request: KibanaRequest) => { - const userSettings = await this.getSettings(request); - return this.getUserSettingDarkMode(userSettings); - }, - }; - } - - private async getSettings(request: KibanaRequest): Promise> { - let result = {}; - if (this.client) { - result = (await this.client.get(request)) as Record; - } else { - this.logger.debug('UserProfileSettingsClient not set'); - } - - return result; - } - - private async getUserSettingDarkMode( - userSettings: Record - ): Promise { - let result; - - if (userSettings?.darkMode) { - result = userSettings.darkMode.toUpperCase() === 'DARK'; - } - - return result; - } -} diff --git a/packages/core/user-settings/core-user-settings-server/index.ts b/packages/core/user-settings/core-user-settings-server/index.ts index c13d17fb4b955..3f74a1d95fee6 100644 --- a/packages/core/user-settings/core-user-settings-server/index.ts +++ b/packages/core/user-settings/core-user-settings-server/index.ts @@ -6,4 +6,4 @@ * Side Public License, v 1. */ -export type { UserSettingsServiceSetup, UserProfileSettingsClientContract } from './types'; +export type { UserSettingsServiceSetup } from './types'; diff --git a/packages/core/user-settings/core-user-settings-server/types.ts b/packages/core/user-settings/core-user-settings-server/types.ts index f852e0e188bfd..b7ef24e7a3053 100644 --- a/packages/core/user-settings/core-user-settings-server/types.ts +++ b/packages/core/user-settings/core-user-settings-server/types.ts @@ -5,13 +5,8 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import { KibanaRequest } from '@kbn/core-http-server'; /** @public */ -export interface UserSettingsServiceSetup { - setUserProfileSettings: (client: UserProfileSettingsClientContract) => void; -} - -export interface UserProfileSettingsClientContract { - get: (request: KibanaRequest) => Promise>; -} +// keeping the empty service contract for now as we might re-use it very soon +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface UserSettingsServiceSetup {} diff --git a/x-pack/plugins/security/server/plugin.ts b/x-pack/plugins/security/server/plugin.ts index 828c8b42ea1b7..7153e1cc6794e 100644 --- a/x-pack/plugins/security/server/plugin.ts +++ b/x-pack/plugins/security/server/plugin.ts @@ -60,9 +60,6 @@ import { setupSpacesClient } from './spaces'; import { registerSecurityUsageCollector } from './usage_collector'; import { UserProfileService } from './user_profile'; import type { UserProfileServiceStartInternal } from './user_profile'; -import { UserProfileSettingsClient } from './user_profile/user_profile_settings_client'; -import type { UserSettingServiceStart } from './user_profile/user_setting_service'; -import { UserSettingService } from './user_profile/user_setting_service'; import type { AuthenticatedUser, SecurityLicense } from '../common'; import { SecurityLicenseService } from '../common/licensing'; @@ -172,9 +169,6 @@ export class SecurityPlugin private readonly userProfileService: UserProfileService; private userProfileStart?: UserProfileServiceStartInternal; - private readonly userSettingService: UserSettingService; - private userSettingServiceStart?: UserSettingServiceStart; - private userProfileSettingsClient: UserProfileSettingsClient; private readonly getUserProfileService = () => { if (!this.userProfileStart) { throw new Error(`userProfileStart is not registered!`); @@ -202,15 +196,8 @@ export class SecurityPlugin this.userProfileService = new UserProfileService( this.initializerContext.logger.get('user-profile') ); - this.userSettingService = new UserSettingService( - this.initializerContext.logger.get('user-settings') - ); this.analyticsService = new AnalyticsService(this.initializerContext.logger.get('analytics')); - - this.userProfileSettingsClient = new UserProfileSettingsClient( - this.initializerContext.logger.get('user-settings-client') - ); } public setup( @@ -238,8 +225,6 @@ export class SecurityPlugin features: depsServices.features, })); - core.userSettings.setUserProfileSettings(this.userProfileSettingsClient); - const { license } = this.securityLicenseService.setup({ license$: licensing.license$, }); @@ -386,8 +371,6 @@ export class SecurityPlugin this.session = session; this.userProfileStart = this.userProfileService.start({ clusterClient, session }); - this.userSettingServiceStart = this.userSettingService.start(this.userProfileStart); - this.userProfileSettingsClient.setUserSettingsServiceStart(this.userSettingServiceStart); // In serverless, we want to redirect users to the list of projects instead of standard "Logged Out" page. const customLogoutURL = diff --git a/x-pack/plugins/security/server/user_profile/user_profile_settings_client.test.ts b/x-pack/plugins/security/server/user_profile/user_profile_settings_client.test.ts deleted file mode 100644 index 46202d5a94ea2..0000000000000 --- a/x-pack/plugins/security/server/user_profile/user_profile_settings_client.test.ts +++ /dev/null @@ -1,46 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { loggingSystemMock } from '@kbn/core/server/mocks'; -import type { httpServerMock } from '@kbn/core-http-server-mocks'; -import type { Logger } from '@kbn/logging'; - -import { UserProfileSettingsClient } from './user_profile_settings_client'; -import type { UserSettingServiceStart } from './user_setting_service'; - -describe('UserProfileSettingsClient', () => { - let mockRequest: ReturnType; - let client: UserProfileSettingsClient; - let logger: Logger; - let userSettingServiceStart: jest.Mocked; - - beforeEach(() => { - userSettingServiceStart = { - getCurrentUserProfileSettings: jest.fn(), - }; - - userSettingServiceStart.getCurrentUserProfileSettings.mockResolvedValue({ darkMode: 'dark' }); - - logger = loggingSystemMock.createLogger(); - client = new UserProfileSettingsClient(logger); - }); - - describe('#get', () => { - it('should return empty before UserSettingServiceStart is set', async () => { - const userSettings = await client.get(mockRequest); - expect(userSettings).toEqual({}); - expect(logger.debug).toHaveBeenCalledWith('UserSettingsServiceStart has not been set yet'); - }); - - it('should return user settings after UserSettingServiceStart is set', async () => { - client.setUserSettingsServiceStart(userSettingServiceStart); - const userSettings = await client.get(mockRequest); - - expect(userSettings).toEqual({ darkMode: 'dark' }); - }); - }); -}); diff --git a/x-pack/plugins/security/server/user_profile/user_profile_settings_client.ts b/x-pack/plugins/security/server/user_profile/user_profile_settings_client.ts deleted file mode 100644 index 03bf4855cbc79..0000000000000 --- a/x-pack/plugins/security/server/user_profile/user_profile_settings_client.ts +++ /dev/null @@ -1,45 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import type { Logger } from '@kbn/core/server'; -import type { KibanaRequest } from '@kbn/core-http-server'; -import type { UserProfileSettingsClientContract } from '@kbn/core-user-settings-server'; - -import type { UserSettingServiceStart } from './user_setting_service'; -/** - * A wrapper client around {@link UserSettingServiceStart} that exposes a method to get the current user's profile - */ -export class UserProfileSettingsClient implements UserProfileSettingsClientContract { - private userSettingServiceStart: UserSettingServiceStart | undefined; - private logger: Logger; - - constructor(logger: Logger) { - this.logger = logger; - } - - /** - * Returns the current user's user profile settings - * - * @param request the KibanaRequest that is required to get the current user and their settings - * @return the User Settings values retrieved from the UserSettingsServiceStart, if it has been set, otherwise, - * default to an empty Record - */ - async get(request: KibanaRequest): Promise> { - let result: Record = {} as Record; - - if (this.userSettingServiceStart) { - result = await this.userSettingServiceStart.getCurrentUserProfileSettings(request); - } else { - this.logger.debug('UserSettingsServiceStart has not been set yet'); - } - - return result; - } - - setUserSettingsServiceStart(userSettingServiceStart: UserSettingServiceStart) { - this.userSettingServiceStart = userSettingServiceStart; - } -} diff --git a/x-pack/plugins/security/server/user_profile/user_setting_service.ts b/x-pack/plugins/security/server/user_profile/user_setting_service.ts deleted file mode 100644 index f423d75e1a041..0000000000000 --- a/x-pack/plugins/security/server/user_profile/user_setting_service.ts +++ /dev/null @@ -1,55 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { KibanaRequest } from '@kbn/core-http-server'; -import type { Logger } from '@kbn/logging'; -import type { - UserProfileGetCurrentParams, - UserProfileServiceStart, -} from '@kbn/security-plugin-types-server'; - -export interface UserSettingServiceStart { - /** - * Returns the currently signed-in user's settings from their User Profile - * - * @param request the KibanaRequest that is required to get the current user and their settings - */ - getCurrentUserProfileSettings(request: KibanaRequest): Promise>; -} - -/** - * A service that wraps the {@link UserProfileServiceStart} so that only the 'getCurrent' method is made available - */ -export class UserSettingService { - private readonly logger: Logger; - - constructor(logger: Logger) { - this.logger = logger; - } - - start(userProfileServiceStart: UserProfileServiceStart): UserSettingServiceStart { - return { - getCurrentUserProfileSettings: async (request) => { - const params: UserProfileGetCurrentParams = { - request, - dataPath: 'userSettings', - }; - - const currentUserProfile = await userProfileServiceStart.getCurrent(params); - - let result = {} as Record; - - if (currentUserProfile?.data?.userSettings) { - result = currentUserProfile?.data?.userSettings as Record; - } else { - this.logger.debug('User Settings not found.'); - } - return result; - }, - }; - } -} diff --git a/x-pack/plugins/security/server/user_profile/user_settings_service.test.ts b/x-pack/plugins/security/server/user_profile/user_settings_service.test.ts deleted file mode 100644 index d27887d5716f9..0000000000000 --- a/x-pack/plugins/security/server/user_profile/user_settings_service.test.ts +++ /dev/null @@ -1,143 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { SecurityGetUserProfileResponse } from '@elastic/elasticsearch/lib/api/types'; - -import { - elasticsearchServiceMock, - httpServerMock, - loggingSystemMock, -} from '@kbn/core/server/mocks'; -import type { UserProfileServiceStart } from '@kbn/security-plugin-types-server'; - -import { UserProfileService } from './user_profile_service'; -import { UserSettingService } from './user_setting_service'; -import type { UserProfileWithSecurity } from '../../common'; -import { licenseMock } from '../../common/licensing/index.mock'; -import { userProfileMock } from '../../common/model/user_profile.mock'; -import { authorizationMock } from '../authorization/index.mock'; -import { sessionMock } from '../session_management/session.mock'; - -const logger = loggingSystemMock.createLogger(); -describe('UserSettingService', () => { - let mockStartParams: { - clusterClient: ReturnType; - session: ReturnType; - }; - - let mockAuthz: ReturnType; - let userProfileService: UserProfileService; - let userSettingsService: UserSettingService; - let userProfileServiceStart: UserProfileServiceStart; - - beforeEach(() => { - mockStartParams = { - clusterClient: elasticsearchServiceMock.createClusterClient(), - session: sessionMock.create(), - }; - - mockAuthz = authorizationMock.create(); - - userProfileService = new UserProfileService(logger); - userSettingsService = new UserSettingService(logger); - - userProfileService.setup({ - authz: mockAuthz, - license: licenseMock.create({ allowUserProfileCollaboration: true }), - }); - - userProfileServiceStart = userProfileService.start(mockStartParams); - }); - - afterEach(() => { - logger.error.mockClear(); - }); - - it('should expose correct start contract', () => { - const userSettingServiceStart = userSettingsService.start(userProfileServiceStart); - expect(userSettingServiceStart).toMatchInlineSnapshot(` - Object { - "getCurrentUserProfileSettings": [Function], - } - `); - }); - - describe('#getCurrentUserProfileSettings', () => { - let mockUserProfile: UserProfileWithSecurity; - let mockRequest: ReturnType; - beforeEach(() => { - mockRequest = httpServerMock.createKibanaRequest(); - }); - - it('returns user settings data', async () => { - mockUserProfile = userProfileMock.createWithSecurity({ - uid: 'UID', - user: { - username: 'user-1', - full_name: 'full-name-1', - realm_name: 'some-realm', - realm_domain: 'some-domain', - roles: ['role-1'], - }, - data: { - kibana: { - userSettings: { - darkMode: 'dark', - }, - }, - }, - }); - - mockStartParams.clusterClient.asInternalUser.security.getUserProfile.mockResolvedValue({ - profiles: [mockUserProfile], - } as unknown as SecurityGetUserProfileResponse); - - mockStartParams.session.get.mockResolvedValue({ - error: null, - value: sessionMock.createValue({ userProfileId: mockUserProfile.uid }), - }); - - userProfileServiceStart = userProfileService.start(mockStartParams); - const userSettingServiceStart = userSettingsService.start(userProfileServiceStart); - await expect( - userSettingServiceStart.getCurrentUserProfileSettings(mockRequest) - ).resolves.toEqual({ darkMode: 'dark' }); - }); - - it('logs a warning and returns ', async () => { - mockUserProfile = userProfileMock.createWithSecurity({ - uid: 'UID', - user: { - username: 'user-1', - full_name: 'full-name-1', - realm_name: 'some-realm', - realm_domain: 'some-domain', - roles: ['role-1'], - }, - data: {}, - }); - - mockStartParams.clusterClient.asInternalUser.security.getUserProfile.mockResolvedValue({ - profiles: [mockUserProfile], - } as unknown as SecurityGetUserProfileResponse); - - mockStartParams.session.get.mockResolvedValue({ - error: null, - value: sessionMock.createValue({ userProfileId: mockUserProfile.uid }), - }); - - userProfileServiceStart = userProfileService.start(mockStartParams); - const userSettingServiceStart = userSettingsService.start(userProfileServiceStart); - - await expect( - userSettingServiceStart.getCurrentUserProfileSettings(mockRequest) - ).resolves.toEqual({}); - - expect(logger.debug).toHaveBeenCalledWith('User Settings not found.'); - }); - }); -}); From b634935d92db3be5e0b4cf74e0778502eeaab64d Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 24 Apr 2024 10:09:52 +0000 Subject: [PATCH 2/5] [CI] Auto-commit changed files from 'node scripts/lint_ts_projects --fix' --- .../core-user-settings-server-internal/tsconfig.json | 4 +++- .../user-settings/core-user-settings-server/tsconfig.json | 1 - x-pack/plugins/security/tsconfig.json | 1 - 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/core/user-settings/core-user-settings-server-internal/tsconfig.json b/packages/core/user-settings/core-user-settings-server-internal/tsconfig.json index a35a40a0d3c49..37fbe2fd5cc02 100644 --- a/packages/core/user-settings/core-user-settings-server-internal/tsconfig.json +++ b/packages/core/user-settings/core-user-settings-server-internal/tsconfig.json @@ -13,8 +13,10 @@ "@kbn/core-base-server-internal", "@kbn/logging", "@kbn/core-http-server-mocks", - "@kbn/core-user-settings-server", "@kbn/core-ui-settings-common", + "@kbn/core-user-profile-server-mocks", + "@kbn/core-user-profile-common", + "@kbn/core-user-profile-server-internal", ], "include": [ "**/*.ts", diff --git a/packages/core/user-settings/core-user-settings-server/tsconfig.json b/packages/core/user-settings/core-user-settings-server/tsconfig.json index 3270f469296eb..931451997d24a 100644 --- a/packages/core/user-settings/core-user-settings-server/tsconfig.json +++ b/packages/core/user-settings/core-user-settings-server/tsconfig.json @@ -7,7 +7,6 @@ ] }, "kbn_references": [ - "@kbn/core-http-server", ], "include": [ "**/*.ts", diff --git a/x-pack/plugins/security/tsconfig.json b/x-pack/plugins/security/tsconfig.json index 61eb1bb0147f3..f3ccbabffff97 100644 --- a/x-pack/plugins/security/tsconfig.json +++ b/x-pack/plugins/security/tsconfig.json @@ -64,7 +64,6 @@ "@kbn/shared-ux-router", "@kbn/core-http-server", "@kbn/core-http-server-mocks", - "@kbn/core-user-settings-server", "@kbn/remote-clusters-plugin", "@kbn/analytics-client", "@kbn/security-plugin-types-common", From 087595b130cb2b16dbc27b6a0d52c863c85b22f1 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Thu, 25 Apr 2024 09:42:47 +0200 Subject: [PATCH 3/5] fix / adapt mocks --- .../src/server.test.ts | 1 + .../src/service_contract.mock.ts | 14 ------------- .../src/user_settings_service.mock.ts | 21 ++++++++++++------- 3 files changed, 14 insertions(+), 22 deletions(-) delete mode 100644 packages/core/user-settings/core-user-settings-server-mocks/src/service_contract.mock.ts diff --git a/packages/core/root/core-root-server-internal/src/server.test.ts b/packages/core/root/core-root-server-internal/src/server.test.ts index 60073cc5fcfd4..2b9e55d466f54 100644 --- a/packages/core/root/core-root-server-internal/src/server.test.ts +++ b/packages/core/root/core-root-server-internal/src/server.test.ts @@ -219,6 +219,7 @@ test('runs services on "start"', async () => { expect(mockCustomBrandingService.start).toHaveBeenCalledTimes(1); expect(mockSecurityService.start).toHaveBeenCalledTimes(1); expect(mockUserProfileService.start).toHaveBeenCalledTimes(1); + expect(mockUserSettingsService.start).toHaveBeenCalledTimes(1); }); test('does not fail on "setup" if there are unused paths detected', async () => { diff --git a/packages/core/user-settings/core-user-settings-server-mocks/src/service_contract.mock.ts b/packages/core/user-settings/core-user-settings-server-mocks/src/service_contract.mock.ts deleted file mode 100644 index d4176ee2bbfb6..0000000000000 --- a/packages/core/user-settings/core-user-settings-server-mocks/src/service_contract.mock.ts +++ /dev/null @@ -1,14 +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 - * 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 { UserSettingsService } from '@kbn/core-user-settings-server-internal'; - -export const serviceContractMock = (): jest.Mocked => { - return { - setup: jest.fn(), - } as unknown as jest.Mocked; -}; diff --git a/packages/core/user-settings/core-user-settings-server-mocks/src/user_settings_service.mock.ts b/packages/core/user-settings/core-user-settings-server-mocks/src/user_settings_service.mock.ts index 74cbc491bad5f..88dca2b79e1c5 100644 --- a/packages/core/user-settings/core-user-settings-server-mocks/src/user_settings_service.mock.ts +++ b/packages/core/user-settings/core-user-settings-server-mocks/src/user_settings_service.mock.ts @@ -6,20 +6,25 @@ * Side Public License, v 1. */ -import { serviceContractMock } from './service_contract.mock'; +import type { PublicMethodsOf } from '@kbn/utility-types'; +import type { + UserSettingsService, + InternalUserSettingsServiceSetup, +} from '@kbn/core-user-settings-server-internal'; -const createSetupContractMock = () => { +const createSetupContractMock = (): jest.Mocked => { return { - setUserProfileSettings: jest.fn(), getUserSettingDarkMode: jest.fn(), }; }; -const createMock = () => { - const mocked = serviceContractMock(); - mocked.setup.mockReturnValue(createSetupContractMock()); - // mocked.start.mockReturnValue(createStartContractMock()); - return mocked; +const createMock = (): jest.Mocked> => { + const mock = { + setup: jest.fn(), + start: jest.fn(), + }; + mock.setup.mockReturnValue(createSetupContractMock()); + return mock; }; export const userSettingsServiceMock = { From c56b9b65f4badc653475cab722156f0bdb7a25a9 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 25 Apr 2024 07:49:58 +0000 Subject: [PATCH 4/5] [CI] Auto-commit changed files from 'node scripts/lint_ts_projects --fix' --- .../user-settings/core-user-settings-server-mocks/tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/core/user-settings/core-user-settings-server-mocks/tsconfig.json b/packages/core/user-settings/core-user-settings-server-mocks/tsconfig.json index 44431c1ebcf0e..09c11388d22c1 100644 --- a/packages/core/user-settings/core-user-settings-server-mocks/tsconfig.json +++ b/packages/core/user-settings/core-user-settings-server-mocks/tsconfig.json @@ -9,6 +9,7 @@ }, "kbn_references": [ "@kbn/core-user-settings-server-internal", + "@kbn/utility-types", ], "include": [ "**/*.ts", From 0ca397ce862eebf39414cbc4c9b6ea2e14b76fa9 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Thu, 25 Apr 2024 12:38:59 +0200 Subject: [PATCH 5/5] fix tests --- .../src/bootstrap/bootstrap_renderer.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/core/rendering/core-rendering-server-internal/src/bootstrap/bootstrap_renderer.test.ts b/packages/core/rendering/core-rendering-server-internal/src/bootstrap/bootstrap_renderer.test.ts index 2f87f6dd27a37..285553ba46a1b 100644 --- a/packages/core/rendering/core-rendering-server-internal/src/bootstrap/bootstrap_renderer.test.ts +++ b/packages/core/rendering/core-rendering-server-internal/src/bootstrap/bootstrap_renderer.test.ts @@ -129,7 +129,7 @@ describe('bootstrapRenderer', () => { }); it('calls getThemeTag with values (true/dark) from the UserSettingsService when provided', async () => { - userSettingsService.getUserSettingDarkMode.mockReturnValueOnce(true); + userSettingsService.getUserSettingDarkMode.mockResolvedValueOnce(true); renderer = bootstrapRendererFactory({ auth, @@ -155,7 +155,7 @@ describe('bootstrapRenderer', () => { }); it('calls getThemeTag with values (false/light) from the UserSettingsService when provided', async () => { - userSettingsService.getUserSettingDarkMode.mockReturnValueOnce(false); + userSettingsService.getUserSettingDarkMode.mockResolvedValueOnce(false); renderer = bootstrapRendererFactory({ auth, @@ -181,7 +181,7 @@ describe('bootstrapRenderer', () => { }); it('calls getThemeTag with values from the UiSettingsClient when values (false/light) from UserSettingsService are `undefined`', async () => { - userSettingsService.getUserSettingDarkMode.mockReturnValueOnce(undefined); + userSettingsService.getUserSettingDarkMode.mockResolvedValueOnce(undefined); renderer = bootstrapRendererFactory({ auth, @@ -207,7 +207,7 @@ describe('bootstrapRenderer', () => { }); it('calls getThemeTag with values from the UiSettingsClient when values (true/dark) from UserSettingsService are `undefined`', async () => { - userSettingsService.getUserSettingDarkMode.mockReturnValueOnce(undefined); + userSettingsService.getUserSettingDarkMode.mockResolvedValueOnce(undefined); renderer = bootstrapRendererFactory({ auth,