setSelectedRows([...rows])}
canSelectAll={false}
loader={loader}
diff --git a/src/realm-settings/KeysListTab.tsx b/src/realm-settings/KeysListTab.tsx
new file mode 100644
index 0000000000..e4f3055135
--- /dev/null
+++ b/src/realm-settings/KeysListTab.tsx
@@ -0,0 +1,180 @@
+import React, { useState } from "react";
+import { useHistory, useRouteMatch } from "react-router-dom";
+import { useTranslation } from "react-i18next";
+import { Button, ButtonVariant, PageSection } from "@patternfly/react-core";
+import { KeyMetadataRepresentation } from "keycloak-admin/lib/defs/keyMetadataRepresentation";
+import { ListEmptyState } from "../components/list-empty-state/ListEmptyState";
+import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable";
+import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
+import { emptyFormatter } from "../util";
+import ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
+
+import "./RealmSettingsSection.css";
+import { cellWidth } from "@patternfly/react-table";
+
+type KeyData = KeyMetadataRepresentation & {
+ provider?: string;
+};
+
+type KeysTabInnerProps = {
+ keys: KeyData[];
+};
+
+export const KeysTabInner = ({ keys }: KeysTabInnerProps) => {
+ const { t } = useTranslation("roles");
+ const history = useHistory();
+ const { url } = useRouteMatch();
+ const [key, setKey] = useState(0);
+ const refresh = () => setKey(new Date().getTime());
+
+ const [publicKey, setPublicKey] = useState("");
+ const [certificate, setCertificate] = useState("");
+
+ const loader = async () => {
+ return keys;
+ };
+
+ React.useEffect(() => {
+ refresh();
+ }, [keys]);
+
+ const [togglePublicKeyDialog, PublicKeyDialog] = useConfirmDialog({
+ titleKey: t("realm-settings:publicKeys").slice(0, -1),
+ messageKey: publicKey,
+ continueButtonLabel: "common:close",
+ continueButtonVariant: ButtonVariant.primary,
+ noCancelButton: true,
+ onConfirm: async () => {},
+ });
+
+ const [toggleCertificateDialog, CertificateDialog] = useConfirmDialog({
+ titleKey: t("realm-settings:certificate"),
+ messageKey: certificate,
+ continueButtonLabel: "common:close",
+ continueButtonVariant: ButtonVariant.primary,
+ noCancelButton: true,
+ onConfirm: async () => {},
+ });
+
+ const goToCreate = () => history.push(`${url}/add-role`);
+
+ const ProviderRenderer = ({ provider }: KeyData) => {
+ return <>{provider}>;
+ };
+
+ const renderPublicKeyButton = (publicKey: string) => {
+ return (
+
+ );
+ };
+
+ const ButtonRenderer = ({ provider, publicKey, certificate }: KeyData) => {
+ if (provider === "ecdsa-generated") {
+ return <>{renderPublicKeyButton(publicKey!)}>;
+ }
+ if (provider === "rsa-generated" || provider === "fallback-RS256") {
+ return (
+ <>
+
+ {renderPublicKeyButton(publicKey!)}
+
+
+ >
+ );
+ }
+ };
+
+ return (
+ <>
+
+
+
+
+ }
+ />
+
+ >
+ );
+};
+
+type KeysProps = {
+ keys: KeyMetadataRepresentation[];
+ realmComponents: ComponentRepresentation[];
+};
+
+export const KeysListTab = ({ keys, realmComponents, ...props }: KeysProps) => {
+ return (
+ {
+ const provider = realmComponents.find(
+ (component: ComponentRepresentation) =>
+ component.id === key.providerId
+ );
+ return { ...key, provider: provider?.name };
+ })}
+ {...props}
+ />
+ );
+};
diff --git a/src/realm-settings/KeysTab.tsx b/src/realm-settings/KeysTab.tsx
new file mode 100644
index 0000000000..fe93ca417a
--- /dev/null
+++ b/src/realm-settings/KeysTab.tsx
@@ -0,0 +1,185 @@
+import React, { useState } from "react";
+import { useHistory, useRouteMatch } from "react-router-dom";
+import { useTranslation } from "react-i18next";
+import { Button, ButtonVariant, PageSection } from "@patternfly/react-core";
+import { KeyMetadataRepresentation } from "keycloak-admin/lib/defs/keyMetadataRepresentation";
+import { ListEmptyState } from "../components/list-empty-state/ListEmptyState";
+import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable";
+import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
+import { emptyFormatter } from "../util";
+import ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
+
+import "./RealmSettingsSection.css";
+import { cellWidth } from "@patternfly/react-table";
+
+type KeyData = KeyMetadataRepresentation & {
+ provider?: string;
+};
+
+type KeysTabInnerProps = {
+ keys: KeyData[];
+};
+
+export const KeysTabInner = ({ keys }: KeysTabInnerProps) => {
+ const { t } = useTranslation("roles");
+ const history = useHistory();
+ const { url } = useRouteMatch();
+ const [key, setKey] = useState(0);
+ const refresh = () => setKey(new Date().getTime());
+
+ const [publicKey, setPublicKey] = useState("");
+ const [certificate, setCertificate] = useState("");
+
+ const loader = async () => {
+ return keys;
+ };
+
+ React.useEffect(() => {
+ refresh();
+ }, [keys]);
+
+ const [togglePublicKeyDialog, PublicKeyDialog] = useConfirmDialog({
+ titleKey: t("realm-settings:publicKeys").slice(0, -1),
+ messageKey: publicKey,
+ continueButtonLabel: "common:close",
+ continueButtonVariant: ButtonVariant.primary,
+ noCancelButton: true,
+ onConfirm: async () => {},
+ });
+
+ const [toggleCertificateDialog, CertificateDialog] = useConfirmDialog({
+ titleKey: t("realm-settings:certificate"),
+ messageKey: certificate,
+ continueButtonLabel: "common:close",
+ continueButtonVariant: ButtonVariant.primary,
+ noCancelButton: true,
+ onConfirm: async () => {},
+ });
+
+ const goToCreate = () => history.push(`${url}/add-role`);
+
+ const ProviderRenderer = ({ provider }: KeyData) => {
+ return <>{provider}>;
+ };
+
+ const ButtonRenderer = ({ provider, publicKey, certificate }: KeyData) => {
+ if (provider === "ecdsa-generated") {
+ return (
+ <>
+
+ >
+ );
+ }
+ if (provider === "rsa-generated" || provider === "fallback-RS256") {
+ return (
+ <>
+
+
+ >
+ );
+ }
+ };
+
+ return (
+ <>
+
+
+
+
+ }
+ />
+
+ >
+ );
+};
+
+type KeysProps = {
+ keys: KeyMetadataRepresentation[];
+ realmComponents: ComponentRepresentation[];
+};
+
+export const KeysTab = ({ keys, realmComponents, ...props }: KeysProps) => {
+ return (
+ {
+ const provider = realmComponents.find(
+ (component: ComponentRepresentation) =>
+ component.id === key.providerId
+ );
+ return { ...key, provider: provider?.providerId };
+ })}
+ {...props}
+ />
+ );
+};
diff --git a/src/realm-settings/RealmSettingsSection.css b/src/realm-settings/RealmSettingsSection.css
index e7732d2dce..b14a033e39 100644
--- a/src/realm-settings/RealmSettingsSection.css
+++ b/src/realm-settings/RealmSettingsSection.css
@@ -16,3 +16,6 @@ div.pf-c-card__body.kc-form-panel__body {
padding-left: 0px;
padding-bottom: var(--pf-global--spacer--2xl);
}
+button#kc-certificate.pf-c-button.pf-m-secondary {
+ margin-left: var(--pf-global--spacer--md);
+}
diff --git a/src/realm-settings/RealmSettingsSection.tsx b/src/realm-settings/RealmSettingsSection.tsx
index 003aaa46f9..da28c0e702 100644
--- a/src/realm-settings/RealmSettingsSection.tsx
+++ b/src/realm-settings/RealmSettingsSection.tsx
@@ -10,6 +10,7 @@ import {
DropdownSeparator,
PageSection,
Tab,
+ Tabs,
TabTitleText,
} from "@patternfly/react-core";
@@ -26,6 +27,9 @@ import { RealmSettingsGeneralTab } from "./GeneralTab";
import { PartialImportDialog } from "./PartialImport";
import { RealmSettingsThemesTab } from "./ThemesTab";
import { RealmSettingsEmailTab } from "./EmailTab";
+import { KeysListTab } from "./KeysListTab";
+import { KeyMetadataRepresentation } from "keycloak-admin/lib/defs/keyMetadataRepresentation";
+import ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
type RealmSettingsHeaderProps = {
onChange: (value: boolean) => void;
@@ -126,6 +130,11 @@ export const RealmSettingsSection = () => {
const form = useForm();
const { control, getValues, setValue } = form;
const [realm, setRealm] = useState();
+ const [activeTab2, setActiveTab2] = useState(0);
+ const [keys, setKeys] = useState([]);
+ const [realmComponents, setRealmComponents] = useState<
+ ComponentRepresentation[]
+ >([]);
useEffect(() => {
return asyncStateFetch(
@@ -138,6 +147,21 @@ export const RealmSettingsSection = () => {
);
}, []);
+ useEffect(() => {
+ const update = async () => {
+ const keysMetaData = await adminClient.realms.getKeys({
+ realm: realmName,
+ });
+ setKeys(keysMetaData.keys!);
+ const realmComponents = await adminClient.components.find({
+ type: "org.keycloak.keys.KeyProvider",
+ realm: realmName,
+ });
+ setRealmComponents(realmComponents);
+ };
+ setTimeout(update, 100);
+ }, []);
+
const setupForm = (realm: RealmRepresentation) => {
Object.entries(realm).map((entry) => setValue(entry[0], entry[1]));
};
@@ -207,6 +231,24 @@ export const RealmSettingsSection = () => {
reset={() => setupForm(realm!)}
/>
+ {t("realm-settings:keys")}}
+ data-testid="rs-keys-tab"
+ >
+ setActiveTab2(key as number)}
+ >
+ {t("keysList")}}
+ >
+
+
+
+
diff --git a/src/realm-settings/messages.json b/src/realm-settings/messages.json
index 1608450234..0c8132169e 100644
--- a/src/realm-settings/messages.json
+++ b/src/realm-settings/messages.json
@@ -30,6 +30,16 @@
"enableStartTLS": "Enable StartTLS",
"username": "Username",
"password": "Password",
+ "keys": "Keys",
+ "keysList": "Keys list",
+ "searchKey":"Search key",
+ "providers": "Providers",
+ "algorithm": "Algorithm",
+ "type": "Type",
+ "kid": "Kid",
+ "provider": "Provider",
+ "publicKeys": "Public keys",
+ "certificate": "Certificate",
"userRegistration": "User registration",
"userRegistrationHelpText": "Enable/disable the registration page. A link for registration will show on login page too.",
"forgotPassword": "Forgot password",