Partial forward-port of dacf0c2a6c
. (#113672)
- Add Authorization type to ES UI shared. - Add convertPrivilegesToArray, patch to also accept privileges that might contain dots in its name, and add tests. Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
abffa79ba2
commit
257e33a50e
|
@ -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;
|
||||
|
|
|
@ -10,6 +10,7 @@ export {
|
|||
AuthorizationProvider,
|
||||
AuthorizationContext,
|
||||
useAuthorizationContext,
|
||||
Authorization,
|
||||
} from './authorization_provider';
|
||||
|
||||
export { WithPrivileges } from './with_privileges';
|
||||
|
|
|
@ -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"');
|
||||
});
|
||||
});
|
|
@ -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 (
|
||||
|
|
|
@ -14,6 +14,7 @@ export {
|
|||
SectionError,
|
||||
PageError,
|
||||
useAuthorizationContext,
|
||||
Authorization,
|
||||
} from './components';
|
||||
|
||||
export { Privileges, MissingPrivileges, Error } from './types';
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -17,4 +17,5 @@ export {
|
|||
PageError,
|
||||
useAuthorizationContext,
|
||||
WithPrivileges,
|
||||
Authorization,
|
||||
} from '../../__packages_do_not_import__/authorization';
|
||||
|
|
|
@ -45,6 +45,7 @@ export {
|
|||
PageError,
|
||||
Error,
|
||||
useAuthorizationContext,
|
||||
Authorization,
|
||||
} from './authorization';
|
||||
|
||||
export { Forms, ace, GlobalFlyout, XJson };
|
||||
|
|
Loading…
Reference in a new issue