diff --git a/src/realm-settings/KeysProvidersTab.tsx b/src/realm-settings/KeysProvidersTab.tsx index 84b7206b1b..1e4764a079 100644 --- a/src/realm-settings/KeysProvidersTab.tsx +++ b/src/realm-settings/KeysProvidersTab.tsx @@ -38,7 +38,7 @@ import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog"; import { useRealm } from "../context/realm-context/RealmContext"; import { Link, useRouteMatch } from "react-router-dom"; import { AESGeneratedModal } from "./key-providers/aes-generated/AESGeneratedModal"; -import { JavaKeystoreModal } from "./JavaKeystoreModal"; +import { JavaKeystoreModal } from "./key-providers/java-keystore/JavaKeystoreModal"; import { HMACGeneratedModal } from "./key-providers/hmac-generated/HMACGeneratedModal"; import { ECDSAGeneratedModal } from "./key-providers/ecdsa-generated/ECDSAGeneratedModal"; import { RSAModal } from "./RSAModal"; diff --git a/src/realm-settings/key-providers/java-keystore/JavaKeystoreForm.tsx b/src/realm-settings/key-providers/java-keystore/JavaKeystoreForm.tsx new file mode 100644 index 0000000000..8c4cf0ddd0 --- /dev/null +++ b/src/realm-settings/key-providers/java-keystore/JavaKeystoreForm.tsx @@ -0,0 +1,471 @@ +import React, { useState } from "react"; +import { + ActionGroup, + AlertVariant, + Button, + FormGroup, + PageSection, + Select, + SelectOption, + SelectVariant, + Switch, + TextInput, + ValidatedOptions, +} from "@patternfly/react-core"; +import { useTranslation } from "react-i18next"; +import { Controller, useForm } from "react-hook-form"; + +import type ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation"; +import { HelpItem } from "../../../components/help-enabler/HelpItem"; +import { useServerInfo } from "../../../context/server-info/ServerInfoProvider"; +import { useAdminClient, useFetch } from "../../../context/auth/AdminClient"; +import { useParams, useRouteMatch } from "react-router-dom"; +import { FormAccess } from "../../../components/form-access/FormAccess"; +import { ViewHeader } from "../../../components/view-header/ViewHeader"; +import { convertToFormValues } from "../../../util"; +import { useAlerts } from "../../../components/alert/Alerts"; + +type JavaKeystoreFormProps = { + handleModalToggle?: () => void; + refresh?: () => void; + editMode?: boolean; + providerType?: string; +}; + +export interface MatchParams { + providerType: string; +} + +export const JavaKeystoreForm = ({ + editMode, + providerType, + handleModalToggle, + refresh, +}: JavaKeystoreFormProps) => { + const { t } = useTranslation("realm-settings"); + const serverInfo = useServerInfo(); + const [isAlgorithmDropdownOpen, setIsAlgorithmDropdownOpen] = useState(false); + + const adminClient = useAdminClient(); + const { addAlert } = useAlerts(); + + const { id } = useParams<{ id: string }>(); + + const providerId = + useRouteMatch("/:providerType?")?.params.providerType; + + const save = async (component: ComponentRepresentation) => { + try { + if (id) { + await adminClient.components.update( + { id }, + { + ...component, + parentId: component.parentId, + providerId: providerType, + providerType: "org.keycloak.keys.KeyProvider", + } + ); + addAlert(t("saveProviderSuccess"), AlertVariant.success); + } else { + await adminClient.components.create({ + ...component, + parentId: component.parentId, + providerId: providerType, + providerType: "org.keycloak.keys.KeyProvider", + }); + handleModalToggle?.(); + addAlert(t("saveProviderSuccess"), AlertVariant.success); + refresh?.(); + } + } catch (error) { + addAlert( + t("saveProviderError", { + error: error.response?.data?.errorMessage || error, + }), + AlertVariant.danger + ); + } + }; + + const form = useForm({ mode: "onChange" }); + + const setupForm = (component: ComponentRepresentation) => { + form.reset(); + Object.entries(component).map(([key, value]) => { + if ( + key === "config" && + component.config?.secretSize && + component.config?.active && + component.config?.algorithm && + component.config?.keystore && + component.config?.keystorePassword && + component.config?.keyAlias && + component.config?.keyPassword + ) { + form.setValue("config.secretSize", value.secretSize[0]); + + form.setValue("config.active", value.active[0]); + + form.setValue("config.algorithm", value.algorithm[0]); + + form.setValue("config.keystore", value.keystore[0]); + + form.setValue("config.keyAlias", value.keyAlias[0]); + + form.setValue("config.keyPassword", value.keyPassword[0]); + + convertToFormValues(value, "config", form.setValue); + } + form.setValue(key, value); + }); + }; + + useFetch( + async () => { + if (editMode) return await adminClient.components.findOne({ id: id }); + }, + (result) => { + if (result) { + setupForm(result); + } + }, + [] + ); + + const allComponentTypes = + serverInfo.componentTypes?.["org.keycloak.keys.KeyProvider"] ?? []; + + const javaKeystoreAlgorithmOptions = + allComponentTypes[3].properties[3].options; + + return ( + + {editMode && ( + + } + fieldId="id" + isRequired + validated={ + form.errors.name ? ValidatedOptions.error : ValidatedOptions.default + } + helperTextInvalid={t("common:required")} + > + + + )} + + } + fieldId="name" + isRequired + validated={ + form.errors.name ? ValidatedOptions.error : ValidatedOptions.default + } + helperTextInvalid={t("common:required")} + > + {!editMode && ( + { + return ( + onChange(value)} + data-testid="display-name-input" + /> + ); + }} + /> + )} + {editMode && ( + <> + + + )} + + + } + > + ( + { + onChange([value.toString()]); + }} + /> + )} + /> + + + } + > + { + return ( + { + onChange([value.toString()]); + }} + /> + ); + }} + /> + + + } + > + ( + + )} + /> + + + } + > + ( + { + onChange([value.toString()]); + }} + data-testid="select-display-name" + > + )} + /> + + + } + > + ( + { + onChange([value.toString()]); + }} + data-testid="select-display-name" + > + )} + /> + + + } + > + ( + { + onChange([value.toString()]); + }} + data-testid="key-alias" + > + )} + /> + + + } + > + ( + { + onChange([value.toString()]); + }} + data-testid="key-password" + > + )} + /> + + + + + + + ); +}; + +export const JavaKeystoreSettings = () => { + const { t } = useTranslation("realm-settings"); + const providerId = useRouteMatch( + "/:realm/realm-settings/keys/:id?/:providerType?/settings" + )?.params.providerType; + return ( + <> + + + + + + ); +}; diff --git a/src/realm-settings/key-providers/java-keystore/JavaKeystoreModal.tsx b/src/realm-settings/key-providers/java-keystore/JavaKeystoreModal.tsx new file mode 100644 index 0000000000..8514e0151f --- /dev/null +++ b/src/realm-settings/key-providers/java-keystore/JavaKeystoreModal.tsx @@ -0,0 +1,36 @@ +import React from "react"; +import { Modal, ModalVariant } from "@patternfly/react-core"; +import { useTranslation } from "react-i18next"; +import { JavaKeystoreForm } from "./JavaKeystoreForm"; + +type JavaKeystoreModalProps = { + providerType: string; + handleModalToggle: () => void; + refresh: () => void; + open: boolean; +}; + +export const JavaKeystoreModal = ({ + providerType, + handleModalToggle, + open, + refresh, +}: JavaKeystoreModalProps) => { + const { t } = useTranslation("realm-settings"); + + return ( + + + + ); +}; diff --git a/src/route-config.ts b/src/route-config.ts index a9beb6d5f0..6251d31c20 100644 --- a/src/route-config.ts +++ b/src/route-config.ts @@ -40,6 +40,7 @@ import { AESGeneratedSettings } from "./realm-settings/key-providers/aes-generat import { HMACGeneratedSettings } from "./realm-settings/key-providers/hmac-generated/HMACGeneratedForm"; import { RSAGeneratedSettings } from "./realm-settings/key-providers/rsa-generated/RSAGeneratedForm"; import { ECDSAGeneratedSettings } from "./realm-settings/key-providers/ecdsa-generated/ECDSAGeneratedForm"; +import { JavaKeystoreSettings } from "./realm-settings/key-providers/java-keystore/JavaKeystoreForm"; import { RSASettings } from "./realm-settings/key-providers/rsa/RSAForm"; export type RouteDef = BreadcrumbsRoute & { @@ -206,6 +207,12 @@ export const routes: RoutesFn = (t: TFunction) => [ breadcrumb: t("realm-settings:editProvider"), access: "view-realm", }, + { + path: "/:realm/realm-settings/keys/:id?/java-keystore/settings", + component: JavaKeystoreSettings, + breadcrumb: t("realm-settings:editProvider"), + access: "view-realm", + }, { path: "/:realm/realm-settings/keys/:id?/rsa-generated/settings", component: RSAGeneratedSettings,