8000 Group count and PartialExport permission fixes by rmartinc · Pull Request #24340 · keycloak/keycloak · GitHub
[go: up one dir, main page]

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 @@ -135,3 +135,6 @@ Stream<GroupModel> getTopLevelGroupsStream(RealmModel realm,

Endpoint `GET {keycloak server}/realms/{realm}/groups/{group_id}/children` added as a way to get subgroups of specific groups that support pagination

= Partial export requires manage-realm permission

The endpoint `POST {keycloak server}/realms/{realm}/partial-export` and the corresponding action in the admin console now require `manage-realm` permission for execution instead of `view-realm`. This endpoint exports the realm configuration into a JSON file and the new permission is more appropriate. The parameters `exportGroupsAndRoles` and `exportClients`, which include the realm groups/roles and clients in the export respectively, continue managing the same permissions (`query-groups` and `view-clients`).
15 changes: 13 additions & 2 deletions js/apps/admin-ui/src/realm-settings/RealmSettingsTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { useEffect, useState } from "react";
import { Controller, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
import { useAccess } from "../context/access/Access";

import { adminClient } from "../admin-client";
import { useAlerts } from "../components/alert/Alerts";
Expand Down Expand Up @@ -71,6 +72,9 @@ const RealmSettingsHeader = ({
const [partialImportOpen, setPartialImportOpen] = useState(false);
const [partialExportOpen, setPartialExportOpen] = useState(false);

const { hasAccess } = useAccess();
const canManageRealm = hasAccess("manage-realm");

const [toggleDisableDialog, DisableConfirm] = useConfirmDialog({
titleKey: "disableConfirmTitle",
messageKey: "disableConfirmRealm",
Expand Down Expand Up @@ -120,6 +124,7 @@ const RealmSettingsHeader = ({
<DropdownItem
key="import"
data-testid="openPartialImportModal"
isDisabled={!canManageRealm}
=> {
setPartialImportOpen(true);
}}
Expand All @@ -129,16 +134,22 @@ const RealmSettingsHeader = ({
<DropdownItem
key="export"
data-testid="openPartialExportModal"
isDisabled={!canManageRealm}
=> setPartialExportOpen(true)}
>
{t("partialExport")}
</DropdownItem>,
<DropdownSeparator key="separator" />,
<DropdownItem key="delete" >
<DropdownItem
key="delete"
isDisabled={!canManageRealm}
>
>
{t("delete")}
</DropdownItem>,
]}
isEnabled={value}
isReadOnly={!canManageRealm}
=> {
if (!value) {
toggleDisableDialog();
Expand Down Expand Up @@ -181,7 +192,7 @@ export const RealmSettingsTabs = ({
convertToFormValues(r, setValue);
};

useEffect(setupForm, []);
useEffect(setupForm, [setValue, realm]);

const save = async (r: RealmRepresentation) => {
r = convertFormValuesToObject(r);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1153,7 +1153,7 @@ private static void fireUpdateEvent(PartialImportResult result, AdminEventBuilde
@Operation( summary = "Partial export of existing realm into a JSON file.")
public Response partialExport(@QueryParam("exportGroupsAndRoles") Boolean exportGroupsAndRoles,
@QueryParam("exportClients") Boolean exportClients) {
auth.realm().requireViewRealm();
auth.realm().requireManageRealm();

boolean groupsAndRolesExported = exportGroupsAndRoles != null && exportGroupsAndRoles;
boolean clientsExported = exportClients != null && exportClients;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public void addTestRealms(List<RealmRepresentation> testRealms) {
builder.user(UserBuilder.create()
.username("multi")
.role(Constants.REALM_MANAGEMENT_CLIENT_ID, AdminRoles.QUERY_GROUPS)
.role(Constants.REALM_MANAGEMENT_CLIENT_ID, AdminRoles.VIEW_REALM)
.role(Constants.REALM_MANAGEMENT_CLIENT_ID, AdminRoles.MANAGE_REALM)
.role(Constants.REALM_MANAGEMENT_CLIENT_ID, AdminRoles.VIEW_CLIENTS)
.addPassword("password"));

Expand Down Expand Up @@ -1335,6 +1335,7 @@ public void invoke(RealmResource realm) {
realm.groups().groups();
}
}, Resource.USER, false);
invoke(realm -> realm.groups().count(), Resource.USER, false);
invoke(new InvocationWithResponse() {
public void invoke(RealmResource realm, AtomicReference<Response> response) {
GroupRepresentation group = new GroupRepresentation();
Expand Down Expand Up @@ -1790,31 +1791,12 @@ public void partialExport() {
// re-enable as part of https://github.com/keycloak/keycloak/issues/14291
ProfileAssume.assumeFeatureDisabled(Profile.Feature.MAP_STORAGE);

invoke(new Invocation() {
public void invoke(RealmResource realm) {
realm.partialExport(false, false);
}
}, clients.get("view-realm"), true);
invoke(new Invocation() {
public void invoke(RealmResource realm) {
realm.partialExport(true, true);
}
}, clients.get("multi"), true);
invoke(new Invocation() {
public void invoke(RealmResource realm) {
realm.partialExport(true, false);
}
}, clients.get("view-realm"), false);
invoke(new Invocation() {
public void invoke(RealmResource realm) {
realm.partialExport(false, true);
}
}, clients.get("view-realm"), false);
invoke(new Invocation() {
public void invoke(RealmResource realm) {
realm.partialExport(false, false);
}
}, clients.get("none"), false);
invoke(realm -> realm.partialExport(false, false), clients.get("view-realm"), false);
invoke(realm -> realm.partialExport(false, false), clients.get("manage-realm"), true);
invoke(realm -> realm.partialExport(true, false), clients.get("manage-realm"), false);
invoke(realm -> realm.partialExport(false, true), clients.get("manage-realm"), false);
invoke(realm -> realm.partialExport(true, true), clients.get("multi"), true);
invoke(realm -> realm.partialExport(false, false), clients.get("none"), false);
}

@Test
Expand Down
0