Realm settings(keys): toggle provider modal for all provider types (#642)
* changes after rebase * add cypress tests * addProviderModal done * fix lint * clean up ids/fieldids * divide modals into separate components * format * cypress * fix realm settings test * clean up cypress tests * try remove after all hook
This commit is contained in:
parent
04140f1737
commit
2746109e78
13 changed files with 2201 additions and 57 deletions
|
@ -4,68 +4,115 @@ import RealmSettingsPage from "../support/pages/admin_console/manage/realm_setti
|
||||||
import { keycloakBefore } from "../support/util/keycloak_before";
|
import { keycloakBefore } from "../support/util/keycloak_before";
|
||||||
import AdminClient from "../support/util/AdminClient";
|
import AdminClient from "../support/util/AdminClient";
|
||||||
|
|
||||||
describe("Realm settings test", () => {
|
// describe("Realm settings test", () => {
|
||||||
const loginPage = new LoginPage();
|
const loginPage = new LoginPage();
|
||||||
const sidebarPage = new SidebarPage();
|
const sidebarPage = new SidebarPage();
|
||||||
const realmSettingsPage = new RealmSettingsPage();
|
const realmSettingsPage = new RealmSettingsPage();
|
||||||
|
|
||||||
describe("Realm settings", () => {
|
describe("Realm settings", () => {
|
||||||
const realmName = "Realm_" + (Math.random() + 1).toString(36).substring(7);
|
const realmName = "Realm_" + (Math.random() + 1).toString(36).substring(7);
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
keycloakBefore();
|
keycloakBefore();
|
||||||
loginPage.logIn();
|
loginPage.logIn();
|
||||||
sidebarPage.goToRealm(realmName);
|
sidebarPage.goToRealm(realmName);
|
||||||
});
|
});
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
await new AdminClient().createRealm(realmName);
|
await new AdminClient().createRealm(realmName);
|
||||||
});
|
});
|
||||||
|
|
||||||
after(async () => {
|
// after(async () => {
|
||||||
await new AdminClient().deleteRealm(realmName);
|
// await new AdminClient().deleteRealm(realmName);
|
||||||
});
|
// });
|
||||||
|
|
||||||
it("Go to general tab", function () {
|
it("Go to general tab", function () {
|
||||||
sidebarPage.goToRealmSettings();
|
sidebarPage.goToRealmSettings();
|
||||||
realmSettingsPage.toggleSwitch(realmSettingsPage.managedAccessSwitch);
|
realmSettingsPage.toggleSwitch(realmSettingsPage.managedAccessSwitch);
|
||||||
realmSettingsPage.save(realmSettingsPage.generalSaveBtn);
|
realmSettingsPage.save(realmSettingsPage.generalSaveBtn);
|
||||||
realmSettingsPage.toggleSwitch(realmSettingsPage.managedAccessSwitch);
|
realmSettingsPage.toggleSwitch(realmSettingsPage.managedAccessSwitch);
|
||||||
realmSettingsPage.save(realmSettingsPage.generalSaveBtn);
|
realmSettingsPage.save(realmSettingsPage.generalSaveBtn);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Go to login tab", function () {
|
it("Go to login tab", function () {
|
||||||
sidebarPage.goToRealmSettings();
|
sidebarPage.goToRealmSettings();
|
||||||
cy.getId("rs-login-tab").click();
|
cy.getId("rs-login-tab").click();
|
||||||
realmSettingsPage.toggleSwitch(realmSettingsPage.userRegSwitch);
|
realmSettingsPage.toggleSwitch(realmSettingsPage.userRegSwitch);
|
||||||
realmSettingsPage.toggleSwitch(realmSettingsPage.forgotPwdSwitch);
|
realmSettingsPage.toggleSwitch(realmSettingsPage.forgotPwdSwitch);
|
||||||
realmSettingsPage.toggleSwitch(realmSettingsPage.rememberMeSwitch);
|
realmSettingsPage.toggleSwitch(realmSettingsPage.rememberMeSwitch);
|
||||||
realmSettingsPage.toggleSwitch(realmSettingsPage.verifyEmailSwitch);
|
realmSettingsPage.toggleSwitch(realmSettingsPage.verifyEmailSwitch);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Go to email tab", function () {
|
it("Go to email tab", function () {
|
||||||
sidebarPage.goToRealmSettings();
|
sidebarPage.goToRealmSettings();
|
||||||
cy.getId("rs-email-tab").click();
|
cy.getId("rs-email-tab").click();
|
||||||
|
|
||||||
realmSettingsPage.addSenderEmail("example@example.com");
|
cy.wait(1000);
|
||||||
|
|
||||||
cy.wait(100);
|
realmSettingsPage.addSenderEmail("example@example.com");
|
||||||
|
|
||||||
realmSettingsPage.toggleCheck(realmSettingsPage.enableSslCheck);
|
realmSettingsPage.toggleCheck(realmSettingsPage.enableSslCheck);
|
||||||
realmSettingsPage.toggleCheck(realmSettingsPage.enableStartTlsCheck);
|
realmSettingsPage.toggleCheck(realmSettingsPage.enableStartTlsCheck);
|
||||||
|
|
||||||
realmSettingsPage.save(realmSettingsPage.emailSaveBtn);
|
realmSettingsPage.save(realmSettingsPage.emailSaveBtn);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Go to themes tab", function () {
|
it("Go to themes tab", function () {
|
||||||
sidebarPage.goToRealmSettings();
|
cy.wait(5000);
|
||||||
cy.getId("rs-themes-tab").click();
|
sidebarPage.goToRealmSettings();
|
||||||
realmSettingsPage.selectLoginThemeType("keycloak");
|
cy.getId("rs-themes-tab").click();
|
||||||
realmSettingsPage.selectAccountThemeType("keycloak");
|
realmSettingsPage.selectLoginThemeType("keycloak");
|
||||||
realmSettingsPage.selectAdminThemeType("base");
|
realmSettingsPage.selectAccountThemeType("keycloak");
|
||||||
realmSettingsPage.selectEmailThemeType("base");
|
realmSettingsPage.selectAdminThemeType("base");
|
||||||
|
realmSettingsPage.selectEmailThemeType("base");
|
||||||
|
|
||||||
realmSettingsPage.saveThemes();
|
realmSettingsPage.saveThemes();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Go to keys tab", function () {
|
||||||
|
cy.wait(5000);
|
||||||
|
|
||||||
|
sidebarPage.goToRealmSettings();
|
||||||
|
|
||||||
|
cy.getId("rs-keys-tab").click();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("add Providers", function () {
|
||||||
|
cy.wait(5000);
|
||||||
|
sidebarPage.goToRealmSettings();
|
||||||
|
|
||||||
|
cy.getId("rs-keys-tab").click();
|
||||||
|
|
||||||
|
cy.wait(10000);
|
||||||
|
|
||||||
|
cy.getId("rs-providers-tab").click();
|
||||||
|
|
||||||
|
realmSettingsPage.toggleAddProviderDropdown();
|
||||||
|
|
||||||
|
cy.getId("option-aes-generated").click();
|
||||||
|
realmSettingsPage.enterConsoleDisplayName("test_aes-generated");
|
||||||
|
cy.wait(200);
|
||||||
|
realmSettingsPage.addProvider();
|
||||||
|
|
||||||
|
realmSettingsPage.toggleAddProviderDropdown();
|
||||||
|
|
||||||
|
cy.getId("option-ecdsa-generated").click();
|
||||||
|
realmSettingsPage.enterConsoleDisplayName("test_ecdsa-generated");
|
||||||
|
cy.wait(200);
|
||||||
|
realmSettingsPage.addProvider();
|
||||||
|
|
||||||
|
realmSettingsPage.toggleAddProviderDropdown();
|
||||||
|
|
||||||
|
cy.getId("option-hmac-generated").click();
|
||||||
|
realmSettingsPage.enterConsoleDisplayName("test_hmac-generated");
|
||||||
|
cy.wait(200);
|
||||||
|
realmSettingsPage.addProvider();
|
||||||
|
|
||||||
|
realmSettingsPage.toggleAddProviderDropdown();
|
||||||
|
|
||||||
|
cy.getId("option-rsa-generated").click();
|
||||||
|
realmSettingsPage.enterConsoleDisplayName("test_rsa-generated");
|
||||||
|
realmSettingsPage.addProvider();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// });
|
||||||
|
|
|
@ -25,10 +25,17 @@ export default class RealmSettingsPage {
|
||||||
fromInput = "sender-email-address";
|
fromInput = "sender-email-address";
|
||||||
enableSslCheck = "enable-ssl";
|
enableSslCheck = "enable-ssl";
|
||||||
enableStartTlsCheck = "enable-start-tls";
|
enableStartTlsCheck = "enable-start-tls";
|
||||||
|
addProviderDropdown = "addProviderDropdown";
|
||||||
|
addProviderButton = "add-provider-button";
|
||||||
|
displayName = "display-name-input";
|
||||||
|
|
||||||
selectLoginThemeType(themeType: string) {
|
selectLoginThemeType(themeType: string) {
|
||||||
|
const themesUrl = "/auth/admin/realms/master/themes";
|
||||||
|
cy.intercept(themesUrl).as("themesFetch");
|
||||||
|
|
||||||
cy.get(this.selectLoginTheme).click();
|
cy.get(this.selectLoginTheme).click();
|
||||||
cy.get(this.loginThemeList).contains(themeType).click();
|
cy.get(this.loginThemeList).contains(themeType).click();
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,6 +97,24 @@ export default class RealmSettingsPage {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleAddProviderDropdown() {
|
||||||
|
const keysUrl = "/auth/admin/realms/master/keys";
|
||||||
|
cy.intercept(keysUrl).as("keysFetch");
|
||||||
|
cy.getId(this.addProviderDropdown).click();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
addProvider() {
|
||||||
|
cy.getId(this.addProviderButton).click();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
enterConsoleDisplayName(name: string) {
|
||||||
|
cy.getId(this.displayName).clear().type(name);
|
||||||
|
}
|
||||||
|
|
||||||
save(saveBtn: string) {
|
save(saveBtn: string) {
|
||||||
cy.getId(saveBtn).click();
|
cy.getId(saveBtn).click();
|
||||||
|
|
||||||
|
|
252
src/realm-settings/AESGeneratedModal.tsx
Normal file
252
src/realm-settings/AESGeneratedModal.tsx
Normal file
|
@ -0,0 +1,252 @@
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import {
|
||||||
|
AlertVariant,
|
||||||
|
Button,
|
||||||
|
ButtonVariant,
|
||||||
|
Form,
|
||||||
|
FormGroup,
|
||||||
|
Modal,
|
||||||
|
ModalVariant,
|
||||||
|
Select,
|
||||||
|
SelectOption,
|
||||||
|
SelectVariant,
|
||||||
|
Switch,
|
||||||
|
TextInput,
|
||||||
|
} from "@patternfly/react-core";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { Controller, useForm } from "react-hook-form";
|
||||||
|
|
||||||
|
import { useAdminClient } from "../context/auth/AdminClient";
|
||||||
|
import { useAlerts } from "../components/alert/Alerts";
|
||||||
|
import type ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
|
||||||
|
import { HelpItem } from "../components/help-enabler/HelpItem";
|
||||||
|
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
|
||||||
|
import { useRealm } from "../context/realm-context/RealmContext";
|
||||||
|
|
||||||
|
type AESGeneratedModalProps = {
|
||||||
|
providerType?: string;
|
||||||
|
handleModalToggle?: () => void;
|
||||||
|
refresh?: () => void;
|
||||||
|
open: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AESGeneratedModal = ({
|
||||||
|
providerType,
|
||||||
|
handleModalToggle,
|
||||||
|
open,
|
||||||
|
refresh,
|
||||||
|
}: // save,
|
||||||
|
AESGeneratedModalProps) => {
|
||||||
|
const { t } = useTranslation("groups");
|
||||||
|
const serverInfo = useServerInfo();
|
||||||
|
const adminClient = useAdminClient();
|
||||||
|
const { addAlert } = useAlerts();
|
||||||
|
const { handleSubmit, control } = useForm({});
|
||||||
|
const [isKeySizeDropdownOpen, setIsKeySizeDropdownOpen] = useState(false);
|
||||||
|
const [displayName, setDisplayName] = useState("");
|
||||||
|
const realm = useRealm();
|
||||||
|
|
||||||
|
const allComponentTypes = serverInfo.componentTypes![
|
||||||
|
"org.keycloak.keys.KeyProvider"
|
||||||
|
];
|
||||||
|
|
||||||
|
const save = async (component: ComponentRepresentation) => {
|
||||||
|
try {
|
||||||
|
await adminClient.components.create({
|
||||||
|
parentId: realm.realm,
|
||||||
|
name: displayName !== "" ? displayName : providerType,
|
||||||
|
providerId: providerType,
|
||||||
|
providerType: "org.keycloak.keys.KeyProvider",
|
||||||
|
...component,
|
||||||
|
});
|
||||||
|
refresh!();
|
||||||
|
addAlert(t("realm-settings:saveProviderSuccess"), AlertVariant.success);
|
||||||
|
handleModalToggle!();
|
||||||
|
} catch (error) {
|
||||||
|
addAlert(
|
||||||
|
t("realm-settings:saveProviderError") +
|
||||||
|
error.response?.data?.errorMessage || error,
|
||||||
|
AlertVariant.danger
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
className="add-provider-modal"
|
||||||
|
variant={ModalVariant.medium}
|
||||||
|
title={t("realm-settings:addProvider")}
|
||||||
|
isOpen={open}
|
||||||
|
onClose={handleModalToggle}
|
||||||
|
actions={[
|
||||||
|
<Button
|
||||||
|
data-testid="add-provider-button"
|
||||||
|
key="confirm"
|
||||||
|
variant="primary"
|
||||||
|
type="submit"
|
||||||
|
form="add-provider"
|
||||||
|
>
|
||||||
|
{t("common:Add")}
|
||||||
|
</Button>,
|
||||||
|
<Button
|
||||||
|
id="modal-cancel"
|
||||||
|
key="cancel"
|
||||||
|
variant={ButtonVariant.link}
|
||||||
|
onClick={() => {
|
||||||
|
handleModalToggle!();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("common:cancel")}
|
||||||
|
</Button>,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Form
|
||||||
|
isHorizontal
|
||||||
|
id="add-provider"
|
||||||
|
className="pf-u-mt-lg"
|
||||||
|
onSubmit={handleSubmit(save!)}
|
||||||
|
>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:consoleDisplayName")}
|
||||||
|
fieldId="kc-console-display-name"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:displayName"
|
||||||
|
forLabel={t("loginTheme")}
|
||||||
|
forID="kc-console-display-name"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="name"
|
||||||
|
control={control}
|
||||||
|
defaultValue={providerType}
|
||||||
|
render={({ onChange }) => (
|
||||||
|
<TextInput
|
||||||
|
aria-label={t("consoleDisplayName")}
|
||||||
|
defaultValue={providerType}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange(value);
|
||||||
|
setDisplayName(value);
|
||||||
|
}}
|
||||||
|
data-testid="display-name-input"
|
||||||
|
></TextInput>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("common:enabled")}
|
||||||
|
fieldId="kc-enabled"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText={t("realm-settings-help:enabled")}
|
||||||
|
forLabel={t("enabled")}
|
||||||
|
forID="kc-enabled"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="config.enabled"
|
||||||
|
control={control}
|
||||||
|
defaultValue={["true"]}
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<Switch
|
||||||
|
id="kc-enabled"
|
||||||
|
label={t("common:on")}
|
||||||
|
labelOff={t("common:off")}
|
||||||
|
isChecked={value[0] === "true"}
|
||||||
|
data-testid={
|
||||||
|
value[0] === "true"
|
||||||
|
? "internationalization-enabled"
|
||||||
|
: "internationalization-disabled"
|
||||||
|
}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange([value + ""]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:active")}
|
||||||
|
fieldId="kc-active"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:active"
|
||||||
|
forLabel={t("active")}
|
||||||
|
forID="kc-active"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="config.active"
|
||||||
|
control={control}
|
||||||
|
defaultValue={["true"]}
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<Switch
|
||||||
|
id="kc-active"
|
||||||
|
label={t("common:on")}
|
||||||
|
labelOff={t("common:off")}
|
||||||
|
isChecked={value[0] === "true"}
|
||||||
|
data-testid={
|
||||||
|
value[0] === "true"
|
||||||
|
? "internationalization-enabled"
|
||||||
|
: "internationalization-disabled"
|
||||||
|
}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange([value + ""]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
{providerType === "aes-generated" && (
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:AESKeySize")}
|
||||||
|
fieldId="kc-aes-keysize"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:AESKeySize"
|
||||||
|
forLabel={t("AESKeySize")}
|
||||||
|
forID="kc-aes-key-size"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="config.secretSize"
|
||||||
|
control={control}
|
||||||
|
defaultValue={["16"]}
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<Select
|
||||||
|
toggleId="kc-aes-keysize"
|
||||||
|
onToggle={() =>
|
||||||
|
setIsKeySizeDropdownOpen(!isKeySizeDropdownOpen)
|
||||||
|
}
|
||||||
|
onSelect={(_, value) => {
|
||||||
|
onChange([value + ""]);
|
||||||
|
setIsKeySizeDropdownOpen(false);
|
||||||
|
}}
|
||||||
|
selections={[value + ""]}
|
||||||
|
isOpen={isKeySizeDropdownOpen}
|
||||||
|
variant={SelectVariant.single}
|
||||||
|
aria-label={t("aesKeySize")}
|
||||||
|
data-testid="select-secret-size"
|
||||||
|
>
|
||||||
|
{allComponentTypes[0].properties[3].options!.map(
|
||||||
|
(item, idx) => (
|
||||||
|
<SelectOption
|
||||||
|
selected={item === value}
|
||||||
|
key={`email-theme-${idx}`}
|
||||||
|
value={item}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</Select>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
)}
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
367
src/realm-settings/ECDSAGeneratedModal.tsx
Normal file
367
src/realm-settings/ECDSAGeneratedModal.tsx
Normal file
|
@ -0,0 +1,367 @@
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import {
|
||||||
|
AlertVariant,
|
||||||
|
Button,
|
||||||
|
ButtonVariant,
|
||||||
|
FileUpload,
|
||||||
|
Form,
|
||||||
|
FormGroup,
|
||||||
|
Modal,
|
||||||
|
ModalVariant,
|
||||||
|
Select,
|
||||||
|
SelectOption,
|
||||||
|
SelectVariant,
|
||||||
|
Switch,
|
||||||
|
TextInput,
|
||||||
|
} from "@patternfly/react-core";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { Controller, useForm } from "react-hook-form";
|
||||||
|
|
||||||
|
import { useAdminClient } from "../context/auth/AdminClient";
|
||||||
|
import { useAlerts } from "../components/alert/Alerts";
|
||||||
|
import type ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
|
||||||
|
import { HelpItem } from "../components/help-enabler/HelpItem";
|
||||||
|
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
|
||||||
|
import { useRealm } from "../context/realm-context/RealmContext";
|
||||||
|
|
||||||
|
type ECDSAGeneratedModalProps = {
|
||||||
|
providerType?: string;
|
||||||
|
handleModalToggle?: () => void;
|
||||||
|
refresh?: () => void;
|
||||||
|
open: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ECDSAGeneratedModal = ({
|
||||||
|
providerType,
|
||||||
|
handleModalToggle,
|
||||||
|
open,
|
||||||
|
refresh,
|
||||||
|
}: // save,
|
||||||
|
ECDSAGeneratedModalProps) => {
|
||||||
|
const { t } = useTranslation("groups");
|
||||||
|
const serverInfo = useServerInfo();
|
||||||
|
const adminClient = useAdminClient();
|
||||||
|
const { addAlert } = useAlerts();
|
||||||
|
const { handleSubmit, control } = useForm({});
|
||||||
|
const [
|
||||||
|
isEllipticCurveDropdownOpen,
|
||||||
|
setIsEllipticCurveDropdownOpen,
|
||||||
|
] = useState(false);
|
||||||
|
const [isRSAalgDropdownOpen, setIsRSAalgDropdownOpen] = useState(false);
|
||||||
|
const [displayName, setDisplayName] = useState("");
|
||||||
|
const realm = useRealm();
|
||||||
|
|
||||||
|
const [keyFileName, setKeyFileName] = useState("");
|
||||||
|
const [certificateFileName, setCertificateFileName] = useState("");
|
||||||
|
|
||||||
|
const allComponentTypes = serverInfo.componentTypes![
|
||||||
|
"org.keycloak.keys.KeyProvider"
|
||||||
|
];
|
||||||
|
|
||||||
|
const save = async (component: ComponentRepresentation) => {
|
||||||
|
try {
|
||||||
|
await adminClient.components.create({
|
||||||
|
parentId: realm.realm,
|
||||||
|
name: displayName !== "" ? displayName : providerType,
|
||||||
|
providerId: providerType,
|
||||||
|
providerType: "org.keycloak.keys.KeyProvider",
|
||||||
|
...component,
|
||||||
|
});
|
||||||
|
refresh!();
|
||||||
|
addAlert(t("realm-settings:saveProviderSuccess"), AlertVariant.success);
|
||||||
|
handleModalToggle!();
|
||||||
|
} catch (error) {
|
||||||
|
addAlert(
|
||||||
|
t("realm-settings:saveProviderError") +
|
||||||
|
error.response?.data?.errorMessage || error,
|
||||||
|
AlertVariant.danger
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
className="add-provider-modal"
|
||||||
|
variant={ModalVariant.medium}
|
||||||
|
title={t("realm-settings:addProvider")}
|
||||||
|
isOpen={open}
|
||||||
|
onClose={handleModalToggle}
|
||||||
|
actions={[
|
||||||
|
<Button
|
||||||
|
data-testid="add-provider-button"
|
||||||
|
key="confirm"
|
||||||
|
variant="primary"
|
||||||
|
type="submit"
|
||||||
|
form="add-provider"
|
||||||
|
>
|
||||||
|
{t("common:Add")}
|
||||||
|
</Button>,
|
||||||
|
<Button
|
||||||
|
id="modal-cancel"
|
||||||
|
key="cancel"
|
||||||
|
variant={ButtonVariant.link}
|
||||||
|
onClick={() => {
|
||||||
|
handleModalToggle!();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("common:cancel")}
|
||||||
|
</Button>,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Form
|
||||||
|
isHorizontal
|
||||||
|
id="add-provider"
|
||||||
|
className="pf-u-mt-lg"
|
||||||
|
onSubmit={handleSubmit(save!)}
|
||||||
|
>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:consoleDisplayName")}
|
||||||
|
fieldId="kc-console-display-name"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:displayName"
|
||||||
|
forLabel={t("loginTheme")}
|
||||||
|
forID="kc-console-display-name"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="name"
|
||||||
|
control={control}
|
||||||
|
defaultValue={providerType}
|
||||||
|
render={({ onChange }) => (
|
||||||
|
<TextInput
|
||||||
|
aria-label={t("consoleDisplayName")}
|
||||||
|
defaultValue={providerType}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange(value);
|
||||||
|
setDisplayName(value);
|
||||||
|
}}
|
||||||
|
data-testid="display-name-input"
|
||||||
|
></TextInput>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("common:enabled")}
|
||||||
|
fieldId="kc-enabled"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText={t("realm-settings-help:enabled")}
|
||||||
|
forLabel={t("enabled")}
|
||||||
|
forID="kc-enabled"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="config.enabled"
|
||||||
|
control={control}
|
||||||
|
defaultValue={["true"]}
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<Switch
|
||||||
|
id="kc-enabled"
|
||||||
|
label={t("common:on")}
|
||||||
|
labelOff={t("common:off")}
|
||||||
|
isChecked={value[0] === "true"}
|
||||||
|
data-testid={
|
||||||
|
value[0] === "true"
|
||||||
|
? "internationalization-enabled"
|
||||||
|
: "internationalization-disabled"
|
||||||
|
}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange([value + ""]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:active")}
|
||||||
|
fieldId="kc-active"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:active"
|
||||||
|
forLabel={t("active")}
|
||||||
|
forID="kc-active"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="config.active"
|
||||||
|
control={control}
|
||||||
|
defaultValue={["true"]}
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<Switch
|
||||||
|
id="kc-active"
|
||||||
|
label={t("common:on")}
|
||||||
|
labelOff={t("common:off")}
|
||||||
|
isChecked={value[0] === "true"}
|
||||||
|
data-testid={
|
||||||
|
value[0] === "true"
|
||||||
|
? "internationalization-enabled"
|
||||||
|
: "internationalization-disabled"
|
||||||
|
}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange([value + ""]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
{providerType === "rsa" && (
|
||||||
|
<>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:algorithm")}
|
||||||
|
fieldId="kc-algorithm"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:algorithm"
|
||||||
|
forLabel={t("algorithm")}
|
||||||
|
forID="kc-algorithm"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="algorithm"
|
||||||
|
control={control}
|
||||||
|
defaultValue=""
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<Select
|
||||||
|
toggleId="kc-rsa-algorithm"
|
||||||
|
onToggle={() =>
|
||||||
|
setIsRSAalgDropdownOpen(!isRSAalgDropdownOpen)
|
||||||
|
}
|
||||||
|
onSelect={(_, value) => {
|
||||||
|
onChange(value as string);
|
||||||
|
setIsRSAalgDropdownOpen(false);
|
||||||
|
}}
|
||||||
|
selections={[value + ""]}
|
||||||
|
variant={SelectVariant.single}
|
||||||
|
aria-label={t("algorithm")}
|
||||||
|
isOpen={isRSAalgDropdownOpen}
|
||||||
|
data-testid="select-rsa-algorithm"
|
||||||
|
>
|
||||||
|
{allComponentTypes[4].properties[3].options!.map(
|
||||||
|
(p, idx) => (
|
||||||
|
<SelectOption
|
||||||
|
selected={p === value}
|
||||||
|
key={`rsa-algorithm-${idx}`}
|
||||||
|
value={p}
|
||||||
|
></SelectOption>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</Select>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:privateRSAKey")}
|
||||||
|
fieldId="kc-private-rsa-key"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:privateRSAKey"
|
||||||
|
forLabel={t("privateRSAKey")}
|
||||||
|
forID="kc-rsa-key"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="config.privateKey"
|
||||||
|
control={control}
|
||||||
|
defaultValue={[]}
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<FileUpload
|
||||||
|
id="importPrivateKey"
|
||||||
|
type="text"
|
||||||
|
value={value[0]}
|
||||||
|
filenamePlaceholder="Upload a PEM file or paste key below"
|
||||||
|
filename={keyFileName}
|
||||||
|
onChange={(value, fileName) => {
|
||||||
|
setKeyFileName(fileName);
|
||||||
|
onChange([value]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:x509Certificate")}
|
||||||
|
fieldId="kc-aes-keysize"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:x509Certificate"
|
||||||
|
forLabel={t("x509Certificate")}
|
||||||
|
forID="kc-x509-certificatw"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="config.certificate"
|
||||||
|
control={control}
|
||||||
|
defaultValue={[]}
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<FileUpload
|
||||||
|
id="importCertificate"
|
||||||
|
type="text"
|
||||||
|
value={value[0]}
|
||||||
|
filenamePlaceholder="Upload a PEM file or paste key below"
|
||||||
|
filename={certificateFileName}
|
||||||
|
onChange={(value, fileName) => {
|
||||||
|
setCertificateFileName(fileName);
|
||||||
|
onChange([value]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{providerType === "ecdsa-generated" && (
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:ellipticCurve")}
|
||||||
|
fieldId="kc-algorithm"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:ellipticCurve"
|
||||||
|
forLabel={t("emailTheme")}
|
||||||
|
forID="kc-email-theme"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="config.ecdsaEllipticCurveKey"
|
||||||
|
control={control}
|
||||||
|
defaultValue={["P-256"]}
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<Select
|
||||||
|
toggleId="kc-elliptic"
|
||||||
|
onToggle={() =>
|
||||||
|
setIsEllipticCurveDropdownOpen(!isEllipticCurveDropdownOpen)
|
||||||
|
}
|
||||||
|
onSelect={(_, value) => {
|
||||||
|
onChange([value + ""]);
|
||||||
|
setIsEllipticCurveDropdownOpen(false);
|
||||||
|
}}
|
||||||
|
selections={[value + ""]}
|
||||||
|
variant={SelectVariant.single}
|
||||||
|
aria-label={t("emailTheme")}
|
||||||
|
isOpen={isEllipticCurveDropdownOpen}
|
||||||
|
placeholderText="Select one..."
|
||||||
|
data-testid="select-email-theme"
|
||||||
|
>
|
||||||
|
{allComponentTypes[1].properties[3].options!.map((p, idx) => (
|
||||||
|
<SelectOption
|
||||||
|
selected={p === value}
|
||||||
|
key={`email-theme-${idx}`}
|
||||||
|
value={p}
|
||||||
|
></SelectOption>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
)}
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
305
src/realm-settings/HMACGeneratedModal.tsx
Normal file
305
src/realm-settings/HMACGeneratedModal.tsx
Normal file
|
@ -0,0 +1,305 @@
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import {
|
||||||
|
AlertVariant,
|
||||||
|
Button,
|
||||||
|
ButtonVariant,
|
||||||
|
Form,
|
||||||
|
FormGroup,
|
||||||
|
Modal,
|
||||||
|
ModalVariant,
|
||||||
|
Select,
|
||||||
|
SelectOption,
|
||||||
|
SelectVariant,
|
||||||
|
Switch,
|
||||||
|
TextInput,
|
||||||
|
} from "@patternfly/react-core";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { Controller, useForm } from "react-hook-form";
|
||||||
|
|
||||||
|
import { useAdminClient } from "../context/auth/AdminClient";
|
||||||
|
import { useAlerts } from "../components/alert/Alerts";
|
||||||
|
import type ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
|
||||||
|
import { HelpItem } from "../components/help-enabler/HelpItem";
|
||||||
|
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
|
||||||
|
import { useRealm } from "../context/realm-context/RealmContext";
|
||||||
|
|
||||||
|
type HMACGeneratedModalProps = {
|
||||||
|
providerType?: string;
|
||||||
|
handleModalToggle?: () => void;
|
||||||
|
refresh?: () => void;
|
||||||
|
open: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const HMACGeneratedModal = ({
|
||||||
|
providerType,
|
||||||
|
handleModalToggle,
|
||||||
|
open,
|
||||||
|
refresh,
|
||||||
|
}: // save,
|
||||||
|
HMACGeneratedModalProps) => {
|
||||||
|
const { t } = useTranslation("groups");
|
||||||
|
const serverInfo = useServerInfo();
|
||||||
|
const adminClient = useAdminClient();
|
||||||
|
const { addAlert } = useAlerts();
|
||||||
|
const { handleSubmit, control } = useForm({});
|
||||||
|
const [isKeySizeDropdownOpen, setIsKeySizeDropdownOpen] = useState(false);
|
||||||
|
const [
|
||||||
|
isEllipticCurveDropdownOpen,
|
||||||
|
setIsEllipticCurveDropdownOpen,
|
||||||
|
] = useState(false);
|
||||||
|
const [displayName, setDisplayName] = useState("");
|
||||||
|
const realm = useRealm();
|
||||||
|
|
||||||
|
const allComponentTypes = serverInfo.componentTypes![
|
||||||
|
"org.keycloak.keys.KeyProvider"
|
||||||
|
];
|
||||||
|
|
||||||
|
const save = async (component: ComponentRepresentation) => {
|
||||||
|
try {
|
||||||
|
await adminClient.components.create({
|
||||||
|
parentId: realm.realm,
|
||||||
|
name: displayName !== "" ? displayName : providerType,
|
||||||
|
providerId: providerType,
|
||||||
|
providerType: "org.keycloak.keys.KeyProvider",
|
||||||
|
...component,
|
||||||
|
});
|
||||||
|
refresh!();
|
||||||
|
addAlert(t("realm-settings:saveProviderSuccess"), AlertVariant.success);
|
||||||
|
handleModalToggle!();
|
||||||
|
} catch (error) {
|
||||||
|
addAlert(
|
||||||
|
t("realm-settings:saveProviderError") +
|
||||||
|
error.response?.data?.errorMessage || error,
|
||||||
|
AlertVariant.danger
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
className="add-provider-modal"
|
||||||
|
variant={ModalVariant.medium}
|
||||||
|
title={t("realm-settings:addProvider")}
|
||||||
|
isOpen={open}
|
||||||
|
onClose={handleModalToggle}
|
||||||
|
actions={[
|
||||||
|
<Button
|
||||||
|
data-testid="add-provider-button"
|
||||||
|
key="confirm"
|
||||||
|
variant="primary"
|
||||||
|
type="submit"
|
||||||
|
form="add-provider"
|
||||||
|
>
|
||||||
|
{t("common:Add")}
|
||||||
|
</Button>,
|
||||||
|
<Button
|
||||||
|
id="modal-cancel"
|
||||||
|
key="cancel"
|
||||||
|
variant={ButtonVariant.link}
|
||||||
|
onClick={() => {
|
||||||
|
handleModalToggle!();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("common:cancel")}
|
||||||
|
</Button>,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Form
|
||||||
|
isHorizontal
|
||||||
|
id="add-provider"
|
||||||
|
className="pf-u-mt-lg"
|
||||||
|
onSubmit={handleSubmit(save!)}
|
||||||
|
>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:consoleDisplayName")}
|
||||||
|
fieldId="kc-console-display-name"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:displayName"
|
||||||
|
forLabel={t("loginTheme")}
|
||||||
|
forID="kc-console-display-name"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="name"
|
||||||
|
control={control}
|
||||||
|
defaultValue={providerType}
|
||||||
|
render={({ onChange }) => (
|
||||||
|
<TextInput
|
||||||
|
aria-label={t("consoleDisplayName")}
|
||||||
|
defaultValue={providerType}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange(value);
|
||||||
|
setDisplayName(value);
|
||||||
|
}}
|
||||||
|
data-testid="display-name-input"
|
||||||
|
></TextInput>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("common:enabled")}
|
||||||
|
fieldId="kc-enabled"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText={t("realm-settings-help:enabled")}
|
||||||
|
forLabel={t("enabled")}
|
||||||
|
forID="kc-enabled"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="config.enabled"
|
||||||
|
control={control}
|
||||||
|
defaultValue={["true"]}
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<Switch
|
||||||
|
id="kc-enabled"
|
||||||
|
label={t("common:on")}
|
||||||
|
labelOff={t("common:off")}
|
||||||
|
isChecked={value[0] === "true"}
|
||||||
|
data-testid={
|
||||||
|
value[0] === "true"
|
||||||
|
? "internationalization-enabled"
|
||||||
|
: "internationalization-disabled"
|
||||||
|
}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange([value + ""]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:active")}
|
||||||
|
fieldId="kc-active"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:active"
|
||||||
|
forLabel={t("active")}
|
||||||
|
forID="kc-active"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="config.active"
|
||||||
|
control={control}
|
||||||
|
defaultValue={["true"]}
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<Switch
|
||||||
|
id="kc-active"
|
||||||
|
label={t("common:on")}
|
||||||
|
labelOff={t("common:off")}
|
||||||
|
isChecked={value[0] === "true"}
|
||||||
|
data-testid={
|
||||||
|
value[0] === "true"
|
||||||
|
? "internationalization-enabled"
|
||||||
|
: "internationalization-disabled"
|
||||||
|
}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange([value + ""]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
{providerType === "hmac-generated" && (
|
||||||
|
<>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:secretSize")}
|
||||||
|
fieldId="kc-aes-keysize"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:secretSize"
|
||||||
|
forLabel={t("emailTheme")}
|
||||||
|
forID="kc-email-theme"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="config.secretSize"
|
||||||
|
control={control}
|
||||||
|
defaultValue={["64"]}
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<Select
|
||||||
|
toggleId="kc-aes-keysize"
|
||||||
|
onToggle={() =>
|
||||||
|
setIsKeySizeDropdownOpen(!isKeySizeDropdownOpen)
|
||||||
|
}
|
||||||
|
onSelect={(_, value) => {
|
||||||
|
onChange([value + ""]);
|
||||||
|
setIsKeySizeDropdownOpen(false);
|
||||||
|
}}
|
||||||
|
selections={[value + ""]}
|
||||||
|
isOpen={isKeySizeDropdownOpen}
|
||||||
|
variant={SelectVariant.single}
|
||||||
|
aria-label={t("aesKeySize")}
|
||||||
|
data-testid="select-secret-size"
|
||||||
|
>
|
||||||
|
{allComponentTypes[2].properties[3].options!.map(
|
||||||
|
(item, idx) => (
|
||||||
|
<SelectOption
|
||||||
|
selected={item === value}
|
||||||
|
key={`email-theme-${idx}`}
|
||||||
|
value={item}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</Select>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:algorithm")}
|
||||||
|
fieldId="kc-algorithm"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:algorithm"
|
||||||
|
forLabel={t("algorithm")}
|
||||||
|
forID="kc-algorithm"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="config.algorithm"
|
||||||
|
control={control}
|
||||||
|
defaultValue={["HS-256"]}
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<Select
|
||||||
|
toggleId="kc-elliptic"
|
||||||
|
onToggle={() =>
|
||||||
|
setIsEllipticCurveDropdownOpen(
|
||||||
|
!isEllipticCurveDropdownOpen
|
||||||
|
)
|
||||||
|
}
|
||||||
|
onSelect={(_, value) => {
|
||||||
|
onChange([value + ""]);
|
||||||
|
setIsEllipticCurveDropdownOpen(false);
|
||||||
|
}}
|
||||||
|
selections={[value + ""]}
|
||||||
|
variant={SelectVariant.single}
|
||||||
|
aria-label={t("emailTheme")}
|
||||||
|
isOpen={isEllipticCurveDropdownOpen}
|
||||||
|
placeholderText="Select one..."
|
||||||
|
data-testid="select-email-theme"
|
||||||
|
>
|
||||||
|
{allComponentTypes[2].properties[4].options!.map(
|
||||||
|
(p, idx) => (
|
||||||
|
<SelectOption
|
||||||
|
selected={p === value}
|
||||||
|
key={`email-theme-${idx}`}
|
||||||
|
value={p}
|
||||||
|
></SelectOption>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</Select>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
366
src/realm-settings/JavaKeystoreModal.tsx
Normal file
366
src/realm-settings/JavaKeystoreModal.tsx
Normal file
|
@ -0,0 +1,366 @@
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import {
|
||||||
|
AlertVariant,
|
||||||
|
Button,
|
||||||
|
ButtonVariant,
|
||||||
|
Form,
|
||||||
|
FormGroup,
|
||||||
|
Modal,
|
||||||
|
ModalVariant,
|
||||||
|
Select,
|
||||||
|
SelectOption,
|
||||||
|
SelectVariant,
|
||||||
|
Switch,
|
||||||
|
TextInput,
|
||||||
|
} from "@patternfly/react-core";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { Controller, useForm } from "react-hook-form";
|
||||||
|
|
||||||
|
import { useAdminClient } from "../context/auth/AdminClient";
|
||||||
|
import { useAlerts } from "../components/alert/Alerts";
|
||||||
|
import type ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
|
||||||
|
import { HelpItem } from "../components/help-enabler/HelpItem";
|
||||||
|
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
|
||||||
|
import { useRealm } from "../context/realm-context/RealmContext";
|
||||||
|
|
||||||
|
type JavaKeystoreModalProps = {
|
||||||
|
providerType?: string;
|
||||||
|
handleModalToggle?: () => void;
|
||||||
|
refresh?: () => void;
|
||||||
|
open: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const JavaKeystoreModal = ({
|
||||||
|
providerType,
|
||||||
|
handleModalToggle,
|
||||||
|
open,
|
||||||
|
refresh,
|
||||||
|
}: // save,
|
||||||
|
JavaKeystoreModalProps) => {
|
||||||
|
const { t } = useTranslation("groups");
|
||||||
|
const serverInfo = useServerInfo();
|
||||||
|
const adminClient = useAdminClient();
|
||||||
|
const { addAlert } = useAlerts();
|
||||||
|
const { handleSubmit, control } = useForm({});
|
||||||
|
const [
|
||||||
|
isEllipticCurveDropdownOpen,
|
||||||
|
setIsEllipticCurveDropdownOpen,
|
||||||
|
] = useState(false);
|
||||||
|
const [displayName, setDisplayName] = useState("");
|
||||||
|
const realm = useRealm();
|
||||||
|
|
||||||
|
const allComponentTypes = serverInfo.componentTypes![
|
||||||
|
"org.keycloak.keys.KeyProvider"
|
||||||
|
];
|
||||||
|
|
||||||
|
const save = async (component: ComponentRepresentation) => {
|
||||||
|
try {
|
||||||
|
await adminClient.components.create({
|
||||||
|
parentId: realm.realm,
|
||||||
|
name: displayName !== "" ? displayName : providerType,
|
||||||
|
providerId: providerType,
|
||||||
|
providerType: "org.keycloak.keys.KeyProvider",
|
||||||
|
...component,
|
||||||
|
});
|
||||||
|
refresh!();
|
||||||
|
addAlert(t("realm-settings:saveProviderSuccess"), AlertVariant.success);
|
||||||
|
handleModalToggle!();
|
||||||
|
} catch (error) {
|
||||||
|
addAlert(
|
||||||
|
t("realm-settings:saveProviderError") +
|
||||||
|
error.response?.data?.errorMessage || error,
|
||||||
|
AlertVariant.danger
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
className="add-provider-modal"
|
||||||
|
variant={ModalVariant.medium}
|
||||||
|
title={t("realm-settings:addProvider")}
|
||||||
|
isOpen={open}
|
||||||
|
onClose={handleModalToggle}
|
||||||
|
actions={[
|
||||||
|
<Button
|
||||||
|
data-testid="add-provider-button"
|
||||||
|
key="confirm"
|
||||||
|
variant="primary"
|
||||||
|
type="submit"
|
||||||
|
form="add-provider"
|
||||||
|
>
|
||||||
|
{t("common:Add")}
|
||||||
|
</Button>,
|
||||||
|
<Button
|
||||||
|
id="modal-cancel"
|
||||||
|
key="cancel"
|
||||||
|
variant={ButtonVariant.link}
|
||||||
|
onClick={() => {
|
||||||
|
handleModalToggle!();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("common:cancel")}
|
||||||
|
</Button>,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Form
|
||||||
|
isHorizontal
|
||||||
|
id="add-provider"
|
||||||
|
className="pf-u-mt-lg"
|
||||||
|
onSubmit={handleSubmit(save!)}
|
||||||
|
>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:consoleDisplayName")}
|
||||||
|
fieldId="kc-console-display-name"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:displayName"
|
||||||
|
forLabel={t("loginTheme")}
|
||||||
|
forID="kc-console-display-name"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="name"
|
||||||
|
control={control}
|
||||||
|
defaultValue={providerType}
|
||||||
|
render={({ onChange }) => (
|
||||||
|
<TextInput
|
||||||
|
aria-label={t("consoleDisplayName")}
|
||||||
|
defaultValue={providerType}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange(value);
|
||||||
|
setDisplayName(value);
|
||||||
|
}}
|
||||||
|
data-testid="display-name-input"
|
||||||
|
></TextInput>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("common:enabled")}
|
||||||
|
fieldId="kc-enabled"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText={t("realm-settings-help:enabled")}
|
||||||
|
forLabel={t("enabled")}
|
||||||
|
forID="kc-enabled"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="config.enabled"
|
||||||
|
control={control}
|
||||||
|
defaultValue={["true"]}
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<Switch
|
||||||
|
id="kc-enabled"
|
||||||
|
label={t("common:on")}
|
||||||
|
labelOff={t("common:off")}
|
||||||
|
isChecked={value[0] === "true"}
|
||||||
|
data-testid={
|
||||||
|
value[0] === "true"
|
||||||
|
? "internationalization-enabled"
|
||||||
|
: "internationalization-disabled"
|
||||||
|
}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange([value + ""]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:active")}
|
||||||
|
fieldId="kc-active"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:active"
|
||||||
|
forLabel={t("active")}
|
||||||
|
forID="kc-active"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="config.active"
|
||||||
|
control={control}
|
||||||
|
defaultValue={["true"]}
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<Switch
|
||||||
|
id="kc-active"
|
||||||
|
label={t("common:on")}
|
||||||
|
labelOff={t("common:off")}
|
||||||
|
isChecked={value[0] === "true"}
|
||||||
|
data-testid={
|
||||||
|
value[0] === "true"
|
||||||
|
? "internationalization-enabled"
|
||||||
|
: "internationalization-disabled"
|
||||||
|
}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange([value + ""]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
{providerType === "java-keystore" && (
|
||||||
|
<>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:algorithm")}
|
||||||
|
fieldId="kc-algorithm"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:algorithm"
|
||||||
|
forLabel={t("algorithm")}
|
||||||
|
forID="kc-email-theme"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="config.algorithm"
|
||||||
|
control={control}
|
||||||
|
defaultValue={["RS256"]}
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<Select
|
||||||
|
toggleId="kc-elliptic"
|
||||||
|
onToggle={() =>
|
||||||
|
setIsEllipticCurveDropdownOpen(
|
||||||
|
!isEllipticCurveDropdownOpen
|
||||||
|
)
|
||||||
|
}
|
||||||
|
onSelect={(_, value) => {
|
||||||
|
onChange([value + ""]);
|
||||||
|
setIsEllipticCurveDropdownOpen(false);
|
||||||
|
}}
|
||||||
|
selections={[value + ""]}
|
||||||
|
variant={SelectVariant.single}
|
||||||
|
aria-label={t("algorithm")}
|
||||||
|
isOpen={isEllipticCurveDropdownOpen}
|
||||||
|
placeholderText="Select one..."
|
||||||
|
data-testid="select-algorithm"
|
||||||
|
>
|
||||||
|
{allComponentTypes[3].properties[3].options!.map(
|
||||||
|
(p, idx) => (
|
||||||
|
<SelectOption
|
||||||
|
selected={p === value}
|
||||||
|
key={`algorithm-${idx}`}
|
||||||
|
value={p}
|
||||||
|
></SelectOption>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</Select>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:keystore")}
|
||||||
|
fieldId="kc-login-theme"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:keystore"
|
||||||
|
forLabel={t("keystore")}
|
||||||
|
forID="kc-keystore"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="config.keystore"
|
||||||
|
control={control}
|
||||||
|
defaultValue={[]}
|
||||||
|
render={({ onChange }) => (
|
||||||
|
<TextInput
|
||||||
|
aria-label={t("keystore")}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange([value + ""]);
|
||||||
|
}}
|
||||||
|
data-testid="select-display-name"
|
||||||
|
></TextInput>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:keystorePassword")}
|
||||||
|
fieldId="kc-login-theme"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:keystorePassword"
|
||||||
|
forLabel={t("keystorePassword")}
|
||||||
|
forID="kc-keystore-password"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="config.keystorePassword"
|
||||||
|
control={control}
|
||||||
|
defaultValue={[]}
|
||||||
|
render={({ onChange }) => (
|
||||||
|
<TextInput
|
||||||
|
aria-label={t("consoleDisplayName")}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange([value + ""]);
|
||||||
|
setDisplayName(value);
|
||||||
|
}}
|
||||||
|
data-testid="select-display-name"
|
||||||
|
></TextInput>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:keyAlias")}
|
||||||
|
fieldId="kc-login-theme"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:keyAlias"
|
||||||
|
forLabel={t("keyAlias")}
|
||||||
|
forID="kc-key-alias"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="config.keyAlias"
|
||||||
|
control={control}
|
||||||
|
defaultValue={[]}
|
||||||
|
render={({ onChange }) => (
|
||||||
|
<TextInput
|
||||||
|
aria-label={t("consoleDisplayName")}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange([value + ""]);
|
||||||
|
}}
|
||||||
|
data-testid="select-display-name"
|
||||||
|
></TextInput>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:keyPassword")}
|
||||||
|
fieldId="kc-login-theme"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:keyPassword"
|
||||||
|
forLabel={t("keyPassword")}
|
||||||
|
forID="kc-key-password"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="config.keyPassword"
|
||||||
|
control={control}
|
||||||
|
defaultValue={[]}
|
||||||
|
render={({ onChange }) => (
|
||||||
|
<TextInput
|
||||||
|
aria-label={t("consoleDisplayName")}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange([value + ""]);
|
||||||
|
setDisplayName(value);
|
||||||
|
}}
|
||||||
|
data-testid="select-display-name"
|
||||||
|
></TextInput>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
|
@ -11,6 +11,7 @@ import {
|
||||||
DataListItemCells,
|
DataListItemCells,
|
||||||
DataListItemRow,
|
DataListItemRow,
|
||||||
Dropdown,
|
Dropdown,
|
||||||
|
DropdownItem,
|
||||||
DropdownToggle,
|
DropdownToggle,
|
||||||
InputGroup,
|
InputGroup,
|
||||||
PageSection,
|
PageSection,
|
||||||
|
@ -26,6 +27,13 @@ import type ComponentRepresentation from "keycloak-admin/lib/defs/componentRepre
|
||||||
import type ComponentTypeRepresentation from "keycloak-admin/lib/defs/componentTypeRepresentation";
|
import type ComponentTypeRepresentation from "keycloak-admin/lib/defs/componentTypeRepresentation";
|
||||||
|
|
||||||
import "./RealmSettingsSection.css";
|
import "./RealmSettingsSection.css";
|
||||||
|
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
|
||||||
|
import { AESGeneratedModal } from "./AESGeneratedModal";
|
||||||
|
import { ECDSAGeneratedModal } from "./ECDSAGeneratedModal";
|
||||||
|
import { HMACGeneratedModal } from "./HMACGeneratedModal";
|
||||||
|
import { JavaKeystoreModal } from "./JavaKeystoreModal";
|
||||||
|
import { RSAModal } from "./RSAModal";
|
||||||
|
import { RSAGeneratedModal } from "./RSAGeneratedModal";
|
||||||
|
|
||||||
type ComponentData = KeyMetadataRepresentation & {
|
type ComponentData = KeyMetadataRepresentation & {
|
||||||
providerDescription?: string;
|
providerDescription?: string;
|
||||||
|
@ -34,9 +42,12 @@ type ComponentData = KeyMetadataRepresentation & {
|
||||||
|
|
||||||
type KeysTabInnerProps = {
|
type KeysTabInnerProps = {
|
||||||
components: ComponentData[];
|
components: ComponentData[];
|
||||||
|
realmComponents: ComponentRepresentation[];
|
||||||
|
keyProviderComponentTypes: ComponentTypeRepresentation[];
|
||||||
|
refresh: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const KeysTabInner = ({ components }: KeysTabInnerProps) => {
|
export const KeysTabInner = ({ components, refresh }: KeysTabInnerProps) => {
|
||||||
const { t } = useTranslation("roles");
|
const { t } = useTranslation("roles");
|
||||||
|
|
||||||
const [id, setId] = useState("");
|
const [id, setId] = useState("");
|
||||||
|
@ -44,10 +55,21 @@ export const KeysTabInner = ({ components }: KeysTabInnerProps) => {
|
||||||
const [filteredComponents, setFilteredComponents] = useState<ComponentData[]>(
|
const [filteredComponents, setFilteredComponents] = useState<ComponentData[]>(
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
|
||||||
|
|
||||||
|
const serverInfo = useServerInfo();
|
||||||
|
const providerTypes = serverInfo.componentTypes![
|
||||||
|
"org.keycloak.keys.KeyProvider"
|
||||||
|
].map((item) => item.id);
|
||||||
|
|
||||||
const itemIds = components.map((_, idx) => "data" + idx);
|
const itemIds = components.map((_, idx) => "data" + idx);
|
||||||
|
|
||||||
const [itemOrder, setItemOrder] = useState<string[]>([]);
|
const [itemOrder, setItemOrder] = useState<string[]>([]);
|
||||||
|
const [providerDropdownOpen, setProviderDropdownOpen] = useState(false);
|
||||||
|
|
||||||
|
const [defaultConsoleDisplayName, setDefaultConsoleDisplayName] = useState(
|
||||||
|
""
|
||||||
|
);
|
||||||
|
|
||||||
const [liveText, setLiveText] = useState("");
|
const [liveText, setLiveText] = useState("");
|
||||||
|
|
||||||
|
@ -96,8 +118,68 @@ export const KeysTabInner = ({ components }: KeysTabInnerProps) => {
|
||||||
setSearchVal(value);
|
setSearchVal(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleModalToggle = () => {
|
||||||
|
setIsCreateModalOpen(!isCreateModalOpen);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
{defaultConsoleDisplayName === "aes-generated" && (
|
||||||
|
<AESGeneratedModal
|
||||||
|
handleModalToggle={handleModalToggle}
|
||||||
|
providerType={defaultConsoleDisplayName}
|
||||||
|
refresh={refresh}
|
||||||
|
open={isCreateModalOpen}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{defaultConsoleDisplayName === "ecdsa-generated" && (
|
||||||
|
<ECDSAGeneratedModal
|
||||||
|
handleModalToggle={handleModalToggle}
|
||||||
|
providerType={defaultConsoleDisplayName}
|
||||||
|
refresh={refresh}
|
||||||
|
open={isCreateModalOpen}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{/* {defaultConsoleDisplayName === "ecdsa-generated" && (
|
||||||
|
<ECDSAGeneratedModal
|
||||||
|
handleModalToggle={handleModalToggle}
|
||||||
|
providerType={defaultConsoleDisplayName}
|
||||||
|
refresh={refresh}
|
||||||
|
open={isCreateModalOpen}
|
||||||
|
/>
|
||||||
|
)} */}
|
||||||
|
{defaultConsoleDisplayName === "hmac-generated" && (
|
||||||
|
<HMACGeneratedModal
|
||||||
|
handleModalToggle={handleModalToggle}
|
||||||
|
providerType={defaultConsoleDisplayName}
|
||||||
|
refresh={refresh}
|
||||||
|
open={isCreateModalOpen}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{defaultConsoleDisplayName === "java-keystore" && (
|
||||||
|
<JavaKeystoreModal
|
||||||
|
handleModalToggle={handleModalToggle}
|
||||||
|
providerType={defaultConsoleDisplayName}
|
||||||
|
refresh={refresh}
|
||||||
|
open={isCreateModalOpen}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{defaultConsoleDisplayName === "rsa" && (
|
||||||
|
<RSAModal
|
||||||
|
handleModalToggle={handleModalToggle}
|
||||||
|
providerType={defaultConsoleDisplayName}
|
||||||
|
refresh={refresh}
|
||||||
|
open={isCreateModalOpen}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{defaultConsoleDisplayName === "rsa-generated" && (
|
||||||
|
<RSAGeneratedModal
|
||||||
|
handleModalToggle={handleModalToggle}
|
||||||
|
providerType={defaultConsoleDisplayName}
|
||||||
|
refresh={refresh}
|
||||||
|
open={isCreateModalOpen}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<PageSection variant="light" padding={{ default: "noPadding" }}>
|
<PageSection variant="light" padding={{ default: "noPadding" }}>
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<>
|
<>
|
||||||
|
@ -125,12 +207,31 @@ export const KeysTabInner = ({ components }: KeysTabInnerProps) => {
|
||||||
<Dropdown
|
<Dropdown
|
||||||
data-testid="addProviderDropdown"
|
data-testid="addProviderDropdown"
|
||||||
className="add-provider-dropdown"
|
className="add-provider-dropdown"
|
||||||
onSelect={() => {}}
|
isOpen={providerDropdownOpen}
|
||||||
toggle={
|
toggle={
|
||||||
<DropdownToggle isPrimary>
|
<DropdownToggle
|
||||||
|
onToggle={(val) => setProviderDropdownOpen(val)}
|
||||||
|
isPrimary
|
||||||
|
>
|
||||||
{t("realm-settings:addProvider")}
|
{t("realm-settings:addProvider")}
|
||||||
</DropdownToggle>
|
</DropdownToggle>
|
||||||
}
|
}
|
||||||
|
dropdownItems={[
|
||||||
|
providerTypes.map((item) => (
|
||||||
|
<DropdownItem
|
||||||
|
onClick={() => {
|
||||||
|
handleModalToggle();
|
||||||
|
|
||||||
|
setProviderDropdownOpen(false);
|
||||||
|
setDefaultConsoleDisplayName(item);
|
||||||
|
}}
|
||||||
|
data-testid={`option-${item}`}
|
||||||
|
key={item}
|
||||||
|
>
|
||||||
|
{item}
|
||||||
|
</DropdownItem>
|
||||||
|
)),
|
||||||
|
]}
|
||||||
/>
|
/>
|
||||||
</ToolbarItem>
|
</ToolbarItem>
|
||||||
</ToolbarGroup>
|
</ToolbarGroup>
|
||||||
|
@ -222,11 +323,13 @@ export const KeysTabInner = ({ components }: KeysTabInnerProps) => {
|
||||||
type KeysProps = {
|
type KeysProps = {
|
||||||
components: ComponentRepresentation[];
|
components: ComponentRepresentation[];
|
||||||
keyProviderComponentTypes: ComponentTypeRepresentation[];
|
keyProviderComponentTypes: ComponentTypeRepresentation[];
|
||||||
|
refresh: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const KeysProviderTab = ({
|
export const KeysProviderTab = ({
|
||||||
components,
|
components,
|
||||||
keyProviderComponentTypes,
|
keyProviderComponentTypes,
|
||||||
|
refresh,
|
||||||
...props
|
...props
|
||||||
}: KeysProps) => {
|
}: KeysProps) => {
|
||||||
return (
|
return (
|
||||||
|
@ -238,6 +341,9 @@ export const KeysProviderTab = ({
|
||||||
);
|
);
|
||||||
return { ...component, providerDescription: provider?.helpText };
|
return { ...component, providerDescription: provider?.helpText };
|
||||||
})}
|
})}
|
||||||
|
keyProviderComponentTypes={keyProviderComponentTypes}
|
||||||
|
refresh={refresh}
|
||||||
|
realmComponents={components}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
297
src/realm-settings/RSAGeneratedModal.tsx
Normal file
297
src/realm-settings/RSAGeneratedModal.tsx
Normal file
|
@ -0,0 +1,297 @@
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import {
|
||||||
|
AlertVariant,
|
||||||
|
Button,
|
||||||
|
ButtonVariant,
|
||||||
|
Form,
|
||||||
|
FormGroup,
|
||||||
|
Modal,
|
||||||
|
ModalVariant,
|
||||||
|
Select,
|
||||||
|
SelectOption,
|
||||||
|
SelectVariant,
|
||||||
|
Switch,
|
||||||
|
TextInput,
|
||||||
|
} from "@patternfly/react-core";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { Controller, useForm } from "react-hook-form";
|
||||||
|
|
||||||
|
import { useAdminClient } from "../context/auth/AdminClient";
|
||||||
|
import { useAlerts } from "../components/alert/Alerts";
|
||||||
|
import type ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
|
||||||
|
import { HelpItem } from "../components/help-enabler/HelpItem";
|
||||||
|
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
|
||||||
|
import { useRealm } from "../context/realm-context/RealmContext";
|
||||||
|
|
||||||
|
type RSAGeneratedModalProps = {
|
||||||
|
providerType?: string;
|
||||||
|
handleModalToggle?: () => void;
|
||||||
|
refresh?: () => void;
|
||||||
|
open: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RSAGeneratedModal = ({
|
||||||
|
providerType,
|
||||||
|
handleModalToggle,
|
||||||
|
open,
|
||||||
|
refresh,
|
||||||
|
}: RSAGeneratedModalProps) => {
|
||||||
|
const { t } = useTranslation("groups");
|
||||||
|
const serverInfo = useServerInfo();
|
||||||
|
const adminClient = useAdminClient();
|
||||||
|
const { addAlert } = useAlerts();
|
||||||
|
const { handleSubmit, control } = useForm({});
|
||||||
|
const [isKeySizeDropdownOpen, setIsKeySizeDropdownOpen] = useState(false);
|
||||||
|
const [isRSAalgDropdownOpen, setIsRSAalgDropdownOpen] = useState(false);
|
||||||
|
const [displayName, setDisplayName] = useState("");
|
||||||
|
const realm = useRealm();
|
||||||
|
|
||||||
|
const allComponentTypes = serverInfo.componentTypes![
|
||||||
|
"org.keycloak.keys.KeyProvider"
|
||||||
|
];
|
||||||
|
|
||||||
|
const save = async (component: ComponentRepresentation) => {
|
||||||
|
try {
|
||||||
|
await adminClient.components.create({
|
||||||
|
parentId: realm.realm,
|
||||||
|
name: displayName !== "" ? displayName : providerType,
|
||||||
|
providerId: providerType,
|
||||||
|
providerType: "org.keycloak.keys.KeyProvider",
|
||||||
|
...component,
|
||||||
|
});
|
||||||
|
refresh!();
|
||||||
|
addAlert(t("realm-settings:saveProviderSuccess"), AlertVariant.success);
|
||||||
|
handleModalToggle!();
|
||||||
|
} catch (error) {
|
||||||
|
addAlert(
|
||||||
|
t("realm-settings:saveProviderError") +
|
||||||
|
error.response?.data?.errorMessage || error,
|
||||||
|
AlertVariant.danger
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
className="add-provider-modal"
|
||||||
|
variant={ModalVariant.medium}
|
||||||
|
title={t("realm-settings:addProvider")}
|
||||||
|
isOpen={open}
|
||||||
|
onClose={handleModalToggle}
|
||||||
|
actions={[
|
||||||
|
<Button
|
||||||
|
data-testid="add-provider-button"
|
||||||
|
key="confirm"
|
||||||
|
variant="primary"
|
||||||
|
type="submit"
|
||||||
|
form="add-provider"
|
||||||
|
>
|
||||||
|
{t("common:Add")}
|
||||||
|
</Button>,
|
||||||
|
<Button
|
||||||
|
id="modal-cancel"
|
||||||
|
key="cancel"
|
||||||
|
variant={ButtonVariant.link}
|
||||||
|
onClick={() => {
|
||||||
|
handleModalToggle!();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("common:cancel")}
|
||||||
|
</Button>,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Form
|
||||||
|
isHorizontal
|
||||||
|
id="add-provider"
|
||||||
|
className="pf-u-mt-lg"
|
||||||
|
onSubmit={handleSubmit(save!)}
|
||||||
|
>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:consoleDisplayName")}
|
||||||
|
fieldId="kc-console-display-name"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:displayName"
|
||||||
|
forLabel={t("loginTheme")}
|
||||||
|
forID="kc-console-display-name"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="name"
|
||||||
|
control={control}
|
||||||
|
defaultValue={providerType}
|
||||||
|
render={({ onChange }) => (
|
||||||
|
<TextInput
|
||||||
|
aria-label={t("consoleDisplayName")}
|
||||||
|
defaultValue={providerType}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange(value);
|
||||||
|
setDisplayName(value);
|
||||||
|
}}
|
||||||
|
data-testid="display-name-input"
|
||||||
|
></TextInput>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("common:enabled")}
|
||||||
|
fieldId="kc-enabled"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText={t("realm-settings-help:enabled")}
|
||||||
|
forLabel={t("enabled")}
|
||||||
|
forID="kc-enabled"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="config.enabled"
|
||||||
|
control={control}
|
||||||
|
defaultValue={["true"]}
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<Switch
|
||||||
|
id="kc-enabled"
|
||||||
|
label={t("common:on")}
|
||||||
|
labelOff={t("common:off")}
|
||||||
|
isChecked={value[0] === "true"}
|
||||||
|
data-testid={
|
||||||
|
value[0] === "true"
|
||||||
|
? "internationalization-enabled"
|
||||||
|
: "internationalization-disabled"
|
||||||
|
}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange([value + ""]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:active")}
|
||||||
|
fieldId="kc-active"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:active"
|
||||||
|
forLabel={t("active")}
|
||||||
|
forID="kc-active"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="config.active"
|
||||||
|
control={control}
|
||||||
|
defaultValue={["true"]}
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<Switch
|
||||||
|
id="kc-active"
|
||||||
|
label={t("common:on")}
|
||||||
|
labelOff={t("common:off")}
|
||||||
|
isChecked={value[0] === "true"}
|
||||||
|
data-testid={
|
||||||
|
value[0] === "true"
|
||||||
|
? "internationalization-enabled"
|
||||||
|
: "internationalization-disabled"
|
||||||
|
}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange([value + ""]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
{providerType === "rsa-generated" && (
|
||||||
|
<>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:algorithm")}
|
||||||
|
fieldId="kc-algorithm"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:algorithm"
|
||||||
|
forLabel={t("algorithm")}
|
||||||
|
forID="kc-algorithm"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="algorithm"
|
||||||
|
defaultValue=""
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<Select
|
||||||
|
toggleId="kc-rsa-algorithm"
|
||||||
|
onToggle={() =>
|
||||||
|
setIsRSAalgDropdownOpen(!isRSAalgDropdownOpen)
|
||||||
|
}
|
||||||
|
onSelect={(_, value) => {
|
||||||
|
onChange(value as string);
|
||||||
|
setIsRSAalgDropdownOpen(false);
|
||||||
|
}}
|
||||||
|
selections={[value + ""]}
|
||||||
|
variant={SelectVariant.single}
|
||||||
|
aria-label={t("algorithm")}
|
||||||
|
isOpen={isRSAalgDropdownOpen}
|
||||||
|
data-testid="select-rsa-algorithm"
|
||||||
|
>
|
||||||
|
{allComponentTypes[5].properties[3].options!.map(
|
||||||
|
(p, idx) => (
|
||||||
|
<SelectOption
|
||||||
|
selected={p === value}
|
||||||
|
key={`rsa-algorithm-${idx}`}
|
||||||
|
value={p}
|
||||||
|
></SelectOption>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</Select>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:AESKeySize")}
|
||||||
|
fieldId="kc-aes-keysize"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:AESKeySize"
|
||||||
|
forLabel={t("AESKeySize")}
|
||||||
|
forID="kc-aes-key-size"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="config.secretSize"
|
||||||
|
control={control}
|
||||||
|
defaultValue={["2048"]}
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<Select
|
||||||
|
toggleId="kc-rsa-keysize"
|
||||||
|
onToggle={() =>
|
||||||
|
setIsKeySizeDropdownOpen(!isKeySizeDropdownOpen)
|
||||||
|
}
|
||||||
|
onSelect={(_, value) => {
|
||||||
|
onChange([value + ""]);
|
||||||
|
setIsKeySizeDropdownOpen(false);
|
||||||
|
}}
|
||||||
|
selections={[value + ""]}
|
||||||
|
isOpen={isKeySizeDropdownOpen}
|
||||||
|
variant={SelectVariant.single}
|
||||||
|
aria-label={t("keySize")}
|
||||||
|
data-testid="select-secret-size"
|
||||||
|
>
|
||||||
|
{allComponentTypes[5].properties[4].options!.map(
|
||||||
|
(item, idx) => (
|
||||||
|
<SelectOption
|
||||||
|
selected={item === value}
|
||||||
|
key={`rsa-generated-key-size-${idx}`}
|
||||||
|
value={item}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</Select>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
317
src/realm-settings/RSAModal.tsx
Normal file
317
src/realm-settings/RSAModal.tsx
Normal file
|
@ -0,0 +1,317 @@
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import {
|
||||||
|
AlertVariant,
|
||||||
|
Button,
|
||||||
|
ButtonVariant,
|
||||||
|
FileUpload,
|
||||||
|
Form,
|
||||||
|
FormGroup,
|
||||||
|
Modal,
|
||||||
|
ModalVariant,
|
||||||
|
Select,
|
||||||
|
SelectOption,
|
||||||
|
SelectVariant,
|
||||||
|
Switch,
|
||||||
|
TextInput,
|
||||||
|
} from "@patternfly/react-core";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { Controller, useForm } from "react-hook-form";
|
||||||
|
|
||||||
|
import { useAdminClient } from "../context/auth/AdminClient";
|
||||||
|
import { useAlerts } from "../components/alert/Alerts";
|
||||||
|
import type ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
|
||||||
|
import { HelpItem } from "../components/help-enabler/HelpItem";
|
||||||
|
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
|
||||||
|
import { useRealm } from "../context/realm-context/RealmContext";
|
||||||
|
|
||||||
|
type RSAModalProps = {
|
||||||
|
providerType?: string;
|
||||||
|
handleModalToggle?: () => void;
|
||||||
|
refresh?: () => void;
|
||||||
|
open: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RSAModal = ({
|
||||||
|
providerType,
|
||||||
|
handleModalToggle,
|
||||||
|
open,
|
||||||
|
refresh,
|
||||||
|
}: // save,
|
||||||
|
RSAModalProps) => {
|
||||||
|
const { t } = useTranslation("groups");
|
||||||
|
const serverInfo = useServerInfo();
|
||||||
|
const adminClient = useAdminClient();
|
||||||
|
const { addAlert } = useAlerts();
|
||||||
|
const { handleSubmit, control } = useForm({});
|
||||||
|
const [isRSAalgDropdownOpen, setIsRSAalgDropdownOpen] = useState(false);
|
||||||
|
const [displayName, setDisplayName] = useState("");
|
||||||
|
const realm = useRealm();
|
||||||
|
|
||||||
|
const [keyFileName, setKeyFileName] = useState("");
|
||||||
|
const [certificateFileName, setCertificateFileName] = useState("");
|
||||||
|
|
||||||
|
const allComponentTypes = serverInfo.componentTypes![
|
||||||
|
"org.keycloak.keys.KeyProvider"
|
||||||
|
];
|
||||||
|
|
||||||
|
const save = async (component: ComponentRepresentation) => {
|
||||||
|
try {
|
||||||
|
await adminClient.components.create({
|
||||||
|
parentId: realm.realm,
|
||||||
|
name: displayName !== "" ? displayName : providerType,
|
||||||
|
providerId: providerType,
|
||||||
|
providerType: "org.keycloak.keys.KeyProvider",
|
||||||
|
...component,
|
||||||
|
});
|
||||||
|
refresh!();
|
||||||
|
addAlert(t("realm-settings:saveProviderSuccess"), AlertVariant.success);
|
||||||
|
handleModalToggle!();
|
||||||
|
} catch (error) {
|
||||||
|
addAlert(
|
||||||
|
t("realm-settings:saveProviderError") +
|
||||||
|
error.response?.data?.errorMessage || error,
|
||||||
|
AlertVariant.danger
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
className="add-provider-modal"
|
||||||
|
variant={ModalVariant.medium}
|
||||||
|
title={t("realm-settings:addProvider")}
|
||||||
|
isOpen={open}
|
||||||
|
onClose={handleModalToggle}
|
||||||
|
actions={[
|
||||||
|
<Button
|
||||||
|
data-testid="add-provider-button"
|
||||||
|
key="confirm"
|
||||||
|
variant="primary"
|
||||||
|
type="submit"
|
||||||
|
form="add-provider"
|
||||||
|
>
|
||||||
|
{t("common:Add")}
|
||||||
|
</Button>,
|
||||||
|
<Button
|
||||||
|
id="modal-cancel"
|
||||||
|
key="cancel"
|
||||||
|
variant={ButtonVariant.link}
|
||||||
|
onClick={() => {
|
||||||
|
handleModalToggle!();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("common:cancel")}
|
||||||
|
</Button>,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Form
|
||||||
|
isHorizontal
|
||||||
|
id="add-provider"
|
||||||
|
className="pf-u-mt-lg"
|
||||||
|
onSubmit={handleSubmit(save!)}
|
||||||
|
>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:consoleDisplayName")}
|
||||||
|
fieldId="kc-console-display-name"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:displayName"
|
||||||
|
forLabel={t("loginTheme")}
|
||||||
|
forID="kc-console-display-name"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="name"
|
||||||
|
control={control}
|
||||||
|
defaultValue={providerType}
|
||||||
|
render={({ onChange }) => (
|
||||||
|
<TextInput
|
||||||
|
aria-label={t("consoleDisplayName")}
|
||||||
|
defaultValue={providerType}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange(value);
|
||||||
|
setDisplayName(value);
|
||||||
|
}}
|
||||||
|
data-testid="display-name-input"
|
||||||
|
></TextInput>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("common:enabled")}
|
||||||
|
fieldId="kc-enabled"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText={t("realm-settings-help:enabled")}
|
||||||
|
forLabel={t("enabled")}
|
||||||
|
forID="kc-enabled"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="config.enabled"
|
||||||
|
control={control}
|
||||||
|
defaultValue={["true"]}
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<Switch
|
||||||
|
id="kc-enabled"
|
||||||
|
label={t("common:on")}
|
||||||
|
labelOff={t("common:off")}
|
||||||
|
isChecked={value[0] === "true"}
|
||||||
|
data-testid={
|
||||||
|
value[0] === "true"
|
||||||
|
? "internationalization-enabled"
|
||||||
|
: "internationalization-disabled"
|
||||||
|
}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange([value + ""]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:active")}
|
||||||
|
fieldId="kc-active"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:active"
|
||||||
|
forLabel={t("active")}
|
||||||
|
forID="kc-active"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="config.active"
|
||||||
|
control={control}
|
||||||
|
defaultValue={["true"]}
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<Switch
|
||||||
|
id="kc-active"
|
||||||
|
label={t("common:on")}
|
||||||
|
labelOff={t("common:off")}
|
||||||
|
isChecked={value[0] === "true"}
|
||||||
|
data-testid={
|
||||||
|
value[0] === "true"
|
||||||
|
? "internationalization-enabled"
|
||||||
|
: "internationalization-disabled"
|
||||||
|
}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange([value + ""]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
{providerType === "rsa" && (
|
||||||
|
<>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:algorithm")}
|
||||||
|
fieldId="kc-algorithm"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:algorithm"
|
||||||
|
forLabel={t("algorithm")}
|
||||||
|
forID="kc-algorithm"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="algorithm"
|
||||||
|
defaultValue=""
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<Select
|
||||||
|
toggleId="kc-rsa-algorithm"
|
||||||
|
onToggle={() =>
|
||||||
|
setIsRSAalgDropdownOpen(!isRSAalgDropdownOpen)
|
||||||
|
}
|
||||||
|
onSelect={(_, value) => {
|
||||||
|
onChange(value as string);
|
||||||
|
setIsRSAalgDropdownOpen(false);
|
||||||
|
}}
|
||||||
|
selections={[value + ""]}
|
||||||
|
variant={SelectVariant.single}
|
||||||
|
aria-label={t("algorithm")}
|
||||||
|
isOpen={isRSAalgDropdownOpen}
|
||||||
|
data-testid="select-rsa-algorithm"
|
||||||
|
>
|
||||||
|
{allComponentTypes[4].properties[3].options!.map(
|
||||||
|
(p, idx) => (
|
||||||
|
<SelectOption
|
||||||
|
selected={p === value}
|
||||||
|
key={`rsa-algorithm-${idx}`}
|
||||||
|
value={p}
|
||||||
|
></SelectOption>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</Select>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:privateRSAKey")}
|
||||||
|
fieldId="kc-private-rsa-key"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:privateRSAKey"
|
||||||
|
forLabel={t("privateRSAKey")}
|
||||||
|
forID="kc-rsa-key"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="config.privateKey"
|
||||||
|
control={control}
|
||||||
|
defaultValue={[]}
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<FileUpload
|
||||||
|
id="importPrivateKey"
|
||||||
|
type="text"
|
||||||
|
value={value[0]}
|
||||||
|
filenamePlaceholder="Upload a PEM file or paste key below"
|
||||||
|
filename={keyFileName}
|
||||||
|
onChange={(value, fileName) => {
|
||||||
|
setKeyFileName(fileName);
|
||||||
|
onChange([value]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("realm-settings:x509Certificate")}
|
||||||
|
fieldId="kc-aes-keysize"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:x509Certificate"
|
||||||
|
forLabel={t("x509Certificate")}
|
||||||
|
forID="kc-x509-certificatw"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="config.certificate"
|
||||||
|
control={control}
|
||||||
|
defaultValue={[]}
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<FileUpload
|
||||||
|
id="importCertificate"
|
||||||
|
type="text"
|
||||||
|
value={value[0]}
|
||||||
|
filenamePlaceholder="Upload a PEM file or paste key below"
|
||||||
|
filename={certificateFileName}
|
||||||
|
onChange={(value, fileName) => {
|
||||||
|
setCertificateFileName(fileName);
|
||||||
|
onChange([value]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
|
@ -56,6 +56,10 @@ button.pf-c-data-list__item-draggable-button.row-drag-button {
|
||||||
margin-right: 0px;
|
margin-right: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pf-c-data-list__item-row.test {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
button.pf-c-button.pf-m-link.add-provider {
|
button.pf-c-button.pf-m-link.add-provider {
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
}
|
}
|
||||||
|
@ -68,3 +72,7 @@ button.pf-c-button.pf-m-link.add-provider {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.add-provider-modal > div.pf-c-modal-box__body {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
|
@ -130,6 +130,8 @@ export const RealmSettingsSection = () => {
|
||||||
const { control, getValues, setValue, reset: resetForm } = form;
|
const { control, getValues, setValue, reset: resetForm } = form;
|
||||||
const [realm, setRealm] = useState<RealmRepresentation>();
|
const [realm, setRealm] = useState<RealmRepresentation>();
|
||||||
const [activeTab, setActiveTab] = useState(0);
|
const [activeTab, setActiveTab] = useState(0);
|
||||||
|
const [key, setKey] = useState(0);
|
||||||
|
// const [keys, setKeys] = useState<KeyMetadataRepresentation[]>([]);
|
||||||
const [realmComponents, setRealmComponents] = useState<
|
const [realmComponents, setRealmComponents] = useState<
|
||||||
ComponentRepresentation[]
|
ComponentRepresentation[]
|
||||||
>();
|
>();
|
||||||
|
@ -155,6 +157,21 @@ export const RealmSettingsSection = () => {
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const refresh = () => {
|
||||||
|
setKey(new Date().getTime());
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const update = async () => {
|
||||||
|
const realmComponents = await adminClient.components.find({
|
||||||
|
type: "org.keycloak.keys.KeyProvider",
|
||||||
|
realm: realmName,
|
||||||
|
});
|
||||||
|
setRealmComponents(realmComponents);
|
||||||
|
};
|
||||||
|
setTimeout(update, 100);
|
||||||
|
}, [key]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (realm) setupForm(realm);
|
if (realm) setupForm(realm);
|
||||||
}, [realm]);
|
}, [realm]);
|
||||||
|
@ -240,18 +257,20 @@ export const RealmSettingsSection = () => {
|
||||||
onSelect={(_, key) => setActiveTab(key as number)}
|
onSelect={(_, key) => setActiveTab(key as number)}
|
||||||
>
|
>
|
||||||
<Tab
|
<Tab
|
||||||
id="setup"
|
id="keysList"
|
||||||
eventKey={0}
|
eventKey={0}
|
||||||
title={<TabTitleText>{t("keysList")}</TabTitleText>}
|
title={<TabTitleText>{t("keysList")}</TabTitleText>}
|
||||||
>
|
>
|
||||||
<KeysListTab realmComponents={realmComponents} />
|
<KeysListTab realmComponents={realmComponents} />
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
id="evaluate"
|
id="providers"
|
||||||
|
data-testid="rs-providers-tab"
|
||||||
eventKey={1}
|
eventKey={1}
|
||||||
title={<TabTitleText>{t("providers")}</TabTitleText>}
|
title={<TabTitleText>{t("providers")}</TabTitleText>}
|
||||||
>
|
>
|
||||||
<KeysProviderTab
|
<KeysProviderTab
|
||||||
|
refresh={refresh}
|
||||||
components={realmComponents}
|
components={realmComponents}
|
||||||
keyProviderComponentTypes={kpComponentTypes}
|
keyProviderComponentTypes={kpComponentTypes}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -11,6 +11,21 @@
|
||||||
"loginTheme": "Select theme for login, OTP, grant, registration and forgot password pages.",
|
"loginTheme": "Select theme for login, OTP, grant, registration and forgot password pages.",
|
||||||
"accountTheme": "Select theme for user account management pages.",
|
"accountTheme": "Select theme for user account management pages.",
|
||||||
"adminConsoleTheme": "Select theme for admin console.",
|
"adminConsoleTheme": "Select theme for admin console.",
|
||||||
"emailTheme": "Select theme for emails that are sent by the server."
|
"emailTheme": "Select theme for emails that are sent by the server.",
|
||||||
|
"displayName": "Display name of provider when linked in admin console",
|
||||||
|
"priority": "Priority of the provider",
|
||||||
|
"enabled": "Set if the keys are enabled",
|
||||||
|
"active": "Set if the keys can be used for signing",
|
||||||
|
"AESKeySize": "Size in bytes for the generated AES key. Size 16 is for AES-128, Size 24 for AES-192, and Size 32 for AES-256. WARN: Bigger keys than 128 are not allowed on some JDK implementations.",
|
||||||
|
"ellipticCurve": "Elliptic curve used in ECDSA",
|
||||||
|
"secretSize": "Size in bytes for the generated secret",
|
||||||
|
"algorithm": "Intended algorithm for the key",
|
||||||
|
"keystore": "Path to keys file",
|
||||||
|
"keystorePassword": "Password for the keys",
|
||||||
|
"keyAlias": "Alias for the private key",
|
||||||
|
"keyPassword": "Password for the private key",
|
||||||
|
"privateRSAKey": "Private RSA Key encoded in PEM format",
|
||||||
|
"x509Certificate": "X509 Certificate encoded in PEM format"
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
{
|
{
|
||||||
"realm-settings": {
|
"realm-settings": {
|
||||||
"partialImport": "Partial import",
|
"partialImport": "Partial import",
|
||||||
|
@ -10,6 +11,8 @@
|
||||||
"disableConfirmTitle": "Disable realm?",
|
"disableConfirmTitle": "Disable realm?",
|
||||||
"disableConfirm": "User and clients can't access the realm if it's disabled. Are you sure you want to continue?",
|
"disableConfirm": "User and clients can't access the realm if it's disabled. Are you sure you want to continue?",
|
||||||
"saveSuccess": "Realm successfully updated",
|
"saveSuccess": "Realm successfully updated",
|
||||||
|
"saveProviderSuccess": "The provider has been saved successfully.",
|
||||||
|
"saveProviderError": "Error saving provider: ",
|
||||||
"saveError": "Realm could not be updated: {error}",
|
"saveError": "Realm could not be updated: {error}",
|
||||||
"general": "General",
|
"general": "General",
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
|
@ -33,8 +36,25 @@
|
||||||
"keys": "Keys",
|
"keys": "Keys",
|
||||||
"keysList": "Keys list",
|
"keysList": "Keys list",
|
||||||
"searchKey":"Search key",
|
"searchKey":"Search key",
|
||||||
|
"keystore": "Keystore",
|
||||||
|
"keystorePassword": "Keystore password",
|
||||||
|
"keyAlias": "Key alias",
|
||||||
|
"keyPassword": "Key password",
|
||||||
"providers": "Providers",
|
"providers": "Providers",
|
||||||
"algorithm": "Algorithm",
|
"algorithm": "Algorithm",
|
||||||
|
"aesGenerated": "aes-generated",
|
||||||
|
"ecdsaGenerated": "ecdsca-generated",
|
||||||
|
"hmacGenerated": "hmac-generated",
|
||||||
|
"javaKeystore": "java-keystore",
|
||||||
|
"rsa": "rsa",
|
||||||
|
"rsaGenerated": "rsa-generated",
|
||||||
|
"consoleDisplayName": "Console Display Name",
|
||||||
|
"AESKeySize": "AES Key Size",
|
||||||
|
"active": "Active",
|
||||||
|
"privateRSAKey": "Private RSA Key",
|
||||||
|
"x509Certificate": "X509 Certificate",
|
||||||
|
"ellipticCurve": "Elliptic Curve",
|
||||||
|
"secretSize": "Secret size",
|
||||||
"type": "Type",
|
"type": "Type",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"kid": "Kid",
|
"kid": "Kid",
|
||||||
|
|
Loading…
Reference in a new issue