Skip to content

Commit

Permalink
shell-ui: Add ability to configure user group mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
JBWatenbergScality committed Mar 15, 2021
1 parent 4c698b5 commit b2d7dc9
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 7 deletions.
6 changes: 4 additions & 2 deletions shell-ui/src/NavBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import type {
Options,
SolutionsNavbarProps,
TranslationAndGroups,
UserGroupsMapping
} from './index';
import type { Node } from 'react';
import { logOut } from './auth/logout';
import {
getAccessiblePathsFromOptions,
getUserGroups,
isEntryAccessibleByTheUser,
normalizePath,
} from './auth/permissionUtils';
Expand Down Expand Up @@ -60,10 +62,10 @@ const translateOptionsToMenu = (
);
};

export const Navbar = ({ options }: { options: Options }): Node => {
export const Navbar = ({ options, userGroupsMapping }: { options: Options, userGroupsMapping?: UserGroupsMapping }): Node => {
const auth = useAuth();

const userGroups: string[] = auth.userData?.profile?.groups || [];
const userGroups: string[] = getUserGroups(auth.userData, userGroupsMapping);
const accessiblePaths = getAccessiblePathsFromOptions(options, userGroups);
useLayoutEffect(() => {
accessiblePaths.forEach((accessiblePath) => {
Expand Down
7 changes: 5 additions & 2 deletions shell-ui/src/UserDataListener.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import { useAuth } from 'oidc-react';
import { useLayoutEffect } from 'react';
import { AUTHENTICATED_EVENT, SolutionsNavbarProps } from './index';
import { getUserGroups } from './auth/permissionUtils';
import { AUTHENTICATED_EVENT, SolutionsNavbarProps, type UserGroupsMapping } from './index';

export const UserDataListener = ({
userGroupsMapping,
onAuthenticated,
}: {
userGroupsMapping?: UserGroupsMapping,
onAuthenticated?: $PropertyType<SolutionsNavbarProps, 'onAuthenticated'>,
}) => {
const auth = useAuth();

useLayoutEffect(() => {
if (onAuthenticated) {
onAuthenticated(
new CustomEvent(AUTHENTICATED_EVENT, { detail: auth.userData }),
new CustomEvent(AUTHENTICATED_EVENT, { detail: {...auth.userData, groups: getUserGroups(auth.userData, userGroupsMapping) } }),
);
}
}, [JSON.stringify(auth.userData), !!onAuthenticated]);
Expand Down
19 changes: 18 additions & 1 deletion shell-ui/src/auth/permissionUtils.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
//@flow
import type { Options, TranslationAndGroups } from '../index';
import type { User } from 'oidc-react';
import type {
Options,
TranslationAndGroups,
UserGroupsMapping,
} from '../index';

export const isEntryAccessibleByTheUser = (
[path, translationAndGroup]: [string, TranslationAndGroups],
Expand Down Expand Up @@ -39,3 +44,15 @@ export const isPathAccessible = (
(accessiblePath) => normalizePath(accessiblePath) === normalizedPath,
);
};

export const getUserGroups = (
user?: User,
userGroupsMapping?: UserGroupsMapping,
): string[] => {
const userOIDCGroups: string[] = user?.profile?.groups || [];
const userMappedGroups = userGroupsMapping
? userGroupsMapping[user?.profile?.email || ''] || []
: [];

return Array.from(new Set([...userOIDCGroups, ...userMappedGroups]));
};
19 changes: 19 additions & 0 deletions shell-ui/src/auth/permissionUtils.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//@flow
import {
getAccessiblePathsFromOptions,
getUserGroups,
isEntryAccessibleByTheUser,
isPathAccessible,
normalizePath,
Expand Down Expand Up @@ -116,3 +117,21 @@ describe('permission utils - isPathAccessible', () => {
expect(isAccessible).toBe(false);
});
});

describe('permission utils - getUserGroups', () => {
it('should return an array of groups when defined in OIDC claims ', () => {
//E
const oidcGroups = ["oidcGroup"];
const groups = getUserGroups({profile: {email: "test@test.com", groups: oidcGroups}}, undefined);
//V
expect(groups).toEqual(oidcGroups);
});

it('should return a merged array of groups when defined in OIDC claims and mapping ', () => {
//E
const oidcAndStaticGroups = ["group"];
const groups = getUserGroups({profile: {email: "test@test.com", groups: oidcAndStaticGroups}}, {'test@test.com': oidcAndStaticGroups});
//V
expect(groups).toEqual(oidcAndStaticGroups);
});
});
7 changes: 5 additions & 2 deletions shell-ui/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export type MenuItems = {[path: string]: TranslationAndGroups }

export type Options = { main: MenuItems, subLogin: MenuItems };

export type UserGroupsMapping = {[email: string]: string[]};

export type SolutionsNavbarProps = {
'oidc-provider-url'?: string,
scopes?: string,
Expand All @@ -44,6 +46,7 @@ type Config = {
scopes?: string,
},
options?: Options,
userGroupsMapping?: UserGroupsMapping
};

const SolutionsNavbar = ({
Expand Down Expand Up @@ -133,15 +136,15 @@ const SolutionsNavbar = ({

return (
<AuthProvider {...oidcConfig}>
<UserDataListener onAuthenticated={onAuthenticated} />
<UserDataListener userGroupsMapping={config.userGroupsMapping} onAuthenticated={onAuthenticated} />
<StyledComponentsProvider
theme={{
// todo manages theme https://github.com/scality/metalk8s/issues/2545
brand: defaultTheme.dark,
logo_path: '/brand/assets/branding-dark.svg',
}}
>
<Navbar options={computedMenuOptions} />
<Navbar options={computedMenuOptions} userGroupsMapping={config.userGroupsMapping} />
</StyledComponentsProvider>
</AuthProvider>
);
Expand Down

0 comments on commit b2d7dc9

Please sign in to comment.