Identity providers(mappers): update "create" form fields for all SAML mapper types (#1282)
This commit is contained in:
parent
ed0949a44f
commit
3b677c6e8e
5 changed files with 586 additions and 175 deletions
|
@ -142,7 +142,7 @@ describe("Identity provider test", () => {
|
|||
masthead.checkNotificationMessage(createMapperSuccessMsg);
|
||||
});
|
||||
|
||||
it("should add SAML mapper", () => {
|
||||
it("should add SAML mapper of type Advanced Attribute to Role", () => {
|
||||
sidebarPage.goToIdentityProviders();
|
||||
|
||||
listingPage.goToItemDetails("saml");
|
||||
|
@ -151,7 +151,7 @@ describe("Identity provider test", () => {
|
|||
|
||||
addMapperPage.emptyStateAddMapper();
|
||||
|
||||
addMapperPage.fillSAMLorOIDCMapper("SAML mapper");
|
||||
addMapperPage.addAdvancedAttrToRoleMapper("SAML mapper");
|
||||
|
||||
masthead.checkNotificationMessage(createMapperSuccessMsg);
|
||||
});
|
||||
|
@ -172,6 +172,78 @@ describe("Identity provider test", () => {
|
|||
masthead.checkNotificationMessage(createMapperSuccessMsg);
|
||||
});
|
||||
|
||||
it("should add SAML mapper of type Hardcoded User Session Attribute", () => {
|
||||
sidebarPage.goToIdentityProviders();
|
||||
|
||||
listingPage.goToItemDetails("saml");
|
||||
|
||||
addMapperPage.goToMappersTab();
|
||||
|
||||
addMapperPage.addMapper();
|
||||
|
||||
addMapperPage.addHardcodedUserSessionAttrMapper(
|
||||
"Hardcoded User Session Attribute"
|
||||
);
|
||||
|
||||
masthead.checkNotificationMessage(createMapperSuccessMsg);
|
||||
});
|
||||
|
||||
it("should add SAML mapper of type Attribute Importer", () => {
|
||||
sidebarPage.goToIdentityProviders();
|
||||
|
||||
listingPage.goToItemDetails("saml");
|
||||
|
||||
addMapperPage.goToMappersTab();
|
||||
|
||||
addMapperPage.addMapper();
|
||||
|
||||
addMapperPage.addAttrImporterMapper("Attribute Importer");
|
||||
|
||||
masthead.checkNotificationMessage(createMapperSuccessMsg);
|
||||
});
|
||||
|
||||
it("should add SAML mapper of type Hardcoded Role", () => {
|
||||
sidebarPage.goToIdentityProviders();
|
||||
|
||||
listingPage.goToItemDetails("saml");
|
||||
|
||||
addMapperPage.goToMappersTab();
|
||||
|
||||
addMapperPage.addMapper();
|
||||
|
||||
addMapperPage.addHardcodedRoleMapper("Hardcoded Role");
|
||||
|
||||
masthead.checkNotificationMessage(createMapperSuccessMsg);
|
||||
});
|
||||
|
||||
it("should add SAML mapper of type Hardcoded Attribute", () => {
|
||||
sidebarPage.goToIdentityProviders();
|
||||
|
||||
listingPage.goToItemDetails("saml");
|
||||
|
||||
addMapperPage.goToMappersTab();
|
||||
|
||||
addMapperPage.addMapper();
|
||||
|
||||
addMapperPage.addHardcodedAttrMapper("Hardcoded Attribute");
|
||||
|
||||
masthead.checkNotificationMessage(createMapperSuccessMsg);
|
||||
});
|
||||
|
||||
it("should add SAML mapper of type SAML Attribute To Role", () => {
|
||||
sidebarPage.goToIdentityProviders();
|
||||
|
||||
listingPage.goToItemDetails("saml");
|
||||
|
||||
addMapperPage.goToMappersTab();
|
||||
|
||||
addMapperPage.addMapper();
|
||||
|
||||
addMapperPage.addSAMLAttributeToRoleMapper("SAML Attribute To Role");
|
||||
|
||||
masthead.checkNotificationMessage(createMapperSuccessMsg);
|
||||
});
|
||||
|
||||
it("should edit Username Template Importer mapper", () => {
|
||||
sidebarPage.goToIdentityProviders();
|
||||
|
||||
|
|
|
@ -7,6 +7,12 @@ export default class AddMapperPage {
|
|||
|
||||
private mapperNameInput = "#kc-name";
|
||||
private mapperRoleInput = "mapper-role-input";
|
||||
private attributeName = "attribute-name";
|
||||
private attributeFriendlyName = "attribute-friendly-name";
|
||||
private attributeValue = "attribute-value";
|
||||
private userAttribute = "user-attribute";
|
||||
private userAttributeName = "user-attribute-name";
|
||||
private userAttributeValue = "user-attribute-value";
|
||||
private userSessionAttribute = "user-session-attribute";
|
||||
private userSessionAttributeValue = "user-session-attribute-value";
|
||||
private newMapperSaveButton = "new-mapper-save-button";
|
||||
|
@ -91,7 +97,7 @@ export default class AddMapperPage {
|
|||
return this;
|
||||
}
|
||||
|
||||
fillSAMLorOIDCMapper(name: string) {
|
||||
addAdvancedAttrToRoleMapper(name: string) {
|
||||
cy.get(this.mapperNameInput).clear();
|
||||
|
||||
cy.get(this.mapperNameInput).clear().type(name);
|
||||
|
@ -150,6 +156,135 @@ export default class AddMapperPage {
|
|||
return this;
|
||||
}
|
||||
|
||||
addHardcodedUserSessionAttrMapper(name: string) {
|
||||
cy.get(this.mapperNameInput).clear();
|
||||
|
||||
cy.get(this.mapperNameInput).clear().type(name);
|
||||
|
||||
cy.get(this.syncmodeSelectToggle).click();
|
||||
|
||||
cy.findByTestId("inherit").click();
|
||||
|
||||
cy.get(this.idpMapperSelectToggle).click();
|
||||
|
||||
cy.findByTestId(this.idpMapperSelect)
|
||||
.contains("Hardcoded User Session Attribute")
|
||||
.click();
|
||||
|
||||
cy.findByTestId(this.userSessionAttribute).clear();
|
||||
cy.findByTestId(this.userSessionAttribute).type("user session attribute");
|
||||
|
||||
cy.findByTestId(this.userSessionAttributeValue).clear();
|
||||
cy.findByTestId(this.userSessionAttributeValue).type(
|
||||
"user session attribute value"
|
||||
);
|
||||
|
||||
this.saveNewMapper();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
addAttrImporterMapper(name: string) {
|
||||
cy.get(this.mapperNameInput).clear();
|
||||
|
||||
cy.get(this.mapperNameInput).clear().type(name);
|
||||
|
||||
cy.get(this.syncmodeSelectToggle).click();
|
||||
|
||||
cy.findByTestId("inherit").click();
|
||||
|
||||
cy.get(this.idpMapperSelectToggle).click();
|
||||
|
||||
cy.findByTestId(this.idpMapperSelect)
|
||||
.contains("Attribute Importer")
|
||||
.click();
|
||||
|
||||
cy.findByTestId(this.attributeName).clear();
|
||||
cy.findByTestId(this.attributeName).type("attribute name");
|
||||
|
||||
cy.findByTestId(this.attributeFriendlyName).clear();
|
||||
cy.findByTestId(this.attributeFriendlyName).type("friendly name");
|
||||
|
||||
cy.findByTestId(this.userAttributeName).clear();
|
||||
cy.findByTestId(this.userAttributeName).type("user attribute name");
|
||||
|
||||
this.saveNewMapper();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
addHardcodedRoleMapper(name: string) {
|
||||
cy.get(this.mapperNameInput).clear();
|
||||
|
||||
cy.get(this.mapperNameInput).clear().type(name);
|
||||
|
||||
cy.get(this.syncmodeSelectToggle).click();
|
||||
|
||||
cy.findByTestId("inherit").click();
|
||||
|
||||
cy.get(this.idpMapperSelectToggle).click();
|
||||
|
||||
cy.findByTestId(this.idpMapperSelect).contains("Hardcoded Role").click();
|
||||
|
||||
cy.findByTestId(this.mapperRoleInput).clear();
|
||||
cy.findByTestId(this.mapperRoleInput).type("admin");
|
||||
|
||||
this.saveNewMapper();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
addHardcodedAttrMapper(name: string) {
|
||||
cy.get(this.mapperNameInput).clear();
|
||||
|
||||
cy.get(this.mapperNameInput).clear().type(name);
|
||||
|
||||
cy.get(this.syncmodeSelectToggle).click();
|
||||
|
||||
cy.findByTestId("inherit").click();
|
||||
|
||||
cy.get(this.idpMapperSelectToggle).click();
|
||||
|
||||
cy.findByTestId(this.idpMapperSelect)
|
||||
.contains("Hardcoded Attribute")
|
||||
.click();
|
||||
|
||||
cy.findByTestId(this.userAttribute).clear();
|
||||
cy.findByTestId(this.userAttribute).type("user session attribute");
|
||||
|
||||
cy.findByTestId(this.userAttributeValue).clear();
|
||||
cy.findByTestId(this.userAttributeValue).type(
|
||||
"user session attribute value"
|
||||
);
|
||||
|
||||
this.saveNewMapper();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
addSAMLAttributeToRoleMapper(name: string) {
|
||||
cy.get(this.mapperNameInput).clear();
|
||||
|
||||
cy.get(this.mapperNameInput).clear().type(name);
|
||||
|
||||
cy.get(this.syncmodeSelectToggle).click();
|
||||
|
||||
cy.findByTestId("inherit").click();
|
||||
|
||||
cy.get(this.idpMapperSelectToggle).click();
|
||||
|
||||
cy.findByTestId(this.idpMapperSelect)
|
||||
.contains("SAML Attribute To Role")
|
||||
.click();
|
||||
|
||||
cy.findByTestId(this.mapperRoleInput).clear();
|
||||
cy.findByTestId(this.mapperRoleInput).type("admin");
|
||||
|
||||
this.saveNewMapper();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
editUsernameTemplateImporterMapper() {
|
||||
cy.get(this.syncmodeSelectToggle).click();
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@ import {
|
|||
import { FormAccess } from "../../components/form-access/FormAccess";
|
||||
import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
|
||||
import type { IdentityProviderAddMapperParams } from "../routes/AddMapper";
|
||||
import _ from "lodash";
|
||||
import { AssociatedRolesModal } from "../../realm-roles/AssociatedRolesModal";
|
||||
import type { RoleRepresentation } from "../../model/role-model";
|
||||
import { useAlerts } from "../../components/alert/Alerts";
|
||||
|
@ -35,8 +34,9 @@ import type { IdentityProviderEditMapperParams } from "../routes/EditMapper";
|
|||
import { convertToFormValues } from "../../util";
|
||||
import { toIdentityProvider } from "../routes/IdentityProvider";
|
||||
import type IdentityProviderMapperRepresentation from "@keycloak/keycloak-admin-client/lib/defs/identityProviderMapperRepresentation";
|
||||
import { AddMapperForm } from "./AddMapperForm";
|
||||
|
||||
type IdPMapperRepresentationWithAttributes =
|
||||
export type IdPMapperRepresentationWithAttributes =
|
||||
IdentityProviderMapperRepresentation & {
|
||||
attributes: KeyValueType[];
|
||||
};
|
||||
|
@ -166,19 +166,39 @@ export const AddMapper = () => {
|
|||
});
|
||||
};
|
||||
|
||||
const syncModes = ["inherit", "import", "legacy", "force"];
|
||||
const [syncModeOpen, setSyncModeOpen] = useState(false);
|
||||
const targetOptions = ["local", "brokerId", "brokerUsername"];
|
||||
const [targetOptionsOpen, setTargetOptionsOpen] = useState(false);
|
||||
const [mapperTypeOpen, setMapperTypeOpen] = useState(false);
|
||||
const [selectedRole, setSelectedRole] = useState<RoleRepresentation[]>([]);
|
||||
|
||||
const formValues = form.getValues();
|
||||
|
||||
const isAdvancedAttrToRole =
|
||||
formValues.identityProviderMapper === "saml-advanced-role-idp-mapper";
|
||||
|
||||
const isAttributeImporter =
|
||||
formValues.identityProviderMapper === "saml-user-attribute-idp-mapper";
|
||||
|
||||
const isHardcodedAttribute =
|
||||
form.getValues().identityProviderMapper ===
|
||||
"hardcoded-attribute-idp-mapper";
|
||||
|
||||
const isHardcodedRole =
|
||||
formValues.identityProviderMapper === "oidc-hardcoded-role-idp-mapper";
|
||||
|
||||
const isHardcodedUserSessionAttribute =
|
||||
formValues.identityProviderMapper ===
|
||||
"hardcoded-user-session-attribute-idp-mapper";
|
||||
|
||||
const isSAMLAttributeToRole =
|
||||
formValues.identityProviderMapper === "saml-role-idp-mapper";
|
||||
|
||||
const isUsernameTemplateImporter =
|
||||
formValues.identityProviderMapper === "saml-username-idp-mapper";
|
||||
|
||||
const toggleModal = () => {
|
||||
setRolesModalOpen(!rolesModalOpen);
|
||||
};
|
||||
|
||||
const formValues = form.getValues();
|
||||
|
||||
return (
|
||||
<PageSection variant="light">
|
||||
<ViewHeader
|
||||
|
@ -232,155 +252,18 @@ export const AddMapper = () => {
|
|||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
<FormGroup
|
||||
label={t("common:name")}
|
||||
labelIcon={
|
||||
<HelpItem
|
||||
id="name-help-icon"
|
||||
helpText="identity-providers-help:addIdpMapperName"
|
||||
forLabel={t("common:name")}
|
||||
forID={t(`common:helpLabel`, { label: t("common:name") })}
|
||||
<AddMapperForm
|
||||
form={form}
|
||||
id={id}
|
||||
providerId={providerId}
|
||||
mapperTypes={mapperTypes}
|
||||
updateMapperType={setMapperType}
|
||||
formValues={formValues}
|
||||
mapperType={mapperType}
|
||||
/>
|
||||
}
|
||||
fieldId="kc-name"
|
||||
isRequired
|
||||
validated={
|
||||
errors.name ? ValidatedOptions.error : ValidatedOptions.default
|
||||
}
|
||||
helperTextInvalid={t("common:required")}
|
||||
>
|
||||
<TextInput
|
||||
ref={register({ required: true })}
|
||||
type="text"
|
||||
datatest-id="name-input"
|
||||
id="kc-name"
|
||||
name="name"
|
||||
isDisabled={!!id}
|
||||
validated={
|
||||
errors.name ? ValidatedOptions.error : ValidatedOptions.default
|
||||
}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup
|
||||
label={t("syncModeOverride")}
|
||||
isRequired
|
||||
labelIcon={
|
||||
<HelpItem
|
||||
helpText="identity-providers-help:syncModeOverride"
|
||||
forLabel={t("syncModeOverride")}
|
||||
forID={t(`common:helpLabel`, { label: t("syncModeOverride") })}
|
||||
/>
|
||||
}
|
||||
fieldId="syncMode"
|
||||
>
|
||||
<Controller
|
||||
name="config.syncMode"
|
||||
defaultValue={syncModes[0]}
|
||||
control={control}
|
||||
render={({ onChange, value }) => (
|
||||
<Select
|
||||
toggleId="syncMode"
|
||||
datatest-id="syncmode-select"
|
||||
required
|
||||
direction="down"
|
||||
onToggle={() => setSyncModeOpen(!syncModeOpen)}
|
||||
onSelect={(_, value) => {
|
||||
onChange(value.toString().toUpperCase());
|
||||
setSyncModeOpen(false);
|
||||
}}
|
||||
selections={t(`syncModes.${value.toLowerCase()}`)}
|
||||
variant={SelectVariant.single}
|
||||
aria-label={t("syncMode")}
|
||||
isOpen={syncModeOpen}
|
||||
>
|
||||
{syncModes.map((option) => (
|
||||
<SelectOption
|
||||
selected={option === value}
|
||||
key={option}
|
||||
data-testid={option}
|
||||
value={option.toUpperCase()}
|
||||
>
|
||||
{t(`syncModes.${option}`)}
|
||||
</SelectOption>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup
|
||||
label={t("mapperType")}
|
||||
labelIcon={
|
||||
<HelpItem
|
||||
helpText={
|
||||
mapperType === "attributeImporter" &&
|
||||
(providerId === "oidc" || providerId === "keycloak-oidc")
|
||||
? `identity-providers-help:oidcAttributeImporter`
|
||||
: `identity-providers-help:${mapperType}`
|
||||
}
|
||||
forLabel={t("mapperType")}
|
||||
forID={t(`common:helpLabel`, { label: t("mapperType") })}
|
||||
/>
|
||||
}
|
||||
fieldId="identityProviderMapper"
|
||||
>
|
||||
<Controller
|
||||
name="identityProviderMapper"
|
||||
defaultValue={
|
||||
providerId === "saml"
|
||||
? "saml-advanced-role-idp-mapper"
|
||||
: "oidc-advanced-role-idp-mapper"
|
||||
}
|
||||
control={control}
|
||||
render={({ onChange, value }) => (
|
||||
<Select
|
||||
toggleId="identityProviderMapper"
|
||||
data-testid="idp-mapper-select"
|
||||
isDisabled={!!id}
|
||||
required
|
||||
direction="down"
|
||||
onToggle={() => setMapperTypeOpen(!mapperTypeOpen)}
|
||||
onSelect={(e, value) => {
|
||||
const theMapper =
|
||||
mapperTypes &&
|
||||
Object.values(mapperTypes).find(
|
||||
(item) =>
|
||||
item.name?.toLowerCase() ===
|
||||
value.toString().toLowerCase()
|
||||
);
|
||||
|
||||
setMapperType(_.camelCase(value.toString()));
|
||||
onChange(theMapper?.id);
|
||||
setMapperTypeOpen(false);
|
||||
}}
|
||||
selections={
|
||||
mapperTypes &&
|
||||
Object.values(mapperTypes).find(
|
||||
(item) => item.id?.toLowerCase() === value
|
||||
)?.name
|
||||
}
|
||||
variant={SelectVariant.single}
|
||||
aria-label={t("syncMode")}
|
||||
isOpen={mapperTypeOpen}
|
||||
>
|
||||
{mapperTypes &&
|
||||
Object.values(mapperTypes).map((option) => (
|
||||
<SelectOption
|
||||
selected={option === value}
|
||||
datatest-id={option.id}
|
||||
key={option.name}
|
||||
value={option.name?.toUpperCase()}
|
||||
>
|
||||
{t(`mapperTypes.${_.camelCase(option.name)}`)}
|
||||
</SelectOption>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
/>
|
||||
</FormGroup>
|
||||
{isSAMLorOIDC ? (
|
||||
<>
|
||||
{formValues.identityProviderMapper ===
|
||||
"saml-advanced-role-idp-mapper" && (
|
||||
{isAdvancedAttrToRole && (
|
||||
<>
|
||||
<FormGroup
|
||||
label={t("common:attributes")}
|
||||
|
@ -430,8 +313,7 @@ export const AddMapper = () => {
|
|||
</FormGroup>
|
||||
</>
|
||||
)}
|
||||
{formValues.identityProviderMapper ===
|
||||
"saml-username-idp-mapper" && (
|
||||
{isUsernameTemplateImporter && (
|
||||
<>
|
||||
<FormGroup
|
||||
label={t("template")}
|
||||
|
@ -526,11 +408,9 @@ export const AddMapper = () => {
|
|||
</FormGroup>
|
||||
</>
|
||||
)}
|
||||
{[
|
||||
"saml-advanced-role-idp-mapper",
|
||||
"oidc-hardcoded-role-idp-mapper",
|
||||
"saml-role-idp-mapper",
|
||||
].includes(formValues.identityProviderMapper!) && (
|
||||
{(isAdvancedAttrToRole ||
|
||||
isHardcodedRole ||
|
||||
isSAMLAttributeToRole) && (
|
||||
<FormGroup
|
||||
label={t("common:role")}
|
||||
labelIcon={
|
||||
|
@ -572,15 +452,11 @@ export const AddMapper = () => {
|
|||
</Button>
|
||||
</FormGroup>
|
||||
)}
|
||||
{[
|
||||
"hardcoded-user-session-attribute-idp-mapper",
|
||||
"hardcoded-attribute-idp-mapper",
|
||||
].includes(formValues.identityProviderMapper!) && (
|
||||
{(isHardcodedAttribute || isHardcodedUserSessionAttribute) && (
|
||||
<>
|
||||
<FormGroup
|
||||
label={
|
||||
formValues.identityProviderMapper ===
|
||||
"hardcoded-user-session-attribute-idp-mapper"
|
||||
isHardcodedUserSessionAttribute
|
||||
? t("userSessionAttribute")
|
||||
: t("userAttribute")
|
||||
}
|
||||
|
@ -607,7 +483,11 @@ export const AddMapper = () => {
|
|||
type="text"
|
||||
defaultValue={currentMapper?.config.attribute}
|
||||
id="kc-attribute"
|
||||
data-testid="user-session-attribute"
|
||||
data-testid={
|
||||
isHardcodedUserSessionAttribute
|
||||
? "user-session-attribute"
|
||||
: "user-attribute"
|
||||
}
|
||||
name="config.attribute"
|
||||
validated={
|
||||
errors.name
|
||||
|
@ -617,14 +497,24 @@ export const AddMapper = () => {
|
|||
/>
|
||||
</FormGroup>
|
||||
<FormGroup
|
||||
label={t("userSessionAttributeValue")}
|
||||
label={
|
||||
isHardcodedUserSessionAttribute
|
||||
? t("userSessionAttributeValue")
|
||||
: t("userAttributeValue")
|
||||
}
|
||||
labelIcon={
|
||||
<HelpItem
|
||||
id="user-session-attribute-value-help-icon"
|
||||
helpText="identity-providers-help:userAttributeValue"
|
||||
forLabel={t("userSessionAttributeValue")}
|
||||
forLabel={
|
||||
isHardcodedUserSessionAttribute
|
||||
? t("userSessionAttributeValue")
|
||||
: t("userAttributeValue")
|
||||
}
|
||||
forID={t(`common:helpLabel`, {
|
||||
label: t("userSessionAttributeValue"),
|
||||
label: isHardcodedUserSessionAttribute
|
||||
? t("userSessionAttributeValue")
|
||||
: t("userAttributeValue"),
|
||||
})}
|
||||
/>
|
||||
}
|
||||
|
@ -640,7 +530,11 @@ export const AddMapper = () => {
|
|||
ref={register()}
|
||||
type="text"
|
||||
defaultValue={currentMapper?.config["attribute-value"]}
|
||||
data-testid="user-session-attribute-value"
|
||||
data-testid={
|
||||
isHardcodedUserSessionAttribute
|
||||
? "user-session-attribute-value"
|
||||
: "user-attribute-value"
|
||||
}
|
||||
id="kc-user-session-attribute-value"
|
||||
name="config.attribute-value"
|
||||
validated={
|
||||
|
@ -652,6 +546,114 @@ export const AddMapper = () => {
|
|||
</FormGroup>
|
||||
</>
|
||||
)}
|
||||
{isAttributeImporter && (
|
||||
<>
|
||||
<FormGroup
|
||||
label={t("mapperAttributeName")}
|
||||
labelIcon={
|
||||
<HelpItem
|
||||
id="user-session-attribute-help-icon"
|
||||
helpText="identity-providers-help:attributeName"
|
||||
forLabel={t("mapperAttributeName")}
|
||||
forID={t(`common:helpLabel`, {
|
||||
label: t("mapperAttributeName"),
|
||||
})}
|
||||
/>
|
||||
}
|
||||
fieldId="kc-attribute-name"
|
||||
validated={
|
||||
errors.name
|
||||
? ValidatedOptions.error
|
||||
: ValidatedOptions.default
|
||||
}
|
||||
helperTextInvalid={t("common:required")}
|
||||
>
|
||||
<TextInput
|
||||
ref={register()}
|
||||
type="text"
|
||||
defaultValue={currentMapper?.config["attribute-name"]}
|
||||
id="kc-attribute-name"
|
||||
data-testid="attribute-name"
|
||||
name="config.attribute-name"
|
||||
validated={
|
||||
errors.name
|
||||
? ValidatedOptions.error
|
||||
: ValidatedOptions.default
|
||||
}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup
|
||||
label={t("mapperAttributeFriendlyName")}
|
||||
labelIcon={
|
||||
<HelpItem
|
||||
id="mapper-attribute-friendly-name"
|
||||
helpText="identity-providers-help:friendlyName"
|
||||
forLabel={t("mapperAttributeFriendlyName")}
|
||||
forID={t(`common:helpLabel`, {
|
||||
label: t("mapperAttributeFriendlyName"),
|
||||
})}
|
||||
/>
|
||||
}
|
||||
fieldId="kc-friendly-name"
|
||||
validated={
|
||||
errors.name
|
||||
? ValidatedOptions.error
|
||||
: ValidatedOptions.default
|
||||
}
|
||||
helperTextInvalid={t("common:required")}
|
||||
>
|
||||
<TextInput
|
||||
ref={register()}
|
||||
type="text"
|
||||
defaultValue={
|
||||
currentMapper?.config["attribute-friendly-name"]
|
||||
}
|
||||
data-testid="attribute-friendly-name"
|
||||
id="kc-attribute-friendly-name"
|
||||
name="config.attribute-friendly-name"
|
||||
validated={
|
||||
errors.name
|
||||
? ValidatedOptions.error
|
||||
: ValidatedOptions.default
|
||||
}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup
|
||||
label={t("mapperUserAttributeName")}
|
||||
labelIcon={
|
||||
<HelpItem
|
||||
id="user-attribute-name-help-icon"
|
||||
helpText="identity-providers-help:userAttributeName"
|
||||
forLabel={t("mapperUserAttributeName")}
|
||||
forID={t(`common:helpLabel`, {
|
||||
label: t("mapperUserAttributeName"),
|
||||
})}
|
||||
/>
|
||||
}
|
||||
fieldId="kc-user-attribute-name"
|
||||
validated={
|
||||
errors.name
|
||||
? ValidatedOptions.error
|
||||
: ValidatedOptions.default
|
||||
}
|
||||
helperTextInvalid={t("common:required")}
|
||||
>
|
||||
<TextInput
|
||||
ref={register()}
|
||||
type="text"
|
||||
defaultValue={currentMapper?.config["attribute-value"]}
|
||||
data-testid="user-attribute-name"
|
||||
id="kc-user-attribute-name"
|
||||
name="config.attribute-value"
|
||||
validated={
|
||||
errors.name
|
||||
? ValidatedOptions.error
|
||||
: ValidatedOptions.default
|
||||
}
|
||||
/>
|
||||
</FormGroup>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
|
|
198
src/identity-providers/add/AddMapperForm.tsx
Normal file
198
src/identity-providers/add/AddMapperForm.tsx
Normal file
|
@ -0,0 +1,198 @@
|
|||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Controller, UseFormMethods } from "react-hook-form";
|
||||
import {
|
||||
FormGroup,
|
||||
Select,
|
||||
SelectOption,
|
||||
SelectVariant,
|
||||
TextInput,
|
||||
ValidatedOptions,
|
||||
} from "@patternfly/react-core";
|
||||
|
||||
import { HelpItem } from "../../components/help-enabler/HelpItem";
|
||||
import _ from "lodash";
|
||||
import type IdentityProviderMapperRepresentation from "@keycloak/keycloak-admin-client/lib/defs/identityProviderMapperRepresentation";
|
||||
import type { IdentityProviderAddMapperParams } from "../routes/AddMapper";
|
||||
import { useParams } from "react-router-dom";
|
||||
import type { IdPMapperRepresentationWithAttributes } from "./AddMapper";
|
||||
|
||||
type AddMapperFormProps = {
|
||||
mapperTypes?: Record<string, IdentityProviderMapperRepresentation>;
|
||||
mapperType: string;
|
||||
providerId: string;
|
||||
id: string;
|
||||
updateMapperType: (mapperType: string) => void;
|
||||
form: UseFormMethods<IdPMapperRepresentationWithAttributes>;
|
||||
formValues: IdPMapperRepresentationWithAttributes;
|
||||
};
|
||||
|
||||
export const AddMapperForm = ({
|
||||
mapperTypes,
|
||||
mapperType,
|
||||
form,
|
||||
id,
|
||||
updateMapperType,
|
||||
formValues,
|
||||
}: AddMapperFormProps) => {
|
||||
const { t } = useTranslation("identity-providers");
|
||||
|
||||
const { control, register, errors } = form;
|
||||
|
||||
const [mapperTypeOpen, setMapperTypeOpen] = useState(false);
|
||||
|
||||
const syncModes = ["inherit", "import", "legacy", "force"];
|
||||
const [syncModeOpen, setSyncModeOpen] = useState(false);
|
||||
const { providerId } = useParams<IdentityProviderAddMapperParams>();
|
||||
|
||||
return (
|
||||
<>
|
||||
<FormGroup
|
||||
label={t("common:name")}
|
||||
labelIcon={
|
||||
<HelpItem
|
||||
id="name-help-icon"
|
||||
helpText="identity-providers-help:addIdpMapperName"
|
||||
forLabel={t("common:name")}
|
||||
forID={t(`common:helpLabel`, { label: t("common:name") })}
|
||||
/>
|
||||
}
|
||||
fieldId="kc-name"
|
||||
isRequired
|
||||
validated={
|
||||
errors.name ? ValidatedOptions.error : ValidatedOptions.default
|
||||
}
|
||||
helperTextInvalid={t("common:required")}
|
||||
>
|
||||
<TextInput
|
||||
ref={register({ required: true })}
|
||||
type="text"
|
||||
datatest-id="name-input"
|
||||
id="kc-name"
|
||||
name="name"
|
||||
isDisabled={!!id}
|
||||
validated={
|
||||
errors.name ? ValidatedOptions.error : ValidatedOptions.default
|
||||
}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup
|
||||
label={t("syncModeOverride")}
|
||||
isRequired
|
||||
labelIcon={
|
||||
<HelpItem
|
||||
helpText="identity-providers-help:syncModeOverride"
|
||||
forLabel={t("syncModeOverride")}
|
||||
forID={t(`common:helpLabel`, { label: t("syncModeOverride") })}
|
||||
/>
|
||||
}
|
||||
fieldId="syncMode"
|
||||
>
|
||||
<Controller
|
||||
name="config.syncMode"
|
||||
defaultValue={syncModes[0]}
|
||||
control={control}
|
||||
render={({ onChange, value }) => (
|
||||
<Select
|
||||
toggleId="syncMode"
|
||||
datatest-id="syncmode-select"
|
||||
required
|
||||
direction="down"
|
||||
onToggle={() => setSyncModeOpen(!syncModeOpen)}
|
||||
onSelect={(_, value) => {
|
||||
onChange(value.toString().toUpperCase());
|
||||
setSyncModeOpen(false);
|
||||
}}
|
||||
selections={t(`syncModes.${value.toLowerCase()}`)}
|
||||
variant={SelectVariant.single}
|
||||
aria-label={t("syncMode")}
|
||||
isOpen={syncModeOpen}
|
||||
>
|
||||
{syncModes.map((option) => (
|
||||
<SelectOption
|
||||
selected={option === value}
|
||||
key={option}
|
||||
data-testid={option}
|
||||
value={option.toUpperCase()}
|
||||
>
|
||||
{t(`syncModes.${option}`)}
|
||||
</SelectOption>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup
|
||||
label={t("mapperType")}
|
||||
labelIcon={
|
||||
<HelpItem
|
||||
helpText={
|
||||
formValues.identityProviderMapper ===
|
||||
"saml-user-attribute-idp-mapper" &&
|
||||
(providerId === "oidc" || providerId === "keycloak-oidc")
|
||||
? `identity-providers-help:oidcAttributeImporter`
|
||||
: `identity-providers-help:${mapperType}`
|
||||
}
|
||||
forLabel={t("mapperType")}
|
||||
forID={t(`common:helpLabel`, { label: t("mapperType") })}
|
||||
/>
|
||||
}
|
||||
fieldId="identityProviderMapper"
|
||||
>
|
||||
<Controller
|
||||
name="identityProviderMapper"
|
||||
defaultValue={
|
||||
providerId === "saml"
|
||||
? "saml-advanced-role-idp-mapper"
|
||||
: "oidc-advanced-role-idp-mapper"
|
||||
}
|
||||
control={control}
|
||||
render={({ onChange, value }) => (
|
||||
<Select
|
||||
toggleId="identityProviderMapper"
|
||||
data-testid="idp-mapper-select"
|
||||
isDisabled={!!id}
|
||||
required
|
||||
direction="down"
|
||||
onToggle={() => setMapperTypeOpen(!mapperTypeOpen)}
|
||||
onSelect={(e, value) => {
|
||||
const theMapper =
|
||||
mapperTypes &&
|
||||
Object.values(mapperTypes).find(
|
||||
(item) =>
|
||||
item.name?.toLowerCase() ===
|
||||
value.toString().toLowerCase()
|
||||
);
|
||||
|
||||
updateMapperType(_.camelCase(value.toString()));
|
||||
onChange(theMapper?.id);
|
||||
setMapperTypeOpen(false);
|
||||
}}
|
||||
selections={
|
||||
mapperTypes &&
|
||||
Object.values(mapperTypes).find(
|
||||
(item) => item.id?.toLowerCase() === value
|
||||
)?.name
|
||||
}
|
||||
variant={SelectVariant.single}
|
||||
aria-label={t("syncMode")}
|
||||
isOpen={mapperTypeOpen}
|
||||
>
|
||||
{mapperTypes &&
|
||||
Object.values(mapperTypes).map((option) => (
|
||||
<SelectOption
|
||||
selected={option === value}
|
||||
datatest-id={option.id}
|
||||
key={option.name}
|
||||
value={option.name?.toUpperCase()}
|
||||
>
|
||||
{t(`mapperTypes.${_.camelCase(option.name)}`)}
|
||||
</SelectOption>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
/>
|
||||
</FormGroup>
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -71,6 +71,9 @@ export default {
|
|||
subjectNameId: "Subject NameID",
|
||||
attributeName: "Attribute [Name]",
|
||||
attributeFriendlyName: "Attribute [Friendly Name]",
|
||||
mapperAttributeName: "Attribute Name",
|
||||
mapperUserAttributeName: "User Attribute Name",
|
||||
mapperAttributeFriendlyName: "Friendly name",
|
||||
httpPostBindingResponse: "HTTP-POST binding response",
|
||||
httpPostBindingAuthnRequest: "HTTP-POST binding for AuthnRequest",
|
||||
httpPostBindingLogout: "HTTP-POST binding logout",
|
||||
|
@ -167,6 +170,7 @@ export default {
|
|||
mapperSaveSuccess: "Mapper saved successfully.",
|
||||
mapperSaveError: "Error saving mapper: {{error}}",
|
||||
userAttribute: "User Attribute",
|
||||
attributeValue: "Attribute Value",
|
||||
userAttributeValue: "User Attribute Value",
|
||||
userSessionAttribute: "User Session Attribute",
|
||||
userSessionAttributeValue: "User Session Attribute Value",
|
||||
|
|
Loading…
Reference in a new issue