changed to use Dynamic components instead (#1662)

* changed to use Dynamic components instead

* fixed merge errors

* fixed PR review issues
This commit is contained in:
Erik Jan de Wit 2021-12-16 17:24:22 +01:00 committed by GitHub
parent 64ee1957c8
commit 97641e51cb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 81 additions and 1444 deletions

View file

@ -37,16 +37,15 @@ export default class ProviderPage {
private cachePolicyList = "#kc-cache-policy + ul";
// Mapper required input values
private userModelAttInput = "data-testid=mapper-userModelAttribute-fld";
private ldapAttInput = "data-testid=mapper-ldapAttribute-fld";
private userModelAttNameInput =
"data-testid=mapper-userModelAttributeName-fld";
private attValueInput = "data-testid=mapper-attributeValue-fld";
private ldapFullNameAttInput = "data-testid=mapper-fullNameAttribute-fld";
private ldapAttNameInput = "data-testid=mapper-ldapAttributeName-fld";
private ldapAttValueInput = "data-testid=mapper-ldapAttributeValue-fld";
private groupInput = "data-testid=mapper-group-fld";
private ldapDnInput = "data-testid=ldap-dn";
private userModelAttInput = "user.model.attribute";
private ldapAttInput = "ldap.attribute";
private userModelAttNameInput = "user.model.attribute";
private attValueInput = "attribute.value";
private ldapFullNameAttInput = "ldap.full.name.attribute";
private ldapAttNameInput = "ldap.attribute.name";
private ldapAttValueInput = "ldap.attribute.value";
private groupInput = "group";
private ldapDnInput = "groups.dn";
// mapper types
private msadUserAcctMapper = "msad-user-account-control-mapper";
@ -247,29 +246,29 @@ export default class ProviderPage {
break;
case this.userAttLdapMapper:
case this.certLdapMapper:
cy.get(`[${this.userModelAttInput}]`).type(userModelAttValue);
cy.get(`[${this.ldapAttInput}]`).type(ldapAttValue);
cy.findByTestId(this.userModelAttInput).type(userModelAttValue);
cy.findByTestId(this.ldapAttInput).type(ldapAttValue);
break;
case this.hcAttMapper:
cy.get(`[${this.userModelAttNameInput}]`).type(userModelAttValue);
cy.get(`[${this.attValueInput}]`).type(ldapAttValue);
cy.findByTestId(this.userModelAttNameInput).type(userModelAttValue);
cy.findByTestId(this.attValueInput).type(ldapAttValue);
break;
case this.fullNameLdapMapper:
cy.get(`[${this.ldapFullNameAttInput}]`).type(ldapAttValue);
cy.findByTestId(this.ldapFullNameAttInput).type(ldapAttValue);
break;
case this.hcLdapAttMapper:
cy.get(`[${this.ldapAttNameInput}]`).type(userModelAttValue);
cy.get(`[${this.ldapAttValueInput}]`).type(ldapAttValue);
cy.findByTestId(this.ldapAttNameInput).type(userModelAttValue);
cy.findByTestId(this.ldapAttValueInput).type(ldapAttValue);
break;
case this.hcLdapGroupMapper:
cy.get(`[${this.groupInput}]`).type(this.groupName);
cy.findByTestId(this.groupInput).type(this.groupName);
break;
case this.groupLdapMapper:
cy.get(`[${this.ldapDnInput}]`).type(ldapDnValue);
cy.findByTestId(this.ldapDnInput).type(ldapDnValue);
break;
case this.roleLdapMapper:
cy.get(`[${this.ldapDnInput}]`).type(ldapDnValue);
cy.findByTestId(this.ldapDnInput).type(ldapDnValue);
// cy select clientID dropdown and choose clientName (var)
cy.get(this.clientIdSelect).click();
cy.get("button").contains(this.clientName).click({ force: true });
@ -303,26 +302,21 @@ export default class ProviderPage {
break;
case this.userAttLdapMapper:
case this.certLdapMapper:
cy.get(`[${this.userModelAttInput}]`).clear();
cy.get(`[${this.userModelAttInput}]`).type(userModelAttValue);
cy.get(`[${this.ldapAttInput}]`).clear();
cy.get(`[${this.ldapAttInput}]`).type(ldapAttValue);
cy.findByTestId(this.userModelAttInput).clear().type(userModelAttValue);
cy.findByTestId(this.ldapAttInput).clear().type(ldapAttValue);
break;
case this.hcAttMapper:
cy.get(`[${this.userModelAttNameInput}]`).clear();
cy.get(`[${this.userModelAttNameInput}]`).type(userModelAttValue);
cy.get(`[${this.attValueInput}]`).clear();
cy.get(`[${this.attValueInput}]`).type(ldapAttValue);
cy.findByTestId(this.userModelAttNameInput)
.clear()
.type(userModelAttValue);
cy.findByTestId(this.attValueInput).clear().type(ldapAttValue);
break;
case this.fullNameLdapMapper:
cy.get(`[${this.ldapFullNameAttInput}]`).clear();
cy.get(`[${this.ldapFullNameAttInput}]`).type(ldapAttValue);
cy.findByTestId(this.ldapFullNameAttInput).clear().type(ldapAttValue);
break;
case this.hcLdapAttMapper:
cy.get(`[${this.ldapAttNameInput}]`).clear();
cy.get(`[${this.ldapAttNameInput}]`).type(userModelAttValue);
cy.get(`[${this.ldapAttValueInput}]`).clear;
cy.get(`[${this.ldapAttValueInput}]`).type(ldapAttValue);
cy.findByTestId(this.ldapAttNameInput).clear().type(userModelAttValue);
cy.findByTestId(this.ldapAttValueInput).clear().type(ldapAttValue);
break;
default:
console.log("Invalid mapper name.");

View file

@ -17,27 +17,22 @@ import type ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/de
import { useAdminClient, useFetch } from "../../../context/auth/AdminClient";
import { ViewHeader } from "../../../components/view-header/ViewHeader";
import { useHistory, useParams } from "react-router-dom";
import { Controller, useForm, useWatch } from "react-hook-form";
import { Controller, FormProvider, useForm, useWatch } from "react-hook-form";
import { useAlerts } from "../../../components/alert/Alerts";
import { useTranslation } from "react-i18next";
import { HelpItem } from "../../../components/help-enabler/HelpItem";
import { FormAccess } from "../../../components/form-access/FormAccess";
import { LdapMapperUserAttribute } from "./LdapMapperUserAttribute";
import { LdapMapperMsadUserAccount } from "./LdapMapperMsadUserAccount";
import { LdapMapperFullNameAttribute } from "./LdapMapperFullNameAttribute";
import { LdapMapperHardcodedLdapRole } from "./LdapMapperHardcodedLdapRole";
import { LdapMapperHardcodedLdapGroup } from "./LdapMapperHardcodedLdapGroup";
import { LdapMapperHardcodedLdapAttribute } from "./LdapMapperHardcodedLdapAttribute";
import { LdapMapperHardcodedAttribute } from "./LdapMapperHardcodedAttribute";
import { LdapMapperRoleGroup } from "./LdapMapperRoleGroup";
import type ComponentTypeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentTypeRepresentation";
import { DynamicComponents } from "../../../components/dynamic/DynamicComponents";
import { useRealm } from "../../../context/realm-context/RealmContext";
import { KeycloakSpinner } from "../../../components/keycloak-spinner/KeycloakSpinner";
import { toUserFederationLdap } from "../../routes/UserFederationLdap";
export default function LdapMapperDetails() {
const form = useForm<ComponentRepresentation>();
const [mapping, setMapping] = useState<ComponentRepresentation>();
const [components, setComponents] = useState<ComponentTypeRepresentation[]>();
const adminClient = useAdminClient();
const { id, mapperId } = useParams<{ id: string; mapperId: string }>();
@ -50,21 +45,25 @@ export default function LdapMapperDetails() {
useFetch(
async () => {
const components = await adminClient.components.listSubComponents({
id,
type: "org.keycloak.storage.ldap.mappers.LDAPStorageMapper",
});
if (mapperId && mapperId !== "new") {
const fetchedMapper = await adminClient.components.findOne({
id: mapperId,
});
if (!fetchedMapper) {
throw new Error(t("common:notFound"));
}
return fetchedMapper;
return { components, fetchedMapper };
}
return { components };
},
(fetchedMapper) => {
({ components, fetchedMapper }) => {
setMapping(fetchedMapper);
if (fetchedMapper) {
setupForm(fetchedMapper);
}
setComponents(components);
if (mapperId !== "new" && !fetchedMapper)
throw new Error(t("common:notFound"));
if (fetchedMapper) setupForm(fetchedMapper);
},
[]
);
@ -74,18 +73,27 @@ export default function LdapMapperDetails() {
};
const save = async (mapper: ComponentRepresentation) => {
const map = convertFormValuesToObject(mapper);
const component: ComponentRepresentation =
convertFormValuesToObject(mapper);
const map = {
...component,
config: Object.entries(component.config || {}).reduce(
(result, [key, value]) => {
result[key] = Array.isArray(value) ? value : [value];
return result;
},
{} as Record<string, string | string[]>
),
};
try {
if (mapperId) {
if (mapperId === "new") {
await adminClient.components.create(map);
history.push(
`/${realm}/user-federation/ldap/${mapper!.parentId}/mappers`
);
} else {
await adminClient.components.update({ id: mapperId }, map);
}
if (mapperId === "new") {
await adminClient.components.create(map);
history.push(
toUserFederationLdap({ realm, id: mapper.parentId!, tab: "mappers" })
);
} else {
await adminClient.components.update({ id: mapperId }, map);
}
setupForm(map as ComponentRepresentation);
addAlert(
@ -113,6 +121,10 @@ export default function LdapMapperDetails() {
const isNew = mapperId === "new";
if (!components) {
return <KeycloakSpinner />;
}
return (
<>
<ViewHeader
@ -230,130 +242,23 @@ export default function LdapMapperDetails() {
selections={value}
variant={SelectVariant.typeahead}
>
<SelectOption
key={0}
value="msad-user-account-control-mapper"
/>
<SelectOption
key={1}
value="msad-lds-user-account-control-mapper"
/>
<SelectOption key={2} value="group-ldap-mapper" />
<SelectOption key={3} value="user-attribute-ldap-mapper" />
<SelectOption key={4} value="role-ldap-mapper" />
<SelectOption key={5} value="hardcoded-attribute-mapper" />
<SelectOption key={6} value="hardcoded-ldap-role-mapper" />
<SelectOption key={7} value="certificate-ldap-mapper" />
<SelectOption key={8} value="full-name-ldap-mapper" />
<SelectOption key={9} value="hardcoded-ldap-group-mapper" />
<SelectOption
key={10}
value="hardcoded-ldap-attribute-mapper"
/>
{components.map((c) => (
<SelectOption key={c.id} value={c.id} />
))}
</Select>
)}
></Controller>
</FormGroup>
)}
{/* When loading existing mappers, load forms based on providerId aka mapper type */}
{mapping
? (mapping.providerId! === "certificate-ldap-mapper" ||
mapping.providerId! === "user-attribute-ldap-mapper") && (
<LdapMapperUserAttribute
form={form}
mapperType={mapping.providerId}
/>
)
: ""}
{mapping
? mapping.providerId! === "msad-user-account-control-mapper" && (
<LdapMapperMsadUserAccount form={form} />
)
: ""}
{/* msad-lds-user-account-control-mapper does not need a component
because it is just id, name, and mapper type*/}
{mapping
? mapping.providerId! === "full-name-ldap-mapper" && (
<LdapMapperFullNameAttribute form={form} />
)
: ""}
{mapping
? mapping.providerId! === "hardcoded-ldap-role-mapper" && (
<LdapMapperHardcodedLdapRole form={form} />
)
: ""}
{mapping
? mapping.providerId! === "hardcoded-ldap-group-mapper" && (
<LdapMapperHardcodedLdapGroup form={form} />
)
: ""}
{mapping
? mapping.providerId! === "hardcoded-ldap-attribute-mapper" && (
<LdapMapperHardcodedLdapAttribute form={form} />
)
: ""}
{mapping
? mapping.providerId! === "hardcoded-attribute-mapper" && (
<LdapMapperHardcodedAttribute form={form} />
)
: ""}
{mapping
? (mapping.providerId! === "role-ldap-mapper" ||
mapping.providerId! === "group-ldap-mapper") && (
<LdapMapperRoleGroup form={form} type={mapping.providerId} />
)
: ""}
{/* When creating new mappers, load forms based on dropdown selection */}
{isNew && mapperType
? mapperType === "certificate-ldap-mapper" && (
<LdapMapperUserAttribute form={form} mapperType={mapperType} />
)
: ""}
{isNew && mapperType
? mapperType === "user-attribute-ldap-mapper" && (
<LdapMapperUserAttribute form={form} mapperType={mapperType} />
)
: ""}
{isNew && mapperType
? mapperType === "msad-user-account-control-mapper" && (
<LdapMapperMsadUserAccount form={form} />
)
: ""}
{isNew && mapperType
? mapperType === "full-name-ldap-mapper" && (
<LdapMapperFullNameAttribute form={form} />
)
: ""}
{isNew && mapperType
? mapperType === "hardcoded-ldap-role-mapper" && (
<LdapMapperHardcodedLdapRole form={form} />
)
: ""}
{isNew && mapperType
? mapperType === "hardcoded-ldap-group-mapper" && (
<LdapMapperHardcodedLdapGroup form={form} />
)
: ""}
{isNew && mapperType
? mapperType === "hardcoded-ldap-attribute-mapper" && (
<LdapMapperHardcodedLdapAttribute form={form} />
)
: ""}
{isNew && mapperType
? mapperType === "hardcoded-attribute-mapper" && (
<LdapMapperHardcodedAttribute form={form} />
)
: ""}
{isNew && mapperType
? mapperType === "role-ldap-mapper" && (
<LdapMapperRoleGroup form={form} type={mapperType} />
)
: ""}
{isNew && mapperType
? mapperType === "group-ldap-mapper" && (
<LdapMapperRoleGroup form={form} type={mapperType} />
)
: ""}
<FormProvider {...form}>
{!!mapperType && (
<DynamicComponents
properties={
components.find((c) => c.id === mapperType)?.properties!
}
/>
)}
</FormProvider>
</FormAccess>
<Form onSubmit={form.handleSubmit(() => save(form.getValues()))}>

View file

@ -1,95 +0,0 @@
import { FormGroup, Switch, TextInput } from "@patternfly/react-core";
import React from "react";
import { HelpItem } from "../../../components/help-enabler/HelpItem";
import { Controller, UseFormMethods } from "react-hook-form";
import { useTranslation } from "react-i18next";
export type LdapMapperFullNameAttributeProps = {
form: UseFormMethods;
};
export const LdapMapperFullNameAttribute = ({
form,
}: LdapMapperFullNameAttributeProps) => {
const { t } = useTranslation("user-federation");
return (
<>
<FormGroup
label={t("ldapFullNameAttribute")}
labelIcon={
<HelpItem
helpText="user-federation-help:ldapFullNameAttributeHelp"
fieldLabelId="user-federation:ldapFullNameAttribute"
/>
}
fieldId="kc-full-name-attribute"
isRequired
>
<TextInput
isRequired
type="text"
defaultValue="cn"
id="kc-full-name-attribute"
data-testid="mapper-fullNameAttribute-fld"
name="config.ldap.full.name.attribute[0]"
ref={form.register}
/>
</FormGroup>
<FormGroup
label={t("readOnly")}
labelIcon={
<HelpItem
helpText="user-federation-help:fullNameLdapReadOnlyHelp"
fieldLabelId="user-federation:readOnly"
/>
}
fieldId="kc-read-only"
hasNoPaddingTop
>
<Controller
name="config.read.only"
defaultValue={["true"]}
control={form.control}
render={({ onChange, value }) => (
<Switch
id={"kc-read-only"}
isDisabled={false}
onChange={(value) => onChange([`${value}`])}
isChecked={value[0] === "true"}
label={t("common:on")}
labelOff={t("common:off")}
/>
)}
></Controller>
</FormGroup>
<FormGroup
label={t("writeOnly")}
labelIcon={
<HelpItem
helpText="user-federation-help:fullNameLdapWriteOnlyHelp"
fieldLabelId="user-federation:writeOnly"
/>
}
fieldId="kc-read-only"
hasNoPaddingTop
>
<Controller
name="config.write.only"
defaultValue={["false"]}
control={form.control}
render={({ onChange, value }) => (
<Switch
id={"kc-write-only"}
isDisabled={false}
onChange={(value) => onChange([`${value}`])}
isChecked={value[0] === "true"}
label={t("common:on")}
labelOff={t("common:off")}
/>
)}
></Controller>
</FormGroup>
</>
);
};

View file

@ -1,60 +0,0 @@
import { FormGroup, TextInput } from "@patternfly/react-core";
import React from "react";
import { HelpItem } from "../../../components/help-enabler/HelpItem";
import type { UseFormMethods } from "react-hook-form";
import { useTranslation } from "react-i18next";
export type LdapMapperHardcodedAttributeProps = {
form: UseFormMethods;
};
export const LdapMapperHardcodedAttribute = ({
form,
}: LdapMapperHardcodedAttributeProps) => {
const { t } = useTranslation("user-federation");
return (
<>
<FormGroup
label={t("userModelAttributeName")}
labelIcon={
<HelpItem
helpText="user-federation-help:userModelAttributeNameHelp"
fieldLabelId="user-federation:userModelAttributeName"
/>
}
fieldId="kc-user-model-attribute"
isRequired
>
<TextInput
isRequired
type="text"
id="kc-user-model-attribute"
data-testid="mapper-userModelAttributeName-fld"
name="config.user.model.attribute[0]"
ref={form.register}
/>
</FormGroup>
<FormGroup
label={t("attributeValue")}
labelIcon={
<HelpItem
helpText="user-federation-help:attributeValueHelp"
fieldLabelId="user-federation:attributeValue"
/>
}
fieldId="kc-attribute-value"
isRequired
>
<TextInput
isRequired
type="text"
id="kc-attribute-value"
data-testid="mapper-attributeValue-fld"
name="config.attribute.value[0]"
ref={form.register}
/>
</FormGroup>
</>
);
};

View file

@ -1,60 +0,0 @@
import { FormGroup, TextInput } from "@patternfly/react-core";
import React from "react";
import { HelpItem } from "../../../components/help-enabler/HelpItem";
import type { UseFormMethods } from "react-hook-form";
import { useTranslation } from "react-i18next";
export type LdapMapperHardcodedLdapAttributeProps = {
form: UseFormMethods;
};
export const LdapMapperHardcodedLdapAttribute = ({
form,
}: LdapMapperHardcodedLdapAttributeProps) => {
const { t } = useTranslation("user-federation");
return (
<>
<FormGroup
label={t("ldapAttributeName")}
labelIcon={
<HelpItem
helpText="user-federation-help:ldapAttributeNameHelp"
fieldLabelId="user-federation:ldapAttributeName"
/>
}
fieldId="kc-ldap-attribute-name"
isRequired
>
<TextInput
isRequired
type="text"
id="kc-ldap-attribute-name"
data-testid="mapper-ldapAttributeName-fld"
name="config.ldap.attribute.name[0]"
ref={form.register}
/>
</FormGroup>
<FormGroup
label={t("ldapAttributeValue")}
labelIcon={
<HelpItem
helpText="user-federation-help:ldapAttributeValueHelp"
fieldLabelId="user-federation:ldapAttributeValue"
/>
}
fieldId="kc-ldap-attribute-value"
isRequired
>
<TextInput
isRequired
type="text"
id="kc-ldap-attribute-value"
data-testid="mapper-ldapAttributeValue-fld"
name="config.ldap.attribute.value[0]"
ref={form.register}
/>
</FormGroup>
</>
);
};

View file

@ -1,43 +0,0 @@
import { FormGroup, TextInput, ValidatedOptions } from "@patternfly/react-core";
import React from "react";
import { HelpItem } from "../../../components/help-enabler/HelpItem";
import type { UseFormMethods } from "react-hook-form";
import { useTranslation } from "react-i18next";
export type LdapMapperHardcodedLdapGroupProps = {
form: UseFormMethods;
};
export const LdapMapperHardcodedLdapGroup = ({
form,
}: LdapMapperHardcodedLdapGroupProps) => {
const { t } = useTranslation("user-federation");
return (
<FormGroup
label={t("group")}
labelIcon={
<HelpItem
helpText="user-federation-help:groupHelp"
fieldLabelId="user-federation:group"
/>
}
fieldId="kc-group"
isRequired
>
<TextInput
isRequired
type="text"
id="kc-group"
data-testid="mapper-group-fld"
name="config.group[0]"
ref={form.register({ required: true })}
validated={
form.errors.config?.group
? ValidatedOptions.error
: ValidatedOptions.default
}
/>
</FormGroup>
);
};

View file

@ -1,96 +0,0 @@
import {
Button,
FormGroup,
TextInput,
ValidatedOptions,
} from "@patternfly/react-core";
import React, { useState } from "react";
import { HelpItem } from "../../../components/help-enabler/HelpItem";
import type { UseFormMethods } from "react-hook-form";
import { useTranslation } from "react-i18next";
import type ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientRepresentation";
import type RoleRepresentation from "@keycloak/keycloak-admin-client/lib/defs/roleRepresentation";
import { AddRoleMappingModal } from "../../../components/role-mapping/AddRoleMappingModal";
import "../../user-federation.css";
export type LdapMapperHardcodedLdapRoleProps = {
form: UseFormMethods;
};
export type CompositeRole = RoleRepresentation & {
parent: RoleRepresentation;
};
export type Row = {
client?: ClientRepresentation;
role: CompositeRole | RoleRepresentation;
};
export const LdapMapperHardcodedLdapRole = ({
form,
}: LdapMapperHardcodedLdapRoleProps) => {
const { t } = useTranslation("user-federation");
const [showAssign, setShowAssign] = useState(false);
const selectRoles = async (rows: Row[]) => {
if (rows[0].client) {
form.setValue(
"config.role[0]",
`${rows[0].client.clientId}.${rows[0].role.name}`
);
} else {
form.setValue("config.role[0]", `${rows[0].role.name}`);
}
};
return (
<>
{showAssign && (
<AddRoleMappingModal
id=""
type="role"
isLDAPmapper
onAssign={selectRoles}
isRadio={true}
onClose={() => setShowAssign(false)}
/>
)}
<FormGroup
label={t("common:role")}
labelIcon={
<HelpItem
helpText="user-federation-help:roleHelp"
fieldLabelId="role"
/>
}
fieldId="kc-role"
isRequired
>
<div className="keycloak__user-federation__assign-role">
<TextInput
isRequired
type="text"
id="kc-role"
data-testid="role"
name="config.role[0]"
ref={form.register({ required: true })}
validated={
form.errors.config?.role
? ValidatedOptions.error
: ValidatedOptions.default
}
/>
<Button
className="keycloak__user-federation__assign-role-btn"
data-testid="selectRole"
onClick={() => setShowAssign(true)}
>
{t("selectRole")}
</Button>
</div>
</FormGroup>
</>
);
};

View file

@ -1,45 +0,0 @@
import { FormGroup, Switch } from "@patternfly/react-core";
import React from "react";
import { HelpItem } from "../../../components/help-enabler/HelpItem";
import { Controller, UseFormMethods } from "react-hook-form";
import { useTranslation } from "react-i18next";
export type LdapMapperMsadUserAccountProps = {
form: UseFormMethods;
};
export const LdapMapperMsadUserAccount = ({
form,
}: LdapMapperMsadUserAccountProps) => {
const { t } = useTranslation("user-federation");
return (
<FormGroup
label={t("passwordPolicyHintsEnabled")}
labelIcon={
<HelpItem
helpText="user-federation-help:passwordPolicyHintsEnabledHelp"
fieldLabelId="user-federation:passwordPolicyHintsEnabled"
/>
}
fieldId="kc-der-formatted"
hasNoPaddingTop
>
<Controller
name="config.ldap.password.policy.hints.enabled"
defaultValue={["false"]}
control={form.control}
render={({ onChange, value }) => (
<Switch
id={"kc-pw-policy-hints-enabled"}
isDisabled={false}
onChange={(value) => onChange([`${value}`])}
isChecked={value[0] === "true"}
label={t("common:on")}
labelOff={t("common:off")}
/>
)}
></Controller>
</FormGroup>
);
};

View file

@ -1,644 +0,0 @@
import {
FormGroup,
Select,
SelectOption,
SelectVariant,
Switch,
TextInput,
ValidatedOptions,
} from "@patternfly/react-core";
import React, { useState } from "react";
import { useParams } from "react-router-dom";
import type { UserFederationLdapMapperParams } from "../../routes/UserFederationLdapMapper";
import { HelpItem } from "../../../components/help-enabler/HelpItem";
import { Controller, UseFormMethods } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { useAdminClient, useFetch } from "../../../context/auth/AdminClient";
import type ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientRepresentation";
export type LdapMapperRoleGroupProps = {
form: UseFormMethods;
type: string;
};
export const LdapMapperRoleGroup = ({
form,
type,
}: LdapMapperRoleGroupProps) => {
const { t } = useTranslation("user-federation");
const adminClient = useAdminClient();
const [isMbAttTypeDropdownOpen, setIsMbAttTypeDropdownOpen] = useState(false);
const [isModeDropdownOpen, setIsModeDropdownOpen] = useState(false);
const [isRetrieveStratDropdownOpen, setIsRetrieveStratDropdownOpen] =
useState(false);
const [isClientIdDropdownOpen, setIsClientIdDropdownOpen] = useState(false);
const [vendorType, setVendorType] = useState<string | undefined>();
const [clients, setClients] = useState<ClientRepresentation[]>([]);
const { id, mapperId } = useParams<UserFederationLdapMapperParams>();
let isRole = true;
const groupMapper = "group-ldap-mapper";
if (type === groupMapper) {
isRole = false;
}
useFetch(
async () => {
const clients = await adminClient.clients.find();
if (clients) {
setClients(clients);
}
return clients;
},
(clients) => setClients(clients),
[]
);
useFetch(
async () => {
return await adminClient.components.findOne({ id });
},
(fetchedComponent) => {
if (fetchedComponent) {
const vendor = fetchedComponent.config?.vendor[0];
setVendorType(vendor);
if (mapperId === "new" && vendor === "ad") {
form.setValue(
isRole
? "config.role.object.classes[0]"
: "config.group.object.classes[0]",
"group"
);
form.setValue("config.membership.user.ldap.attribute[0]", "cn");
}
} else if (id) {
throw new Error(t("common:notFound"));
}
},
[]
);
return (
<>
<FormGroup
label={isRole ? t("ldapRolesDn") : t("ldapGroupsDn")}
labelIcon={
<HelpItem
helpText={`user-federation-help:${
isRole ? "ldapRolesDnHelp" : "ldapGroupsDnHelp"
}`}
fieldLabelId={`user-federation:${
isRole ? "ldapRolesDn" : "ldapGroupsDn"
}`}
/>
}
fieldId="kc-ldap-dn"
isRequired
>
<TextInput
isRequired
type="text"
id="kc-ldap-dn"
data-testid="ldap-dn"
name={isRole ? "config.roles.dn[0]" : "config.groups.dn[0]"}
ref={form.register({ required: true })}
validated={
isRole
? form.errors.config?.["roles-dn"]
? ValidatedOptions.error
: ValidatedOptions.default
: form.errors.config?.["groups-dn"]
? ValidatedOptions.error
: ValidatedOptions.default
}
/>
</FormGroup>
<FormGroup
label={
isRole ? t("roleNameLdapAttribute") : t("groupNameLdapAttribute")
}
labelIcon={
<HelpItem
helpText={`user-federation-help:
${
isRole
? "roleNameLdapAttributeHelp"
: "groupNameLdapAttributeHelp"
}`}
fieldLabelId={`user-federation:${
isRole ? "roleNameLdapAttribute" : "groupNameLdapAttribute"
}`}
/>
}
fieldId="kc-name-attribute"
isRequired
>
<TextInput
isRequired
type="text"
id="kc-name-attribute"
data-testid="name-attribute"
defaultValue="cn"
name={
isRole
? "config.role.name.ldap.attribute[0]"
: "config.group.name.ldap.attribute[0]"
}
ref={form.register}
/>
</FormGroup>
<FormGroup
label={isRole ? t("roleObjectClasses") : t("groupObjectClasses")}
labelIcon={
<HelpItem
helpText={`user-federation-help:
${isRole ? "roleObjectClassesHelp" : "groupObjectClassesHelp"}
`}
fieldLabelId={`user-federation:${
isRole ? "roleObjectClasses" : "groupObjectClasses"
}`}
/>
}
fieldId="kc-object-classes"
isRequired
>
<TextInput
isRequired
type="text"
id="kc-object-classes"
data-testid="object-classes"
defaultValue="groupOfNames"
name={
isRole
? "config.role.object.classes[0]"
: "config.group.object.classes[0]"
}
ref={form.register}
/>
</FormGroup>
{!isRole && (
<>
<FormGroup
label={t("preserveGroupInheritance")}
labelIcon={
<HelpItem
helpText="user-federation-help:preserveGroupInheritanceHelp"
fieldLabelId="user-federation:preserveGroupInheritance"
/>
}
fieldId="kc-preserve-inheritance"
hasNoPaddingTop
>
<Controller
name="config.preserve.group.inheritance"
defaultValue={["true"]}
control={form.control}
render={({ onChange, value }) => (
<Switch
id={"kc-preserve-inheritance"}
isDisabled={false}
onChange={(value) => onChange([`${value}`])}
isChecked={value[0] === "true"}
label={t("common:on")}
labelOff={t("common:off")}
/>
)}
></Controller>
</FormGroup>
<FormGroup
label={t("ignoreMissingGroups")}
labelIcon={
<HelpItem
helpText="user-federation-help:ignoreMissingGroupsHelp"
fieldLabelId="user-federation:ignoreMissingGroups"
/>
}
fieldId="kc-ignore-missing"
hasNoPaddingTop
>
<Controller
name="config.ignore.missing.groups"
defaultValue={["false"]}
control={form.control}
render={({ onChange, value }) => (
<Switch
id={"kc-ignore-missing"}
isDisabled={false}
onChange={(value) => onChange([`${value}`])}
isChecked={value[0] === "true"}
label={t("common:on")}
labelOff={t("common:off")}
/>
)}
></Controller>
</FormGroup>
</>
)}
<FormGroup
label={t("membershipLdapAttribute")}
labelIcon={
<HelpItem
helpText="user-federation-help:membershipLdapAttributeHelp"
fieldLabelId="user-federation:membershipLdapAttribute"
/>
}
fieldId="kc-membership-ldap-attribute"
isRequired
>
<TextInput
isRequired
type="text"
defaultValue="member"
id="kc-membership-ldap-attribute"
data-testid="membership-ldap-attribute"
name="config.membership.ldap.attribute[0]"
ref={form.register}
/>
</FormGroup>
<FormGroup
label={t("membershipAttributeType")}
labelIcon={
<HelpItem
helpText="user-federation-help:membershipAttributeTypeHelp"
fieldLabelId="user-federation:membershipAttributeType"
/>
}
fieldId="kc-membership-attribute-type"
>
<Controller
name="config.membership.attribute.type[0]"
defaultValue="DN"
control={form.control}
render={({ onChange, value }) => (
<Select
toggleId="kc-membership-attribute-type"
onToggle={() =>
setIsMbAttTypeDropdownOpen(!isMbAttTypeDropdownOpen)
}
isOpen={isMbAttTypeDropdownOpen}
onSelect={(_, value) => {
onChange(value as string);
setIsMbAttTypeDropdownOpen(false);
}}
selections={value}
variant={SelectVariant.single}
>
<SelectOption key={0} value="DN">
DN
</SelectOption>
<SelectOption key={1} value="UID">
UID
</SelectOption>
</Select>
)}
></Controller>
</FormGroup>
<FormGroup
label={t("membershipUserLdapAttribute")}
labelIcon={
<HelpItem
helpText="user-federation-help:membershipUserLdapAttributeHelp"
fieldLabelId="user-federation:membershipUserLdapAttribute"
/>
}
fieldId="kc-membership-user-ldap-attribute"
isRequired
>
<TextInput
isRequired
type="text"
id="kc-membership-user-ldap-attribute"
data-testid="membership-user-ldap-attribute"
defaultValue="uid"
name="config.membership.user.ldap.attribute[0]"
ref={form.register}
/>
</FormGroup>
<FormGroup
label={t("ldapFilter")}
labelIcon={
<HelpItem
helpText="user-federation:ldapFilterHelp"
fieldLabelId="user-federation:ldapFilter"
/>
}
fieldId="kc-ldap-filter"
>
<TextInput
type="text"
id="kc-ldap-filter"
data-testid="ldap-filter"
name={
isRole
? "config.roles.ldap.filter[0]"
: "config.groups.ldap.filter[0]"
}
ref={form.register}
/>
</FormGroup>
<FormGroup
label={t("mode")}
labelIcon={
<HelpItem
helpText="user-federation-help:modeHelp"
fieldLabelId="user-federation:mode"
/>
}
fieldId="kc-mode"
>
<Controller
name="config.mode[0]"
defaultValue="READ_ONLY"
control={form.control}
render={({ onChange, value }) => (
<Select
toggleId="kc-mode"
onToggle={() => setIsModeDropdownOpen(!isModeDropdownOpen)}
isOpen={isModeDropdownOpen}
onSelect={(_, value) => {
onChange(value as string);
setIsModeDropdownOpen(false);
}}
selections={value}
variant={SelectVariant.single}
>
<SelectOption key={0} value="READ_ONLY">
READ_ONLY
</SelectOption>
<SelectOption key={1} value="LDAP_ONLY">
LDAP_ONLY
</SelectOption>
<SelectOption key={2} value="IMPORT">
IMPORT
</SelectOption>
</Select>
)}
></Controller>
</FormGroup>
{isRole ? (
<FormGroup
label={t("userRolesRetrieveStrategy")}
labelIcon={
<HelpItem
helpText="user-federation-help:userRolesRetrieveStrategyHelp"
fieldLabelId="user-federation:userRolesRetrieveStrategy"
/>
}
fieldId="kc-user-retrieve-strategy"
>
<Controller
name="config.user.roles.retrieve.strategy[0]"
defaultValue="LOAD_ROLES_BY_MEMBER_ATTRIBUTE"
control={form.control}
render={({ onChange, value }) => (
<Select
toggleId="kc-user-retrieve-strategy"
onToggle={() =>
setIsRetrieveStratDropdownOpen(!isRetrieveStratDropdownOpen)
}
isOpen={isRetrieveStratDropdownOpen}
onSelect={(_, value) => {
onChange(value as string);
setIsRetrieveStratDropdownOpen(false);
}}
selections={value}
variant={SelectVariant.single}
>
<SelectOption key={0} value="LOAD_ROLES_BY_MEMBER_ATTRIBUTE">
LOAD_ROLES_BY_MEMBER_ATTRIBUTE
</SelectOption>
<SelectOption
key={1}
value="GET_ROLES_FROM_USER_MEMBEROF_ATTRIBUTE"
>
GET_ROLES_FROM_USER_MEMBEROF_ATTRIBUTE
</SelectOption>
<SelectOption
hidden={vendorType !== "ad"}
key={2}
value="LOAD_ROLES_BY_MEMBER_ATTRIBUTE_RECURSIVELY"
>
LOAD_ROLES_BY_MEMBER_ATTRIBUTE_RECURSIVELY
</SelectOption>
</Select>
)}
></Controller>
</FormGroup>
) : (
<FormGroup
label={t("userGroupsRetrieveStrategy")}
labelIcon={
<HelpItem
helpText="user-federation-help:userGroupsRetrieveStrategyHelp"
fieldLabelId="user-federation:userGroupsRetrieveStrategy"
/>
}
fieldId="kc-user-retrieve-strategy"
>
<Controller
name="config.user.roles.retrieve.strategy[0]"
defaultValue="LOAD_GROUPS_BY_MEMBER_ATTRIBUTE"
control={form.control}
render={({ onChange, value }) => (
<Select
toggleId="kc-user-retrieve-strategy"
onToggle={() =>
setIsRetrieveStratDropdownOpen(!isRetrieveStratDropdownOpen)
}
isOpen={isRetrieveStratDropdownOpen}
onSelect={(_, value) => {
onChange(value as string);
setIsRetrieveStratDropdownOpen(false);
}}
selections={value}
variant={SelectVariant.single}
>
<SelectOption key={0} value="LOAD_GROUPS_BY_MEMBER_ATTRIBUTE">
LOAD_GROUPS_BY_MEMBER_ATTRIBUTE
</SelectOption>
<SelectOption
key={1}
value="GET_GROUPS_FROM_USER_MEMBEROF_ATTRIBUTE"
>
GET_GROUPS_FROM_USER_MEMBEROF_ATTRIBUTE
</SelectOption>
<SelectOption
hidden={vendorType !== "ad"}
key={2}
value="LOAD_GROUPS_BY_MEMBER_ATTRIBUTE_RECURSIVELY"
>
LOAD_GROUPS_BY_MEMBER_ATTRIBUTE_RECURSIVELY
</SelectOption>
</Select>
)}
></Controller>
</FormGroup>
)}
<FormGroup
label={t("memberofLdapAttribute")}
labelIcon={
<HelpItem
helpText="user-federation-help:memberofLdapAttributeHelp"
fieldLabelId="user-federation:memberofLdapAttribute"
/>
}
fieldId="kc-member-of-attribute"
isRequired
>
<TextInput
isRequired
type="text"
id="kc-member-of-attribute"
defaultValue="memberOf"
data-testid="member-of-attribute"
name="config.memberof.ldap.attribute[0]"
ref={form.register}
/>
</FormGroup>
{isRole && (
<>
<FormGroup
label={t("useRealmRolesMapping")}
labelIcon={
<HelpItem
helpText="user-federation-help:useRealmRolesMappingHelp"
fieldLabelId="user-federation:useRealmRolesMapping"
/>
}
fieldId="kc-use-realm-roles"
hasNoPaddingTop
>
<Controller
name="config.use.realm.roles.mapping"
defaultValue={["true"]}
control={form.control}
render={({ onChange, value }) => (
<Switch
id={"kc-use-realm-roles"}
isDisabled={false}
onChange={(value) => onChange([`${value}`])}
isChecked={value[0] === "true"}
label={t("common:on")}
labelOff={t("common:off")}
/>
)}
></Controller>
</FormGroup>
<FormGroup
label={t("common:clientId")}
labelIcon={
<HelpItem
helpText="user-federation-help:clientIdHelp"
fieldLabelId="clientId"
/>
}
fieldId="kc-client-id"
>
<Controller
name="config.client.id[0]"
defaultValue=""
control={form.control}
render={({ onChange, value }) => (
<Select
toggleId="kc-client-id"
onToggle={() =>
setIsClientIdDropdownOpen(!isClientIdDropdownOpen)
}
isOpen={isClientIdDropdownOpen}
onSelect={(_, value) => {
onChange(value as string);
setIsClientIdDropdownOpen(false);
}}
selections={value}
variant={SelectVariant.single}
>
{clients.map((client) => (
<SelectOption key={client.id} value={client.id}>
{client.clientId}
</SelectOption>
))}
</Select>
)}
></Controller>
</FormGroup>
</>
)}
{!isRole && (
<>
<FormGroup
label={t("mappedGroupAttributes")}
labelIcon={
<HelpItem
helpText="user-federation-help:mappedGroupAttributesHelp"
fieldLabelId="user-federation:mappedGroupAttributes"
/>
}
fieldId="kc-mapped-attributes"
>
<TextInput
type="text"
id="kc-mapped-attributes"
data-testid="mapped-attributes"
name="config.mapped.group.attributes[0]"
ref={form.register}
/>
</FormGroup>
<FormGroup
label={t("dropNonexistingGroupsDuringSync")}
labelIcon={
<HelpItem
helpText="user-federation-help:dropNonexistingGroupsDuringSyncHelp"
fieldLabelId="user-federation:dropNonexistingGroupsDuringSync"
/>
}
fieldId="kc-drop-nonexisting"
hasNoPaddingTop
>
<Controller
name="config.drop.non.existing.groups.during.sync"
defaultValue={["false"]}
control={form.control}
render={({ onChange, value }) => (
<Switch
id={"kc-drop-nonexisting"}
isDisabled={false}
onChange={(value) => onChange([`${value}`])}
isChecked={value[0] === "true"}
label={t("common:on")}
labelOff={t("common:off")}
/>
)}
></Controller>
</FormGroup>
<FormGroup
label={t("groupsPath")}
labelIcon={
<HelpItem
helpText="user-federation-help:groupsPathHelp"
fieldLabelId="user-federation:groupsPath"
/>
}
fieldId="kc-path"
isRequired
>
<TextInput
isRequired
type="text"
id="kc-path"
data-testid="path"
defaultValue="/"
name="config.groups.path[0]"
ref={form.register({ required: true })}
validated={
form.errors.config?.["groups-path"]
? ValidatedOptions.error
: ValidatedOptions.default
}
/>
</FormGroup>
</>
)}
</>
);
};

View file

@ -1,219 +0,0 @@
import { FormGroup, Switch, TextInput } from "@patternfly/react-core";
import React from "react";
import { HelpItem } from "../../../components/help-enabler/HelpItem";
import { Controller, UseFormMethods } from "react-hook-form";
import { useTranslation } from "react-i18next";
export type LdapMapperUserAttributeProps = {
form: UseFormMethods;
mapperType: string | undefined;
};
export const LdapMapperUserAttribute = ({
form,
mapperType,
}: LdapMapperUserAttributeProps) => {
const { t } = useTranslation("user-federation");
return (
<>
<FormGroup
label={t("userModelAttribute")}
labelIcon={
<HelpItem
helpText="user-federation-help:userModelAttributeHelp"
fieldLabelId="user-federation:userModelAttribute"
/>
}
fieldId="kc-user-model-attribute"
isRequired
>
<TextInput
isRequired
type="text"
id="kc-user-model-attribute"
data-testid="mapper-userModelAttribute-fld"
name="config.user.model.attribute[0]"
ref={form.register}
/>
</FormGroup>
<FormGroup
label={t("ldapAttribute")}
labelIcon={
<HelpItem
helpText="user-federation:ldapAttributeHelp"
fieldLabelId="user-federation:ldapAttribute"
/>
}
fieldId="kc-ldap-attribute"
isRequired
>
<TextInput
isRequired
type="text"
id="kc-ldap-attribute"
data-testid="mapper-ldapAttribute-fld"
name="config.ldap.attribute[0]"
ref={form.register}
/>
</FormGroup>
<FormGroup
label={t("readOnly")}
labelIcon={
<HelpItem
helpText="user-federation-help:readOnlyHelp"
fieldLabelId="user-federation:readOnly"
/>
}
fieldId="kc-read-only"
hasNoPaddingTop
>
<Controller
name="config.read.only"
defaultValue={
mapperType === "user-attribute-ldap-mapper" ? ["true"] : ["false"]
}
control={form.control}
render={({ onChange, value }) => (
<Switch
id={"kc-read-only"}
isDisabled={false}
onChange={(value) => onChange([`${value}`])}
isChecked={value[0] === "true"}
label={t("common:on")}
labelOff={t("common:off")}
/>
)}
></Controller>
</FormGroup>
<FormGroup
label={t("alwaysReadValueFromLdap")}
labelIcon={
<HelpItem
helpText="user-federation:alwaysReadValueFromLdapHelp"
fieldLabelId="user-federation:alwaysReadValueFromLdap"
/>
}
fieldId="kc-always-read-value"
hasNoPaddingTop
>
<Controller
name="config.always.read.value.from.ldap"
defaultValue={["false"]}
control={form.control}
render={({ onChange, value }) => (
<Switch
id={"kc-always-read-value"}
isDisabled={false}
onChange={(value) => onChange([`${value}`])}
isChecked={value[0] === "true"}
label={t("common:on")}
labelOff={t("common:off")}
/>
)}
></Controller>
</FormGroup>
<FormGroup
label={t("isMandatoryInLdap")}
labelIcon={
<HelpItem
helpText="user-federation-help:isMandatoryInLdapHelp"
fieldLabelId="user-federation:isMandatoryInLdap"
/>
}
fieldId="kc-is-mandatory"
hasNoPaddingTop
>
<Controller
name="config.is.mandatory.in.ldap"
defaultValue={["false"]}
control={form.control}
render={({ onChange, value }) => (
<Switch
id={"kc-is-mandatory"}
isDisabled={false}
onChange={(value) => onChange([`${value}`])}
isChecked={value[0] === "true"}
label={t("common:on")}
labelOff={t("common:off")}
/>
)}
></Controller>
</FormGroup>
<FormGroup
label={t("attributeDefaultValue")}
labelIcon={
<HelpItem
helpText="user-federation-help:attributeDefaultValueHelp"
fieldLabelId="user-federation:attributeDefaultValue"
/>
}
fieldId="kc-attribute-default-value"
>
<TextInput
type="text"
id="kc-attribute-default-value"
data-testid="mapper-attributeDefaultValue-fld"
name="config.attribute.default.value[0]"
ref={form.register}
/>
</FormGroup>
<FormGroup
label={t("isBinaryAttribute")}
labelIcon={
<HelpItem
helpText="user-federation-help:isBinaryAttributeHelp"
fieldLabelId="user-federation:isBinaryAttribute"
/>
}
fieldId="kc-is-binary"
hasNoPaddingTop
>
<Controller
name="config.is.binary.attribute"
defaultValue={["false"]}
control={form.control}
render={({ onChange, value }) => (
<Switch
id={"kc-is-binary"}
isDisabled={false}
onChange={(value) => onChange([`${value}`])}
isChecked={value[0] === "true"}
label={t("common:on")}
labelOff={t("common:off")}
/>
)}
></Controller>
</FormGroup>
{mapperType === "certificate-ldap-mapper" ? (
<FormGroup
label={t("derFormatted")}
labelIcon={
<HelpItem
helpText="user-federation-help:derFormattedHelp"
fieldLabelId="user-federation:derFormatted"
/>
}
fieldId="kc-der-formatted"
hasNoPaddingTop
>
<Controller
name="config.is.der.formatted"
defaultValue={["false"]}
control={form.control}
render={({ onChange, value }) => (
<Switch
id="kc-der-formatted"
isDisabled={false}
onChange={(value) => onChange([`${value}`])}
isChecked={value[0] === "true"}
label={t("common:on")}
labelOff={t("common:off")}
/>
)}
></Controller>
</FormGroup>
) : null}
</>
);
};