From 6b3990e1b92d496f5d622d2e311732373817e158 Mon Sep 17 00:00:00 2001 From: Sarah Rambacher Date: Fri, 30 Oct 2020 16:15:37 -0400 Subject: [PATCH] 540 user fed settings (#198) * all fields roughed in working on tab * reduce to just the settings without page * remove unused imports * fix some comments * correct some typos and capitalization * remove ldap translation --- src/i18n.ts | 2 + .../UserFedLDAPSettingsTab.stories.tsx | 17 ++ src/user-federation/LdapSettingsAdvanced.tsx | 81 +++++ src/user-federation/LdapSettingsCache.tsx | 51 ++++ .../LdapSettingsConnection.tsx | 224 ++++++++++++++ src/user-federation/LdapSettingsGeneral.tsx | 66 ++++ .../LdapSettingsKerberosIntegration.tsx | 60 ++++ src/user-federation/LdapSettingsSearching.tsx | 283 ++++++++++++++++++ .../LdapSettingsSynchronization.tsx | 96 ++++++ .../UserFederationLdapSettingsTab.tsx | 54 ++++ src/user-federation/help.json | 43 +++ src/user-federation/messages.json | 96 +++--- 12 files changed, 1028 insertions(+), 45 deletions(-) create mode 100644 src/stories/UserFedLDAPSettingsTab.stories.tsx create mode 100644 src/user-federation/LdapSettingsAdvanced.tsx create mode 100644 src/user-federation/LdapSettingsCache.tsx create mode 100644 src/user-federation/LdapSettingsConnection.tsx create mode 100644 src/user-federation/LdapSettingsGeneral.tsx create mode 100644 src/user-federation/LdapSettingsKerberosIntegration.tsx create mode 100644 src/user-federation/LdapSettingsSearching.tsx create mode 100644 src/user-federation/LdapSettingsSynchronization.tsx create mode 100644 src/user-federation/UserFederationLdapSettingsTab.tsx create mode 100644 src/user-federation/help.json diff --git a/src/i18n.ts b/src/i18n.ts index 1cf0aeaa83..b675a95306 100644 --- a/src/i18n.ts +++ b/src/i18n.ts @@ -16,6 +16,7 @@ import sessions from "./sessions/messages.json"; import events from "./events/messages.json"; import storybook from "./stories/messages.json"; import userFederation from "./user-federation/messages.json"; +import userFederationHelp from "./user-federation/help.json"; const initOptions = { defaultNS: "common", @@ -36,6 +37,7 @@ const initOptions = { ...events, ...storybook, ...userFederation, + ...userFederationHelp, }, }, lng: "en", diff --git a/src/stories/UserFedLDAPSettingsTab.stories.tsx b/src/stories/UserFedLDAPSettingsTab.stories.tsx new file mode 100644 index 0000000000..f572e8b925 --- /dev/null +++ b/src/stories/UserFedLDAPSettingsTab.stories.tsx @@ -0,0 +1,17 @@ +import React from "react"; +import { Meta } from "@storybook/react"; +import { Page } from "@patternfly/react-core"; +import { UserFederationLdapSettingsTab } from "../user-federation/UserFederationLdapSettingsTab"; + +export default { + title: "User Federation LDAP Settings Tab", + component: UserFederationLdapSettingsTab, +} as Meta; + +export const view = () => { + return ( + + + + ); +}; diff --git a/src/user-federation/LdapSettingsAdvanced.tsx b/src/user-federation/LdapSettingsAdvanced.tsx new file mode 100644 index 0000000000..cd20d2f0de --- /dev/null +++ b/src/user-federation/LdapSettingsAdvanced.tsx @@ -0,0 +1,81 @@ +import { Form, FormGroup, Switch } from "@patternfly/react-core"; +import { useTranslation } from "react-i18next"; +import React from "react"; +import { HelpItem } from "../components/help-enabler/HelpItem"; + +export const LdapSettingsAdvanced = () => { + const { t } = useTranslation("user-federation"); + const helpText = useTranslation("user-federation-help").t; + + return ( + <> +
+ + } + fieldId="kc-enable-ldapv3-password" + hasNoPaddingTop + > + undefined as any} + label={t("common:on")} + labelOff={t("common:off")} + /> + + + + } + fieldId="kc-validate-password-policy" + hasNoPaddingTop + > + undefined as any} + label={t("common:on")} + labelOff={t("common:off")} + /> + + + + } + fieldId="kc-trust-email" + hasNoPaddingTop + > + undefined as any} + label={t("common:on")} + labelOff={t("common:off")} + /> + +
+ + ); +}; diff --git a/src/user-federation/LdapSettingsCache.tsx b/src/user-federation/LdapSettingsCache.tsx new file mode 100644 index 0000000000..7e32514025 --- /dev/null +++ b/src/user-federation/LdapSettingsCache.tsx @@ -0,0 +1,51 @@ +import { Form, FormGroup, Select, SelectOption } from "@patternfly/react-core"; +import { useTranslation } from "react-i18next"; +import React from "react"; +import { HelpItem } from "../components/help-enabler/HelpItem"; + +export const LdapSettingsCache = () => { + const { t } = useTranslation("user-federation"); + const helpText = useTranslation("user-federation-help").t; + + return ( + <> + {/* Cache settings */} +
+ + } + fieldId="kc-cache-policy" + > + + +
+ + ); +}; diff --git a/src/user-federation/LdapSettingsConnection.tsx b/src/user-federation/LdapSettingsConnection.tsx new file mode 100644 index 0000000000..b198b4b850 --- /dev/null +++ b/src/user-federation/LdapSettingsConnection.tsx @@ -0,0 +1,224 @@ +import { + Button, + Form, + FormGroup, + InputGroup, + Select, + SelectOption, + Switch, + TextInput, +} from "@patternfly/react-core"; +import { useTranslation } from "react-i18next"; +import React from "react"; +import { HelpItem } from "../components/help-enabler/HelpItem"; +import { EyeIcon } from "@patternfly/react-icons"; + +export const LdapSettingsConnection = () => { + const { t } = useTranslation("user-federation"); + const helpText = useTranslation("user-federation-help").t; + + return ( + <> + {/* Cache settings */} +
+ + } + fieldId="kc-connection-url" + isRequired + > + + + + + } + fieldId="kc-enable-start-tls" + hasNoPaddingTop + > + undefined as any} + label={t("common:on")} + labelOff={t("common:off")} + /> + + + + } + fieldId="kc-use-truststore-spi" + > + + + + + } + fieldId="kc-connection-pooling" + hasNoPaddingTop + > + undefined as any} + label={t("common:on")} + labelOff={t("common:off")} + /> + + + + } + fieldId="kc-connection-timeout" + > + + + + + } + fieldId="kc-bind-type" + isRequired + > + + + + + } + fieldId="kc-bind-dn" + > + + + + + } + fieldId="kc-bind-credentials" + isRequired + > + + + + + +
+ + ); +}; diff --git a/src/user-federation/LdapSettingsGeneral.tsx b/src/user-federation/LdapSettingsGeneral.tsx new file mode 100644 index 0000000000..c8214c8104 --- /dev/null +++ b/src/user-federation/LdapSettingsGeneral.tsx @@ -0,0 +1,66 @@ +import { Form, FormGroup, Select, TextInput } from "@patternfly/react-core"; +import { useTranslation } from "react-i18next"; +import React from "react"; +import { HelpItem } from "../components/help-enabler/HelpItem"; + +export const LdapSettingsGeneral = () => { + const { t } = useTranslation("user-federation"); + const helpText = useTranslation("user-federation-help").t; + + return ( + <> + {/* Cache settings */} +
+ + } + fieldId="kc-console-display-name" + isRequired + > + + + + + } + fieldId="kc-vendor" + isRequired + > + + +
+ + ); +}; diff --git a/src/user-federation/LdapSettingsKerberosIntegration.tsx b/src/user-federation/LdapSettingsKerberosIntegration.tsx new file mode 100644 index 0000000000..d62ed7aa44 --- /dev/null +++ b/src/user-federation/LdapSettingsKerberosIntegration.tsx @@ -0,0 +1,60 @@ +import { Form, FormGroup, Switch } from "@patternfly/react-core"; +import { useTranslation } from "react-i18next"; +import React from "react"; +import { HelpItem } from "../components/help-enabler/HelpItem"; + +export const LdapSettingsKerberosIntegration = () => { + const { t } = useTranslation("user-federation"); + const helpText = useTranslation("user-federation-help").t; + + return ( + <> + {/* Kerberos integration */} +
+ + } + fieldId="kc-allow-kerberos-authentication" + hasNoPaddingTop + > + undefined as any} + label={t("common:on")} + labelOff={t("common:off")} + /> + + + + } + fieldId="kc-use-kerberos-password-authentication" + hasNoPaddingTop + > + undefined as any} + label={t("common:on")} + labelOff={t("common:off")} + /> + +
+ + ); +}; diff --git a/src/user-federation/LdapSettingsSearching.tsx b/src/user-federation/LdapSettingsSearching.tsx new file mode 100644 index 0000000000..e96750db6c --- /dev/null +++ b/src/user-federation/LdapSettingsSearching.tsx @@ -0,0 +1,283 @@ +import { + Form, + FormGroup, + Select, + SelectOption, + Switch, + TextInput, +} from "@patternfly/react-core"; +import { useTranslation } from "react-i18next"; +import React from "react"; +import { HelpItem } from "../components/help-enabler/HelpItem"; + +export const LdapSettingsSearching = () => { + const { t } = useTranslation("user-federation"); + const helpText = useTranslation("user-federation-help").t; + + return ( + <> + {/* Cache settings */} +
+ + } + fieldId="kc-edit-mode" + > + + + + + } + fieldId="kc-console-users-dn" + isRequired + > + + + + + } + fieldId="kc-username-ldap-attribute" + isRequired + > + + + + + } + fieldId="kc-rdn-ldap-attribute" + isRequired + > + + + + + } + fieldId="kc-uuid-ldap-attribute" + isRequired + > + + + + + } + fieldId="kc-user-object-classes" + isRequired + > + + + + + } + fieldId="kc-user-ldap-filter" + > + + + + + } + fieldId="kc-search-scope" + > + + + + + } + fieldId="kc-read-timeout" + > + + + + + } + fieldId="kc-console-pagination" + hasNoPaddingTop + > + undefined as any} + label={t("common:on")} + labelOff={t("common:off")} + /> + +
+ + ); +}; diff --git a/src/user-federation/LdapSettingsSynchronization.tsx b/src/user-federation/LdapSettingsSynchronization.tsx new file mode 100644 index 0000000000..68b5447bdd --- /dev/null +++ b/src/user-federation/LdapSettingsSynchronization.tsx @@ -0,0 +1,96 @@ +import { Form, FormGroup, Switch, TextInput } from "@patternfly/react-core"; +import { useTranslation } from "react-i18next"; +import React from "react"; +import { HelpItem } from "../components/help-enabler/HelpItem"; + +export const LdapSettingsSynchronization = () => { + const { t } = useTranslation("user-federation"); + const helpText = useTranslation("user-federation-help").t; + + return ( + <> + {/* Synchronization settings */} +
+ + } + fieldId="kc-import-users" + hasNoPaddingTop + > + undefined as any} //TODO: switch shows/hides other fields + label={t("common:on")} + labelOff={t("common:off")} + /> + + + + } + fieldId="kc-batch-size" + > + + + + + } + fieldId="kc-periodic-full-sync" + hasNoPaddingTop + > + undefined as any} + /> + + + + } + fieldId="kc-periodic-changed-users-sync" + hasNoPaddingTop + > + undefined as any} + label={t("common:on")} + labelOff={t("common:off")} + /> + +
+ + ); +}; diff --git a/src/user-federation/UserFederationLdapSettingsTab.tsx b/src/user-federation/UserFederationLdapSettingsTab.tsx new file mode 100644 index 0000000000..c5fbd4c43c --- /dev/null +++ b/src/user-federation/UserFederationLdapSettingsTab.tsx @@ -0,0 +1,54 @@ +import { PageSection } from "@patternfly/react-core"; +import { useTranslation } from "react-i18next"; +import React from "react"; +import { ScrollForm } from "../components/scroll-form/ScrollForm"; +import { LdapSettingsAdvanced } from "./LdapSettingsAdvanced"; +import { LdapSettingsKerberosIntegration } from "./LdapSettingsKerberosIntegration"; +import { LdapSettingsCache } from "./LdapSettingsCache"; +import { LdapSettingsSynchronization } from "./LdapSettingsSynchronization"; +import { LdapSettingsGeneral } from "./LdapSettingsGeneral"; +import { LdapSettingsConnection } from "./LdapSettingsConnection"; +import { LdapSettingsSearching } from "./LdapSettingsSearching"; + +export const UserFederationLdapSettingsTab = () => { + const { t } = useTranslation("user-federation"); + + return ( + <> + + + {/* General settings */} + + + {/* Connection settings */} + + + {/* Searching and updating settings */} + + + {/* Synchronization settings */} + + + {/* Kerberos integration */} + + + {/* Cache settings */} + + + {/* Advanced settings */} + + + + + ); +}; diff --git a/src/user-federation/help.json b/src/user-federation/help.json new file mode 100644 index 0000000000..c7b18c909c --- /dev/null +++ b/src/user-federation/help.json @@ -0,0 +1,43 @@ +{ + "user-federation-help": { + "generalOptions": "General options", + "consoleDisplayNameHelp": "Display name of provider when linked in admin console", + "vendorHelp": "LDAP vendor (provider)", + + "consoleDisplayConnectionUrlHelp": "Connection URL to your LDAP server", + "enableStarttlsHelp": "Encrypts the connection to LDAP using STARTTLS, which will disable connection pooling", + "useTruststoreSpiHelp": "Specifies whether LDAP connection will use the Truststore SPI with the truststore configured in standalone.xml/domain.sml. 'Always' means that it will always use it. 'Never' means that it will not use it. 'Only for ldaps' means that it will use it if your connection URL use ldaps. Note even if standalone.xml/domain.xml is not configured, the default java cacerts or certificate specified by 'javax.net.ssl.trustStore' property will be used.", + "connectionPoolingHelp": "Determines if Keycloak should use connection pooling for accessing LDAP server", + "connectionTimeoutHelp": "LDAP connection timeout in milliseconds", + "bindTypeHelp": "Type of the authentication method used during LDAP bind operation. It is used in most of the requests sent to the LDAP server. Currently only 'none' (anonymous LDAP authentication) or 'simple' (bind credential + bind password authentication) mechanisms are available.", + "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.", + "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'.", + "uuidLdapAttributeHelp": "Name of LDAP attribute, which is used as unique object identifier (UUID) for objects in LDAP. For many LDAP server vendors, is is 'entryUUID'; however some are different. For example for Active directory it should be 'objectGUID'. If your LDAP server does not support the notion of UUID, you can use any other attribute that is supposed to be unique among LDAP users in tree. For example 'uid' or 'entryDN'.", + "userObjectClassesHelp": "All values of LDAP objectClass attribute for users in LDAP divided by comma. For example: 'inetOrgPerson, organizationalPerson'. Newly created Keycloak users will be written to LDAP with all those object classes and existing LDAP user records are found just if they contain all those object classes.", + "userLdapFilterHelp": "Additional LDAP filter for filtering searched users. Leave this empty if you don't need additional filter. Make sure that it starts with '(' and ends with ')'", + "searchScopeHelp": "For one level, the search applies only for users in the DNs specified by User DNs. For subtree, the search applies to the whole subtree. See LDAP documentation for more details.", + "readTimeoutHelp": "LDAP read timeout in milliseconds. This timeout applies for LDAP read operations.", + "paginationHelp": "Does the LDAP server support pagination", + + "importUsersHelp": "Import users", + "batchSizeHelp": "Count of LDAP users to be imported from LDAP to Keycloak within a single transaction", + "periodicFullSyncHelp": "Whether periodic full synchronization of LDAP users to Keycloak should be enabled or not", + "periodicChangedUsersSyncHelp": "Whether periodic synchronization of changed or newly created LDAP users to Keycloak should be enabled or not", + + "allowKerberosAuthenticationHelp": "Enable/disable HTTP authentication of users with SPNEGO/Kerberos tokens. The data about authenticated users will be provisioned from this LDAP server", + "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.", + + "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", + "trustEmailHelp": "If enabled, email provided by this provider is not verified even if verification is enabled for the realm.", + + "IDK-periodicChangedUsersSyncHelp": "Should newly created users be created within LDAP store? Priority affects which provider is chosen to sync the new user." + } +} diff --git a/src/user-federation/messages.json b/src/user-federation/messages.json index 4c00724674..a2ed5a9adf 100644 --- a/src/user-federation/messages.json +++ b/src/user-federation/messages.json @@ -2,54 +2,60 @@ "user-federation": { "userFederation": "User federation", "descriptionLanding": "This is the description for the user federation landing page", - "createClient": "Create client", - "importClient": "Import client", - "clientID": "Client ID", - "type": "Type", - "homeURL": "Home URL", - "description": "Description", - "name": "Name", - "formatOption": "Format option", - "downloadAdaptorTitle": "Download adaptor configs", - "details": "Details", - "clientList": "Client list", - "clientSettings": "Client details", - "selectEncryptionType": "Select Encryption type", - "generalSettings": "General Settings", - "capabilityConfig": "Capability config", - "clientsExplain": "Clients are applications and services that can request authentication of a user", - "createSuccess": "Client created successfully", - "createError": "Could not create client: '{{error}}'", - "clientImportError": "Could not import client", - "clientSaveSuccess": "Client successfully updated", - "clientSaveError": "Client could not be updated:", - "clientImportSuccess": "Client imported successfully", - "clientDeletedSuccess": "The client has been deleted", - "clientDeleteError": "Could not delete client:", - "clientDeleteConfirmTitle": "Delete client?", - "disableConfirmTitle": "Disable client?", - "disableConfirm": "If you disable this client, you cannot initiate a login or obtain access tokens.", - "clientDeleteConfirm": "If you delete this client, all associated data will be removed.", - "clientAuthentication": "Client authentication", - "authentication": "Authentication", - "authenticationFlow": "Authentication flow", - "standardFlow": "Standard flow", - "directAccess": "Direct access", - "serviceAccount": "Service account", - "enableServiceAccount": "Enable service account", - "displayOnClient": "Display client on screen", - "consentScreenText": "Client consent screen text", - "loginSettings": "Login settings", - "accessSettings": "Access settings", - "rootUrl": "Root URL", - "validRedirectUri": "Valid redirect URIs", - "loginTheme": "Login theme", - "consentRequired": "Consent required", - "searchForClient": "Search for client", "userFederationExplanation": "Keycloak can federate external user databases. Out of the box we have support for LDAP and Active Directory.", "getStarted": "To get started, select a provider from the list below.", "providers": "Add providers", "addKerberos": "Add Kerberos providers", - "addLdap": "Add LDAP providers" + "addLdap": "Add LDAP providers", + + "syncChangedUsers": "Sync changed users", + "syncAllUsers": "Sync all users", + "unlinkUsers": "Unlink users", + "removeImported": "Remove imported", + "deleteProvider": "Delete provider", + + "generalOptions": "General options", + "consoleDisplayName": "Console display name", + "vendor": "Vendor", + + "connectionAndAuthenticationSettings": "Connection and authentication settings", + "connectionURL": "Connection URL", + "enableStarttls": "Enable StartTLS", + "useTruststoreSpi": "Use Truststore SPI", + "connectionPooling": "Connection pooling", + "connectionTimeout": "Connection timeout", + "bindType": "Bind type", + "bindDn": "Bind DN", + "bindCredentials": "Bind credentials", + + "ldapSearchingAndUpdatingSettings": "LDAP searching and updating", + "editMode": "Edit mode", + "usersDN": "Users DN", + "usernameLdapAttribute": "Username LDAP attribute", + "rdnLdapAttribute": "RDN LDAP attribute", + "uuidLdapAttribute": "UUID LDAP attribute", + "userObjectClasses": "User object classes", + "userLdapFilter": "User LDAP filter", + "searchScope": "Search scope", + "readTimeout": "Read timeout", + "pagination": "Pagination", + + "synchronizationSettings": "Synchronization settings", + "importUsers": "Import users", + "batchSize": "Batch size", + "periodicFullSync": "Periodic full sync", + "periodicChangedUsersSync": "Periodic changed users sync", + + "kerberosIntegration": "Kerberos integration", + "allowKerberosAuthentication": "Allow Kerberos authentication", + "useKerberosForPasswordAuthentication": "Use Kerberos for password authentication", + + "cacheSettings": "Cache settings", + "cachePolicy": "Cache policy", + + "advancedSettings": "Advanced settings", + "enableLdapv3Password": "Enable the LDAPv3 password modify extended operation", + "validatePasswordPolicy": "Validate password policy", + "trustEmail": "Trust email" } }