From 6effbcd4c6faaf36c52792ab3b8feceaf0761c20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20David=20Guti=C3=A9rrez?= Date: Fri, 27 Sep 2024 13:57:13 +0200 Subject: [PATCH 01/25] feat(core): create serverSecurity service - Create basic types - Create CoreServerSecurity implementation - Create runtime dependencies of serverSecurity - hooks - useServerUserLogged, - useServerUserPermissions, - useServerUserPermissionsRequirements, - useServerUserPermissionsIsAdminRequirements, - hocs - withServerUserAuthorizationPrompt, - withServerUserLogged, - ui - ServerButtonPermissions - ServerElementPermissions - Export the serverSecurity service in the lifecycle methods of core plugin --- plugins/wazuh-core/docs/README.md | 6 +- plugins/wazuh-core/public/plugin.ts | 58 ++- plugins/wazuh-core/public/services/index.ts | 1 + .../public/services/server-security/README.md | 55 +++ .../public/services/server-security/index.ts | 2 + .../server-security/server-security.ts | 67 ++++ .../public/services/server-security/types.ts | 58 +++ .../server-security/ui/components/button.tsx | 80 ++++ .../server-security/ui/components/creator.tsx | 33 ++ .../server-security/ui/components/element.tsx | 103 +++++ .../server-security/ui/components/format.tsx | 71 ++++ .../server-security/ui/components/loading.tsx | 23 ++ .../server-security/ui/components/prompt.tsx | 55 +++ .../server-security/ui/hocs/creator.tsx | 63 ++++ .../server-security/ui/hooks/creator.ts | 59 +++ .../wz-user-permissions.test.ts | 351 ++++++++++++++++++ .../server-security/wz-user-permissions.ts | 160 ++++++++ plugins/wazuh-core/public/types.ts | 25 +- 18 files changed, 1266 insertions(+), 4 deletions(-) create mode 100644 plugins/wazuh-core/public/services/index.ts create mode 100644 plugins/wazuh-core/public/services/server-security/README.md create mode 100644 plugins/wazuh-core/public/services/server-security/index.ts create mode 100644 plugins/wazuh-core/public/services/server-security/server-security.ts create mode 100644 plugins/wazuh-core/public/services/server-security/types.ts create mode 100644 plugins/wazuh-core/public/services/server-security/ui/components/button.tsx create mode 100644 plugins/wazuh-core/public/services/server-security/ui/components/creator.tsx create mode 100644 plugins/wazuh-core/public/services/server-security/ui/components/element.tsx create mode 100644 plugins/wazuh-core/public/services/server-security/ui/components/format.tsx create mode 100644 plugins/wazuh-core/public/services/server-security/ui/components/loading.tsx create mode 100644 plugins/wazuh-core/public/services/server-security/ui/components/prompt.tsx create mode 100644 plugins/wazuh-core/public/services/server-security/ui/hocs/creator.tsx create mode 100644 plugins/wazuh-core/public/services/server-security/ui/hooks/creator.ts create mode 100644 plugins/wazuh-core/public/services/server-security/wz-user-permissions.test.ts create mode 100644 plugins/wazuh-core/public/services/server-security/wz-user-permissions.ts diff --git a/plugins/wazuh-core/docs/README.md b/plugins/wazuh-core/docs/README.md index c1bdc0b37f..42a33475ac 100644 --- a/plugins/wazuh-core/docs/README.md +++ b/plugins/wazuh-core/docs/README.md @@ -15,6 +15,8 @@ This plugin provides some core services: ## Frontend -- Configuration: manage the plugins configuration -- Utils - Constants +- Utils +- Configuration: manage the plugins configuration +- Dashboard Security: manage the security related to Wazuh dashboard +- Server Security: manage the security related to Wazuh server diff --git a/plugins/wazuh-core/public/plugin.ts b/plugins/wazuh-core/public/plugin.ts index ef08e41595..8b72b6609d 100644 --- a/plugins/wazuh-core/public/plugin.ts +++ b/plugins/wazuh-core/public/plugin.ts @@ -11,11 +11,16 @@ import { } from '../common/constants'; import { DashboardSecurity } from './utils/dashboard-security'; import * as hooks from './hooks'; +import { CoreServerSecurity } from './services'; +import { BehaviorSubject } from 'rxjs'; export class WazuhCorePlugin implements Plugin { _internal: { [key: string]: any } = {}; + runtime: { [key: string]: any } = { + setup: {}, + }; services: { [key: string]: any } = {}; public async setup(core: CoreSetup): Promise { const noop = () => {}; @@ -46,12 +51,54 @@ export class WazuhCorePlugin this.services.dashboardSecurity = new DashboardSecurity(logger, core.http); + // TODO: replace by the current session data + let userSessionData = { + account: { + administrator: false, + administrator_requirements: '', + }, + policies: { rbac_mode: 'white' }, + }; + const userSession$ = new BehaviorSubject(userSessionData); + + this.services.serverSecurity = new CoreServerSecurity(logger, { + getUserPermissions: () => {}, // TODO: implement + }); + await this.services.dashboardSecurity.setup(); + this.runtime.securityServer = this.services.serverSecurity.setup({ + userSession$: userSession$, // TODO: replace + getUserSession: () => userSessionData, // TODO: replace + useLoadingLogo: () => { + // TODO: implement + // const { + // ['customization.logo.app']: customlogoApp, + // ['customization.enabled']: customizationEnabled, + // } = useConfiguration(); + // const customImage = customizationEnabled && customlogoApp; + // const imageSrc = getHttp().basePath.prepend( + // customImage + // ? getAssetURL(customImage) + // : getThemeAssetURL('logo.svg'), + // ); + }, + }); + return { ...this.services, utils, API_USER_STATUS_RUN_AS, + hooks: { + ...hooks, + ...this.runtime.setup.securityServer.hooks, + }, + hocs: { + ...this.runtime.setup.securityServer.hocs, + }, + ui: { + ...this.runtime.setup.securityServer.ui, + }, }; } @@ -66,7 +113,16 @@ export class WazuhCorePlugin ...this.services, utils, API_USER_STATUS_RUN_AS, - hooks, + hooks: { + ...hooks, + ...this.runtime.setup.securityServer.hooks, + }, + hocs: { + ...this.runtime.setup.securityServer.hocs, + }, + ui: { + ...this.runtime.setup.securityServer.ui, + }, }; } diff --git a/plugins/wazuh-core/public/services/index.ts b/plugins/wazuh-core/public/services/index.ts new file mode 100644 index 0000000000..fac2bc12b4 --- /dev/null +++ b/plugins/wazuh-core/public/services/index.ts @@ -0,0 +1 @@ +export * from './server-security'; diff --git a/plugins/wazuh-core/public/services/server-security/README.md b/plugins/wazuh-core/public/services/server-security/README.md new file mode 100644 index 0000000000..609943a8ae --- /dev/null +++ b/plugins/wazuh-core/public/services/server-security/README.md @@ -0,0 +1,55 @@ +# Server security + +The `serverSecurity` service is created in the core plugin and manage the security related to the Wazuh server. + +- Permissions + +## Features + +### Service + +- Expose methods to check the missing permission for the current user or a generic method + +### Others + +The service creates in the `setup` lifecycle method the following resources: + +- hooks + - useServerUserPermissions: the permissions of the logged user + ```tsx + const userPermissions = useServerUserPermissions(); + ``` + - useServerUserPermissionsRequirements: the missing permissions of the required permissions for the logged user + ```tsx + const [missingPermissions, userPermissions] = + useServerUserPermissionsRequirements(requiredPermissions); + ``` + - useServerUserPermissionsIsAdminRequirements: the missing requirements for "administrator users" + ```tsx + const [administratorRequirements, userSession] = + useServerUserPermissionsIsAdminRequirements(); + ``` + - useServerUserLogged: user is logged status + ```tsx + const useIsLogged = useServerUserLogged(); + ``` +- HOCs + - withServerUserAuthorizationPromptChanged: + ```tsx + withServerUserAuthorizationPromptChanged(permissions, { + isAdmininistrator: true, + })(WrappedComponent); + ``` + - withServerUserLogged: when the user is not logged, display a loading + ```tsx + withServerUserLogged(WrappedComponent); + ``` + - withServerUserAuthorizationPrompt: + ```tsx + withServerUserAuthorizationPrompt(permissions, { isAdmininistrator: true })( + WrappedComponent, + ); + ``` +- UI components + - ServerButtonPermissions + - ServerElementPermissions diff --git a/plugins/wazuh-core/public/services/server-security/index.ts b/plugins/wazuh-core/public/services/server-security/index.ts new file mode 100644 index 0000000000..771c8730ca --- /dev/null +++ b/plugins/wazuh-core/public/services/server-security/index.ts @@ -0,0 +1,2 @@ +export * from './types'; +export { CoreServerSecurity } from './server-security'; diff --git a/plugins/wazuh-core/public/services/server-security/server-security.ts b/plugins/wazuh-core/public/services/server-security/server-security.ts new file mode 100644 index 0000000000..c1e9c45313 --- /dev/null +++ b/plugins/wazuh-core/public/services/server-security/server-security.ts @@ -0,0 +1,67 @@ +import { ILogger } from '../../../common/services/configuration'; +import { checkMissingUserPermissions } from './wz-user-permissions'; +import { + ServerSecurity, + ServerSecurityCombinedPermission, + ServerSecuritySetupDeps, + ServerSecuritySetupReturn, +} from './types'; +import { createServerSecurityHooks } from './ui/hooks/creator'; +import { createServerSecurityHOCS } from './ui/hocs/creator'; +import { createServerSecurityUI } from './ui/components/creator'; +import { LoadingServerUserLogging } from './ui/components/loading'; +import { WzEmptyPromptNoPermissions } from './ui/components/prompt'; + +export class CoreServerSecurity implements ServerSecurity { + private getUserPermissions: any; + constructor(private logger: ILogger, { getUserPermissions }) { + this.getUserPermissions = getUserPermissions; + } + setup(deps: ServerSecuritySetupDeps): ServerSecuritySetupReturn { + this.logger.debug('Setup'); + + this.logger.debug('Creating runtime hooks'); + const hooks = createServerSecurityHooks({ + ...deps, + checkMissingUserPermissions: this.checkMissingUserPermissions, + }); + this.logger.debug('Created runtime hooks'); + + this.logger.debug('Creating runtime HOCs'); + const hocs = createServerSecurityHOCS({ + ...deps, + ...hooks, + LoadingServerUserLogging, + PromptNoPermissions: WzEmptyPromptNoPermissions, + }); + this.logger.debug('Created runtime HOCs'); + + this.logger.debug('Creating UI components'); + const ui = createServerSecurityUI(hooks); + this.logger.debug('Creating UI components'); + + this.logger.debug('Setup finished'); + + return { + hooks, + hocs, + ui, + }; + } + start() {} + stop() {} + checkMissingUserPermissions( + requiredPermissions: ServerSecurityCombinedPermission[], + userPermissions: any, + ) { + return checkMissingUserPermissions(requiredPermissions, userPermissions); + } + getMissingUserPermissions( + requiredPermissions: ServerSecurityCombinedPermission[], + ) { + return checkMissingUserPermissions( + requiredPermissions, + this.getUserPermissions(), + ); + } +} diff --git a/plugins/wazuh-core/public/services/server-security/types.ts b/plugins/wazuh-core/public/services/server-security/types.ts new file mode 100644 index 0000000000..6a36b73c24 --- /dev/null +++ b/plugins/wazuh-core/public/services/server-security/types.ts @@ -0,0 +1,58 @@ +import React from 'react'; + +export interface ServerSecurityPermission { + action: string; + resource: string; +} + +export type ServerSecurityCombinedPermission = + | ServerSecurityPermission + | ServerSecurityPermission[]; + +export interface ServerSecuritySetupDeps { + userSession$: any; + getUserSession: any; + useLoadingLogo: any; +} + +export interface ServerSecuritySetupReturn { + hooks: { + useServerUserLogged: () => boolean; + useServerUserPermissions: () => any; + useServerUserPermissionsRequirements: ( + permissions: ServerSecurityCombinedPermission, + ) => [ServerSecurityCombinedPermission, any]; + useServerUserPermissionsIsAdminRequirements: () => [string, any]; + }; + hocs: { + withServerUserAuthorizationPrompt: ( + permissions: ServerSecurityCombinedPermission | null, + otherPermissions: { isAdmininistrator: boolean | null }, + ) => (WrappedComponent: React.Component) => React.ReactElement; + withServerUserLogged: ( + WrappedComponent: React.Component, + ) => React.ReactElement; + }; + ui: { + ServerButtonPermissions: React.Component; + ServerElementPermissions: React.Component; + }; +} + +export interface ServerSecurity { + setup: (deps: ServerSecuritySetupDeps) => ServerSecuritySetupReturn; + start: () => void; + stop: () => void; + checkMissingUserPermissions: ( + requiredPermissions: ServerSecurityCombinedPermission[], + userPermissions: any, + ) => ServerSecurityCombinedPermission[] | false; + getMissingUserPermissions: ( + requiredPermissions: ServerSecurityCombinedPermission[], + ) => ServerSecurityCombinedPermission[] | false; +} + +export interface ServerSecurityUserSession { + logged: boolean; + policies: any; +} diff --git a/plugins/wazuh-core/public/services/server-security/ui/components/button.tsx b/plugins/wazuh-core/public/services/server-security/ui/components/button.tsx new file mode 100644 index 0000000000..776f1c5054 --- /dev/null +++ b/plugins/wazuh-core/public/services/server-security/ui/components/button.tsx @@ -0,0 +1,80 @@ +/* + * Wazuh app - Button with Wazuh API permissions and/or roles required to be useful + * Copyright (C) 2015-2022 Wazuh, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Find more information about this on the LICENSE file. + */ + +import React from 'react'; + +import { + EuiSwitch, + EuiButton, + EuiButtonEmpty, + EuiButtonIcon, + EuiLink, +} from '@elastic/eui'; + +import { + ServerElementPermissionsProps, + ServerElementPermissions, +} from './element'; + +interface IServerButtonPermissionsProps + extends Omit< + ServerElementPermissionsProps, + 'children' | 'additionalPropsFunction' + > { + buttonType?: 'default' | 'empty' | 'icon' | 'link' | 'switch'; + rest: any; +} + +export const ServerButtonPermissions = ({ + buttonType = 'default', + permissions, + administrator, + tooltip, + ...rest +}: IServerButtonPermissionsProps) => { + const Button = + buttonType === 'empty' + ? EuiButtonEmpty + : buttonType === 'icon' + ? EuiButtonIcon + : buttonType === 'link' + ? EuiLink + : buttonType === 'switch' + ? EuiSwitch + : EuiButton; + + return ( + { + const additionalProps = { + ...(!['link', 'switch'].includes(buttonType) + ? { isDisabled: disabled } + : { disabled }), + onClick: disabled || !rest.onClick ? undefined : rest.onClick, + onChange: + !disabled || rest.onChange || buttonType === 'switch' + ? rest.onChange + : undefined, + }; + if (buttonType == 'switch') delete additionalProps.onClick; + + return additionalProps; + }} + {...rest} + > +