mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
SSO LDAP: Add configuration for root ca, client key and client certificate (#92866)
* Add missing properties with `_value` prefix * Add RadioButtonGrpoup * Add file/value section for certs * Add mapping for keys and certificates * Rename base and file types * Add styles * Add base64 values configuration flags * Add function to render root ca certificate contents * generate i18n files
This commit is contained in:
parent
13c8f4d212
commit
b213ecc2dd
@ -1,5 +1,5 @@
|
||||
import { css } from '@emotion/css';
|
||||
import { useId } from 'react';
|
||||
import { Dispatch, SetStateAction, useEffect, useId, useState } from 'react';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
|
||||
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
|
||||
@ -12,25 +12,41 @@ import {
|
||||
Icon,
|
||||
Input,
|
||||
Label,
|
||||
MultiSelect,
|
||||
Select,
|
||||
Stack,
|
||||
Switch,
|
||||
Text,
|
||||
TextLink,
|
||||
Tooltip,
|
||||
RadioButtonGroup,
|
||||
SecretInput,
|
||||
} from '@grafana/ui';
|
||||
import { t, Trans } from 'app/core/internationalization';
|
||||
import { LdapPayload } from 'app/types';
|
||||
import { LdapPayload, MapKeyCertConfigured } from 'app/types';
|
||||
|
||||
interface Props {
|
||||
onClose: () => void;
|
||||
mapKeyCertConfigured: MapKeyCertConfigured;
|
||||
setMapKeyCertConfigured: Dispatch<SetStateAction<MapKeyCertConfigured>>;
|
||||
}
|
||||
|
||||
const serverConfig = 'settings.config.servers.0';
|
||||
const tlsOptions: Array<SelectableValue<string>> = ['TLS1.2', 'TLS1.3'].map((v) => ({ label: v, value: v }));
|
||||
enum EncryptionProvider {
|
||||
Base64 = 'base64',
|
||||
FilePath = 'path',
|
||||
}
|
||||
|
||||
export const LdapDrawerComponent = ({
|
||||
onClose,
|
||||
mapKeyCertConfigured: mapCertConfigured,
|
||||
setMapKeyCertConfigured: setMapCertConfigured,
|
||||
}: Props) => {
|
||||
const [encryptionProvider, setEncryptionProvider] = useState(EncryptionProvider.Base64);
|
||||
|
||||
export const LdapDrawerComponent = ({ onClose }: Props) => {
|
||||
const styles = useStyles2(getStyles);
|
||||
const { register, setValue, watch } = useFormContext<LdapPayload>();
|
||||
const { getValues, register, setValue, watch } = useFormContext<LdapPayload>();
|
||||
|
||||
const nameId = useId();
|
||||
const surnameId = useId();
|
||||
@ -38,6 +54,22 @@ export const LdapDrawerComponent = ({ onClose }: Props) => {
|
||||
const memberOfId = useId();
|
||||
const emailId = useId();
|
||||
|
||||
useEffect(() => {
|
||||
const { client_cert, client_key, root_ca_cert } = getValues(serverConfig);
|
||||
setEncryptionProvider(
|
||||
!client_cert.length && !client_key.length && !root_ca_cert?.length
|
||||
? EncryptionProvider.Base64
|
||||
: EncryptionProvider.FilePath
|
||||
);
|
||||
}, [getValues]);
|
||||
|
||||
const renderMultiSelectLabel = (value: string) => {
|
||||
if (value.length >= 5) {
|
||||
return `${value.slice(0, 2)}...${value.slice(-2)}`;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
const groupMappingsLabel = (
|
||||
<Label
|
||||
className={styles.sectionLabel}
|
||||
@ -48,7 +80,7 @@ export const LdapDrawerComponent = ({ onClose }: Props) => {
|
||||
);
|
||||
|
||||
const useTlsDescription = (
|
||||
<Trans i18nKey="ldap-drawer.extra-security-section.use-ssl.tooltip">
|
||||
<Trans i18nKey="ldap-drawer.extra-security-section.use-ssl-tooltip">
|
||||
For a complete list of supported ciphers and TLS versions, refer to:{' '}
|
||||
{
|
||||
<TextLink style={{ fontSize: 'inherit' }} href="https://go.dev/src/crypto/tls/cipher_suites.go" external>
|
||||
@ -62,18 +94,18 @@ export const LdapDrawerComponent = ({ onClose }: Props) => {
|
||||
<Drawer title={t('ldap-drawer.title', 'Advanced settings')} onClose={onClose}>
|
||||
<CollapsableSection label={t('ldap-drawer.misc-section.label', 'Misc')} isOpen={true}>
|
||||
<Field
|
||||
label={t('ldap-drawer.misc-section.allow-sign-up.label', 'Allow sign up')}
|
||||
label={t('ldap-drawer.misc-section.allow-sign-up-label', 'Allow sign up')}
|
||||
description={t(
|
||||
'ldap-drawer.misc-section.allow-sign-up.descrition',
|
||||
'ldap-drawer.misc-section.allow-sign-up-descrition',
|
||||
'If not enabled, only existing Grafana users can log in using LDAP'
|
||||
)}
|
||||
>
|
||||
<Switch id="allow-sign-up" {...register('settings.allowSignUp')} />
|
||||
</Field>
|
||||
<Field
|
||||
label={t('ldap-drawer.misc-section.port.label', 'Port')}
|
||||
label={t('ldap-drawer.misc-section.port-label', 'Port')}
|
||||
description={t(
|
||||
'ldap-drawer.misc-section.port.description',
|
||||
'ldap-drawer.misc-section.port-description',
|
||||
'Default port is 389 without SSL or 636 with SSL'
|
||||
)}
|
||||
>
|
||||
@ -81,13 +113,13 @@ export const LdapDrawerComponent = ({ onClose }: Props) => {
|
||||
id="port"
|
||||
placeholder="389"
|
||||
type="number"
|
||||
{...register('settings.config.servers.0.port', { valueAsNumber: true })}
|
||||
{...register(`${serverConfig}.port`, { valueAsNumber: true })}
|
||||
/>
|
||||
</Field>
|
||||
<Field
|
||||
label={t('ldap-drawer.misc-section.timeout.label', 'Timeout')}
|
||||
label={t('ldap-drawer.misc-section.timeout-label', 'Timeout')}
|
||||
description={t(
|
||||
'ldap-drawer.misc-section.timeout.description',
|
||||
'ldap-drawer.misc-section.timeout-description',
|
||||
'Timeout in seconds for the connection to the LDAP server'
|
||||
)}
|
||||
>
|
||||
@ -95,7 +127,7 @@ export const LdapDrawerComponent = ({ onClose }: Props) => {
|
||||
id="timeout"
|
||||
placeholder="10"
|
||||
type="number"
|
||||
{...register('settings.config.servers.0.timeout', { valueAsNumber: true })}
|
||||
{...register(`${serverConfig}.timeout`, { valueAsNumber: true })}
|
||||
/>
|
||||
</Field>
|
||||
</CollapsableSection>
|
||||
@ -106,72 +138,70 @@ export const LdapDrawerComponent = ({ onClose }: Props) => {
|
||||
the application correctly retrieves and displays user information.
|
||||
</Trans>
|
||||
</Text>
|
||||
<Field label={t('ldap-drawer.attributes-section.name.label', 'Name')}>
|
||||
<Input id={nameId} {...register('settings.config.servers.0.attributes.name')} />
|
||||
<Field label={t('ldap-drawer.attributes-section.name-label', 'Name')}>
|
||||
<Input id={nameId} {...register(`${serverConfig}.attributes.name`)} />
|
||||
</Field>
|
||||
<Field label={t('ldap-drawer.attributes-section.surname.label', 'Surname')}>
|
||||
<Input id={surnameId} {...register('settings.config.servers.0.attributes.surname')} />
|
||||
<Field label={t('ldap-drawer.attributes-section.surname-label', 'Surname')}>
|
||||
<Input id={surnameId} {...register(`${serverConfig}.attributes.surname`)} />
|
||||
</Field>
|
||||
<Field label={t('ldap-drawer.attributes-section.username.label', 'Username')}>
|
||||
<Input id={usernameId} {...register('settings.config.servers.0.attributes.username')} />
|
||||
<Field label={t('ldap-drawer.attributes-section.username-label', 'Username')}>
|
||||
<Input id={usernameId} {...register(`${serverConfig}.attributes.username`)} />
|
||||
</Field>
|
||||
<Field label={t('ldap-drawer.attributes-section.member-of.label', 'Member Of')}>
|
||||
<Input id={memberOfId} {...register('settings.config.servers.0.attributes.member_of')} />
|
||||
<Field label={t('ldap-drawer.attributes-section.member-of-label', 'Member Of')}>
|
||||
<Input id={memberOfId} {...register(`${serverConfig}.attributes.member_of`)} />
|
||||
</Field>
|
||||
<Field label={t('ldap-drawer.attributes-section.email.label', 'Email')}>
|
||||
<Input id={emailId} {...register('settings.config.servers.0.attributes.email')} />
|
||||
<Field label={t('ldap-drawer.attributes-section.email-label', 'Email')}>
|
||||
<Input id={emailId} {...register(`${serverConfig}.attributes.email`)} />
|
||||
</Field>
|
||||
</CollapsableSection>
|
||||
<CollapsableSection label={groupMappingsLabel} isOpen={true}>
|
||||
<Field
|
||||
htmlFor="skip-org-role-sync"
|
||||
label={t('ldap-drawer.group-mapping-section.skip-org-role-sync.label', 'Skip organization role sync')}
|
||||
label={t('ldap-drawer.group-mapping-section.skip-org-role-sync-label', 'Skip organization role sync')}
|
||||
description={t(
|
||||
'ldap-drawer.group-mapping-section.skip-org-role-sync.description',
|
||||
'ldap-drawer.group-mapping-section.skip-org-role-sync-description',
|
||||
'Prevent synchronizing users’ organization roles from your IdP'
|
||||
)}
|
||||
>
|
||||
<Switch id="skip-org-role-sync" {...register('settings.config.servers.0.skip_org_role_sync')} />
|
||||
<Switch id="skip-org-role-sync" {...register(`${serverConfig}.skip_org_role_sync`)} />
|
||||
</Field>
|
||||
<Field
|
||||
htmlFor="group-search-filter"
|
||||
label={t('ldap-drawer.group-mapping-section.group-search-filter.label', 'Group search filter')}
|
||||
label={t('ldap-drawer.group-mapping-section.group-search-filter-label', 'Group search filter')}
|
||||
description={t(
|
||||
'ldap-drawer.group-mapping-section.group-search-filter.description',
|
||||
'ldap-drawer.group-mapping-section.group-search-filter-description',
|
||||
'Used to filter and identify group entries within the directory'
|
||||
)}
|
||||
>
|
||||
<Input id="group-search-filter" {...register('settings.config.servers.0.group_search_filter')} />
|
||||
<Input id="group-search-filter" {...register(`${serverConfig}.group_search_filter`)} />
|
||||
</Field>
|
||||
<Field
|
||||
htmlFor="group-search-base-dns"
|
||||
label={t('ldap-drawer.group-mapping-section.group-search-base-dns.label', 'Group search base DNS')}
|
||||
label={t('ldap-drawer.group-mapping-section.group-search-base-dns-label', 'Group search base DNS')}
|
||||
description={t(
|
||||
'ldap-drawer.group-mapping-section.group-search-base-dns.description',
|
||||
'ldap-drawer.group-mapping-section.group-search-base-dns-description',
|
||||
'Separate by commas or spaces'
|
||||
)}
|
||||
>
|
||||
<Input
|
||||
id="group-search-base-dns"
|
||||
onChange={({ currentTarget: { value } }) =>
|
||||
setValue('settings.config.servers.0.group_search_base_dns', [value])
|
||||
}
|
||||
onChange={({ currentTarget: { value } }) => setValue(`${serverConfig}.group_search_base_dns`, [value])}
|
||||
/>
|
||||
</Field>
|
||||
<Field
|
||||
htmlFor="group-search-filter-user-attribute"
|
||||
label={t(
|
||||
'ldap-drawer.group-mapping-section.group-search-filter-user-attribute.label',
|
||||
'ldap-drawer.group-mapping-section.group-search-filter-user-attribute-label',
|
||||
'Group name attribute'
|
||||
)}
|
||||
description={t(
|
||||
'ldap-drawer.group-mapping-section.group-search-filter-user-attribute.description',
|
||||
'ldap-drawer.group-mapping-section.group-search-filter-user-attribute-description',
|
||||
'Identifies users within group entries for filtering purposes'
|
||||
)}
|
||||
>
|
||||
<Input
|
||||
id="group-search-filter-user-attribute"
|
||||
{...register('settings.config.servers.0.group_search_filter_user_attribute')}
|
||||
{...register(`${serverConfig}.group_search_filter_user_attribute`)}
|
||||
/>
|
||||
</Field>
|
||||
<Divider />
|
||||
@ -181,67 +211,203 @@ export const LdapDrawerComponent = ({ onClose }: Props) => {
|
||||
isOpen={true}
|
||||
>
|
||||
<Field
|
||||
label={t('ldap-drawer.extra-security-section.use-ssl.label', 'Use SSL')}
|
||||
label={t('ldap-drawer.extra-security-section.use-ssl-label', 'Use SSL')}
|
||||
description={t(
|
||||
'ldap-drawer.extra-security-section.use-ssl.description',
|
||||
'ldap-drawer.extra-security-section.use-ssl-description',
|
||||
'Set to true if LDAP server should use TLS connection (either with STARTTLS or LDAPS)'
|
||||
)}
|
||||
>
|
||||
<Stack>
|
||||
<Switch id="use-ssl" {...register('settings.config.servers.0.use_ssl')} />
|
||||
<Switch id="use-ssl" {...register(`${serverConfig}.use_ssl`)} />
|
||||
<Tooltip content={useTlsDescription} interactive>
|
||||
<Icon name="info-circle" />
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
</Field>
|
||||
{watch('settings.config.servers.0.use_ssl') && (
|
||||
{watch(`${serverConfig}.use_ssl`) && (
|
||||
<>
|
||||
<Field
|
||||
label={t('ldap-drawer.extra-security-section.start-tls.label', 'Start TLS')}
|
||||
label={t('ldap-drawer.extra-security-section.start-tls-label', 'Start TLS')}
|
||||
description={t(
|
||||
'ldap-drawer.extra-security-section.start-tls.description',
|
||||
'ldap-drawer.extra-security-section.start-tls-description',
|
||||
'If set to true, use LDAP with STARTTLS instead of LDAPS'
|
||||
)}
|
||||
>
|
||||
<Switch id="start-tls" {...register('settings.config.servers.0.start_tls')} />
|
||||
<Switch id="start-tls" {...register(`${serverConfig}.start_tls`)} />
|
||||
</Field>
|
||||
<Field
|
||||
htmlFor="min-tls-version"
|
||||
label={t('ldap-drawer.extra-security-section.min-tls-version.label', 'Min TLS version')}
|
||||
label={t('ldap-drawer.extra-security-section.min-tls-version-label', 'Min TLS version')}
|
||||
description={t(
|
||||
'ldap-drawer.extra-security-section.min-tls-version.description',
|
||||
'ldap-drawer.extra-security-section.min-tls-version-description',
|
||||
'This is the minimum TLS version allowed. Accepted values are: TLS1.2, TLS1.3.'
|
||||
)}
|
||||
>
|
||||
<Select
|
||||
id="min-tls-version"
|
||||
options={tlsOptions}
|
||||
value={watch('settings.config.servers.0.min_tls_version')}
|
||||
onChange={({ value }) => setValue('settings.config.servers.0.min_tls_version', value)}
|
||||
value={watch(`${serverConfig}.min_tls_version`)}
|
||||
onChange={({ value }) => setValue(`${serverConfig}.min_tls_version`, value)}
|
||||
/>
|
||||
</Field>
|
||||
<Field
|
||||
label={t('ldap-drawer.extra-security-section.tls-ciphers.label', 'TLS ciphers')}
|
||||
label={t('ldap-drawer.extra-security-section.tls-ciphers-label', 'TLS ciphers')}
|
||||
description={t(
|
||||
'ldap-drawer.extra-security-section.tls-ciphers.description',
|
||||
'ldap-drawer.extra-security-section.tls-ciphers-description',
|
||||
'List of comma- or space-separated ciphers'
|
||||
)}
|
||||
>
|
||||
<Input
|
||||
id="tls-ciphers"
|
||||
placeholder={t(
|
||||
'ldap-drawer.extra-security-section.tls-ciphers.placeholder',
|
||||
'ldap-drawer.extra-security-section.tls-ciphers-placeholder',
|
||||
'e.g. ["TLS_AES_256_GCM_SHA384"]'
|
||||
)}
|
||||
value={watch('settings.config.servers.0.tls_ciphers')}
|
||||
value={watch(`${serverConfig}.tls_ciphers`) || ''}
|
||||
onChange={({ currentTarget: { value } }) =>
|
||||
setValue(
|
||||
'settings.config.servers.0.tls_ciphers',
|
||||
value?.split(/,|\s/).map((v: string) => v.trim())
|
||||
`${serverConfig}.tls_ciphers`,
|
||||
value?.split(/,|\s/).map((v) => v.trim())
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Field>
|
||||
<Field
|
||||
label={t(
|
||||
'ldap-drawer.extra-security-section.encryption-provider-label',
|
||||
'Encryption key and certificate provision specification.'
|
||||
)}
|
||||
description={t(
|
||||
'ldap-drawer.extra-security-section.encryption-provider-description',
|
||||
'X.509 certificate provides the public part, while the private key issued in a PKCS#8 format provides the private part of the asymmetric encryption.'
|
||||
)}
|
||||
>
|
||||
<RadioButtonGroup
|
||||
id="encryption-provider"
|
||||
options={[
|
||||
{
|
||||
label: t(
|
||||
'ldap-drawer.extra-security-section.encryption-provider-base-64',
|
||||
'Base64-encoded content'
|
||||
),
|
||||
value: EncryptionProvider.Base64,
|
||||
},
|
||||
{
|
||||
label: t('ldap-drawer.extra-security-section.encryption-provider-file-path', 'Path to files'),
|
||||
value: EncryptionProvider.FilePath,
|
||||
},
|
||||
]}
|
||||
value={encryptionProvider}
|
||||
onChange={setEncryptionProvider}
|
||||
/>
|
||||
</Field>
|
||||
{encryptionProvider === EncryptionProvider.Base64 && (
|
||||
<>
|
||||
<Field
|
||||
label={t(
|
||||
'ldap-drawer.extra-security-section.root-ca-cert-value-label',
|
||||
'Root CA certificate content'
|
||||
)}
|
||||
>
|
||||
<MultiSelect
|
||||
id="root-ca-cert"
|
||||
allowCustomValue
|
||||
onChange={(v) => {
|
||||
setValue(
|
||||
`${serverConfig}.root_ca_cert_value`,
|
||||
v.filter(({ v }) => typeof v === 'string')?.map(({ v }) => v)
|
||||
);
|
||||
}}
|
||||
value={watch(`${serverConfig}.root_ca_cert_value`)?.map((v) => ({
|
||||
label: renderMultiSelectLabel(v),
|
||||
value: v,
|
||||
}))}
|
||||
/>
|
||||
</Field>
|
||||
<Field
|
||||
label={t('ldap-drawer.extra-security-section.client-cert-value-label', 'Client certificate content')}
|
||||
>
|
||||
<SecretInput
|
||||
id="client-cert"
|
||||
placeholder={t(
|
||||
'ldap-drawer.extra-security-section.client-cert-value-placeholder',
|
||||
'Client certificate content in base64'
|
||||
)}
|
||||
isConfigured={mapCertConfigured.clientCertValue}
|
||||
onReset={() => {
|
||||
setValue(`${serverConfig}.client_cert_value`, '');
|
||||
setMapCertConfigured({ ...mapCertConfigured, clientCertValue: false });
|
||||
}}
|
||||
/>
|
||||
</Field>
|
||||
<Field label={t('ldap-drawer.extra-security-section.client-key-value-label', 'Client key content')}>
|
||||
<SecretInput
|
||||
id="client-key"
|
||||
placeholder={t(
|
||||
'ldap-drawer.extra-security-section.client-key-value-placeholder',
|
||||
'Client key content in base64'
|
||||
)}
|
||||
isConfigured={mapCertConfigured.clientKeyCertValue}
|
||||
onReset={() => {
|
||||
setValue(`${serverConfig}.client_key_value`, '');
|
||||
setMapCertConfigured({ ...mapCertConfigured, clientKeyCertValue: false });
|
||||
}}
|
||||
/>
|
||||
</Field>
|
||||
</>
|
||||
)}
|
||||
{encryptionProvider === EncryptionProvider.FilePath && (
|
||||
<>
|
||||
<Field label={t('ldap-drawer.extra-security-section.root-ca-cert-label', 'Root CA certificate path')}>
|
||||
<SecretInput
|
||||
id="root-ca-cert"
|
||||
placeholder={t(
|
||||
'ldap-drawer.extra-security-section.root-ca-cert-placeholder',
|
||||
'/path/to/root_ca_cert.pem'
|
||||
)}
|
||||
isConfigured={mapCertConfigured.rootCaCertPath}
|
||||
onReset={() => {
|
||||
setValue(`${serverConfig}.root_ca_cert`, '');
|
||||
setMapCertConfigured({ ...mapCertConfigured, rootCaCertPath: false });
|
||||
}}
|
||||
value={watch(`${serverConfig}.root_ca_cert`)}
|
||||
onChange={({ currentTarget: { value } }) => setValue(`${serverConfig}.root_ca_cert`, value)}
|
||||
/>
|
||||
</Field>
|
||||
<Field label={t('ldap-drawer.extra-security-section.client-cert-label', 'Client certificate path')}>
|
||||
<SecretInput
|
||||
id="client-cert"
|
||||
placeholder={t(
|
||||
'ldap-drawer.extra-security-section.client-cert-placeholder',
|
||||
'/path/to/client_cert.pem'
|
||||
)}
|
||||
isConfigured={mapCertConfigured.clientCertPath}
|
||||
onReset={() => {
|
||||
setValue(`${serverConfig}.client_cert`, '');
|
||||
setMapCertConfigured({ ...mapCertConfigured, clientCertPath: false });
|
||||
}}
|
||||
value={watch(`${serverConfig}.client_cert`)}
|
||||
onChange={({ currentTarget: { value } }) => setValue(`${serverConfig}.client_cert`, value)}
|
||||
/>
|
||||
</Field>
|
||||
<Field label={t('ldap-drawer.extra-security-section.client-key-label', 'Client key path')}>
|
||||
<SecretInput
|
||||
id="client-key"
|
||||
placeholder={t(
|
||||
'ldap-drawer.extra-security-section.client-key-placeholder',
|
||||
'/path/to/client_key.pem'
|
||||
)}
|
||||
isConfigured={mapCertConfigured.clientKeyCertPath}
|
||||
onReset={() => {
|
||||
setValue(`${serverConfig}.client_key`, '');
|
||||
setMapCertConfigured({ ...mapCertConfigured, clientKeyCertPath: false });
|
||||
}}
|
||||
value={watch(`${serverConfig}.client_key`)}
|
||||
onChange={({ currentTarget: { value } }) => setValue(`${serverConfig}.client_key`, value)}
|
||||
/>
|
||||
</Field>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</CollapsableSection>
|
||||
|
@ -10,7 +10,7 @@ import { Page } from 'app/core/components/Page/Page';
|
||||
import config from 'app/core/config';
|
||||
import { t, Trans } from 'app/core/internationalization';
|
||||
import { Loader } from 'app/features/plugins/admin/components/Loader';
|
||||
import { LdapPayload, StoreState } from 'app/types';
|
||||
import { LdapPayload, MapKeyCertConfigured, StoreState } from 'app/types';
|
||||
|
||||
import { LdapDrawerComponent } from './LdapDrawer';
|
||||
|
||||
@ -44,7 +44,9 @@ const emptySettings: LdapPayload = {
|
||||
bind_dn: '',
|
||||
bind_password: '',
|
||||
client_cert: '',
|
||||
client_cert_value: '',
|
||||
client_key: '',
|
||||
client_key_value: '',
|
||||
group_mappings: [],
|
||||
group_search_base_dns: [],
|
||||
group_search_filter: '',
|
||||
@ -53,6 +55,7 @@ const emptySettings: LdapPayload = {
|
||||
min_tls_version: '',
|
||||
port: 389,
|
||||
root_ca_cert: '',
|
||||
root_ca_cert_value: [],
|
||||
search_base_dns: [],
|
||||
search_filter: '',
|
||||
skip_org_role_sync: false,
|
||||
@ -75,6 +78,17 @@ export const LdapSettingsPage = () => {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [isDrawerOpen, setIsDrawerOpen] = useState(false);
|
||||
|
||||
const [mapKeyCertConfigured, setMapKeyCertConfigured] = useState<MapKeyCertConfigured>({
|
||||
// values
|
||||
rootCaCertValue: false,
|
||||
clientCertValue: false,
|
||||
clientKeyCertValue: false,
|
||||
// paths
|
||||
rootCaCertPath: false,
|
||||
clientCertPath: false,
|
||||
clientKeyCertPath: false,
|
||||
});
|
||||
|
||||
const methods = useForm<LdapPayload>({ defaultValues: emptySettings });
|
||||
const { getValues, handleSubmit, register, reset } = methods;
|
||||
|
||||
@ -91,6 +105,16 @@ export const LdapSettingsPage = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
const serverConfig = payload.settings.config.servers[0];
|
||||
setMapKeyCertConfigured({
|
||||
rootCaCertValue: serverConfig.root_ca_cert_value?.length > 0,
|
||||
clientCertValue: serverConfig.client_cert_value !== '',
|
||||
clientKeyCertValue: serverConfig.client_key_value !== '',
|
||||
rootCaCertPath: serverConfig.root_ca_cert !== '',
|
||||
clientCertPath: serverConfig.client_cert !== '',
|
||||
clientKeyCertPath: serverConfig.client_key !== '',
|
||||
});
|
||||
|
||||
reset(payload);
|
||||
setIsLoading(false);
|
||||
}
|
||||
@ -300,7 +324,13 @@ export const LdapSettingsPage = () => {
|
||||
</Box>
|
||||
</section>
|
||||
)}
|
||||
{isDrawerOpen && <LdapDrawerComponent onClose={() => setIsDrawerOpen(false)} />}
|
||||
{isDrawerOpen && (
|
||||
<LdapDrawerComponent
|
||||
onClose={() => setIsDrawerOpen(false)}
|
||||
mapKeyCertConfigured={mapKeyCertConfigured}
|
||||
setMapKeyCertConfigured={setMapKeyCertConfigured}
|
||||
/>
|
||||
)}
|
||||
</form>
|
||||
</FormProvider>
|
||||
</Page.Contents>
|
||||
|
@ -84,7 +84,9 @@ export interface LdapServerConfig {
|
||||
bind_dn: string;
|
||||
bind_password?: string;
|
||||
client_cert: string;
|
||||
client_cert_value: string;
|
||||
client_key: string;
|
||||
client_key_value: string;
|
||||
group_mappings: GroupMapping[];
|
||||
group_search_base_dns: string[];
|
||||
group_search_filter: string;
|
||||
@ -93,6 +95,7 @@ export interface LdapServerConfig {
|
||||
min_tls_version?: string;
|
||||
port: number;
|
||||
root_ca_cert: string;
|
||||
root_ca_cert_value: string[];
|
||||
search_base_dns: string[];
|
||||
search_filter: string;
|
||||
skip_org_role_sync: boolean;
|
||||
@ -135,3 +138,12 @@ export interface LdapPayload {
|
||||
settings: LdapSettings;
|
||||
source: string;
|
||||
}
|
||||
|
||||
export interface MapKeyCertConfigured {
|
||||
rootCaCertValue: boolean;
|
||||
clientCertValue: boolean;
|
||||
clientKeyCertValue: boolean;
|
||||
rootCaCertPath: boolean;
|
||||
clientCertPath: boolean;
|
||||
clientKeyCertPath: boolean;
|
||||
}
|
||||
|
@ -1005,78 +1005,61 @@
|
||||
"ldap-drawer": {
|
||||
"attributes-section": {
|
||||
"description": "Specify the LDAP attributes that map to the user‘s given name, surname, and email address, ensuring the application correctly retrieves and displays user information.",
|
||||
"email": {
|
||||
"label": "Email"
|
||||
},
|
||||
"email-label": "Email",
|
||||
"label": "Attributes",
|
||||
"member-of": {
|
||||
"label": "Member Of"
|
||||
},
|
||||
"name": {
|
||||
"label": "Name"
|
||||
},
|
||||
"surname": {
|
||||
"label": "Surname"
|
||||
},
|
||||
"username": {
|
||||
"label": "Username"
|
||||
}
|
||||
"member-of-label": "Member Of",
|
||||
"name-label": "Name",
|
||||
"surname-label": "Surname",
|
||||
"username-label": "Username"
|
||||
},
|
||||
"extra-security-section": {
|
||||
"client-cert-label": "Client certificate path",
|
||||
"client-cert-placeholder": "/path/to/client_cert.pem",
|
||||
"client-cert-value-label": "Client certificate content",
|
||||
"client-cert-value-placeholder": "Client certificate content in base64",
|
||||
"client-key-label": "Client key path",
|
||||
"client-key-placeholder": "/path/to/client_key.pem",
|
||||
"client-key-value-label": "Client key content",
|
||||
"client-key-value-placeholder": "Client key content in base64",
|
||||
"encryption-provider-base-64": "Base64-encoded content",
|
||||
"encryption-provider-description": "X.509 certificate provides the public part, while the private key issued in a PKCS#8 format provides the private part of the asymmetric encryption.",
|
||||
"encryption-provider-file-path": "Path to files",
|
||||
"encryption-provider-label": "Encryption key and certificate provision specification.",
|
||||
"label": "Extra security measures",
|
||||
"min-tls-version": {
|
||||
"description": "This is the minimum TLS version allowed. Accepted values are: TLS1.2, TLS1.3.",
|
||||
"label": "Min TLS version"
|
||||
},
|
||||
"start-tls": {
|
||||
"description": "If set to true, use LDAP with STARTTLS instead of LDAPS",
|
||||
"label": "Start TLS"
|
||||
},
|
||||
"tls-ciphers": {
|
||||
"description": "List of comma- or space-separated ciphers",
|
||||
"label": "TLS ciphers",
|
||||
"placeholder": "e.g. [\"TLS_AES_256_GCM_SHA384\"]"
|
||||
},
|
||||
"use-ssl": {
|
||||
"description": "Set to true if LDAP server should use TLS connection (either with STARTTLS or LDAPS)",
|
||||
"label": "Use SSL",
|
||||
"tooltip": "For a complete list of supported ciphers and TLS versions, refer to: {\n <TextLink style={{ fontSize: 'inherit' }} href=\"https://go.dev/src/crypto/tls/cipher_suites.go\" external>\n https://go.dev/src/crypto/tls/cipher_suites.go\n </TextLink>}"
|
||||
}
|
||||
"min-tls-version-description": "This is the minimum TLS version allowed. Accepted values are: TLS1.2, TLS1.3.",
|
||||
"min-tls-version-label": "Min TLS version",
|
||||
"root-ca-cert-label": "Root CA certificate path",
|
||||
"root-ca-cert-placeholder": "/path/to/root_ca_cert.pem",
|
||||
"root-ca-cert-value-label": "Root CA certificate content",
|
||||
"start-tls-description": "If set to true, use LDAP with STARTTLS instead of LDAPS",
|
||||
"start-tls-label": "Start TLS",
|
||||
"tls-ciphers-description": "List of comma- or space-separated ciphers",
|
||||
"tls-ciphers-label": "TLS ciphers",
|
||||
"tls-ciphers-placeholder": "e.g. [\"TLS_AES_256_GCM_SHA384\"]",
|
||||
"use-ssl-description": "Set to true if LDAP server should use TLS connection (either with STARTTLS or LDAPS)",
|
||||
"use-ssl-label": "Use SSL",
|
||||
"use-ssl-tooltip": "For a complete list of supported ciphers and TLS versions, refer to: {\n <TextLink style={{ fontSize: 'inherit' }} href=\"https://go.dev/src/crypto/tls/cipher_suites.go\" external>\n https://go.dev/src/crypto/tls/cipher_suites.go\n </TextLink>}"
|
||||
},
|
||||
"group-mapping-section": {
|
||||
"description": "Map LDAP groups to Grafana org roles",
|
||||
"group-search-base-dns": {
|
||||
"description": "Separate by commas or spaces",
|
||||
"label": "Group search base DNS"
|
||||
},
|
||||
"group-search-filter": {
|
||||
"description": "Used to filter and identify group entries within the directory",
|
||||
"label": "Group search filter"
|
||||
},
|
||||
"group-search-filter-user-attribute": {
|
||||
"description": "Identifies users within group entries for filtering purposes",
|
||||
"label": "Group name attribute"
|
||||
},
|
||||
"group-search-base-dns-description": "Separate by commas or spaces",
|
||||
"group-search-base-dns-label": "Group search base DNS",
|
||||
"group-search-filter-description": "Used to filter and identify group entries within the directory",
|
||||
"group-search-filter-label": "Group search filter",
|
||||
"group-search-filter-user-attribute-description": "Identifies users within group entries for filtering purposes",
|
||||
"group-search-filter-user-attribute-label": "Group name attribute",
|
||||
"label": "Group mapping",
|
||||
"skip-org-role-sync": {
|
||||
"description": "Prevent synchronizing users’ organization roles from your IdP",
|
||||
"label": "Skip organization role sync"
|
||||
}
|
||||
"skip-org-role-sync-description": "Prevent synchronizing users’ organization roles from your IdP",
|
||||
"skip-org-role-sync-label": "Skip organization role sync"
|
||||
},
|
||||
"misc-section": {
|
||||
"allow-sign-up": {
|
||||
"descrition": "If not enabled, only existing Grafana users can log in using LDAP",
|
||||
"label": "Allow sign up"
|
||||
},
|
||||
"allow-sign-up-descrition": "If not enabled, only existing Grafana users can log in using LDAP",
|
||||
"allow-sign-up-label": "Allow sign up",
|
||||
"label": "Misc",
|
||||
"port": {
|
||||
"description": "Default port is 389 without SSL or 636 with SSL",
|
||||
"label": "Port"
|
||||
},
|
||||
"timeout": {
|
||||
"description": "Timeout in seconds for the connection to the LDAP server",
|
||||
"label": "Timeout"
|
||||
}
|
||||
"port-description": "Default port is 389 without SSL or 636 with SSL",
|
||||
"port-label": "Port",
|
||||
"timeout-description": "Timeout in seconds for the connection to the LDAP server",
|
||||
"timeout-label": "Timeout"
|
||||
},
|
||||
"title": "Advanced settings"
|
||||
},
|
||||
|
@ -1005,78 +1005,61 @@
|
||||
"ldap-drawer": {
|
||||
"attributes-section": {
|
||||
"description": "Ŝpęčįƒy ŧĥę ĿĐÅP äŧŧřįþūŧęş ŧĥäŧ mäp ŧő ŧĥę ūşęř&ľşqūő;ş ģįvęʼn ʼnämę, şūřʼnämę, äʼnđ ęmäįľ äđđřęşş, ęʼnşūřįʼnģ ŧĥę äppľįčäŧįőʼn čőřřęčŧľy řęŧřįęvęş äʼnđ đįşpľäyş ūşęř įʼnƒőřmäŧįőʼn.",
|
||||
"email": {
|
||||
"label": "Ēmäįľ"
|
||||
},
|
||||
"email-label": "Ēmäįľ",
|
||||
"label": "Åŧŧřįþūŧęş",
|
||||
"member-of": {
|
||||
"label": "Męmþęř ؃"
|
||||
},
|
||||
"name": {
|
||||
"label": "Ńämę"
|
||||
},
|
||||
"surname": {
|
||||
"label": "Ŝūřʼnämę"
|
||||
},
|
||||
"username": {
|
||||
"label": "Ůşęřʼnämę"
|
||||
}
|
||||
"member-of-label": "Męmþęř ؃",
|
||||
"name-label": "Ńämę",
|
||||
"surname-label": "Ŝūřʼnämę",
|
||||
"username-label": "Ůşęřʼnämę"
|
||||
},
|
||||
"extra-security-section": {
|
||||
"client-cert-label": "Cľįęʼnŧ čęřŧįƒįčäŧę päŧĥ",
|
||||
"client-cert-placeholder": "/päŧĥ/ŧő/čľįęʼnŧ_čęřŧ.pęm",
|
||||
"client-cert-value-label": "Cľįęʼnŧ čęřŧįƒįčäŧę čőʼnŧęʼnŧ",
|
||||
"client-cert-value-placeholder": "Cľįęʼnŧ čęřŧįƒįčäŧę čőʼnŧęʼnŧ įʼn þäşę64",
|
||||
"client-key-label": "Cľįęʼnŧ ĸęy päŧĥ",
|
||||
"client-key-placeholder": "/päŧĥ/ŧő/čľįęʼnŧ_ĸęy.pęm",
|
||||
"client-key-value-label": "Cľįęʼnŧ ĸęy čőʼnŧęʼnŧ",
|
||||
"client-key-value-placeholder": "Cľįęʼnŧ ĸęy čőʼnŧęʼnŧ įʼn þäşę64",
|
||||
"encryption-provider-base-64": "ßäşę64-ęʼnčőđęđ čőʼnŧęʼnŧ",
|
||||
"encryption-provider-description": "X.509 čęřŧįƒįčäŧę přővįđęş ŧĥę pūþľįč päřŧ, ŵĥįľę ŧĥę přįväŧę ĸęy įşşūęđ įʼn ä PĶCŜ#8 ƒőřmäŧ přővįđęş ŧĥę přįväŧę päřŧ őƒ ŧĥę äşymmęŧřįč ęʼnčřypŧįőʼn.",
|
||||
"encryption-provider-file-path": "Päŧĥ ŧő ƒįľęş",
|
||||
"encryption-provider-label": "Ēʼnčřypŧįőʼn ĸęy äʼnđ čęřŧįƒįčäŧę přővįşįőʼn şpęčįƒįčäŧįőʼn.",
|
||||
"label": "Ēχŧřä şęčūřįŧy męäşūřęş",
|
||||
"min-tls-version": {
|
||||
"description": "Ŧĥįş įş ŧĥę mįʼnįmūm ŦĿŜ vęřşįőʼn äľľőŵęđ. Åččępŧęđ väľūęş äřę: ŦĿŜ1.2, ŦĿŜ1.3.",
|
||||
"label": "Mįʼn ŦĿŜ vęřşįőʼn"
|
||||
},
|
||||
"start-tls": {
|
||||
"description": "Ĩƒ şęŧ ŧő ŧřūę, ūşę ĿĐÅP ŵįŧĥ ŜŦÅŖŦŦĿŜ įʼnşŧęäđ őƒ ĿĐÅPŜ",
|
||||
"label": "Ŝŧäřŧ ŦĿŜ"
|
||||
},
|
||||
"tls-ciphers": {
|
||||
"description": "Ŀįşŧ őƒ čőmmä- őř şpäčę-şępäřäŧęđ čįpĥęřş",
|
||||
"label": "ŦĿŜ čįpĥęřş",
|
||||
"placeholder": "ę.ģ. [\"ŦĿŜ_ÅĒŜ_256_ĞCM_ŜĦÅ384\"]"
|
||||
},
|
||||
"use-ssl": {
|
||||
"description": "Ŝęŧ ŧő ŧřūę įƒ ĿĐÅP şęřvęř şĥőūľđ ūşę ŦĿŜ čőʼnʼnęčŧįőʼn (ęįŧĥęř ŵįŧĥ ŜŦÅŖŦŦĿŜ őř ĿĐÅPŜ)",
|
||||
"label": "Ůşę ŜŜĿ",
|
||||
"tooltip": "Főř ä čőmpľęŧę ľįşŧ őƒ şūppőřŧęđ čįpĥęřş äʼnđ ŦĿŜ vęřşįőʼnş, řęƒęř ŧő: {\n <ŦęχŧĿįʼnĸ şŧyľę={{ fontSize: 'inherit' }} ĥřęƒ=\"ĥŧŧpş://ģő.đęv/şřč/čřypŧő/ŧľş/čįpĥęř_şūįŧęş.ģő\" ęχŧęřʼnäľ>\n ĥŧŧpş://ģő.đęv/şřč/čřypŧő/ŧľş/čįpĥęř_şūįŧęş.ģő\n </ŦęχŧĿįʼnĸ>}"
|
||||
}
|
||||
"min-tls-version-description": "Ŧĥįş įş ŧĥę mįʼnįmūm ŦĿŜ vęřşįőʼn äľľőŵęđ. Åččępŧęđ väľūęş äřę: ŦĿŜ1.2, ŦĿŜ1.3.",
|
||||
"min-tls-version-label": "Mįʼn ŦĿŜ vęřşįőʼn",
|
||||
"root-ca-cert-label": "Ŗőőŧ CÅ čęřŧįƒįčäŧę päŧĥ",
|
||||
"root-ca-cert-placeholder": "/päŧĥ/ŧő/řőőŧ_čä_čęřŧ.pęm",
|
||||
"root-ca-cert-value-label": "Ŗőőŧ CÅ čęřŧįƒįčäŧę čőʼnŧęʼnŧ",
|
||||
"start-tls-description": "Ĩƒ şęŧ ŧő ŧřūę, ūşę ĿĐÅP ŵįŧĥ ŜŦÅŖŦŦĿŜ įʼnşŧęäđ őƒ ĿĐÅPŜ",
|
||||
"start-tls-label": "Ŝŧäřŧ ŦĿŜ",
|
||||
"tls-ciphers-description": "Ŀįşŧ őƒ čőmmä- őř şpäčę-şępäřäŧęđ čįpĥęřş",
|
||||
"tls-ciphers-label": "ŦĿŜ čįpĥęřş",
|
||||
"tls-ciphers-placeholder": "ę.ģ. [\"ŦĿŜ_ÅĒŜ_256_ĞCM_ŜĦÅ384\"]",
|
||||
"use-ssl-description": "Ŝęŧ ŧő ŧřūę įƒ ĿĐÅP şęřvęř şĥőūľđ ūşę ŦĿŜ čőʼnʼnęčŧįőʼn (ęįŧĥęř ŵįŧĥ ŜŦÅŖŦŦĿŜ őř ĿĐÅPŜ)",
|
||||
"use-ssl-label": "Ůşę ŜŜĿ",
|
||||
"use-ssl-tooltip": "Főř ä čőmpľęŧę ľįşŧ őƒ şūppőřŧęđ čįpĥęřş äʼnđ ŦĿŜ vęřşįőʼnş, řęƒęř ŧő: {\n <ŦęχŧĿįʼnĸ şŧyľę={{ fontSize: 'inherit' }} ĥřęƒ=\"ĥŧŧpş://ģő.đęv/şřč/čřypŧő/ŧľş/čįpĥęř_şūįŧęş.ģő\" ęχŧęřʼnäľ>\n ĥŧŧpş://ģő.đęv/şřč/čřypŧő/ŧľş/čįpĥęř_şūįŧęş.ģő\n </ŦęχŧĿįʼnĸ>}"
|
||||
},
|
||||
"group-mapping-section": {
|
||||
"description": "Mäp ĿĐÅP ģřőūpş ŧő Ğřäƒäʼnä őřģ řőľęş",
|
||||
"group-search-base-dns": {
|
||||
"description": "Ŝępäřäŧę þy čőmmäş őř şpäčęş",
|
||||
"label": "Ğřőūp şęäřčĥ þäşę ĐŃŜ"
|
||||
},
|
||||
"group-search-filter": {
|
||||
"description": "Ůşęđ ŧő ƒįľŧęř äʼnđ įđęʼnŧįƒy ģřőūp ęʼnŧřįęş ŵįŧĥįʼn ŧĥę đįřęčŧőřy",
|
||||
"label": "Ğřőūp şęäřčĥ ƒįľŧęř"
|
||||
},
|
||||
"group-search-filter-user-attribute": {
|
||||
"description": "Ĩđęʼnŧįƒįęş ūşęřş ŵįŧĥįʼn ģřőūp ęʼnŧřįęş ƒőř ƒįľŧęřįʼnģ pūřpőşęş",
|
||||
"label": "Ğřőūp ʼnämę äŧŧřįþūŧę"
|
||||
},
|
||||
"group-search-base-dns-description": "Ŝępäřäŧę þy čőmmäş őř şpäčęş",
|
||||
"group-search-base-dns-label": "Ğřőūp şęäřčĥ þäşę ĐŃŜ",
|
||||
"group-search-filter-description": "Ůşęđ ŧő ƒįľŧęř äʼnđ įđęʼnŧįƒy ģřőūp ęʼnŧřįęş ŵįŧĥįʼn ŧĥę đįřęčŧőřy",
|
||||
"group-search-filter-label": "Ğřőūp şęäřčĥ ƒįľŧęř",
|
||||
"group-search-filter-user-attribute-description": "Ĩđęʼnŧįƒįęş ūşęřş ŵįŧĥįʼn ģřőūp ęʼnŧřįęş ƒőř ƒįľŧęřįʼnģ pūřpőşęş",
|
||||
"group-search-filter-user-attribute-label": "Ğřőūp ʼnämę äŧŧřįþūŧę",
|
||||
"label": "Ğřőūp mäppįʼnģ",
|
||||
"skip-org-role-sync": {
|
||||
"description": "Přęvęʼnŧ şyʼnčĥřőʼnįžįʼnģ ūşęřş’ őřģäʼnįžäŧįőʼn řőľęş ƒřőm yőūř ĨđP",
|
||||
"label": "Ŝĸįp őřģäʼnįžäŧįőʼn řőľę şyʼnč"
|
||||
}
|
||||
"skip-org-role-sync-description": "Přęvęʼnŧ şyʼnčĥřőʼnįžįʼnģ ūşęřş’ őřģäʼnįžäŧįőʼn řőľęş ƒřőm yőūř ĨđP",
|
||||
"skip-org-role-sync-label": "Ŝĸįp őřģäʼnįžäŧįőʼn řőľę şyʼnč"
|
||||
},
|
||||
"misc-section": {
|
||||
"allow-sign-up": {
|
||||
"descrition": "Ĩƒ ʼnőŧ ęʼnäþľęđ, őʼnľy ęχįşŧįʼnģ Ğřäƒäʼnä ūşęřş čäʼn ľőģ įʼn ūşįʼnģ ĿĐÅP",
|
||||
"label": "Åľľőŵ şįģʼn ūp"
|
||||
},
|
||||
"allow-sign-up-descrition": "Ĩƒ ʼnőŧ ęʼnäþľęđ, őʼnľy ęχįşŧįʼnģ Ğřäƒäʼnä ūşęřş čäʼn ľőģ įʼn ūşįʼnģ ĿĐÅP",
|
||||
"allow-sign-up-label": "Åľľőŵ şįģʼn ūp",
|
||||
"label": "Mįşč",
|
||||
"port": {
|
||||
"description": "Đęƒäūľŧ pőřŧ įş 389 ŵįŧĥőūŧ ŜŜĿ őř 636 ŵįŧĥ ŜŜĿ",
|
||||
"label": "Pőřŧ"
|
||||
},
|
||||
"timeout": {
|
||||
"description": "Ŧįmęőūŧ įʼn şęčőʼnđş ƒőř ŧĥę čőʼnʼnęčŧįőʼn ŧő ŧĥę ĿĐÅP şęřvęř",
|
||||
"label": "Ŧįmęőūŧ"
|
||||
}
|
||||
"port-description": "Đęƒäūľŧ pőřŧ įş 389 ŵįŧĥőūŧ ŜŜĿ őř 636 ŵįŧĥ ŜŜĿ",
|
||||
"port-label": "Pőřŧ",
|
||||
"timeout-description": "Ŧįmęőūŧ įʼn şęčőʼnđş ƒőř ŧĥę čőʼnʼnęčŧįőʼn ŧő ŧĥę ĿĐÅP şęřvęř",
|
||||
"timeout-label": "Ŧįmęőūŧ"
|
||||
},
|
||||
"title": "Åđväʼnčęđ şęŧŧįʼnģş"
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user