Group count and PartialExport permission fixes
Closes https://github.com/keycloak/keycloak/issues/12171
This commit is contained in:
parent
c23e1e0e2b
commit
7deb4ca545
4 changed files with 25 additions and 29 deletions
|
@ -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`).
|
|
@ -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";
|
||||
|
@ -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",
|
||||
|
@ -120,6 +124,7 @@ const RealmSettingsHeader = ({
|
|||
<DropdownItem
|
||||
key="import"
|
||||
data-testid="openPartialImportModal"
|
||||
isDisabled={!canManageRealm}
|
||||
onClick={() => {
|
||||
setPartialImportOpen(true);
|
||||
}}
|
||||
|
@ -129,16 +134,22 @@ const RealmSettingsHeader = ({
|
|||
<DropdownItem
|
||||
key="export"
|
||||
data-testid="openPartialExportModal"
|
||||
isDisabled={!canManageRealm}
|
||||
onClick={() => setPartialExportOpen(true)}
|
||||
>
|
||||
{t("partialExport")}
|
||||
</DropdownItem>,
|
||||
<DropdownSeparator key="separator" />,
|
||||
<DropdownItem key="delete" onClick={toggleDeleteDialog}>
|
||||
<DropdownItem
|
||||
key="delete"
|
||||
isDisabled={!canManageRealm}
|
||||
onClick={toggleDeleteDialog}
|
||||
>
|
||||
{t("delete")}
|
||||
</DropdownItem>,
|
||||
]}
|
||||
isEnabled={value}
|
||||
isReadOnly={!canManageRealm}
|
||||
onToggle={(value) => {
|
||||
if (!value) {
|
||||
toggleDisableDialog();
|
||||
|
@ -181,7 +192,7 @@ export const RealmSettingsTabs = ({
|
|||
convertToFormValues(r, setValue);
|
||||
};
|
||||
|
||||
useEffect(setupForm, []);
|
||||
useEffect(setupForm, [setValue, realm]);
|
||||
|
||||
const save = async (r: RealmRepresentation) => {
|
||||
r = convertFormValuesToObject(r);
|
||||
|
|
|
@ -1160,7 +1160,7 @@ public class RealmAdminResource {
|
|||
@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;
|
||||
|
|
|
@ -127,7 +127,7 @@ public class PermissionsTest extends AbstractKeycloakTest {
|
|||
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"));
|
||||
|
||||
|
@ -1345,6 +1345,7 @@ public class PermissionsTest extends AbstractKeycloakTest {
|
|||
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();
|
||||
|
@ -1800,31 +1801,12 @@ public class PermissionsTest extends AbstractKeycloakTest {
|
|||
// 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
|
||||
|
|
Loading…
Reference in a new issue