@keycloakify/keycloak-admin-ui
Version:
Repackaged Keycloak Admin UI
351 lines • 19.3 kB
JavaScript
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { KeycloakDataTable, ScrollForm, useAlerts, useFetch, } from "../../ui-shared";
import { AlertVariant, Button, ButtonVariant, Divider, DropdownItem, Form, PageSection, Tab, TabTitleText, ToolbarItem, } from "@patternfly/react-core";
import { useMemo, useState } from "react";
import { Controller, FormProvider, useForm, useFormContext, useWatch, } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { Link, useNavigate } from "react-router-dom";
import { useAdminClient } from "../../admin-client";
import { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog";
import { DynamicComponents } from "../../components/dynamic/DynamicComponents";
import { FixedButtonsGroup } from "../../components/form/FixedButtonGroup";
import { FormAccess } from "../../components/form/FormAccess";
import { KeycloakSpinner } from "../../ui-shared";
import { ListEmptyState } from "../../ui-shared";
import { PermissionsTab } from "../../components/permission-tab/PermissionTab";
import { RoutableTabs, useRoutableTab, } from "../../components/routable-tabs/RoutableTabs";
import { ViewHeader } from "../../components/view-header/ViewHeader";
import { useRealm } from "../../context/realm-context/RealmContext";
import { useServerInfo } from "../../context/server-info/ServerInfoProvider";
import { toUpperCase } from "../../util";
import useIsFeatureEnabled, { Feature } from "../../utils/useIsFeatureEnabled";
import { useParams } from "../../utils/useParams";
import { toIdentityProviderAddMapper } from "../../identity-providers/routes/AddMapper";
import { toIdentityProviderEditMapper } from "../../identity-providers/routes/EditMapper";
import { toIdentityProvider, } from "../../identity-providers/routes/IdentityProvider";
import { toIdentityProviders } from "../../identity-providers/routes/IdentityProviders";
import { AdvancedSettings } from "../../identity-providers/add/AdvancedSettings";
import { DescriptorSettings } from "../../identity-providers/add/DescriptorSettings";
import { DiscoverySettings } from "../../identity-providers/add/DiscoverySettings";
import { ExtendedNonDiscoverySettings } from "../../identity-providers/add/ExtendedNonDiscoverySettings";
import { GeneralSettings } from "../../identity-providers/add/GeneralSettings";
import { OIDCAuthentication } from "../../identity-providers/add/OIDCAuthentication";
import { OIDCGeneralSettings } from "../../identity-providers/add/OIDCGeneralSettings";
import { ReqAuthnConstraints } from "../../identity-providers/add/ReqAuthnConstraintsSettings";
import { SamlGeneralSettings } from "../../identity-providers/add/SamlGeneralSettings";
const Header = ({ onChange, value, save, toggleDeleteDialog }) => {
var _a, _b;
const { adminClient } = useAdminClient();
const { t } = useTranslation();
const { alias: displayName } = useParams();
const [provider, setProvider] = useState();
const { addAlert, addError } = useAlerts();
const { setValue, formState, control } = useFormContext();
const validateSignature = useWatch({
control,
name: "config.validateSignature",
});
const useMetadataDescriptorUrl = useWatch({
control,
name: "config.useMetadataDescriptorUrl",
});
const metadataDescriptorUrl = useWatch({
control,
name: "config.metadataDescriptorUrl",
});
useFetch(() => adminClient.identityProviders.findOne({ alias: displayName }), (fetchedProvider) => {
if (!fetchedProvider) {
throw new Error(t("notFound"));
}
setProvider(fetchedProvider);
}, []);
const [toggleDisableDialog, DisableConfirm] = useConfirmDialog({
titleKey: "disableProvider",
messageKey: t("disableConfirmIdentityProvider", { provider: displayName }),
continueButtonLabel: "disable",
onConfirm: () => {
onChange(!value);
save();
},
});
const importSamlKeys = async (providerId, metadataDescriptorUrl) => {
try {
const result = await adminClient.identityProviders.importFromUrl({
providerId: providerId,
fromUrl: metadataDescriptorUrl,
});
if (result.signingCertificate) {
setValue(`config.signingCertificate`, result.signingCertificate);
addAlert(t("importKeysSuccess"), AlertVariant.success);
}
else {
addError("importKeysError", t("importKeysErrorNoSigningCertificate"));
}
}
catch (error) {
addError("importKeysError", error);
}
};
const reloadSamlKeys = async (alias) => {
try {
const result = await adminClient.identityProviders.reloadKeys({
alias: alias,
});
if (result) {
addAlert(t("reloadKeysSuccess"), AlertVariant.success);
}
else {
addAlert(t("reloadKeysSuccessButFalse"), AlertVariant.warning);
}
}
catch (error) {
addError("reloadKeysError", error);
}
};
return (_jsxs(_Fragment, { children: [_jsx(DisableConfirm, {}), _jsx(ViewHeader, { titleKey: toUpperCase(provider
? provider.displayName
? provider.displayName
: provider.providerId
: ""), divider: false, dropdownItems: [
...(((_a = provider === null || provider === void 0 ? void 0 : provider.providerId) === null || _a === void 0 ? void 0 : _a.includes("saml")) &&
validateSignature === "true" &&
useMetadataDescriptorUrl === "true" &&
metadataDescriptorUrl &&
!formState.isDirty &&
value
? [
_jsx(DropdownItem, { onClick: () => reloadSamlKeys(provider.alias), children: t("reloadKeys") }, "reloadKeys"),
]
: ((_b = provider === null || provider === void 0 ? void 0 : provider.providerId) === null || _b === void 0 ? void 0 : _b.includes("saml")) &&
validateSignature === "true" &&
useMetadataDescriptorUrl !== "true" &&
metadataDescriptorUrl &&
!formState.isDirty
? [
_jsx(DropdownItem, { onClick: () => importSamlKeys(provider.providerId, metadataDescriptorUrl), children: t("importKeys") }, "importKeys"),
]
: []),
_jsx(Divider, {}, "separator"),
_jsx(DropdownItem, { onClick: () => toggleDeleteDialog(), children: t("delete") }, "delete"),
], isEnabled: value, onToggle: (value) => {
if (!value) {
toggleDisableDialog();
}
else {
onChange(value);
save();
}
} })] }));
};
const MapperLink = ({ name, mapperId, provider }) => {
const { realm } = useRealm();
const { alias } = useParams();
return (_jsx(Link, { to: toIdentityProviderEditMapper({
realm,
alias,
providerId: provider === null || provider === void 0 ? void 0 : provider.providerId,
id: mapperId,
}), children: name }));
};
export default function DetailSettings() {
const { adminClient } = useAdminClient();
const { t } = useTranslation();
const { alias, providerId } = useParams();
const isFeatureEnabled = useIsFeatureEnabled();
const form = useForm();
const { handleSubmit, getValues, reset } = form;
const [provider, setProvider] = useState();
const [selectedMapper, setSelectedMapper] = useState();
const serverInfo = useServerInfo();
const providerInfo = useMemo(() => {
var _a, _b;
const namespaces = [
"org.keycloak.broker.social.SocialIdentityProvider",
"org.keycloak.broker.provider.IdentityProvider",
];
for (const namespace of namespaces) {
const social = (_b = (_a = serverInfo.componentTypes) === null || _a === void 0 ? void 0 : _a[namespace]) === null || _b === void 0 ? void 0 : _b.find(({ id }) => id === providerId);
if (social) {
return social;
}
}
}, [serverInfo, providerId]);
const { addAlert, addError } = useAlerts();
const navigate = useNavigate();
const { realm } = useRealm();
const [key, setKey] = useState(0);
const refresh = () => setKey(key + 1);
useFetch(() => adminClient.identityProviders.findOne({ alias }), (fetchedProvider) => {
var _a, _b;
if (!fetchedProvider) {
throw new Error(t("notFound"));
}
reset(fetchedProvider);
setProvider(fetchedProvider);
if (fetchedProvider.config.authnContextClassRefs) {
form.setValue("config.authnContextClassRefs", JSON.parse((_a = fetchedProvider.config) === null || _a === void 0 ? void 0 : _a.authnContextClassRefs));
}
if (fetchedProvider.config.authnContextDeclRefs) {
form.setValue("config.authnContextDeclRefs", JSON.parse((_b = fetchedProvider.config) === null || _b === void 0 ? void 0 : _b.authnContextDeclRefs));
}
}, []);
const toTab = (tab) => toIdentityProvider({
realm,
alias,
providerId,
tab,
});
const useTab = (tab) => useRoutableTab(toTab(tab));
const settingsTab = useTab("settings");
const mappersTab = useTab("mappers");
const permissionsTab = useTab("permissions");
const save = async (savedProvider) => {
var _a, _b, _c, _d;
const p = savedProvider || getValues();
const origAuthnContextClassRefs = (_a = p.config) === null || _a === void 0 ? void 0 : _a.authnContextClassRefs;
if ((_b = p.config) === null || _b === void 0 ? void 0 : _b.authnContextClassRefs)
p.config.authnContextClassRefs = JSON.stringify(p.config.authnContextClassRefs);
const origAuthnContextDeclRefs = (_c = p.config) === null || _c === void 0 ? void 0 : _c.authnContextDeclRefs;
if ((_d = p.config) === null || _d === void 0 ? void 0 : _d.authnContextDeclRefs)
p.config.authnContextDeclRefs = JSON.stringify(p.config.authnContextDeclRefs);
try {
await adminClient.identityProviders.update({ alias }, {
...p,
config: { ...provider === null || provider === void 0 ? void 0 : provider.config, ...p.config },
alias,
providerId,
});
if (origAuthnContextClassRefs) {
p.config.authnContextClassRefs = origAuthnContextClassRefs;
}
if (origAuthnContextDeclRefs) {
p.config.authnContextDeclRefs = origAuthnContextDeclRefs;
}
reset(p);
addAlert(t("updateSuccessIdentityProvider"), AlertVariant.success);
}
catch (error) {
addError("updateErrorIdentityProvider", error);
}
};
const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({
titleKey: "deleteProvider",
messageKey: t("deleteConfirmIdentityProvider", { provider: alias }),
continueButtonLabel: "delete",
continueButtonVariant: ButtonVariant.danger,
onConfirm: async () => {
try {
await adminClient.identityProviders.del({ alias: alias });
addAlert(t("deletedSuccessIdentityProvider"), AlertVariant.success);
navigate(toIdentityProviders({ realm }));
}
catch (error) {
addError("deleteErrorIdentityProvider", error);
}
},
});
const [toggleDeleteMapperDialog, DeleteMapperConfirm] = useConfirmDialog({
titleKey: "deleteProviderMapper",
messageKey: t("deleteMapperConfirm", {
mapper: selectedMapper === null || selectedMapper === void 0 ? void 0 : selectedMapper.name,
}),
continueButtonLabel: "delete",
continueButtonVariant: ButtonVariant.danger,
onConfirm: async () => {
try {
await adminClient.identityProviders.delMapper({
alias: alias,
id: selectedMapper === null || selectedMapper === void 0 ? void 0 : selectedMapper.mapperId,
});
addAlert(t("deleteMapperSuccess"), AlertVariant.success);
refresh();
navigate(toIdentityProvider({ providerId, alias, tab: "mappers", realm }));
}
catch (error) {
addError("deleteErrorIdentityProvider", error);
}
},
});
if (!provider) {
return _jsx(KeycloakSpinner, {});
}
const isOIDC = provider.providerId.includes("oidc");
const isSAML = provider.providerId.includes("saml");
const isSocial = !isOIDC && !isSAML;
const loader = async () => {
const [loaderMappers, loaderMapperTypes] = await Promise.all([
adminClient.identityProviders.findMappers({ alias }),
adminClient.identityProviders.findMapperTypes({ alias }),
]);
const components = loaderMappers.map((loaderMapper) => {
const mapperType = Object.values(loaderMapperTypes).find((loaderMapperType) => loaderMapper.identityProviderMapper === loaderMapperType.id);
const result = {
...mapperType,
name: loaderMapper.name,
type: mapperType === null || mapperType === void 0 ? void 0 : mapperType.name,
mapperId: loaderMapper.id,
};
return result;
});
return components;
};
const sections = [
{
title: t("generalSettings"),
panel: (_jsxs(FormAccess, { role: "manage-identity-providers", isHorizontal: true, onSubmit: handleSubmit(save), children: [isSocial && _jsx(GeneralSettings, { create: false, id: providerId }), isOIDC && _jsx(OIDCGeneralSettings, {}), isSAML && _jsx(SamlGeneralSettings, { isAliasReadonly: true }), providerInfo && (_jsx(DynamicComponents, { stringify: true, properties: providerInfo.properties }))] })),
},
{
title: t("oidcSettings"),
isHidden: !isOIDC,
panel: (_jsxs(_Fragment, { children: [_jsx(DiscoverySettings, { readOnly: false }), _jsxs(Form, { isHorizontal: true, className: "pf-v5-u-py-lg", children: [_jsx(Divider, {}), _jsx(OIDCAuthentication, { create: false })] }), _jsx(ExtendedNonDiscoverySettings, {})] })),
},
{
title: t("samlSettings"),
isHidden: !isSAML,
panel: _jsx(DescriptorSettings, { readOnly: false }),
},
{
title: t("reqAuthnConstraints"),
isHidden: !isSAML,
panel: (_jsx(FormAccess, { role: "manage-identity-providers", isHorizontal: true, onSubmit: handleSubmit(save), children: _jsx(ReqAuthnConstraints, {}) })),
},
{
title: t("advancedSettings"),
panel: (_jsxs(FormAccess, { role: "manage-identity-providers", isHorizontal: true, onSubmit: handleSubmit(save), children: [_jsx(AdvancedSettings, { isOIDC: isOIDC, isSAML: isSAML }), _jsx(FixedButtonsGroup, { name: "idp-details", isSubmit: true, reset: reset })] })),
},
];
return (_jsxs(FormProvider, { ...form, children: [_jsx(DeleteConfirm, {}), _jsx(DeleteMapperConfirm, {}), _jsx(Controller, { name: "enabled", control: form.control, defaultValue: true, render: ({ field }) => (_jsx(Header, { value: field.value || false, onChange: field.onChange, save: save, toggleDeleteDialog: toggleDeleteDialog })) }), _jsx(PageSection, { variant: "light", className: "pf-v5-u-p-0", children: _jsxs(RoutableTabs, { isBox: true, defaultLocation: toTab("settings"), children: [_jsx(Tab, { id: "settings", title: _jsx(TabTitleText, { children: t("settings") }), ...settingsTab, children: _jsx(ScrollForm, { label: t("jumpToSection"), className: "pf-v5-u-px-lg", sections: sections }) }), _jsx(Tab, { id: "mappers", "data-testid": "mappers-tab", title: _jsx(TabTitleText, { children: t("mappers") }), ...mappersTab, children: _jsx(KeycloakDataTable, { emptyState: _jsx(ListEmptyState, { message: t("noMappers"), instructions: t("noMappersInstructions"), primaryActionText: t("addMapper"), onPrimaryAction: () => navigate(toIdentityProviderAddMapper({
realm,
alias: alias,
providerId: provider.providerId,
tab: "mappers",
})) }), loader: loader, ariaLabelKey: "mappersList", searchPlaceholderKey: "searchForMapper", toolbarItem: _jsx(ToolbarItem, { children: _jsx(Button, { id: "add-mapper-button", component: (props) => (_jsx(Link, { ...props, to: toIdentityProviderAddMapper({
realm,
alias: alias,
providerId: provider.providerId,
tab: "mappers",
}) })), "data-testid": "addMapper", children: t("addMapper") }) }), columns: [
{
name: "name",
displayKey: "name",
cellRenderer: (row) => (_jsx(MapperLink, { ...row, provider: provider })),
},
{
name: "category",
displayKey: "category",
},
{
name: "type",
displayKey: "type",
},
], actions: [
{
title: t("delete"),
onRowClick: (mapper) => {
setSelectedMapper(mapper);
toggleDeleteMapperDialog();
},
},
] }, key) }), isFeatureEnabled(Feature.AdminFineGrainedAuthz) && (_jsx(Tab, { id: "permissions", "data-testid": "permissionsTab", title: _jsx(TabTitleText, { children: t("permissions") }), ...permissionsTab, children: _jsx(PermissionsTab, { id: alias, type: "identityProviders" }) }))] }) })] }));
}
//# sourceMappingURL=DetailSettings.js.map