Fine-grained permissions for user section. (#2451)

This commit is contained in:
Stan Silvert 2022-04-21 11:03:48 -04:00 committed by GitHub
parent d5f6aca82e
commit 1c296a1641
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 39 additions and 12 deletions

View file

@ -16,9 +16,15 @@ export type AttributesFormProps = {
form: UseFormMethods<AttributeForm>;
save?: (model: AttributeForm) => void;
reset?: () => void;
fineGrainedAccess?: boolean;
};
export const AttributesForm = ({ form, reset, save }: AttributesFormProps) => {
export const AttributesForm = ({
form,
reset,
save,
fineGrainedAccess,
}: AttributesFormProps) => {
const { t } = useTranslation("roles");
const noSaveCancelButtons = !save && !reset;
const {
@ -30,6 +36,7 @@ export const AttributesForm = ({ form, reset, save }: AttributesFormProps) => {
<FormAccess
role="manage-realm"
onSubmit={save ? handleSubmit(save) : undefined}
fineGrainedAccess={fineGrainedAccess}
>
<FormProvider {...form}>
<KeyValueInput name="attributes" />

View file

@ -56,6 +56,7 @@ export const UserAttributes = ({ user: defaultUser }: UserAttributesProps) => {
<AttributesForm
form={form}
save={save}
fineGrainedAccess={user.access?.manage}
reset={() =>
form.reset({
attributes: convertAttributes(),

View file

@ -153,6 +153,7 @@ export const UserForm = ({
isHorizontal
onSubmit={handleSubmit(save)}
role="manage-users"
fineGrainedAccess={user?.access?.manage}
className="pf-u-mt-lg"
>
{open && (

View file

@ -216,6 +216,7 @@ export const UserGroups = ({ user }: UserGroupsProps) => {
data-testid={`leave-${group.name}`}
onClick={() => leave([group])}
variant="link"
isDisabled={!user.access?.manageGroupMembership}
>
{t("leave")}
</Button>
@ -286,6 +287,7 @@ export const UserGroups = ({ user }: UserGroupsProps) => {
className="kc-join-group-button"
onClick={toggleModal}
data-testid="add-group-button"
isDisabled={!user.access?.manageGroupMembership}
>
{t("joinGroup")}
</Button>

View file

@ -23,6 +23,7 @@ import {
SearchIcon,
WarningTriangleIcon,
} from "@patternfly/react-icons";
import type { IRowData } from "@patternfly/react-table";
import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation";
import type ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation";
import type UserRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userRepresentation";
@ -113,7 +114,10 @@ export default function UsersSection() {
}
try {
const users = await adminClient.users.find({ ...params });
const users = await adminClient.users.find({
briefRepresentation: true,
...params,
});
if (realm?.bruteForceProtected) {
const brutes = await Promise.all(
users.map((user: BruteUser) =>
@ -344,15 +348,20 @@ export default function UsersSection() {
)
}
toolbarItem={toolbar}
actions={[
{
title: t("common:delete"),
onRowClick: (user) => {
setSelectedRows([user]);
toggleDeleteDialog();
actionResolver={(rowData: IRowData) => {
const user: UserRepresentation = rowData.data;
if (!user.access?.manage) return [];
return [
{
title: t("common:delete"),
onClick: () => {
setSelectedRows([user]);
toggleDeleteDialog();
},
},
},
]}
];
}}
columns={[
{
name: "username",

View file

@ -157,11 +157,16 @@ const UsersTabs = () => {
dropdownItems={[
<DropdownItem
key="impersonate"
isDisabled={!user?.access?.impersonate}
onClick={() => toggleImpersonateDialog()}
>
{t("impersonate")}
</DropdownItem>,
<DropdownItem key="delete" onClick={() => toggleDeleteDialog()}>
<DropdownItem
key="delete"
isDisabled={!user?.access?.manage}
onClick={() => toggleDeleteDialog()}
>
{t("common:delete")}
</DropdownItem>,
]}
@ -196,6 +201,7 @@ const UsersTabs = () => {
<Tab
eventKey="credentials"
data-testid="credentials"
isHidden={!user.access?.manage}
title={<TabTitleText>{t("common:credentials")}</TabTitleText>}
>
<UserCredentials user={user} />
@ -203,6 +209,7 @@ const UsersTabs = () => {
<Tab
eventKey="role-mapping"
data-testid="role-mapping-tab"
isHidden={!user.access?.mapRoles}
title={<TabTitleText>{t("roleMapping")}</TabTitleText>}
>
<UserRoleMapping id={id} name={user.username!} />

View file

@ -15,7 +15,7 @@ export const UserRoute: RouteDef = {
path: "/:realm/users/:id/:tab",
component: lazy(() => import("../UsersTabs")),
breadcrumb: (t) => t("users:userDetails"),
access: "manage-users",
access: "view-users",
};
export const toUser = (params: UserParams): LocationDescriptorObject => ({