From 3ac040dc349ef8e23505a85437d6f80ccfb7c2e0 Mon Sep 17 00:00:00 2001 From: Erik Jan de Wit Date: Tue, 6 Dec 2022 10:57:21 -0500 Subject: [PATCH] Added group sync to group mapper (#3943) --- .../public/resources/en/user-federation.json | 4 ++ .../ldap/mappers/LdapMapperDetails.tsx | 50 ++++++++++++++++--- .../src/resources/userStorageProvider.ts | 2 +- 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/apps/admin-ui/public/resources/en/user-federation.json b/apps/admin-ui/public/resources/en/user-federation.json index 3d4ec9a31f..53b8e38e77 100644 --- a/apps/admin-ui/public/resources/en/user-federation.json +++ b/apps/admin-ui/public/resources/en/user-federation.json @@ -10,6 +10,10 @@ "addLdapWizardTitle": "Add LDAP user federation provider", "syncChangedUsers": "Sync changed users", "syncAllUsers": "Sync all users", + "syncLDAPGroupsToKeycloak": "Sync LDAP groups to Keycloak", + "syncKeycloakGroupsToLDAP": "Sync Keycloak groups to LDAP", + "syncLDAPGroupsSuccessful": "Data successfully synced {{result}}", + "syncLDAPGroupsError": "Data could not be synced due {{error}}", "unlinkUsers": "Unlink users", "removeImported": "Remove imported", "deleteProvider": "Delete provider", diff --git a/apps/admin-ui/src/user-federation/ldap/mappers/LdapMapperDetails.tsx b/apps/admin-ui/src/user-federation/ldap/mappers/LdapMapperDetails.tsx index aa6766956d..46003500e4 100644 --- a/apps/admin-ui/src/user-federation/ldap/mappers/LdapMapperDetails.tsx +++ b/apps/admin-ui/src/user-federation/ldap/mappers/LdapMapperDetails.tsx @@ -32,6 +32,7 @@ import { KeycloakSpinner } from "../../../components/keycloak-spinner/KeycloakSp import { KeycloakTextInput } from "../../../components/keycloak-text-input/KeycloakTextInput"; import { toUserFederationLdap } from "../../routes/UserFederationLdap"; import { useConfirmDialog } from "../../../components/confirm-dialog/ConfirmDialog"; +import { DirectionType } from "libs/keycloak-admin-client/lib/resources/userStorageProvider"; export default function LdapMapperDetails() { const form = useForm(); @@ -46,6 +47,8 @@ export default function LdapMapperDetails() { const { addAlert, addError } = useAlerts(); const [isMapperDropdownOpen, setIsMapperDropdownOpen] = useState(false); + const [key, setKey] = useState(0); + const refresh = () => setKey(key + 1); useFetch( async () => { @@ -118,6 +121,24 @@ export default function LdapMapperDetails() { } }; + const sync = async (direction: DirectionType) => { + try { + const result = await adminClient.userStorageProvider.mappersSync({ + parentId: mapping?.parentId || "", + id: mapperId, + direction, + }); + addAlert( + t("syncLDAPGroupsSuccessful", { + result: result.status, + }) + ); + } catch (error) { + addError("user-federation:syncLDAPGroupsError", error); + } + refresh(); + }; + const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({ titleKey: "common:deleteMappingTitle", messageKey: "common:deleteMappingConfirm", @@ -141,16 +162,17 @@ export default function LdapMapperDetails() { name: "providerId", }); - const isNew = mapperId === "new"; - if (!components) { return ; } + const isNew = mapperId === "new"; + const mapper = components.find((c) => c.id === mapperType); return ( <> {t("common:delete")} , + mapper?.metadata.fedToKeycloakSyncSupported && ( + sync("fedToKeycloak")} + > + {t("syncLDAPGroupsToKeycloak")} + + ), + mapper?.metadata.keycloakToFedSyncSupported && ( + { + sync("keycloakToFed"); + }} + > + {t("syncKeycloakGroupsToLDAP")} + + ), ] } /> @@ -284,11 +324,7 @@ export default function LdapMapperDetails() { )} {!!mapperType && ( - c.id === mapperType)?.properties! - } - /> + )} diff --git a/libs/keycloak-admin-client/src/resources/userStorageProvider.ts b/libs/keycloak-admin-client/src/resources/userStorageProvider.ts index da130b4c2a..93156592ac 100644 --- a/libs/keycloak-admin-client/src/resources/userStorageProvider.ts +++ b/libs/keycloak-admin-client/src/resources/userStorageProvider.ts @@ -3,7 +3,7 @@ import type SynchronizationResultRepresentation from "../defs/synchronizationRes import Resource from "./resource.js"; type ActionType = "triggerFullSync" | "triggerChangedUsersSync"; -type DirectionType = "fedToKeycloak" | "keycloakToFed"; +export type DirectionType = "fedToKeycloak" | "keycloakToFed"; type NameResponse = { id: string; name: string;