Add User federation kerberos settings controllers (#224)

* add form controllers to user fed kerberos settings

* comments out test buttons

* add optional settings with todos

* correct the kerberos help text

* updates cache policy dropdowns

* use ComponentRepresentation

* use FormAccess component

* fix required settings and i18n

* remove unused form

* remove unused file

Co-authored-by: jenny-s51 <jshandel12@gmail.com>
This commit is contained in:
Sarah Rambacher 2020-11-24 08:56:31 -05:00 committed by GitHub
parent dc2ceef27b
commit ad09c883e3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 330 additions and 93 deletions

View file

@ -56,6 +56,14 @@
"required": "Required field",
"maxLength": "Max length {{length}}",
"createRealm": "Create Realm"
"createRealm": "Create Realm",
"Sunday": "Sunday",
"Monday": "Monday",
"Tuesday": "Tuesday",
"Wednesday": "Wednesday",
"Thursday": "Thursday",
"Friday": "Friday",
"Saturday": "Saturday"
}
}

View file

@ -1,16 +1,55 @@
import { Form, FormGroup, Select, SelectOption } from "@patternfly/react-core";
import {
FormGroup,
Select,
SelectOption,
SelectVariant,
TextInput,
} from "@patternfly/react-core";
import { useTranslation } from "react-i18next";
import React from "react";
import { HelpItem } from "../components/help-enabler/HelpItem";
import React, { useState } from "react";
import { useForm, Controller } from "react-hook-form";
import ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
import { FormAccess } from "../components/form-access/FormAccess";
export const KerberosSettingsCache = () => {
const { t } = useTranslation("user-federation");
const helpText = useTranslation("user-federation-help").t;
const [isCachePolicyDropdownOpen, setIsCachePolicyDropdownOpen] = useState(
false
);
const [isEvictionHourDropdownOpen, setIsEvictionHourDropdownOpen] = useState(
false
);
const [
isEvictionMinuteDropdownOpen,
setIsEvictionMinuteDropdownOpen,
] = useState(false);
const [isEvictionDayDropdownOpen, setIsEvictionDayDropdownOpen] = useState(
false
);
const { control, register } = useForm<ComponentRepresentation>();
const hourOptions = [
<SelectOption key={0} value={t("common:selectOne")} isPlaceholder />,
];
for (let index = 1; index <= 24; index++) {
hourOptions.push(<SelectOption key={index + 1} value={index} />);
}
const minuteOptions = [
<SelectOption key={0} value={t("common:selectOne")} isPlaceholder />,
];
for (let index = 1; index <= 60; index++) {
minuteOptions.push(<SelectOption key={index + 1} value={index} />);
}
return (
<>
{/* Cache settings */}
<Form isHorizontal>
<FormAccess role="manage-realm" isHorizontal>
<FormGroup
label={t("cachePolicy")}
labelIcon={
@ -22,30 +61,180 @@ export const KerberosSettingsCache = () => {
}
fieldId="kc-cache-policy"
>
<Select
toggleId="kc-cache-policy"
// isOpen={openType}
onToggle={() => {}}
// variant={SelectVariant.single}
// value={selected}
// selections={selected}
// onSelect={(_, value) => {
// setSelected(value as string);
// setOpenType(false);
// }}
aria-label="Select Input"
>
{/* {configFormats.map((configFormat) => ( */}
<SelectOption
key={"key"}
value={"value"}
// isSelected={selected === configFormat.id}
>
{"display name"}
</SelectOption>
</Select>
<Controller
name="cachePolicy"
defaultValue=""
control={control}
render={({ onChange, value }) => (
<Select
toggleId="kc-cache-policy"
required
onToggle={() =>
setIsCachePolicyDropdownOpen(!isCachePolicyDropdownOpen)
}
isOpen={isCachePolicyDropdownOpen}
onSelect={(_, value) => {
onChange(value as string);
setIsCachePolicyDropdownOpen(false);
}}
selections={value}
variant={SelectVariant.single}
>
<SelectOption
key={0}
value={t("common:selectOne")}
isPlaceholder
/>
<SelectOption key={1} value="Default" />
<SelectOption key={2} value="Something" />
</Select>
)}
></Controller>
</FormGroup>
</Form>
{/* TODO: Field shows only if cache policy is EVICT_WEEKLY */}
<FormGroup
label={t("evictionDay")}
labelIcon={
<HelpItem
helpText={helpText("evictionDayHelp")}
forLabel={t("evictionDay")}
forID="kc-eviction-day"
/>
}
fieldId="kc-eviction-day"
>
<Controller
name="evictionDay"
defaultValue=""
control={control}
render={({ onChange, value }) => (
<Select
toggleId="kc-eviction-day"
required
onToggle={() =>
setIsEvictionDayDropdownOpen(!isEvictionDayDropdownOpen)
}
isOpen={isEvictionDayDropdownOpen}
onSelect={(_, value) => {
onChange(value as string);
setIsEvictionDayDropdownOpen(false);
}}
selections={value}
variant={SelectVariant.single}
>
<SelectOption
key={0}
value={t("common:selectOne")}
isPlaceholder
/>
<SelectOption key={1} value={t("common:Sunday")} />
<SelectOption key={2} value={t("common:Monday")} />
<SelectOption key={3} value={t("common:Tuesday")} />
<SelectOption key={4} value={t("common:Wednesday")} />
<SelectOption key={5} value={t("common:Thursday")} />
<SelectOption key={6} value={t("common:Friday")} />
<SelectOption key={7} value={t("common:Saturday")} />
</Select>
)}
></Controller>
</FormGroup>
{/* TODO: Field shows only if cache policy is EVICT_WEEKLY or EVICT_DAILY */}
{/* TODO: Investigate whether this should be a number field instead of a dropdown/text field */}
<FormGroup
label={t("evictionHour")}
labelIcon={
<HelpItem
helpText={helpText("evictionHourHelp")}
forLabel={t("evictionHour")}
forID="kc-eviction-hour"
/>
}
fieldId="kc-eviction-hour"
>
<Controller
name="evictionHour"
defaultValue=""
control={control}
render={({ onChange, value }) => (
<Select
toggleId="kc-eviction-hour"
onToggle={() =>
setIsEvictionHourDropdownOpen(!isEvictionHourDropdownOpen)
}
isOpen={isEvictionHourDropdownOpen}
onSelect={(_, value) => {
onChange(value as string);
setIsEvictionHourDropdownOpen(false);
}}
selections={value}
variant={SelectVariant.single}
>
{hourOptions}
</Select>
)}
></Controller>
</FormGroup>
{/* TODO: Field shows only if cache policy is EVICT_WEEKLY or EVICT_DAILY */}
{/* TODO: Investigate whether this should be a number field instead of a dropdown/text field */}
<FormGroup
label={t("evictionMinute")}
labelIcon={
<HelpItem
helpText={helpText("evictionMinuteHelp")}
forLabel={t("evictionMinute")}
forID="kc-eviction-minute"
/>
}
fieldId="kc-eviction-minute"
>
<Controller
name="evictionMinute"
defaultValue=""
control={control}
render={({ onChange, value }) => (
<Select
toggleId="kc-eviction-minute"
onToggle={() =>
setIsEvictionMinuteDropdownOpen(!isEvictionMinuteDropdownOpen)
}
isOpen={isEvictionMinuteDropdownOpen}
onSelect={(_, value) => {
onChange(value as string);
setIsEvictionMinuteDropdownOpen(false);
}}
selections={value}
variant={SelectVariant.single}
>
{minuteOptions}
</Select>
)}
></Controller>
</FormGroup>
{/* TODO: Field shows only if cache policy is MAX_LIFESPAN */}
<FormGroup
label={t("maxLifespan")}
labelIcon={
<HelpItem
helpText={helpText("maxLifespanHelp")}
forLabel={t("maxLifespan")}
forID="kc-max-lifespan"
/>
}
fieldId="kc-max-lifespan"
>
<TextInput
isRequired
type="text"
id="kc-max-lifespan"
name="maxLifespan"
ref={register}
/>
</FormGroup>
</FormAccess>
</>
);
};

View file

@ -1,23 +1,29 @@
import {
Form,
FormGroup,
Select,
SelectOption,
SelectVariant,
Switch,
TextInput,
} from "@patternfly/react-core";
import { useTranslation } from "react-i18next";
import React from "react";
import { HelpItem } from "../components/help-enabler/HelpItem";
import React, { useState } from "react";
import { useForm, Controller } from "react-hook-form";
import ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
import { FormAccess } from "../components/form-access/FormAccess";
export const KerberosSettingsRequired = () => {
const { t } = useTranslation("user-federation");
const helpText = useTranslation("user-federation-help").t;
const [isEditModeDropdownOpen, setIsEditModeDropdownOpen] = useState(false);
const { register, control } = useForm<ComponentRepresentation>();
return (
<>
{/* Required settings */}
<Form isHorizontal>
<FormAccess role="manage-realm" isHorizontal>
<FormGroup
label={t("consoleDisplayName")}
labelIcon={
@ -34,9 +40,8 @@ export const KerberosSettingsRequired = () => {
isRequired
type="text"
id="kc-console-display-name"
name="kc-console-display-name"
// value={value1}
// onChange={this.handleTextInputChange1}
name="consoleDisplayName"
ref={register}
/>
</FormGroup>
@ -56,9 +61,8 @@ export const KerberosSettingsRequired = () => {
isRequired
type="text"
id="kc-kerberos-realm"
name="kc-kerberos-realm"
// value={value1}
// onChange={this.handleTextInputChange1}
name="kerberosRealm"
ref={register}
/>
</FormGroup>
@ -78,9 +82,8 @@ export const KerberosSettingsRequired = () => {
isRequired
type="text"
id="kc-server-principal"
name="kc-server-principal"
// value={value1}
// onChange={this.handleTextInputChange1}
name="serverPrincipal"
ref={register}
/>
</FormGroup>
@ -100,9 +103,8 @@ export const KerberosSettingsRequired = () => {
isRequired
type="text"
id="kc-key-tab"
name="kc-key-tab"
// value={value1}
// onChange={this.handleTextInputChange1}
name="keyTab"
ref={register}
/>
</FormGroup>
@ -118,14 +120,22 @@ export const KerberosSettingsRequired = () => {
fieldId="kc-debug"
hasNoPaddingTop
>
<Switch
id={"kc-debug"}
isChecked={true}
isDisabled={false}
onChange={() => undefined as any}
label={t("common:on")}
labelOff={t("common:off")}
/>
{" "}
<Controller
name="debug"
defaultValue={false}
control={control}
render={({ onChange, value }) => (
<Switch
id={"kc-debug"}
isDisabled={false}
onChange={onChange}
isChecked={value}
label={t("common:on")}
labelOff={t("common:off")}
/>
)}
></Controller>
</FormGroup>
<FormGroup
@ -140,50 +150,64 @@ export const KerberosSettingsRequired = () => {
fieldId="kc-allow-password-authentication"
hasNoPaddingTop
>
<Switch
id={"kc-allow-password-authentication"}
isChecked={true}
isDisabled={false}
onChange={() => undefined as any}
label={t("common:on")}
labelOff={t("common:off")}
/>
<Controller
name="allowPasswordAuthentication"
defaultValue={false}
control={control}
render={({ onChange, value }) => (
<Switch
id={"kc-allow-password-authentication"}
isDisabled={false}
onChange={onChange}
isChecked={value}
label={t("common:on")}
labelOff={t("common:off")}
/>
)}
></Controller>
</FormGroup>
{/* TODO: Field shows only if allowPasswordAuthentication is TRUE */}
<FormGroup
label={t("editMode")}
labelIcon={
<HelpItem
helpText={helpText("editModeHelp")}
helpText={helpText("editModeKerberosHelp")}
forLabel={t("editMode")}
forID="kc-edit-mode"
/>
}
fieldId="kc-edit-mode"
>
<Select
toggleId="kc-edit-mode"
// isOpen={openType}
onToggle={() => {}}
// variant={SelectVariant.single}
// value={selected}
// selections={selected}
// onSelect={(_, value) => {
// setSelected(value as string);
// setOpenType(false);
// }}
aria-label="edit mode" // TODO
>
{/* {configFormats.map((configFormat) => ( */}
<SelectOption
key={"key"}
value={"value"}
// isSelected={selected === configFormat.id}
>
{"display name"}
</SelectOption>
{/* ))} */}
</Select>
{" "}
<Controller
name="editMode"
defaultValue=""
control={control}
render={({ onChange, value }) => (
<Select
toggleId="kc-edit-mode"
required
onToggle={() =>
setIsEditModeDropdownOpen(!isEditModeDropdownOpen)
}
isOpen={isEditModeDropdownOpen}
onSelect={(_, value) => {
onChange(value as string);
setIsEditModeDropdownOpen(false);
}}
selections={value}
variant={SelectVariant.single}
>
<SelectOption
key={0}
value={t("common:selectOne")}
isPlaceholder
/>
<SelectOption key={1} value="UNSYNCED" />
</Select>
)}
></Controller>
</FormGroup>
<FormGroup
@ -198,16 +222,23 @@ export const KerberosSettingsRequired = () => {
fieldId="kc-update-first-login"
hasNoPaddingTop
>
<Switch
id={"kc-update-first-login"}
isChecked={true}
isDisabled={false}
onChange={() => undefined as any}
label={t("common:on")}
labelOff={t("common:off")}
/>
<Controller
name="updateFirstLogin"
defaultValue={false}
control={control}
render={({ onChange, value }) => (
<Switch
id={"kc-update-first-login"}
isDisabled={false}
onChange={onChange}
isChecked={value}
label={t("common:on")}
labelOff={t("common:off")}
/>
)}
></Controller>
</FormGroup>
</Form>
</FormAccess>
</>
);
};

View file

@ -22,7 +22,7 @@ export const LdapSettingsSearching = () => {
label={t("editMode")}
labelIcon={
<HelpItem
helpText={helpText("editModeHelp")}
helpText={helpText("editModeLdapHelp")}
forLabel={t("editMode")}
forID="kc-edit-mode"
/>

View file

@ -13,7 +13,7 @@
"bindDnHelp": "DN of the LDAP admin, which will be used by Keycloak to access LDAP server",
"bindCredentialsHelp": "Password of LDAP admin. This field is able to obtain its value from vault, use ${vault.ID} format.",
"editModeHelp": "READ_ONLY is a read-only LDAP store. WRITABLE means data will be synced back to LDAP on demand. UNSYNCED means user data will be imported, but not synced back to LDAP.",
"editModeLdapHelp": "READ_ONLY is a read-only LDAP store. WRITABLE means data will be synced back to LDAP on demand. UNSYNCED means user data will be imported, but not synced back to LDAP.",
"usersDNHelp": "Full DN of LDAP tree where your users are. This DN is the parent of LDAP users. It could be for example 'ou=users,dc=example,dc=com' assuming that your typical user will have DN like 'uid='john',ou=users,dc=example,dc=com'",
"usernameLdapAttributeHelp": "Name of LDAP attribute, which is mapped as Keycloak username. For many LDAP server vendors it can be 'uid'. For Active directory it can be 'sAMAccountName' or 'cn'. The attribute should be filled for all LDAP user records you want to import from LDAP to Keycloak.",
"rdnLdapAttributeHelp": "Name of LDAP attribute, which is used as RDN (top attribute) of typical user DN. Usually it's the same as Username LDAP attribute, however it is not required. For example for Active directory, it is common to use 'cn' as RDN attribute when username attribute might be 'sAMAccountName'.",
@ -33,6 +33,10 @@
"useKerberosForPasswordAuthenticationHelp": "User Kerberos login module for authenticate username/password against Kerberos server instead of authenticating against LDAP server with Directory Service API",
"cachePolicyHelp": "Cache Policy for this storage provider. 'DEFAULT' is whatever the default settings are for the global cache. 'EVICT_DAILY' is a time of day every day that the cache will be invalidated. 'EVICT_WEEKLY' is a day of the week and time the cache will be invalidated. 'MAX_LIFESPAN' is the time in milliseconds that will be the lifespan of a cache entry.",
"evictionDayHelp": "Day of the week the entry will become invalid",
"evictionHourHelp": "Hour of the day the entry will become invalid",
"evictionMinuteHelp": "Minute of the hour the entry will become invalid",
"maxLifespanHelp": "Max lifespan of cache entry in milliseconds",
"enableLdapv3PasswordHelp": "Use the LDAPv3 Password Modify Extended Operation (RFC-3062). The password modify extended operation usually requires that LDAP user already has password in the LDAP server. So when this is used with 'Sync Registrations', it can be good to add also 'Hardcoded LDAP attribute mapper' with randomly generated initial password.",
"validatePasswordPolicyHelp": "Determines if Keycloak should validate the password with the realm password policy before updating it",
@ -46,6 +50,7 @@
"keyTabHelp": "Location of Kerberos KeyTab file containing the credentials of server principal. For example, /etc/krb5.keytab",
"debugHelp": "Enable/disable debug logging to standard output for Krb5LoginModule",
"allowPasswordAuthenticationHelp": "Enable/disable possibility of username/password authentication against Kerberos database",
"editModeKerberosHelp": "READ_ONLY means that password updates are not allowed and user always authenticates with Kerberos password. UNSYNCED means that the user can change the password in the Keycloak database and this one will be used instead of the Kerberos password",
"updateFirstLoginHelp": "Update profile on first login"
}
}

View file

@ -52,6 +52,10 @@
"cacheSettings": "Cache settings",
"cachePolicy": "Cache policy",
"evictionDay": "Eviction day",
"evictionHour": "Eviction hour",
"evictionMinute": "Eviction minute",
"maxLifespan": "Max lifespan",
"advancedSettings": "Advanced settings",
"enableLdapv3Password": "Enable the LDAPv3 password modify extended operation",