Skip to content

Commit

Permalink
Partial forward-port of dacf0c2.
Browse files Browse the repository at this point in the history
- Add Authorization type to ES UI shared.
- Add convertPrivilegesToArray, patch to also accept privileges that might contain dots in its name, and add tests.
  • Loading branch information
cjcenizal committed Oct 1, 2021
1 parent 7b05ecb commit 0bc3baf
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export {
AuthorizationProvider,
AuthorizationContext,
useAuthorizationContext,
Authorization,
} from './authorization_provider';

export { WithPrivileges } from './with_privileges';
Expand Down
Original file line number Diff line number Diff line change
@@ -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"');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 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.
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 [section, privilege];

return [p.slice(0, indexOfFirstPeriod), p.slice(indexOfFirstPeriod + 1)];
});
};

export const WithPrivileges = ({ privileges: requiredPrivileges, children }: Props) => {
const { isLoading, privileges } = useAuthorizationContext();
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
Expand All @@ -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 (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export {
SectionError,
PageError,
useAuthorizationContext,
Authorization,
} from './components';

export { Privileges, MissingPrivileges, Error } from './types';
2 changes: 1 addition & 1 deletion src/plugins/es_ui_shared/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
1 change: 1 addition & 0 deletions src/plugins/es_ui_shared/public/authorization/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ export {
PageError,
useAuthorizationContext,
WithPrivileges,
Authorization,
} from '../../__packages_do_not_import__/authorization';
1 change: 1 addition & 0 deletions src/plugins/es_ui_shared/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export {
PageError,
Error,
useAuthorizationContext,
Authorization,
} from './authorization';

export { Forms, ace, GlobalFlyout, XJson };
Expand Down

0 comments on commit 0bc3baf

Please sign in to comment.