Auth: Translate Auth provider form fields (#105059)
* first pass at translating all of auth config * rename variables * translate missing phrases * add more
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { useState } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
|
|
||||||
import { AppEvents } from '@grafana/data';
|
import { AppEvents } from '@grafana/data';
|
||||||
@@ -22,7 +22,7 @@ import { FormPrompt } from '../../core/components/FormPrompt/FormPrompt';
|
|||||||
import { Page } from '../../core/components/Page/Page';
|
import { Page } from '../../core/components/Page/Page';
|
||||||
|
|
||||||
import { FieldRenderer } from './FieldRenderer';
|
import { FieldRenderer } from './FieldRenderer';
|
||||||
import { sectionFields } from './fields';
|
import { getSectionFields } from './fields';
|
||||||
import { SSOProvider, SSOProviderDTO } from './types';
|
import { SSOProvider, SSOProviderDTO } from './types';
|
||||||
import { dataToDTO, dtoToData } from './utils/data';
|
import { dataToDTO, dtoToData } from './utils/data';
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ export const ProviderConfigForm = ({ config, provider, isLoading }: ProviderConf
|
|||||||
const [isSaving, setIsSaving] = useState(false);
|
const [isSaving, setIsSaving] = useState(false);
|
||||||
const [submitError, setSubmitError] = useState(false);
|
const [submitError, setSubmitError] = useState(false);
|
||||||
const dataSubmitted = isSubmitted && !submitError;
|
const dataSubmitted = isSubmitted && !submitError;
|
||||||
const sections = sectionFields[provider];
|
const sections = useMemo(() => getSectionFields()[provider], [provider]);
|
||||||
const [resetConfig, setResetConfig] = useState(false);
|
const [resetConfig, setResetConfig] = useState(false);
|
||||||
|
|
||||||
const additionalActionsMenu = (
|
const additionalActionsMenu = (
|
||||||
@@ -211,7 +211,13 @@ export const ProviderConfigForm = ({ config, provider, isLoading }: ProviderConf
|
|||||||
onClick={() => onSaveAttempt(true)}
|
onClick={() => onSaveAttempt(true)}
|
||||||
variant={isEnabled ? 'secondary' : undefined}
|
variant={isEnabled ? 'secondary' : undefined}
|
||||||
>
|
>
|
||||||
{isSaving ? (isEnabled ? 'Disabling...' : 'Saving...') : isEnabled ? 'Disable' : 'Save and enable'}
|
{isSaving
|
||||||
|
? isEnabled
|
||||||
|
? t('auth-config.provider-config-form.disabling', 'Disabling...')
|
||||||
|
: t('auth-config.provider-config-form.saving', 'Saving...')
|
||||||
|
: isEnabled
|
||||||
|
? t('auth-config.provider-config-form.disable', 'Disable')
|
||||||
|
: t('auth-config.provider-config-form.save-and-enable', 'Save and enable')}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button type={'submit'} disabled={isSaving} variant={'secondary'} onClick={() => onSaveAttempt(false)}>
|
<Button type={'submit'} disabled={isSaving} variant={'secondary'} onClick={() => onSaveAttempt(false)}>
|
||||||
|
|||||||
@@ -22,10 +22,15 @@ type Section = Record<
|
|||||||
}>
|
}>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export const sectionFields: Section = {
|
export const getSectionFields = (): Section => {
|
||||||
|
const generalSettingsLabel = t('auth-config.fields.section-general-settings', 'General settings');
|
||||||
|
const userMappingLabel = t('auth-config.fields.section-user-mapping', 'User mapping');
|
||||||
|
const extraSecurityLabel = t('auth-config.fields.section-extra-security', 'Extra security measures');
|
||||||
|
|
||||||
|
return {
|
||||||
azuread: [
|
azuread: [
|
||||||
{
|
{
|
||||||
name: 'General settings',
|
name: generalSettingsLabel,
|
||||||
id: 'general',
|
id: 'general',
|
||||||
fields: [
|
fields: [
|
||||||
'name',
|
'name',
|
||||||
@@ -43,7 +48,7 @@ export const sectionFields: Section = {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'User mapping',
|
name: userMappingLabel,
|
||||||
id: 'user',
|
id: 'user',
|
||||||
fields: ['roleAttributeStrict', 'orgMapping', 'allowAssignGrafanaAdmin', 'skipOrgRoleSync'],
|
fields: ['roleAttributeStrict', 'orgMapping', 'allowAssignGrafanaAdmin', 'skipOrgRoleSync'],
|
||||||
},
|
},
|
||||||
@@ -66,7 +71,7 @@ export const sectionFields: Section = {
|
|||||||
],
|
],
|
||||||
generic_oauth: [
|
generic_oauth: [
|
||||||
{
|
{
|
||||||
name: 'General settings',
|
name: generalSettingsLabel,
|
||||||
id: 'general',
|
id: 'general',
|
||||||
fields: [
|
fields: [
|
||||||
'name',
|
'name',
|
||||||
@@ -84,7 +89,7 @@ export const sectionFields: Section = {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'User mapping',
|
name: userMappingLabel,
|
||||||
id: 'user',
|
id: 'user',
|
||||||
fields: [
|
fields: [
|
||||||
'nameAttributePath',
|
'nameAttributePath',
|
||||||
@@ -101,7 +106,7 @@ export const sectionFields: Section = {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Extra security measures',
|
name: extraSecurityLabel,
|
||||||
id: 'extra',
|
id: 'extra',
|
||||||
fields: [
|
fields: [
|
||||||
'allowedOrganizations',
|
'allowedOrganizations',
|
||||||
@@ -124,17 +129,23 @@ export const sectionFields: Section = {
|
|||||||
],
|
],
|
||||||
google: [
|
google: [
|
||||||
{
|
{
|
||||||
name: 'General settings',
|
name: generalSettingsLabel,
|
||||||
id: 'general',
|
id: 'general',
|
||||||
fields: ['name', 'clientId', 'clientSecret', 'scopes', 'allowSignUp', 'autoLogin', 'signoutRedirectUrl'],
|
fields: ['name', 'clientId', 'clientSecret', 'scopes', 'allowSignUp', 'autoLogin', 'signoutRedirectUrl'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'User mapping',
|
name: userMappingLabel,
|
||||||
id: 'user',
|
id: 'user',
|
||||||
fields: ['roleAttributePath', 'roleAttributeStrict', 'orgMapping', 'allowAssignGrafanaAdmin', 'skipOrgRoleSync'],
|
fields: [
|
||||||
|
'roleAttributePath',
|
||||||
|
'roleAttributeStrict',
|
||||||
|
'orgMapping',
|
||||||
|
'allowAssignGrafanaAdmin',
|
||||||
|
'skipOrgRoleSync',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Extra security measures',
|
name: extraSecurityLabel,
|
||||||
id: 'extra',
|
id: 'extra',
|
||||||
fields: [
|
fields: [
|
||||||
'validateHd',
|
'validateHd',
|
||||||
@@ -152,17 +163,23 @@ export const sectionFields: Section = {
|
|||||||
],
|
],
|
||||||
github: [
|
github: [
|
||||||
{
|
{
|
||||||
name: 'General settings',
|
name: generalSettingsLabel,
|
||||||
id: 'general',
|
id: 'general',
|
||||||
fields: ['name', 'clientId', 'clientSecret', 'scopes', 'allowSignUp', 'autoLogin', 'signoutRedirectUrl'],
|
fields: ['name', 'clientId', 'clientSecret', 'scopes', 'allowSignUp', 'autoLogin', 'signoutRedirectUrl'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'User mapping',
|
name: userMappingLabel,
|
||||||
id: 'user',
|
id: 'user',
|
||||||
fields: ['roleAttributePath', 'roleAttributeStrict', 'orgMapping', 'allowAssignGrafanaAdmin', 'skipOrgRoleSync'],
|
fields: [
|
||||||
|
'roleAttributePath',
|
||||||
|
'roleAttributeStrict',
|
||||||
|
'orgMapping',
|
||||||
|
'allowAssignGrafanaAdmin',
|
||||||
|
'skipOrgRoleSync',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Extra security measures',
|
name: extraSecurityLabel,
|
||||||
id: 'extra',
|
id: 'extra',
|
||||||
fields: [
|
fields: [
|
||||||
'allowedOrganizations',
|
'allowedOrganizations',
|
||||||
@@ -179,17 +196,23 @@ export const sectionFields: Section = {
|
|||||||
],
|
],
|
||||||
gitlab: [
|
gitlab: [
|
||||||
{
|
{
|
||||||
name: 'General settings',
|
name: generalSettingsLabel,
|
||||||
id: 'general',
|
id: 'general',
|
||||||
fields: ['name', 'clientId', 'clientSecret', 'scopes', 'allowSignUp', 'autoLogin', 'signoutRedirectUrl'],
|
fields: ['name', 'clientId', 'clientSecret', 'scopes', 'allowSignUp', 'autoLogin', 'signoutRedirectUrl'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'User mapping',
|
name: userMappingLabel,
|
||||||
id: 'user',
|
id: 'user',
|
||||||
fields: ['roleAttributePath', 'roleAttributeStrict', 'orgMapping', 'allowAssignGrafanaAdmin', 'skipOrgRoleSync'],
|
fields: [
|
||||||
|
'roleAttributePath',
|
||||||
|
'roleAttributeStrict',
|
||||||
|
'orgMapping',
|
||||||
|
'allowAssignGrafanaAdmin',
|
||||||
|
'skipOrgRoleSync',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Extra security measures',
|
name: extraSecurityLabel,
|
||||||
id: 'extra',
|
id: 'extra',
|
||||||
fields: [
|
fields: [
|
||||||
'allowedDomains',
|
'allowedDomains',
|
||||||
@@ -205,7 +228,7 @@ export const sectionFields: Section = {
|
|||||||
],
|
],
|
||||||
okta: [
|
okta: [
|
||||||
{
|
{
|
||||||
name: 'General settings',
|
name: generalSettingsLabel,
|
||||||
id: 'general',
|
id: 'general',
|
||||||
fields: [
|
fields: [
|
||||||
'name',
|
'name',
|
||||||
@@ -221,7 +244,7 @@ export const sectionFields: Section = {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'User mapping',
|
name: userMappingLabel,
|
||||||
id: 'user',
|
id: 'user',
|
||||||
fields: [
|
fields: [
|
||||||
'roleAttributePath',
|
'roleAttributePath',
|
||||||
@@ -233,7 +256,7 @@ export const sectionFields: Section = {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Extra security measures',
|
name: extraSecurityLabel,
|
||||||
id: 'extra',
|
id: 'extra',
|
||||||
fields: [
|
fields: [
|
||||||
'allowedDomains',
|
'allowedDomains',
|
||||||
@@ -248,85 +271,138 @@ export const sectionFields: Section = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// These field names should not be translated because they refer to specific technical terminology.
|
||||||
|
// We put them in variables so they can be referred to in otherwise translated descriptions and not
|
||||||
|
// risk being translated.
|
||||||
|
const clientIDLabel = 'Client ID';
|
||||||
|
const clientSecretLabel = 'Client secret';
|
||||||
|
const scopesLabel = 'Scopes';
|
||||||
|
const openIDConnectDiscoveryLabel = 'OpenID Connect Discovery URL';
|
||||||
|
const authURLLabel = 'Auth URL';
|
||||||
|
const tokenURLLabel = 'Token URL';
|
||||||
|
const apiURLLabel = 'API URL';
|
||||||
|
const jmesPathLabel = 'JMESPath';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List all the fields that can be used in the form
|
* List all the fields that can be used in the form
|
||||||
*/
|
*/
|
||||||
export function fieldMap(provider: string): Record<string, FieldData> {
|
export function fieldMap(provider: string): Record<string, FieldData> {
|
||||||
|
const orgMappingLabel = t('auth-config.fields.organization-mapping-label', 'Organization mapping');
|
||||||
|
const orgAttributePathLabel = t(
|
||||||
|
'auth-config.fields.organization-attribute-path-label',
|
||||||
|
'Organization attribute path'
|
||||||
|
);
|
||||||
|
|
||||||
|
const teamsURLLabel = t('auth-config.fields.teams-url-label', 'Teams URL');
|
||||||
|
const teamIDsAttributePathLabel = t('auth-config.fields.team-ids-attribute-path-label', 'Team IDs attribute path');
|
||||||
|
|
||||||
|
const allowedGroupsLabel = t('auth-config.fields.allowed-groups-label', 'Allowed groups');
|
||||||
|
const groupsAttributePathLabel = t('auth-config.fields.groups-attribute-path-label', 'Groups attribute path');
|
||||||
|
const teamIDsLabel = t('auth-config.fields.team-ids-label', 'Team IDs');
|
||||||
|
const allowedDomainsLabel = t('auth-config.fields.allowed-domains-label', 'Allowed domains');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
clientAuthentication: {
|
clientAuthentication: {
|
||||||
label: 'Client authentication',
|
label: t('auth-config.fields.client-authentication-label', 'Client authentication'),
|
||||||
type: 'select',
|
type: 'select',
|
||||||
description: 'The client authentication method used to authenticate to the token endpoint.',
|
description: t(
|
||||||
|
'auth-config.fields.client-authentication-description',
|
||||||
|
'The client authentication method used to authenticate to the token endpoint.'
|
||||||
|
),
|
||||||
multi: false,
|
multi: false,
|
||||||
options: clientAuthenticationOptions(provider),
|
options: clientAuthenticationOptions(provider),
|
||||||
defaultValue: { value: 'none', label: 'None' },
|
defaultValue: { value: 'none', label: 'None' },
|
||||||
validation: {
|
validation: {
|
||||||
required: true,
|
required: true,
|
||||||
message: 'This field is required',
|
message: t('auth-config.fields.required', 'This field is required'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
clientId: {
|
clientId: {
|
||||||
label: 'Client Id',
|
label: clientIDLabel,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
description: 'The client Id of your OAuth2 app.',
|
description: t('auth-config.fields.client-id-description', 'The {{ clientIDLabel }} of your OAuth2 app.', {
|
||||||
|
clientIDLabel,
|
||||||
|
}),
|
||||||
validation: {
|
validation: {
|
||||||
required: true,
|
required: true,
|
||||||
message: 'This field is required',
|
message: t('auth-config.fields.required', 'This field is required'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
clientSecret: {
|
clientSecret: {
|
||||||
label: 'Client secret',
|
label: clientSecretLabel,
|
||||||
type: 'secret',
|
type: 'secret',
|
||||||
description: 'The client secret of your OAuth2 app.',
|
description: t(
|
||||||
|
'auth-config.fields.client-secret-description',
|
||||||
|
'The {{ clientSecretLabel }} of your OAuth2 app.',
|
||||||
|
{
|
||||||
|
clientSecretLabel,
|
||||||
|
}
|
||||||
|
),
|
||||||
},
|
},
|
||||||
managedIdentityClientId: {
|
managedIdentityClientId: {
|
||||||
label: 'FIC managed identity client Id',
|
label: t('auth-config.fields.managed-identity-client-id-label', 'FIC managed identity client ID'),
|
||||||
type: 'text',
|
type: 'text',
|
||||||
description: 'The managed identity client Id of the federated identity credential of your OAuth2 app.',
|
description: t(
|
||||||
|
'auth-config.fields.managed-identity-client-id-description',
|
||||||
|
'The managed identity client ID of the federated identity credential of your OAuth2 app.'
|
||||||
|
),
|
||||||
},
|
},
|
||||||
federatedCredentialAudience: {
|
federatedCredentialAudience: {
|
||||||
label: 'FIC audience',
|
label: t('auth-config.fields.federated-credential-audience-label', 'FIC audience'),
|
||||||
type: 'text',
|
type: 'text',
|
||||||
description: 'The audience of the federated identity credential of your OAuth2 app.',
|
description: t(
|
||||||
|
'auth-config.fields.federated-credential-audience-description',
|
||||||
|
'The audience of the federated identity credential of your OAuth2 app.'
|
||||||
|
),
|
||||||
},
|
},
|
||||||
allowedOrganizations: {
|
allowedOrganizations: {
|
||||||
label: 'Allowed organizations',
|
label: t('auth-config.fields.allowed-organizations-label', 'Allowed organizations'),
|
||||||
type: 'select',
|
type: 'select',
|
||||||
description:
|
description: t(
|
||||||
'List of comma- or space-separated organizations. The user should be a member \n' +
|
'auth-config.fields.allowed-organizations-description',
|
||||||
'of at least one organization to log in.',
|
'List of comma- or space-separated organizations. The user should be a member \nof at least one organization to log in.'
|
||||||
|
),
|
||||||
multi: true,
|
multi: true,
|
||||||
allowCustomValue: true,
|
allowCustomValue: true,
|
||||||
options: [],
|
options: [],
|
||||||
placeholder: 'Enter organizations (my-team, myteam...) and press Enter to add',
|
placeholder: t(
|
||||||
|
'auth-config.fields.allowed-organizations-placeholder',
|
||||||
|
'Enter organizations (my-team, myteam...) and press Enter to add'
|
||||||
|
),
|
||||||
},
|
},
|
||||||
allowedDomains: {
|
allowedDomains: {
|
||||||
label: 'Allowed domains',
|
label: allowedDomainsLabel,
|
||||||
type: 'select',
|
type: 'select',
|
||||||
description:
|
description: t(
|
||||||
'List of comma- or space-separated domains. The user should belong to at least \n' + 'one domain to log in.',
|
'auth-config.fields.allowed-domains-description',
|
||||||
|
'List of comma- or space-separated domains. The user should belong to at least \none domain to log in.'
|
||||||
|
),
|
||||||
multi: true,
|
multi: true,
|
||||||
allowCustomValue: true,
|
allowCustomValue: true,
|
||||||
options: [],
|
options: [],
|
||||||
},
|
},
|
||||||
authUrl: {
|
authUrl: {
|
||||||
label: 'Auth URL',
|
label: authURLLabel,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
description: 'The authorization endpoint of your OAuth2 provider.',
|
description: t('auth-config.fields.auth-url-description', 'The authorization endpoint of your OAuth2 provider.'),
|
||||||
validation: {
|
validation: {
|
||||||
required: true,
|
required: true,
|
||||||
validate: (value) => {
|
validate: (value) => {
|
||||||
return isUrlValid(value);
|
return isUrlValid(value);
|
||||||
},
|
},
|
||||||
message: 'This field is required and must be a valid URL.',
|
message: t('auth-config.fields.auth-url-required', 'This field is required and must be a valid URL.'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
authStyle: {
|
authStyle: {
|
||||||
label: 'Auth style',
|
label: t('auth-config.fields.auth-style-label', 'Auth style'),
|
||||||
type: 'select',
|
type: 'select',
|
||||||
description:
|
description: t(
|
||||||
'It determines how "Client Id" and "Client secret" are sent to Oauth2 provider. Default is AutoDetect.',
|
'auth-config.fields.auth-style-description',
|
||||||
|
'It determines how "{{ clientIDLabel }}" and "{{ clientSecretLabel }}" are sent to Oauth2 provider. Default is AutoDetect.',
|
||||||
|
{ clientIDLabel, clientSecretLabel }
|
||||||
|
),
|
||||||
multi: false,
|
multi: false,
|
||||||
options: [
|
options: [
|
||||||
{ value: 'AutoDetect', label: 'AutoDetect' },
|
{ value: 'AutoDetect', label: 'AutoDetect' },
|
||||||
@@ -336,27 +412,33 @@ export function fieldMap(provider: string): Record<string, FieldData> {
|
|||||||
defaultValue: { value: 'AutoDetect', label: 'AutoDetect' },
|
defaultValue: { value: 'AutoDetect', label: 'AutoDetect' },
|
||||||
},
|
},
|
||||||
tokenUrl: {
|
tokenUrl: {
|
||||||
label: 'Token URL',
|
label: tokenURLLabel,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
description: 'The token endpoint of your OAuth2 provider.',
|
description: t('auth-config.fields.token-url-description', 'The token endpoint of your OAuth2 provider.'),
|
||||||
validation: {
|
validation: {
|
||||||
required: true,
|
required: true,
|
||||||
validate: (value) => {
|
validate: (value) => {
|
||||||
return isUrlValid(value);
|
return isUrlValid(value);
|
||||||
},
|
},
|
||||||
message: 'This field is required and must be a valid URL.',
|
message: t('auth-config.fields.token-url-required', 'This field is required and must be a valid URL.'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
scopes: {
|
scopes: {
|
||||||
label: 'Scopes',
|
label: scopesLabel,
|
||||||
type: 'select',
|
type: 'select',
|
||||||
description: 'List of comma- or space-separated OAuth2 scopes.',
|
description: t(
|
||||||
|
'auth-config.fields.scopes-description',
|
||||||
|
'List of comma- or space-separated OAuth2 {{ scopesLabel }}.',
|
||||||
|
{
|
||||||
|
scopesLabel,
|
||||||
|
}
|
||||||
|
),
|
||||||
multi: true,
|
multi: true,
|
||||||
allowCustomValue: true,
|
allowCustomValue: true,
|
||||||
options: [],
|
options: [],
|
||||||
},
|
},
|
||||||
allowedGroups: {
|
allowedGroups: {
|
||||||
label: 'Allowed groups',
|
label: allowedGroupsLabel,
|
||||||
type: 'select',
|
type: 'select',
|
||||||
description: (
|
description: (
|
||||||
<>
|
<>
|
||||||
@@ -366,7 +448,8 @@ export function fieldMap(provider: string): Record<string, FieldData> {
|
|||||||
{provider === 'generic_oauth' &&
|
{provider === 'generic_oauth' &&
|
||||||
t(
|
t(
|
||||||
'auth-config.fields.allowed-groups-description-oauth',
|
'auth-config.fields.allowed-groups-description-oauth',
|
||||||
'If you configure "Allowed groups", you must also configure "Groups attribute path".'
|
'If you configure "{{ allowedGroupsLabel }}", you must also configure "{{ groupsAttributePathLabel }}".',
|
||||||
|
{ allowedGroupsLabel, groupsAttributePathLabel }
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
@@ -385,12 +468,18 @@ export function fieldMap(provider: string): Record<string, FieldData> {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
message: 'Allowed groups must be Object Ids.',
|
message: t(
|
||||||
|
'auth-config.fields.allowed-groups-object-ids',
|
||||||
|
'{{ allowedGroupsLabel }} must be {{ objectIDsField }}.',
|
||||||
|
{
|
||||||
|
objectIDsField: 'Object IDs',
|
||||||
|
}
|
||||||
|
),
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
},
|
},
|
||||||
apiUrl: {
|
apiUrl: {
|
||||||
label: 'API URL',
|
label: apiURLLabel,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
description: (
|
description: (
|
||||||
<Trans i18nKey="auth-config.fields.api-url-description">
|
<Trans i18nKey="auth-config.fields.api-url-description">
|
||||||
@@ -415,116 +504,159 @@ export function fieldMap(provider: string): Record<string, FieldData> {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
message: 'This field must be a valid URL if set.',
|
message: t('auth-config.fields.api-url-required', 'This field must be a valid URL if set.'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
roleAttributePath: {
|
roleAttributePath: {
|
||||||
label: 'Role attribute path',
|
label: t('auth-config.fields.role-attribute-path-label', 'Role attribute path'),
|
||||||
description: 'JMESPath expression to use for Grafana role lookup.',
|
description: t(
|
||||||
|
'auth-config.fields.role-attribute-path-description',
|
||||||
|
'{{ jmesPathLabel }} expression to use for Grafana role lookup.',
|
||||||
|
{ jmesPathLabel }
|
||||||
|
),
|
||||||
type: 'text',
|
type: 'text',
|
||||||
validation: {
|
validation: {
|
||||||
required: false,
|
required: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
label: 'Display name',
|
label: t('auth-config.fields.display-name-label', 'Display name'),
|
||||||
description:
|
description: t(
|
||||||
'Will be displayed on the login page as "Sign in with ...". Helpful if you use more than one identity providers or SSO protocols.',
|
'auth-config.fields.display-name-description',
|
||||||
|
'Will be displayed on the login page as "Sign in with ...". Helpful if you use more than one identity providers or SSO protocols.'
|
||||||
|
),
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
allowSignUp: {
|
allowSignUp: {
|
||||||
label: 'Allow sign up',
|
label: t('auth-config.fields.allow-sign-up-label', 'Allow sign up'),
|
||||||
description: 'If not enabled, only existing Grafana users can log in using OAuth.',
|
description: t(
|
||||||
|
'auth-config.fields.allow-sign-up-description',
|
||||||
|
'If not enabled, only existing Grafana users can log in using OAuth.'
|
||||||
|
),
|
||||||
type: 'switch',
|
type: 'switch',
|
||||||
},
|
},
|
||||||
autoLogin: {
|
autoLogin: {
|
||||||
label: 'Auto login',
|
label: t('auth-config.fields.auto-login-label', 'Auto login'),
|
||||||
description: 'Log in automatically, skipping the login screen.',
|
description: t('auth-config.fields.auto-login-description', 'Log in automatically, skipping the login screen.'),
|
||||||
type: 'switch',
|
type: 'switch',
|
||||||
},
|
},
|
||||||
signoutRedirectUrl: {
|
signoutRedirectUrl: {
|
||||||
label: 'Sign out redirect URL',
|
label: t('auth-config.fields.signout-redirect-url-label', 'Sign out redirect URL'),
|
||||||
description: 'The URL to redirect the user to after signing out from Grafana.',
|
description: t(
|
||||||
|
'auth-config.fields.signout-redirect-url-description',
|
||||||
|
'The URL to redirect the user to after signing out from Grafana.'
|
||||||
|
),
|
||||||
type: 'text',
|
type: 'text',
|
||||||
validation: {
|
validation: {
|
||||||
required: false,
|
required: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
emailAttributeName: {
|
emailAttributeName: {
|
||||||
label: 'Email attribute name',
|
label: t('auth-config.fields.email-attribute-name-label', 'Email attribute name'),
|
||||||
description: 'Name of the key to use for user email lookup within the attributes map of OAuth2 ID token.',
|
description: t(
|
||||||
|
'auth-config.fields.email-attribute-name-description',
|
||||||
|
'Name of the key to use for user email lookup within the attributes map of OAuth2 ID token.'
|
||||||
|
),
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
emailAttributePath: {
|
emailAttributePath: {
|
||||||
label: 'Email attribute path',
|
label: t('auth-config.fields.email-attribute-path-label', 'Email attribute path'),
|
||||||
description: 'JMESPath expression to use for user email lookup from the user information.',
|
description: t(
|
||||||
|
'auth-config.fields.email-attribute-path-description',
|
||||||
|
'JMESPath expression to use for user email lookup from the user information.'
|
||||||
|
),
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
nameAttributePath: {
|
nameAttributePath: {
|
||||||
label: 'Name attribute path',
|
label: t('auth-config.fields.name-attribute-path-label', 'Name attribute path'),
|
||||||
description:
|
description: t(
|
||||||
'JMESPath expression to use for user name lookup from the user ID token. \n' +
|
'auth-config.fields.name-attribute-path-description',
|
||||||
'This name will be used as the user’s display name.',
|
"JMESPath expression to use for user name lookup from the user ID token. \nThis name will be used as the user's display name."
|
||||||
|
),
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
loginAttributePath: {
|
loginAttributePath: {
|
||||||
label: 'Login attribute path',
|
label: t('auth-config.fields.login-attribute-path-label', 'Login attribute path'),
|
||||||
description: 'JMESPath expression to use for user login lookup from the user ID token.',
|
description: t(
|
||||||
|
'auth-config.fields.login-attribute-path-description',
|
||||||
|
'JMESPath expression to use for user login lookup from the user ID token.'
|
||||||
|
),
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
idTokenAttributeName: {
|
idTokenAttributeName: {
|
||||||
label: 'ID token attribute name',
|
label: t('auth-config.fields.id-token-attribute-name-label', 'ID token attribute name'),
|
||||||
description: 'The name of the key used to extract the ID token from the returned OAuth2 token.',
|
description: t(
|
||||||
|
'auth-config.fields.id-token-attribute-name-description',
|
||||||
|
'The name of the key used to extract the ID token from the returned OAuth2 token.'
|
||||||
|
),
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
roleAttributeStrict: {
|
roleAttributeStrict: {
|
||||||
label: 'Role attribute strict mode',
|
label: t('auth-config.fields.role-attribute-strict-label', 'Role attribute strict mode'),
|
||||||
description: 'If enabled, denies user login if the Grafana role cannot be extracted using Role attribute path.',
|
description: t(
|
||||||
|
'auth-config.fields.role-attribute-strict-description',
|
||||||
|
'If enabled, denies user login if the Grafana role cannot be extracted using Role attribute path.'
|
||||||
|
),
|
||||||
type: 'switch',
|
type: 'switch',
|
||||||
},
|
},
|
||||||
allowAssignGrafanaAdmin: {
|
allowAssignGrafanaAdmin: {
|
||||||
label: 'Allow assign Grafana admin',
|
label: t('auth-config.fields.allow-assign-grafana-admin-label', 'Allow assign Grafana admin'),
|
||||||
description: 'If enabled, it will automatically sync the Grafana server administrator role.',
|
description: t(
|
||||||
|
'auth-config.fields.allow-assign-grafana-admin-description',
|
||||||
|
'If enabled, it will automatically sync the Grafana server administrator role.'
|
||||||
|
),
|
||||||
type: 'switch',
|
type: 'switch',
|
||||||
hidden: !contextSrv.isGrafanaAdmin,
|
hidden: !contextSrv.isGrafanaAdmin,
|
||||||
},
|
},
|
||||||
skipOrgRoleSync: {
|
skipOrgRoleSync: {
|
||||||
label: 'Skip organization role sync',
|
label: t('auth-config.fields.skip-org-role-sync-label', 'Skip organization role sync'),
|
||||||
description: 'Prevent synchronizing users’ organization roles from your IdP.',
|
description: t(
|
||||||
|
'auth-config.fields.skip-org-role-sync-description',
|
||||||
|
"Prevent synchronizing users' organization roles from your IdP."
|
||||||
|
),
|
||||||
type: 'switch',
|
type: 'switch',
|
||||||
},
|
},
|
||||||
orgMapping: {
|
orgMapping: {
|
||||||
label: 'Organization mapping',
|
label: orgMappingLabel,
|
||||||
description: orgMappingDescription(provider),
|
description: orgMappingDescription(provider),
|
||||||
type: 'select',
|
type: 'select',
|
||||||
hidden: !contextSrv.isGrafanaAdmin,
|
hidden: !contextSrv.isGrafanaAdmin,
|
||||||
multi: true,
|
multi: true,
|
||||||
allowCustomValue: true,
|
allowCustomValue: true,
|
||||||
options: [],
|
options: [],
|
||||||
placeholder: 'Enter mappings (my-team:1:Viewer...) and press Enter to add',
|
placeholder: t(
|
||||||
|
'auth-config.fields.organization-mapping-placeholder',
|
||||||
|
'Enter mappings (my-team:1:Viewer...) and press Enter to add'
|
||||||
|
),
|
||||||
},
|
},
|
||||||
orgAttributePath: {
|
orgAttributePath: {
|
||||||
label: 'Organization attribute path',
|
label: orgAttributePathLabel,
|
||||||
description:
|
description: t(
|
||||||
'JMESPath expression to use for organization lookup. If you configure "Organization mapping", you must also configure "Organization attribute path".',
|
'auth-config.fields.organization-attribute-path-description',
|
||||||
|
'JMESPath expression to use for organization lookup. If you configure "{{ orgMappingLabel }}", you must also configure "{{ orgAttributePathLabel }}".',
|
||||||
|
{ orgMappingLabel, orgAttributePathLabel }
|
||||||
|
),
|
||||||
type: 'text',
|
type: 'text',
|
||||||
hidden: !(['generic_oauth', 'okta'].includes(provider) && contextSrv.isGrafanaAdmin),
|
hidden: !(['generic_oauth', 'okta'].includes(provider) && contextSrv.isGrafanaAdmin),
|
||||||
},
|
},
|
||||||
defineAllowedGroups: {
|
defineAllowedGroups: {
|
||||||
label: 'Define allowed groups',
|
label: t('auth-config.fields.define-allowed-groups-label', 'Define allowed groups'),
|
||||||
type: 'switch',
|
type: 'switch',
|
||||||
},
|
},
|
||||||
defineAllowedTeamsIds: {
|
defineAllowedTeamsIds: {
|
||||||
label: 'Define allowed teams ids',
|
label: t('auth-config.fields.define-allowed-teams-ids-label', 'Define allowed teams IDs'),
|
||||||
type: 'switch',
|
type: 'switch',
|
||||||
},
|
},
|
||||||
forceUseGraphApi: {
|
forceUseGraphApi: {
|
||||||
label: 'Force use Graph API',
|
label: t('auth-config.fields.force-use-graph-api-label', 'Force use Graph API'),
|
||||||
description: "If enabled, Grafana will fetch the users' groups using the Microsoft Graph API.",
|
description: t(
|
||||||
|
'auth-config.fields.force-use-graph-api-description',
|
||||||
|
"If enabled, Grafana will fetch the users' groups using the Microsoft Graph API."
|
||||||
|
),
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
},
|
},
|
||||||
usePkce: {
|
usePkce: {
|
||||||
label: 'Use PKCE',
|
label: t('auth-config.fields.use-pkce-label', 'Use PKCE'),
|
||||||
description: (
|
description: (
|
||||||
<Trans i18nKey="auth-config.fields.use-pkce-description">
|
<Trans i18nKey="auth-config.fields.use-pkce-description">
|
||||||
If enabled, Grafana will use{' '}
|
If enabled, Grafana will use{' '}
|
||||||
@@ -537,55 +669,69 @@ export function fieldMap(provider: string): Record<string, FieldData> {
|
|||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
},
|
},
|
||||||
useRefreshToken: {
|
useRefreshToken: {
|
||||||
label: 'Use refresh token',
|
label: t('auth-config.fields.use-refresh-token-label', 'Use refresh token'),
|
||||||
description:
|
description: t(
|
||||||
'If enabled, Grafana will fetch a new access token using the refresh token provided by the OAuth2 provider.',
|
'auth-config.fields.use-refresh-token-description',
|
||||||
|
'If enabled, Grafana will fetch a new access token using the refresh token provided by the OAuth2 provider.'
|
||||||
|
),
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
},
|
},
|
||||||
tlsClientCa: {
|
tlsClientCa: {
|
||||||
label: 'TLS client ca',
|
label: t('auth-config.fields.tls-client-ca-label', 'TLS client CA'),
|
||||||
description: 'The file path to the trusted certificate authority list. Is not applicable on Grafana Cloud.',
|
description: t(
|
||||||
|
'auth-config.fields.tls-client-ca-description',
|
||||||
|
'The file path to the trusted certificate authority list. Is not applicable on Grafana Cloud.'
|
||||||
|
),
|
||||||
type: 'text',
|
type: 'text',
|
||||||
hidden: !config.localFileSystemAvailable,
|
hidden: !config.localFileSystemAvailable,
|
||||||
},
|
},
|
||||||
tlsClientCert: {
|
tlsClientCert: {
|
||||||
label: 'TLS client cert',
|
label: t('auth-config.fields.tls-client-cert-label', 'TLS client cert'),
|
||||||
description: 'The file path to the certificate. Is not applicable on Grafana Cloud.',
|
description: t(
|
||||||
|
'auth-config.fields.tls-client-cert-description',
|
||||||
|
'The file path to the certificate. Is not applicable on Grafana Cloud.'
|
||||||
|
),
|
||||||
type: 'text',
|
type: 'text',
|
||||||
hidden: !config.localFileSystemAvailable,
|
hidden: !config.localFileSystemAvailable,
|
||||||
},
|
},
|
||||||
tlsClientKey: {
|
tlsClientKey: {
|
||||||
label: 'TLS client key',
|
label: t('auth-config.fields.tls-client-key-label', 'TLS client key'),
|
||||||
description: 'The file path to the key. Is not applicable on Grafana Cloud.',
|
description: t(
|
||||||
|
'auth-config.fields.tls-client-key-description',
|
||||||
|
'The file path to the key. Is not applicable on Grafana Cloud.'
|
||||||
|
),
|
||||||
type: 'text',
|
type: 'text',
|
||||||
hidden: !config.localFileSystemAvailable,
|
hidden: !config.localFileSystemAvailable,
|
||||||
},
|
},
|
||||||
tlsSkipVerifyInsecure: {
|
tlsSkipVerifyInsecure: {
|
||||||
label: 'TLS skip verify',
|
label: t('auth-config.fields.tls-skip-verify-label', 'TLS skip verify'),
|
||||||
description:
|
description: t(
|
||||||
'If enabled, the client accepts any certificate presented by the server and any host \n' +
|
'auth-config.fields.tls-skip-verify-description',
|
||||||
'name in that certificate. You should only use this for testing, because this mode leaves \n' +
|
'If enabled, the client accepts any certificate presented by the server and any host \nname in that certificate. You should only use this for testing, because this mode leaves \nSSL/TLS susceptible to man-in-the-middle attacks.'
|
||||||
'SSL/TLS susceptible to man-in-the-middle attacks.',
|
),
|
||||||
type: 'switch',
|
type: 'switch',
|
||||||
},
|
},
|
||||||
groupsAttributePath: {
|
groupsAttributePath: {
|
||||||
label: 'Groups attribute path',
|
label: groupsAttributePathLabel,
|
||||||
description:
|
description: t(
|
||||||
'JMESPath expression to use for user group lookup. If you configure "Allowed groups", \n' +
|
'auth-config.fields.groups-attribute-path-description',
|
||||||
'you must also configure "Groups attribute path".',
|
'JMESPath expression to use for user group lookup. If you configure "{{ allowedGroupsLabel }}", \nyou must also configure "{{ groupsAttributePathLabel }}".',
|
||||||
|
{ allowedGroupsLabel, groupsAttributePathLabel }
|
||||||
|
),
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
teamsUrl: {
|
teamsUrl: {
|
||||||
label: 'Teams URL',
|
label: teamsURLLabel,
|
||||||
description: (
|
description: (
|
||||||
<>
|
<>
|
||||||
<Trans i18nKey="auth-config.fields.teams-url-description">
|
<Trans i18nKey="auth-config.fields.teams-url-description">
|
||||||
The URL used to query for Team Ids. If not set, the default value is /teams.
|
The URL used to query for Team IDs. If not set, the default value is /teams.
|
||||||
</Trans>{' '}
|
</Trans>{' '}
|
||||||
{provider === 'generic_oauth' &&
|
{provider === 'generic_oauth' &&
|
||||||
t(
|
t(
|
||||||
'auth-config.fields.teams-url-description-oauth',
|
'auth-config.fields.teams-url-description-oauth',
|
||||||
'If you configure "Teams URL", you must also configure "Team Ids attribute path".'
|
'If you configure "{{ teamsURLLabel }}", you must also configure "{{ teamIDsAttributePathLabel }}".',
|
||||||
|
{ teamsURLLabel, teamIDsAttributePathLabel }
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
@@ -602,13 +748,20 @@ export function fieldMap(provider: string): Record<string, FieldData> {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
message: 'This field must be set if Team Ids are configured and must be a valid URL.',
|
message: t(
|
||||||
|
'auth-config.fields.teams-url-required',
|
||||||
|
'This field must be set if "{{ teamIDsLabel }}" are configured and must be a valid URL.',
|
||||||
|
{ teamIDsLabel }
|
||||||
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
teamIdsAttributePath: {
|
teamIdsAttributePath: {
|
||||||
label: 'Team Ids attribute path',
|
label: teamIDsAttributePathLabel,
|
||||||
description:
|
description: t(
|
||||||
'The JMESPath expression to use for Grafana Team Id lookup within the results returned by the "Teams URL" endpoint.',
|
'auth-config.fields.team-ids-attribute-path-description',
|
||||||
|
'The JMESPath expression to use for Grafana Team ID lookup within the results returned by the "{{ teamsURLLabel }}" endpoint.',
|
||||||
|
{ teamsURLLabel }
|
||||||
|
),
|
||||||
type: 'text',
|
type: 'text',
|
||||||
validation: {
|
validation: {
|
||||||
validate: (value, formValues) => {
|
validate: (value, formValues) => {
|
||||||
@@ -617,32 +770,36 @@ export function fieldMap(provider: string): Record<string, FieldData> {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
message: 'This field must be set if Team Ids are configured.',
|
message: t(
|
||||||
|
'auth-config.fields.team-ids-attribute-path-required',
|
||||||
|
'This field must be set if "{{ teamIDsLabel }}" are configured.',
|
||||||
|
{ teamIDsLabel }
|
||||||
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
teamIds: {
|
teamIds: {
|
||||||
label: 'Team Ids',
|
label: teamIDsLabel,
|
||||||
type: 'select',
|
type: 'select',
|
||||||
description: (
|
description: (
|
||||||
<>
|
<>
|
||||||
{provider === 'github'
|
{provider === 'github'
|
||||||
? t('auth-config.fields.team-ids-github', 'Integer list of Team Ids.')
|
? t('auth-config.fields.team-ids-github', 'Integer list of Team IDs.')
|
||||||
: t('auth-config.fields.team-ids-other', 'String list of Team Ids.')}{' '}
|
: t('auth-config.fields.team-ids-other', 'String list of Team IDs.')}{' '}
|
||||||
<Trans i18nKey="auth-config.fields.team-ids-description">
|
<Trans i18nKey="auth-config.fields.team-ids-description">
|
||||||
If set, the user must be a member of one of the given teams to log in.
|
If set, the user must be a member of one of the given teams to log in.
|
||||||
</Trans>{' '}
|
</Trans>{' '}
|
||||||
{provider === 'generic_oauth' &&
|
{provider === 'generic_oauth' &&
|
||||||
t(
|
t(
|
||||||
'auth-config.fields.team-ids-description-oauth',
|
'auth-config.fields.team-ids-description-oauth',
|
||||||
'If you configure "{{teamIds}}", you must also configure "{{teamsUrl}}" and "{{teamIdsAttributePath}}".',
|
'If you configure "{{ teamIDsLabel }}", you must also configure "{{ teamsURLLabel }}" and "{{ teamIDsAttributePathLabel }}".',
|
||||||
{ teamIds: 'Team Ids', teamsUrl: 'Teams URL', teamIdsAttributePath: 'Team Ids attribute path' }
|
{ teamIDsLabel, teamsURLLabel, teamIDsAttributePathLabel }
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
multi: true,
|
multi: true,
|
||||||
allowCustomValue: true,
|
allowCustomValue: true,
|
||||||
options: [],
|
options: [],
|
||||||
placeholder: 'Enter Team Ids and press Enter to add',
|
placeholder: t('auth-config.fields.team-ids-placeholder', 'Enter Team IDs and press Enter to add'),
|
||||||
validation:
|
validation:
|
||||||
provider === 'github'
|
provider === 'github'
|
||||||
? {
|
? {
|
||||||
@@ -655,25 +812,34 @@ export function fieldMap(provider: string): Record<string, FieldData> {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
message: 'Team Ids must be numbers.',
|
message: t('auth-config.fields.team-ids-numbers', 'Team IDs must be numbers.'),
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
},
|
},
|
||||||
hostedDomain: {
|
hostedDomain: {
|
||||||
label: 'Hosted domain',
|
label: t('auth-config.fields.hosted-domain-label', 'Hosted domain'),
|
||||||
description: 'The domain under which Grafana is hosted and accessible.',
|
description: t(
|
||||||
|
'auth-config.fields.hosted-domain-description',
|
||||||
|
'The domain under which Grafana is hosted and accessible.'
|
||||||
|
),
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
validateHd: {
|
validateHd: {
|
||||||
label: 'Validate hosted domain',
|
label: t('auth-config.fields.validate-hosted-domain-label', 'Validate hosted domain'),
|
||||||
description:
|
description: t(
|
||||||
'If enabled, Grafana will match the Hosted Domain retrieved from the Google ID Token against the Allowed Domains list specified by the user.',
|
'auth-config.fields.validate-hosted-domain-description',
|
||||||
|
'If enabled, Grafana will match the Hosted Domain retrieved from the Google ID Token against the "{{ allowedDomainsLabel }}" list specified by the user.',
|
||||||
|
{ allowedDomainsLabel }
|
||||||
|
),
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
},
|
},
|
||||||
serverDiscoveryUrl: {
|
serverDiscoveryUrl: {
|
||||||
label: 'OpenID Connect Discovery URL',
|
label: openIDConnectDiscoveryLabel,
|
||||||
description:
|
description: t(
|
||||||
'The .well-known/openid-configuration endpoint for your IdP. The info extracted from this URL will be used to populate the Auth URL, Token URL and API URL fields.',
|
'auth-config.fields.server-discovery-url-description',
|
||||||
|
'The .well-known/openid-configuration endpoint for your IdP. The info extracted from this URL will be used to populate the "{{ authURLLabel }}", "{{ tokenURLLabel }}" and "{{ apiURLLabel }}" fields.',
|
||||||
|
{ authURLLabel, tokenURLLabel, apiURLLabel }
|
||||||
|
),
|
||||||
type: 'custom',
|
type: 'custom',
|
||||||
content: (setValue) => <ServerDiscoveryField setValue={setValue} />,
|
content: (setValue) => <ServerDiscoveryField setValue={setValue} />,
|
||||||
},
|
},
|
||||||
@@ -688,24 +854,40 @@ function isNumeric(value: string) {
|
|||||||
function orgMappingDescription(provider: string): string {
|
function orgMappingDescription(provider: string): string {
|
||||||
switch (provider) {
|
switch (provider) {
|
||||||
case 'azuread':
|
case 'azuread':
|
||||||
return 'List of "<GroupID>:<OrgIdOrName>:<Role>" mappings.';
|
return t(
|
||||||
|
'auth-config.fields.org-mapping-description-azuread',
|
||||||
|
'List of "<GroupID>:<OrgIdOrName>:<Role>" mappings.'
|
||||||
|
);
|
||||||
case 'github':
|
case 'github':
|
||||||
return 'List of "<GitHubTeamName>:<OrgIdOrName>:<Role>" mappings.';
|
return t(
|
||||||
|
'auth-config.fields.org-mapping-description-github',
|
||||||
|
'List of "<GitHubTeamName>:<OrgIdOrName>:<Role>" mappings.'
|
||||||
|
);
|
||||||
case 'gitlab':
|
case 'gitlab':
|
||||||
return 'List of "<GitlabGroupName>:<OrgIdOrName>:<Role>';
|
return t(
|
||||||
|
'auth-config.fields.org-mapping-description-gitlab',
|
||||||
|
'List of "<GitlabGroupName>:<OrgIdOrName>:<Role>" mappings.'
|
||||||
|
);
|
||||||
case 'google':
|
case 'google':
|
||||||
return 'List of "<GoogleGroupName>:<OrgIdOrName>:<Role>';
|
return t(
|
||||||
|
'auth-config.fields.org-mapping-description-google',
|
||||||
|
'List of "<GoogleGroupName>:<OrgIdOrName>:<Role>" mappings.'
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
// Generic OAuth, Okta
|
// Generic OAuth, Okta
|
||||||
return 'List of "<ExternalName>:<OrgIdOrName>:<Role>" mappings.';
|
return t(
|
||||||
|
'auth-config.fields.org-mapping-description-generic',
|
||||||
|
'List of "<ExternalName>:<OrgIdOrName>:<Role>" mappings.'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function clientAuthenticationOptions(provider: string): Array<SelectableValue<string>> {
|
function clientAuthenticationOptions(provider: string): Array<SelectableValue<string>> {
|
||||||
|
// Other options are purposefully not translated
|
||||||
switch (provider) {
|
switch (provider) {
|
||||||
case 'azuread':
|
case 'azuread':
|
||||||
return [
|
return [
|
||||||
{ value: 'none', label: 'None' },
|
{ value: 'none', label: t('auth-config.fields.client-authentication-none', 'None') },
|
||||||
{ value: 'client_secret_post', label: 'Client secret' },
|
{ value: 'client_secret_post', label: 'Client secret' },
|
||||||
{ value: 'managed_identity', label: 'Managed identity' },
|
{ value: 'managed_identity', label: 'Managed identity' },
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { SelectableValue } from '@grafana/data';
|
import { SelectableValue } from '@grafana/data';
|
||||||
|
|
||||||
import { fieldMap, sectionFields } from '../fields';
|
import { fieldMap, getSectionFields } from '../fields';
|
||||||
import { FieldData, SSOProvider, SSOProviderDTO } from '../types';
|
import { FieldData, SSOProvider, SSOProviderDTO } from '../types';
|
||||||
|
|
||||||
import { isSelectableValue } from './guards';
|
import { isSelectableValue } from './guards';
|
||||||
@@ -86,7 +86,7 @@ const valuesToString = (values: Array<SelectableValue<string>>) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getFieldsForProvider = (provider: string) => {
|
const getFieldsForProvider = (provider: string) => {
|
||||||
const sections = sectionFields[provider];
|
const sections = getSectionFields()[provider];
|
||||||
|
|
||||||
// include the enabled field because it is not part of the fields defined for providers
|
// include the enabled field because it is not part of the fields defined for providers
|
||||||
const fields = ['enabled'];
|
const fields = ['enabled'];
|
||||||
@@ -133,5 +133,5 @@ export function dtoToData(dto: SSOProviderDTO, provider: string) {
|
|||||||
export function getArrayFields(obj: Record<string, FieldData>, providerFields: string[]): Array<keyof SSOProviderDTO> {
|
export function getArrayFields(obj: Record<string, FieldData>, providerFields: string[]): Array<keyof SSOProviderDTO> {
|
||||||
return Object.entries(obj)
|
return Object.entries(obj)
|
||||||
.filter(([key, value]) => providerFields.includes(key) && value.type === 'select')
|
.filter(([key, value]) => providerFields.includes(key) && value.type === 'select')
|
||||||
.map(([key]) => key as keyof SSOProviderDTO);
|
.map(([key]) => key as keyof SSOProviderDTO); // TODO: replace this with a type guard
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2628,16 +2628,109 @@
|
|||||||
"refer-documentation-configure-authentication": "Refer to the documentation on how to configure authentication"
|
"refer-documentation-configure-authentication": "Refer to the documentation on how to configure authentication"
|
||||||
},
|
},
|
||||||
"fields": {
|
"fields": {
|
||||||
|
"allow-assign-grafana-admin-description": "If enabled, it will automatically sync the Grafana server administrator role.",
|
||||||
|
"allow-assign-grafana-admin-label": "Allow assign Grafana admin",
|
||||||
|
"allow-sign-up-description": "If not enabled, only existing Grafana users can log in using OAuth.",
|
||||||
|
"allow-sign-up-label": "Allow sign up",
|
||||||
|
"allowed-domains-description": "List of comma- or space-separated domains. The user should belong to at least \none domain to log in.",
|
||||||
|
"allowed-domains-label": "Allowed domains",
|
||||||
"allowed-groups-description": "List of comma- or space-separated groups. The user should be a member of at least one group to log in.",
|
"allowed-groups-description": "List of comma- or space-separated groups. The user should be a member of at least one group to log in.",
|
||||||
"allowed-groups-description-oauth": "If you configure \"Allowed groups\", you must also configure \"Groups attribute path\".",
|
"allowed-groups-description-oauth": "If you configure \"{{ allowedGroupsLabel }}\", you must also configure \"{{ groupsAttributePathLabel }}\".",
|
||||||
|
"allowed-groups-label": "Allowed groups",
|
||||||
|
"allowed-groups-object-ids": "{{ allowedGroupsLabel }} must be {{ objectIDsField }}.",
|
||||||
|
"allowed-organizations-description": "List of comma- or space-separated organizations. The user should be a member \nof at least one organization to log in.",
|
||||||
|
"allowed-organizations-label": "Allowed organizations",
|
||||||
|
"allowed-organizations-placeholder": "Enter organizations (my-team, myteam...) and press Enter to add",
|
||||||
"api-url-description": "The user information endpoint of your OAuth2 provider. Information returned by this endpoint must be compatible with <2>OpenID UserInfo</2>.",
|
"api-url-description": "The user information endpoint of your OAuth2 provider. Information returned by this endpoint must be compatible with <2>OpenID UserInfo</2>.",
|
||||||
|
"api-url-required": "This field must be a valid URL if set.",
|
||||||
|
"auth-style-description": "It determines how \"{{ clientIDLabel }}\" and \"{{ clientSecretLabel }}\" are sent to Oauth2 provider. Default is AutoDetect.",
|
||||||
|
"auth-style-label": "Auth style",
|
||||||
|
"auth-url-description": "The authorization endpoint of your OAuth2 provider.",
|
||||||
|
"auth-url-required": "This field is required and must be a valid URL.",
|
||||||
|
"auto-login-description": "Log in automatically, skipping the login screen.",
|
||||||
|
"auto-login-label": "Auto login",
|
||||||
|
"client-authentication-description": "The client authentication method used to authenticate to the token endpoint.",
|
||||||
|
"client-authentication-label": "Client authentication",
|
||||||
|
"client-authentication-none": "None",
|
||||||
|
"client-id-description": "The {{ clientIDLabel }} of your OAuth2 app.",
|
||||||
|
"client-secret-description": "The {{ clientSecretLabel }} of your OAuth2 app.",
|
||||||
|
"define-allowed-groups-label": "Define allowed groups",
|
||||||
|
"define-allowed-teams-ids-label": "Define allowed teams IDs",
|
||||||
|
"display-name-description": "Will be displayed on the login page as \"Sign in with ...\". Helpful if you use more than one identity providers or SSO protocols.",
|
||||||
|
"display-name-label": "Display name",
|
||||||
|
"email-attribute-name-description": "Name of the key to use for user email lookup within the attributes map of OAuth2 ID token.",
|
||||||
|
"email-attribute-name-label": "Email attribute name",
|
||||||
|
"email-attribute-path-description": "JMESPath expression to use for user email lookup from the user information.",
|
||||||
|
"email-attribute-path-label": "Email attribute path",
|
||||||
|
"federated-credential-audience-description": "The audience of the federated identity credential of your OAuth2 app.",
|
||||||
|
"federated-credential-audience-label": "FIC audience",
|
||||||
|
"force-use-graph-api-description": "If enabled, Grafana will fetch the users' groups using the Microsoft Graph API.",
|
||||||
|
"force-use-graph-api-label": "Force use Graph API",
|
||||||
|
"groups-attribute-path-description": "JMESPath expression to use for user group lookup. If you configure \"{{ allowedGroupsLabel }}\", \nyou must also configure \"{{ groupsAttributePathLabel }}\".",
|
||||||
|
"groups-attribute-path-label": "Groups attribute path",
|
||||||
|
"hosted-domain-description": "The domain under which Grafana is hosted and accessible.",
|
||||||
|
"hosted-domain-label": "Hosted domain",
|
||||||
|
"id-token-attribute-name-description": "The name of the key used to extract the ID token from the returned OAuth2 token.",
|
||||||
|
"id-token-attribute-name-label": "ID token attribute name",
|
||||||
|
"login-attribute-path-description": "JMESPath expression to use for user login lookup from the user ID token.",
|
||||||
|
"login-attribute-path-label": "Login attribute path",
|
||||||
|
"managed-identity-client-id-description": "The managed identity client ID of the federated identity credential of your OAuth2 app.",
|
||||||
|
"managed-identity-client-id-label": "FIC managed identity client ID",
|
||||||
|
"name-attribute-path-description": "JMESPath expression to use for user name lookup from the user ID token. \nThis name will be used as the user's display name.",
|
||||||
|
"name-attribute-path-label": "Name attribute path",
|
||||||
|
"org-mapping-description-azuread": "List of \"<GroupID>:<OrgIdOrName>:<Role>\" mappings.",
|
||||||
|
"org-mapping-description-generic": "List of \"<ExternalName>:<OrgIdOrName>:<Role>\" mappings.",
|
||||||
|
"org-mapping-description-github": "List of \"<GitHubTeamName>:<OrgIdOrName>:<Role>\" mappings.",
|
||||||
|
"org-mapping-description-gitlab": "List of \"<GitlabGroupName>:<OrgIdOrName>:<Role>\" mappings.",
|
||||||
|
"org-mapping-description-google": "List of \"<GoogleGroupName>:<OrgIdOrName>:<Role>\" mappings.",
|
||||||
|
"organization-attribute-path-description": "JMESPath expression to use for organization lookup. If you configure \"{{ orgMappingLabel }}\", you must also configure \"{{ orgAttributePathLabel }}\".",
|
||||||
|
"organization-attribute-path-label": "Organization attribute path",
|
||||||
|
"organization-mapping-label": "Organization mapping",
|
||||||
|
"organization-mapping-placeholder": "Enter mappings (my-team:1:Viewer...) and press Enter to add",
|
||||||
|
"required": "This field is required",
|
||||||
|
"role-attribute-path-description": "{{ jmesPathLabel }} expression to use for Grafana role lookup.",
|
||||||
|
"role-attribute-path-label": "Role attribute path",
|
||||||
|
"role-attribute-strict-description": "If enabled, denies user login if the Grafana role cannot be extracted using Role attribute path.",
|
||||||
|
"role-attribute-strict-label": "Role attribute strict mode",
|
||||||
|
"scopes-description": "List of comma- or space-separated OAuth2 {{ scopesLabel }}.",
|
||||||
|
"section-extra-security": "Extra security measures",
|
||||||
|
"section-general-settings": "General settings",
|
||||||
|
"section-user-mapping": "User mapping",
|
||||||
|
"server-discovery-url-description": "The .well-known/openid-configuration endpoint for your IdP. The info extracted from this URL will be used to populate the \"{{ authURLLabel }}\", \"{{ tokenURLLabel }}\" and \"{{ apiURLLabel }}\" fields.",
|
||||||
|
"signout-redirect-url-description": "The URL to redirect the user to after signing out from Grafana.",
|
||||||
|
"signout-redirect-url-label": "Sign out redirect URL",
|
||||||
|
"skip-org-role-sync-description": "Prevent synchronizing users' organization roles from your IdP.",
|
||||||
|
"skip-org-role-sync-label": "Skip organization role sync",
|
||||||
|
"team-ids-attribute-path-description": "The JMESPath expression to use for Grafana Team ID lookup within the results returned by the \"{{ teamsURLLabel }}\" endpoint.",
|
||||||
|
"team-ids-attribute-path-label": "Team IDs attribute path",
|
||||||
|
"team-ids-attribute-path-required": "This field must be set if \"{{ teamIDsLabel }}\" are configured.",
|
||||||
"team-ids-description": "If set, the user must be a member of one of the given teams to log in.",
|
"team-ids-description": "If set, the user must be a member of one of the given teams to log in.",
|
||||||
"team-ids-description-oauth": "If you configure \"{{teamIds}}\", you must also configure \"{{teamsUrl}}\" and \"{{teamIdsAttributePath}}\".",
|
"team-ids-description-oauth": "If you configure \"{{ teamIDsLabel }}\", you must also configure \"{{ teamsURLLabel }}\" and \"{{ teamIDsAttributePathLabel }}\".",
|
||||||
"team-ids-github": "Integer list of Team Ids.",
|
"team-ids-github": "Integer list of Team IDs.",
|
||||||
|
"team-ids-label": "Team IDs",
|
||||||
|
"team-ids-numbers": "Team IDs must be numbers.",
|
||||||
"team-ids-other": "String list of Team Ids.",
|
"team-ids-other": "String list of Team Ids.",
|
||||||
"teams-url-description": "The URL used to query for Team Ids. If not set, the default value is /teams.",
|
"team-ids-placeholder": "Enter Team IDs and press Enter to add",
|
||||||
"teams-url-description-oauth": "If you configure \"Teams URL\", you must also configure \"Team Ids attribute path\".",
|
"teams-url-description": "The URL used to query for Team IDs. If not set, the default value is /teams.",
|
||||||
"use-pkce-description": "If enabled, Grafana will use <2>Proof Key for Code Exchange (PKCE)</2> with the OAuth2 Authorization Code Grant."
|
"teams-url-description-oauth": "If you configure \"{{ teamsURLLabel }}\", you must also configure \"{{ teamIDsAttributePathLabel }}\".",
|
||||||
|
"teams-url-label": "Teams URL",
|
||||||
|
"teams-url-required": "This field must be set if \"{{ teamIDsLabel }}\" are configured and must be a valid URL.",
|
||||||
|
"tls-client-ca-description": "The file path to the trusted certificate authority list. Is not applicable on Grafana Cloud.",
|
||||||
|
"tls-client-ca-label": "TLS client CA",
|
||||||
|
"tls-client-cert-description": "The file path to the certificate. Is not applicable on Grafana Cloud.",
|
||||||
|
"tls-client-cert-label": "TLS client cert",
|
||||||
|
"tls-client-key-description": "The file path to the key. Is not applicable on Grafana Cloud.",
|
||||||
|
"tls-client-key-label": "TLS client key",
|
||||||
|
"tls-skip-verify-description": "If enabled, the client accepts any certificate presented by the server and any host \nname in that certificate. You should only use this for testing, because this mode leaves \nSSL/TLS susceptible to man-in-the-middle attacks.",
|
||||||
|
"tls-skip-verify-label": "TLS skip verify",
|
||||||
|
"token-url-description": "The token endpoint of your OAuth2 provider.",
|
||||||
|
"token-url-required": "This field is required and must be a valid URL.",
|
||||||
|
"use-pkce-description": "If enabled, Grafana will use <2>Proof Key for Code Exchange (PKCE)</2> with the OAuth2 Authorization Code Grant.",
|
||||||
|
"use-pkce-label": "Use PKCE",
|
||||||
|
"use-refresh-token-description": "If enabled, Grafana will fetch a new access token using the refresh token provided by the OAuth2 provider.",
|
||||||
|
"use-refresh-token-label": "Use refresh token",
|
||||||
|
"validate-hosted-domain-description": "If enabled, Grafana will match the Hosted Domain retrieved from the Google ID Token against the \"{{ allowedDomainsLabel }}\" list specified by the user.",
|
||||||
|
"validate-hosted-domain-label": "Validate hosted domain"
|
||||||
},
|
},
|
||||||
"provider-card": {
|
"provider-card": {
|
||||||
"text-badge-enabled": "Enabled",
|
"text-badge-enabled": "Enabled",
|
||||||
@@ -2647,12 +2740,15 @@
|
|||||||
"additional-actions-menu": {
|
"additional-actions-menu": {
|
||||||
"label-reset-to-default-values": "Reset to default values"
|
"label-reset-to-default-values": "Reset to default values"
|
||||||
},
|
},
|
||||||
|
"disable": "Disable",
|
||||||
|
"disabling": "Disabling...",
|
||||||
"discard": "Discard",
|
"discard": "Discard",
|
||||||
"enabled-label-enabled": "Enabled",
|
"enabled-label-enabled": "Enabled",
|
||||||
"label-enabled": "Enabled",
|
"label-enabled": "Enabled",
|
||||||
"reset-configuration": "Are you sure you want to reset this configuration?",
|
"reset-configuration": "Are you sure you want to reset this configuration?",
|
||||||
"reset-configuration-description": "After resetting these settings Grafana will use the provider configuration from the system (config file/environment variables) if any.",
|
"reset-configuration-description": "After resetting these settings Grafana will use the provider configuration from the system (config file/environment variables) if any.",
|
||||||
"save": "Save",
|
"save": "Save",
|
||||||
|
"save-and-enable": "Save and enable",
|
||||||
"saving": "Saving...",
|
"saving": "Saving...",
|
||||||
"title-more-actions": "More actions",
|
"title-more-actions": "More actions",
|
||||||
"title-reset": "Reset",
|
"title-reset": "Reset",
|
||||||
|
|||||||
Reference in New Issue
Block a user