diff --git a/x-pack/plugins/enterprise_search/kibana.json b/x-pack/plugins/enterprise_search/kibana.json index 5f33fa27c6640..9df01988fbd89 100644 --- a/x-pack/plugins/enterprise_search/kibana.json +++ b/x-pack/plugins/enterprise_search/kibana.json @@ -2,9 +2,9 @@ "id": "enterpriseSearch", "version": "kibana", "kibanaVersion": "kibana", - "requiredPlugins": ["features", "spaces", "licensing", "data", "charts", "infra"], + "requiredPlugins": ["features", "spaces", "security", "licensing", "data", "charts", "infra"], "configPath": ["enterpriseSearch"], - "optionalPlugins": ["usageCollection", "security", "home", "cloud"], + "optionalPlugins": ["usageCollection", "home", "cloud"], "server": true, "ui": true, "requiredBundles": ["home", "kibanaReact"], diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.test.ts index 39392d0c5c78e..4cc907c3de9e4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.test.ts @@ -33,12 +33,6 @@ describe('KibanaLogic', () => { expect(KibanaLogic.values.config).toEqual({}); }); - it('gracefully handles disabled security', () => { - mountKibanaLogic({ ...mockKibanaValues, security: undefined } as any); - - expect(KibanaLogic.values.security).toEqual({}); - }); - it('gracefully handles non-cloud installs', () => { mountKibanaLogic({ ...mockKibanaValues, cloud: undefined } as any); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts b/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts index d3b76f8dee9f0..5a894c7b00748 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts @@ -29,14 +29,13 @@ interface KibanaLogicProps { renderHeaderActions(HeaderActions: FC): void; // Required plugins charts: ChartsPluginStart; + security: SecurityPluginStart; // Optional plugins cloud?: CloudSetup; - security?: SecurityPluginStart; } -export interface KibanaValues extends Omit { +export interface KibanaValues extends Omit { navigateToUrl(path: string, options?: CreateHrefOptions): Promise; cloud: Partial; - security: Partial; } export const KibanaLogic = kea>({ @@ -54,7 +53,7 @@ export const KibanaLogic = kea>({ }, {}, ], - security: [props.security || {}, {}], + security: [props.security, {}], setBreadcrumbs: [props.setBreadcrumbs, {}], setChromeIsVisible: [props.setChromeIsVisible, {}], setDocTitle: [props.setDocTitle, {}], diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/account_settings/account_settings.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/account_settings/account_settings.tsx index 313d3ffa59d48..2e92a00e3aa12 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/account_settings/account_settings.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/account_settings/account_settings.tsx @@ -20,11 +20,11 @@ export const AccountSettings: React.FC = () => { const [currentUser, setCurrentUser] = useState(null); useEffect(() => { - security!.authc!.getCurrentUser().then(setCurrentUser); + security.authc.getCurrentUser().then(setCurrentUser); }, [security.authc]); - const PersonalInfo = useMemo(() => security!.uiApi!.components.getPersonalInfo, [security.uiApi]); - const ChangePassword = useMemo(() => security!.uiApi!.components.getChangePassword, [ + const PersonalInfo = useMemo(() => security.uiApi.components.getPersonalInfo, [security.uiApi]); + const ChangePassword = useMemo(() => security.uiApi.components.getChangePassword, [ security.uiApi, ]); diff --git a/x-pack/plugins/enterprise_search/public/plugin.ts b/x-pack/plugins/enterprise_search/public/plugin.ts index bfa4005e4f3ff..db781594e6b17 100644 --- a/x-pack/plugins/enterprise_search/public/plugin.ts +++ b/x-pack/plugins/enterprise_search/public/plugin.ts @@ -44,14 +44,14 @@ export interface ClientData extends InitialAppData { interface PluginsSetup { cloud?: CloudSetup; home?: HomePublicPluginSetup; - security?: SecurityPluginSetup; + security: SecurityPluginSetup; } export interface PluginsStart { cloud?: CloudSetup; licensing: LicensingPluginStart; charts: ChartsPluginStart; data: DataPublicPluginStart; - security?: SecurityPluginStart; + security: SecurityPluginStart; } export class EnterpriseSearchPlugin implements Plugin { diff --git a/x-pack/plugins/enterprise_search/server/lib/check_access.test.ts b/x-pack/plugins/enterprise_search/server/lib/check_access.test.ts index ed105eed9dd6e..9d62c0794651e 100644 --- a/x-pack/plugins/enterprise_search/server/lib/check_access.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/check_access.test.ts @@ -52,6 +52,30 @@ describe('checkAccess', () => { spaces: mockSpaces, } as any; + describe('when security is disabled', () => { + it('should deny all access', async () => { + const security = { + authz: { mode: { useRbacForRequest: () => false } }, + }; + expect(await checkAccess({ ...mockDependencies, security })).toEqual({ + hasAppSearchAccess: false, + hasWorkplaceSearchAccess: false, + }); + }); + }); + + describe('when the current request is unauthenticated', () => { + it('should deny all access', async () => { + const request = { + auth: { isAuthenticated: false }, + }; + expect(await checkAccess({ ...mockDependencies, request })).toEqual({ + hasAppSearchAccess: false, + hasWorkplaceSearchAccess: false, + }); + }); + }); + describe('when the space is disabled', () => { it('should deny all access', async () => { mockSpaces.spacesService.getActiveSpace.mockResolvedValueOnce(disabledSpace); @@ -63,17 +87,6 @@ describe('checkAccess', () => { }); describe('when the Spaces plugin is unavailable', () => { - describe('when security is disabled', () => { - it('should allow all access', async () => { - const spaces = undefined; - const security = undefined; - expect(await checkAccess({ ...mockDependencies, spaces, security })).toEqual({ - hasAppSearchAccess: true, - hasWorkplaceSearchAccess: true, - }); - }); - }); - describe('when getActiveSpace returns 403 forbidden', () => { it('should deny all access', async () => { mockSpaces.spacesService.getActiveSpace.mockReturnValueOnce( @@ -105,16 +118,6 @@ describe('checkAccess', () => { mockSpaces.spacesService.getActiveSpace.mockResolvedValueOnce(enabledSpace); }); - describe('when security is disabled', () => { - it('should allow all access', async () => { - const security = undefined; - expect(await checkAccess({ ...mockDependencies, security })).toEqual({ - hasAppSearchAccess: true, - hasWorkplaceSearchAccess: true, - }); - }); - }); - describe('when the user is a superuser', () => { it('should allow all access when enabled at the space ', async () => { const security = { diff --git a/x-pack/plugins/enterprise_search/server/lib/check_access.ts b/x-pack/plugins/enterprise_search/server/lib/check_access.ts index 0e83e8022a7ba..d933b9ac41412 100644 --- a/x-pack/plugins/enterprise_search/server/lib/check_access.ts +++ b/x-pack/plugins/enterprise_search/server/lib/check_access.ts @@ -16,7 +16,7 @@ import { callEnterpriseSearchConfigAPI } from './enterprise_search_config_api'; interface CheckAccess { request: KibanaRequest; - security?: SecurityPluginSetup; + security: SecurityPluginSetup; spaces: SpacesPluginStart; config: ConfigType; log: Logger; @@ -43,21 +43,18 @@ export const checkAccess = async ({ request, log, }: CheckAccess): Promise => { - const isRbacEnabled = security?.authz.mode.useRbacForRequest(request) ?? false; + const isRbacEnabled = security.authz.mode.useRbacForRequest(request); - // We can only retrieve the active space when either: - // 1) security is enabled, and the request has already been authenticated - // 2) security is disabled - const attemptSpaceRetrieval = !isRbacEnabled || request.auth.isAuthenticated; + // If security has been disabled, always hide the plugin + if (!isRbacEnabled) { + return DENY_ALL_PLUGINS; + } - // If we can't retrieve the current space, then assume the feature is available + // We can only retrieve the active space when security is enabled and the request has already been authenticated + const attemptSpaceRetrieval = request.auth.isAuthenticated; let allowedAtSpace = false; - if (!spaces) { - allowedAtSpace = true; - } - - if (spaces && attemptSpaceRetrieval) { + if (attemptSpaceRetrieval) { try { const space = await spaces.spacesService.getActiveSpace(request); allowedAtSpace = !space.disabledFeatures?.includes('enterpriseSearch'); @@ -75,17 +72,12 @@ export const checkAccess = async ({ return DENY_ALL_PLUGINS; } - // If security has been disabled, always show the plugin - if (!isRbacEnabled) { - return ALLOW_ALL_PLUGINS; - } - // If the user is a "superuser" or has the base Kibana all privilege globally, always show the plugin const isSuperUser = async (): Promise => { try { - const { hasAllRequested } = await security!.authz + const { hasAllRequested } = await security.authz .checkPrivilegesWithRequest(request) - .globally({ kibana: security!.authz.actions.ui.get('enterpriseSearch', 'all') }); + .globally({ kibana: security.authz.actions.ui.get('enterpriseSearch', 'all') }); return hasAllRequested; } catch (err) { if (err.statusCode === 401 || err.statusCode === 403) { diff --git a/x-pack/plugins/enterprise_search/server/plugin.ts b/x-pack/plugins/enterprise_search/server/plugin.ts index 26572134aa31c..63ac8ed02afbe 100644 --- a/x-pack/plugins/enterprise_search/server/plugin.ts +++ b/x-pack/plugins/enterprise_search/server/plugin.ts @@ -52,7 +52,7 @@ import { ConfigType } from './'; interface PluginsSetup { usageCollection?: UsageCollectionSetup; - security?: SecurityPluginSetup; + security: SecurityPluginSetup; features: FeaturesPluginSetup; infra: InfraPluginSetup; }