Added posibilty to import SAML XML (#3049)
This commit is contained in:
parent
2ecbb60d56
commit
c60c83b6cc
7 changed files with 77 additions and 25 deletions
|
@ -503,6 +503,7 @@
|
|||
"importFile": "Import file",
|
||||
"importSuccess": "New certificate imported",
|
||||
"importError": "Could not import certificate {{error}}",
|
||||
"importParseError": "Could not parse the file {{error}}",
|
||||
"tokenLifespan": {
|
||||
"expires": "Expires in",
|
||||
"never": "Never expires"
|
||||
|
|
|
@ -2,5 +2,6 @@
|
|||
"helpToggleInfo": "This toggle will enable / disable part of the help info in the console. Includes any help text, links and popovers.",
|
||||
"showPassword": "Show password field in clear text",
|
||||
"helpFileUpload": "Upload a JSON file",
|
||||
"helpFileUploadClient": "Upload a JSON or XML file",
|
||||
"dragHelp": "Press space or enter to begin dragging, and use the arrow keys to navigate up or down. Press enter to confirm the drag, or any other key to cancel the drag operation."
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
import { useState } from "react";
|
||||
import { Link, useHistory } from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { FormProvider, useForm } from "react-hook-form";
|
||||
import {
|
||||
ActionGroup,
|
||||
AlertVariant,
|
||||
|
@ -5,23 +9,29 @@ import {
|
|||
FormGroup,
|
||||
PageSection,
|
||||
} from "@patternfly/react-core";
|
||||
import { Language } from "@patternfly/react-code-editor";
|
||||
|
||||
import type ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientRepresentation";
|
||||
import { useState } from "react";
|
||||
import { FormProvider, useForm } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link, useHistory } from "react-router-dom";
|
||||
|
||||
import { useAlerts } from "../../components/alert/Alerts";
|
||||
import { FormAccess } from "../../components/form-access/FormAccess";
|
||||
import { JsonFileUpload } from "../../components/json-file-upload/JsonFileUpload";
|
||||
import { ViewHeader } from "../../components/view-header/ViewHeader";
|
||||
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
|
||||
import { useAdminClient } from "../../context/auth/AdminClient";
|
||||
import { useRealm } from "../../context/realm-context/RealmContext";
|
||||
import { convertFormValuesToObject, convertToFormValues } from "../../util";
|
||||
import {
|
||||
addTrailingSlash,
|
||||
convertFormValuesToObject,
|
||||
convertToFormValues,
|
||||
} from "../../util";
|
||||
import { CapabilityConfig } from "../add/CapabilityConfig";
|
||||
import { ClientDescription } from "../ClientDescription";
|
||||
import { toClient } from "../routes/Client";
|
||||
import { toClients } from "../routes/Clients";
|
||||
import { FileUploadForm } from "../../components/json-file-upload/FileUploadForm";
|
||||
import { getAuthorizationHeaders } from "../../utils/getAuthorizationHeaders";
|
||||
|
||||
const isXml = (text: string) => text.startsWith("<");
|
||||
|
||||
export default function ImportForm() {
|
||||
const { t } = useTranslation("clients");
|
||||
|
@ -34,17 +44,43 @@ export default function ImportForm() {
|
|||
|
||||
const { addAlert, addError } = useAlerts();
|
||||
|
||||
const handleFileChange = (obj?: object) => {
|
||||
const defaultClient = {
|
||||
protocol: "",
|
||||
clientId: "",
|
||||
name: "",
|
||||
description: "",
|
||||
const handleFileChange = async (contents: string) => {
|
||||
try {
|
||||
const parsed = await parseFileContents(contents);
|
||||
|
||||
convertToFormValues(parsed, setValue);
|
||||
setImported(parsed);
|
||||
} catch (error) {
|
||||
addError("clients:importParseError", error);
|
||||
}
|
||||
};
|
||||
|
||||
convertToFormValues(obj || defaultClient, setValue);
|
||||
setImported(obj || defaultClient);
|
||||
};
|
||||
async function parseFileContents(
|
||||
contents: string
|
||||
): Promise<ClientRepresentation> {
|
||||
if (!isXml(contents)) {
|
||||
return JSON.parse(contents);
|
||||
}
|
||||
|
||||
const response = await fetch(
|
||||
`${addTrailingSlash(
|
||||
adminClient.baseUrl
|
||||
)}admin/realms/${realm}/client-description-converter`,
|
||||
{
|
||||
method: "POST",
|
||||
body: contents,
|
||||
headers: getAuthorizationHeaders(await adminClient.getAccessToken()),
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Server responded with invalid status: ${response.statusText}`
|
||||
);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
const save = async (client: ClientRepresentation) => {
|
||||
try {
|
||||
|
@ -74,7 +110,13 @@ export default function ImportForm() {
|
|||
role="manage-clients"
|
||||
>
|
||||
<FormProvider {...form}>
|
||||
<JsonFileUpload id="realm-file" onChange={handleFileChange} />
|
||||
<FileUploadForm
|
||||
id="realm-file"
|
||||
language={Language.json}
|
||||
extension=".json,.xml"
|
||||
helpText="common-help:helpFileUploadClient"
|
||||
onChange={handleFileChange}
|
||||
/>
|
||||
<ClientDescription hasConfigureAccess />
|
||||
<FormGroup label={t("common:type")} fieldId="kc-type">
|
||||
<KeycloakTextInput
|
||||
|
|
|
@ -4,6 +4,7 @@ import { initReactI18next } from "react-i18next";
|
|||
import type KeycloakAdminClient from "@keycloak/keycloak-admin-client";
|
||||
|
||||
import environment from "./environment";
|
||||
import { getAuthorizationHeaders } from "./utils/getAuthorizationHeaders";
|
||||
|
||||
export const DEFAULT_LOCALE = "en";
|
||||
|
||||
|
@ -60,9 +61,9 @@ const initOptions = async (
|
|||
postProcess: ["overrideProcessor"],
|
||||
backend: {
|
||||
loadPath: constructLoadPath,
|
||||
customHeaders: {
|
||||
Authorization: `Bearer ${await adminClient.getAccessToken()}`,
|
||||
},
|
||||
customHeaders: getAuthorizationHeaders(
|
||||
await adminClient.getAccessToken()
|
||||
),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -9,6 +9,7 @@ import { useRealm } from "../../context/realm-context/RealmContext";
|
|||
import { DiscoverySettings } from "./DiscoverySettings";
|
||||
import { DiscoveryEndpointField } from "../component/DiscoveryEndpointField";
|
||||
import { addTrailingSlash } from "../../util";
|
||||
import { getAuthorizationHeaders } from "../../utils/getAuthorizationHeaders";
|
||||
|
||||
export const OpenIdConnectSettings = () => {
|
||||
const { t } = useTranslation("identity-providers");
|
||||
|
@ -45,9 +46,7 @@ export const OpenIdConnectSettings = () => {
|
|||
{
|
||||
method: "POST",
|
||||
body: formData,
|
||||
headers: {
|
||||
Authorization: `Bearer ${await adminClient.getAccessToken()}`,
|
||||
},
|
||||
headers: getAuthorizationHeaders(await adminClient.getAccessToken()),
|
||||
}
|
||||
);
|
||||
if (response.ok) {
|
||||
|
|
|
@ -13,6 +13,7 @@ import { DiscoveryEndpointField } from "../component/DiscoveryEndpointField";
|
|||
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
|
||||
import environment from "../../environment";
|
||||
import { addTrailingSlash } from "../../util";
|
||||
import { getAuthorizationHeaders } from "../../utils/getAuthorizationHeaders";
|
||||
|
||||
export const SamlConnectSettings = () => {
|
||||
const { t } = useTranslation("identity-providers");
|
||||
|
@ -51,9 +52,7 @@ export const SamlConnectSettings = () => {
|
|||
{
|
||||
method: "POST",
|
||||
body: formData,
|
||||
headers: {
|
||||
Authorization: `bearer ${await adminClient.getAccessToken()}`,
|
||||
},
|
||||
headers: getAuthorizationHeaders(await adminClient.getAccessToken()),
|
||||
}
|
||||
);
|
||||
if (response.ok) {
|
||||
|
|
9
src/utils/getAuthorizationHeaders.ts
Normal file
9
src/utils/getAuthorizationHeaders.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
export function getAuthorizationHeaders(
|
||||
accessToken?: string
|
||||
): Record<string, string> {
|
||||
if (!accessToken) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return { Authorization: `Bearer ${accessToken}` };
|
||||
}
|
Loading…
Reference in a new issue