Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ import {

import { PrivilegesRolesForm } from './space_assign_role_privilege_form';
import type { Space } from '../../../../../common';
import { FEATURE_PRIVILEGES_ALL, FEATURE_PRIVILEGES_READ } from '../../../../../common/constants';
import {
FEATURE_PRIVILEGES_ALL,
FEATURE_PRIVILEGES_CUSTOM,
FEATURE_PRIVILEGES_READ,
} from '../../../../../common/constants';
import { spacesManagerMock } from '../../../../spaces_manager/spaces_manager.mock';
import {
createPrivilegeAPIClientMock,
Expand Down Expand Up @@ -316,6 +320,11 @@ describe('PrivilegesRolesForm', () => {

await userEvent.click(screen.getByTestId('custom-privilege-button'));

expect(screen.getByTestId(`${FEATURE_PRIVILEGES_CUSTOM}-privilege-button`)).toHaveAttribute(
'aria-pressed',
String(true)
);

expect(
screen.getByTestId('space-assign-role-privilege-customization-form')
).toBeInTheDocument();
Expand All @@ -330,5 +339,74 @@ describe('PrivilegesRolesForm', () => {
String(true)
);
});

it('allows modifying individual features after selecting a base privilege within the customize table', async () => {
const user = userEvent.setup();

getRolesSpy.mockResolvedValue([]);
getAllKibanaPrivilegeSpy.mockResolvedValue(createRawKibanaPrivileges(kibanaFeatures));

const featureIds: string[] = kibanaFeatures.map((kibanaFeature) => kibanaFeature.id);

const roles: Role[] = [
createRole('test_role_1', [
{ base: [FEATURE_PRIVILEGES_READ], feature: {}, spaces: [space.id] },
]),
];

renderPrivilegeRolesForm({
preSelectedRoles: roles,
});

await waitFor(() => null);

expect(screen.getByTestId(`${FEATURE_PRIVILEGES_READ}-privilege-button`)).toHaveAttribute(
'aria-pressed',
String(true)
);

await user.click(screen.getByTestId('custom-privilege-button'));

expect(screen.getByTestId(`${FEATURE_PRIVILEGES_CUSTOM}-privilege-button`)).toHaveAttribute(
'aria-pressed',
String(true)
);

expect(
screen.getByTestId('space-assign-role-privilege-customization-form')
).toBeInTheDocument();

// By default all features are set to the none privilege
expect(screen.queryByTestId(`${featureIds[0]}_read`)).not.toHaveAttribute(
'aria-pressed',
String(true)
);

await user.click(screen.getByTestId('changeAllPrivilegesButton'));

// change all privileges to read
await user.click(screen.getByTestId(`changeAllPrivileges-${FEATURE_PRIVILEGES_READ}`));

featureIds.forEach((_, idx) => {
// verify that all features are set to read
expect(screen.queryByTestId(`${featureIds[idx]}_read`)).toHaveAttribute(
'aria-pressed',
String(true)
);
});

// change a single feature to all
await user.click(screen.getByTestId(`${featureIds[0]}_all`));

expect(screen.queryByTestId(`${featureIds[0]}_read`)).not.toHaveAttribute(
'aria-pressed',
String(true)
);

expect(screen.getByTestId(`${featureIds[0]}_all`)).toHaveAttribute(
'aria-pressed',
String(true)
);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import type { KibanaFeature, KibanaFeatureConfig } from '@kbn/features-plugin/co
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { type RawKibanaPrivileges } from '@kbn/security-authorization-core';
import type { Role } from '@kbn/security-plugin-types-common';
import type { Role, RoleKibanaPrivilege } from '@kbn/security-plugin-types-common';
import type { BulkUpdateRoleResponse } from '@kbn/security-plugin-types-public/src/roles/roles_api_client';
import { KibanaPrivileges } from '@kbn/security-role-management-model';
import { KibanaPrivilegeTable, PrivilegeFormCalculator } from '@kbn/security-ui-components';
Expand Down Expand Up @@ -513,10 +513,48 @@ export const PrivilegesRolesForm: FC<PrivilegesRolesFormProps> = (props) => {
// apply selected changes only to the designated customization anchor, this way we delay reconciling the intending privileges
// to all of the selected roles till we decide to commit the changes chosen
setRoleCustomizationAnchor(({ value, privilegeIndex }) => {
let privilege;
let privilege: RoleKibanaPrivilege;

if ((privilege = value!.kibana?.[privilegeIndex!])) {
privilege.base = _privilege;
// empty out base to setup customizing all features
privilege.base = [];

const securedFeatures = new KibanaPrivileges(
kibanaPrivileges,
features
).getSecuredFeatures();

securedFeatures.forEach((feature) => {
const nextFeaturePrivilege = feature
.getPrimaryFeaturePrivileges({
includeMinimalFeaturePrivileges: true,
})
.find((pfp) => {
if (pfp?.disabled || pfp?.requireAllSpaces) {
return false;
}
return Array.isArray(_privilege) && _privilege.includes(pfp.id);
});

let newPrivileges: string[] = [];

if (nextFeaturePrivilege) {
newPrivileges = [nextFeaturePrivilege.id];
feature.getSubFeaturePrivileges().forEach((psf) => {
if (Array.isArray(_privilege) && _privilege.includes(psf.id)) {
if (!psf.requireAllSpaces) {
newPrivileges.push(psf.id);
}
}
});
}

if (newPrivileges.length === 0) {
delete privilege.feature[feature.id];
} else {
privilege.feature[feature.id] = newPrivileges;
}
});
}

return { value, privilegeIndex };
Expand Down