diff --git a/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/authorization_provider.tsx b/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/authorization_provider.tsx index be49a7697afc..7d8d00156e54 100644 --- a/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/authorization_provider.tsx +++ b/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/authorization_provider.tsx @@ -13,7 +13,7 @@ import { useRequest } from '../../../public/request'; import { Privileges, Error as CustomError } from '../types'; -interface Authorization { +export interface Authorization { isLoading: boolean; apiError: CustomError | null; privileges: Privileges; diff --git a/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/index.ts b/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/index.ts index f8eb7e3c7c0c..75d79a204f14 100644 --- a/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/index.ts +++ b/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/index.ts @@ -10,6 +10,7 @@ export { AuthorizationProvider, AuthorizationContext, useAuthorizationContext, + Authorization, } from './authorization_provider'; export { WithPrivileges } from './with_privileges'; diff --git a/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/with_privileges.test.ts b/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/with_privileges.test.ts new file mode 100644 index 000000000000..243bfdb995f5 --- /dev/null +++ b/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/with_privileges.test.ts @@ -0,0 +1,28 @@ +/* + * 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 { convertPrivilegesToArray } from './with_privileges'; + +describe('convertPrivilegesToArray', () => { + test('extracts section and privilege', () => { + expect(convertPrivilegesToArray('index.index_name')).toEqual([['index', 'index_name']]); + expect(convertPrivilegesToArray(['index.index_name', 'cluster.management'])).toEqual([ + ['index', 'index_name'], + ['cluster', 'management'], + ]); + expect(convertPrivilegesToArray('index.index_name.with-many.dots')).toEqual([ + ['index', 'index_name.with-many.dots'], + ]); + }); + + test('throws when it cannot extract section and privilege', () => { + expect(() => { + convertPrivilegesToArray('bad_privilege_string'); + }).toThrow('Required privilege must have the format "section.privilege"'); + }); +}); diff --git a/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/with_privileges.tsx b/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/with_privileges.tsx index c0e675877c56..6485bd7f45e5 100644 --- a/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/with_privileges.tsx +++ b/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/with_privileges.tsx @@ -10,13 +10,14 @@ import { MissingPrivileges } from '../types'; import { useAuthorizationContext } from './authorization_provider'; +type Privileges = string | string[]; interface Props { /** * Each required privilege must have the format "section.privilege". * To indicate that *all* privileges from a section are required, we can use the asterix * e.g. "index.*" */ - privileges: string | string[]; + privileges: Privileges; children: (childrenProps: { isLoading: boolean; hasPrivileges: boolean; @@ -26,24 +27,30 @@ interface Props { type Privilege = [string, string]; -const toArray = (value: string | string[]): string[] => +const toArray = (value: Privileges): string[] => Array.isArray(value) ? (value as string[]) : ([value] as string[]); +export const convertPrivilegesToArray = (privileges: Privileges): Privilege[] => { + return toArray(privileges).map((p) => { + // Since an privilege can contain a dot in its name: + // * `section` needs to be extracted from the beginning of the string until the first dot + // * `privilege` should be everything after the dot + const indexOfFirstPeriod = p.indexOf('.'); + if (indexOfFirstPeriod === -1) { + throw new Error('Required privilege must have the format "section.privilege"'); + } + + return [p.slice(0, indexOfFirstPeriod), p.slice(indexOfFirstPeriod + 1)]; + }); +}; + export const WithPrivileges = ({ privileges: requiredPrivileges, children }: Props) => { const { isLoading, privileges } = useAuthorizationContext(); - - const privilegesToArray: Privilege[] = toArray(requiredPrivileges).map((p) => { - const [section, privilege] = p.split('.'); - if (!privilege) { - // Oh! we forgot to use the dot "." notation. - throw new Error('Required privilege must have the format "section.privilege"'); - } - return [section, privilege]; - }); + const privilegesArray = convertPrivilegesToArray(requiredPrivileges); const hasPrivileges = isLoading ? false - : privilegesToArray.every((privilege) => { + : privilegesArray.every((privilege) => { const [section, requiredPrivilege] = privilege; if (!privileges.missingPrivileges[section]) { // if the section does not exist in our missingPriviledges, everything is OK @@ -61,7 +68,7 @@ export const WithPrivileges = ({ privileges: requiredPrivileges, children }: Pro return !privileges.missingPrivileges[section]!.includes(requiredPrivilege); }); - const privilegesMissing = privilegesToArray.reduce((acc, [section, privilege]) => { + const privilegesMissing = privilegesArray.reduce((acc, [section, privilege]) => { if (privilege === '*') { acc[section] = privileges.missingPrivileges[section] || []; } else if ( diff --git a/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/index.ts b/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/index.ts index e63d98512a2c..9ccbc5a5cd3d 100644 --- a/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/index.ts +++ b/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/index.ts @@ -14,6 +14,7 @@ export { SectionError, PageError, useAuthorizationContext, + Authorization, } from './components'; export { Privileges, MissingPrivileges, Error } from './types'; diff --git a/src/plugins/es_ui_shared/common/index.ts b/src/plugins/es_ui_shared/common/index.ts index b8cfe0ae4858..1c2955b8e5e2 100644 --- a/src/plugins/es_ui_shared/common/index.ts +++ b/src/plugins/es_ui_shared/common/index.ts @@ -6,4 +6,4 @@ * Side Public License, v 1. */ -export { Privileges, MissingPrivileges } from '../__packages_do_not_import__/authorization'; +export { Privileges, MissingPrivileges } from '../__packages_do_not_import__/authorization/types'; diff --git a/src/plugins/es_ui_shared/public/authorization/index.ts b/src/plugins/es_ui_shared/public/authorization/index.ts index f68ad3da2a4b..b8fb2f45794e 100644 --- a/src/plugins/es_ui_shared/public/authorization/index.ts +++ b/src/plugins/es_ui_shared/public/authorization/index.ts @@ -17,4 +17,5 @@ export { PageError, useAuthorizationContext, WithPrivileges, + Authorization, } from '../../__packages_do_not_import__/authorization'; diff --git a/src/plugins/es_ui_shared/public/index.ts b/src/plugins/es_ui_shared/public/index.ts index 9db00bc4be8d..2dc50536ca63 100644 --- a/src/plugins/es_ui_shared/public/index.ts +++ b/src/plugins/es_ui_shared/public/index.ts @@ -45,6 +45,7 @@ export { PageError, Error, useAuthorizationContext, + Authorization, } from './authorization'; export { Forms, ace, GlobalFlyout, XJson };