mirror of https://github.com/grafana/grafana
prometheushacktoberfestmetricsmonitoringalertinggrafanagoinfluxdbmysqlpostgresanalyticsdata-visualizationdashboardbusiness-intelligenceelasticsearch
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
934 lines
32 KiB
934 lines
32 KiB
import { validate as uuidValidate } from 'uuid';
|
|
|
|
import { SelectableValue } from '@grafana/data';
|
|
import { Trans } from '@grafana/i18n';
|
|
import { t } from '@grafana/i18n/internal';
|
|
import { config } from '@grafana/runtime';
|
|
import { TextLink } from '@grafana/ui';
|
|
import { contextSrv } from 'app/core/core';
|
|
|
|
import { ServerDiscoveryField } from './components/ServerDiscoveryField';
|
|
import { FieldData, SSOProvider, SSOSettingsField } from './types';
|
|
import { isSelectableValue, isSelectableValueArray } from './utils/guards';
|
|
import { isUrlValid } from './utils/url';
|
|
|
|
type Section = Record<
|
|
SSOProvider['provider'],
|
|
Array<{
|
|
name: string;
|
|
id: string;
|
|
hidden?: boolean;
|
|
fields: SSOSettingsField[];
|
|
}>
|
|
>;
|
|
|
|
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: [
|
|
{
|
|
name: generalSettingsLabel,
|
|
id: 'general',
|
|
fields: [
|
|
'name',
|
|
'clientAuthentication',
|
|
'clientId',
|
|
'clientSecret',
|
|
'managedIdentityClientId',
|
|
'federatedCredentialAudience',
|
|
'scopes',
|
|
'authUrl',
|
|
'tokenUrl',
|
|
'allowSignUp',
|
|
'autoLogin',
|
|
'signoutRedirectUrl',
|
|
],
|
|
},
|
|
{
|
|
name: userMappingLabel,
|
|
id: 'user',
|
|
fields: ['roleAttributeStrict', 'orgMapping', 'allowAssignGrafanaAdmin', 'skipOrgRoleSync'],
|
|
},
|
|
{
|
|
name: extraSecurityLabel,
|
|
id: 'extra',
|
|
fields: [
|
|
'allowedOrganizations',
|
|
'allowedDomains',
|
|
'allowedGroups',
|
|
'forceUseGraphApi',
|
|
'usePkce',
|
|
'useRefreshToken',
|
|
'tlsSkipVerifyInsecure',
|
|
'tlsClientCert',
|
|
'tlsClientKey',
|
|
'tlsClientCa',
|
|
'workloadIdentityTokenFile',
|
|
],
|
|
},
|
|
],
|
|
generic_oauth: [
|
|
{
|
|
name: generalSettingsLabel,
|
|
id: 'general',
|
|
fields: [
|
|
'name',
|
|
'clientId',
|
|
'clientSecret',
|
|
'authStyle',
|
|
'scopes',
|
|
'serverDiscoveryUrl',
|
|
'authUrl',
|
|
'tokenUrl',
|
|
'apiUrl',
|
|
'allowSignUp',
|
|
'autoLogin',
|
|
'signoutRedirectUrl',
|
|
],
|
|
},
|
|
{
|
|
name: userMappingLabel,
|
|
id: 'user',
|
|
fields: [
|
|
'nameAttributePath',
|
|
'loginAttributePath',
|
|
'emailAttributeName',
|
|
'emailAttributePath',
|
|
'idTokenAttributeName',
|
|
'roleAttributePath',
|
|
'roleAttributeStrict',
|
|
'orgMapping',
|
|
'orgAttributePath',
|
|
'allowAssignGrafanaAdmin',
|
|
'skipOrgRoleSync',
|
|
],
|
|
},
|
|
{
|
|
name: extraSecurityLabel,
|
|
id: 'extra',
|
|
fields: [
|
|
'allowedOrganizations',
|
|
'allowedDomains',
|
|
'defineAllowedGroups',
|
|
{ name: 'allowedGroups', dependsOn: 'defineAllowedGroups' },
|
|
{ name: 'groupsAttributePath', dependsOn: 'defineAllowedGroups' },
|
|
'defineAllowedTeamsIds',
|
|
{ name: 'teamIds', dependsOn: 'defineAllowedTeamsIds' },
|
|
{ name: 'teamsUrl', dependsOn: 'defineAllowedTeamsIds' },
|
|
{ name: 'teamIdsAttributePath', dependsOn: 'defineAllowedTeamsIds' },
|
|
'usePkce',
|
|
'useRefreshToken',
|
|
'tlsSkipVerifyInsecure',
|
|
'tlsClientCert',
|
|
'tlsClientKey',
|
|
'tlsClientCa',
|
|
],
|
|
},
|
|
],
|
|
google: [
|
|
{
|
|
name: generalSettingsLabel,
|
|
id: 'general',
|
|
fields: ['name', 'clientId', 'clientSecret', 'scopes', 'allowSignUp', 'autoLogin', 'signoutRedirectUrl'],
|
|
},
|
|
{
|
|
name: userMappingLabel,
|
|
id: 'user',
|
|
fields: [
|
|
'roleAttributePath',
|
|
'roleAttributeStrict',
|
|
'orgMapping',
|
|
'allowAssignGrafanaAdmin',
|
|
'skipOrgRoleSync',
|
|
],
|
|
},
|
|
{
|
|
name: extraSecurityLabel,
|
|
id: 'extra',
|
|
fields: [
|
|
'validateHd',
|
|
'hostedDomain',
|
|
'allowedDomains',
|
|
'allowedGroups',
|
|
'usePkce',
|
|
'useRefreshToken',
|
|
'tlsSkipVerifyInsecure',
|
|
'tlsClientCert',
|
|
'tlsClientKey',
|
|
'tlsClientCa',
|
|
],
|
|
},
|
|
],
|
|
github: [
|
|
{
|
|
name: generalSettingsLabel,
|
|
id: 'general',
|
|
fields: ['name', 'clientId', 'clientSecret', 'scopes', 'allowSignUp', 'autoLogin', 'signoutRedirectUrl'],
|
|
},
|
|
{
|
|
name: userMappingLabel,
|
|
id: 'user',
|
|
fields: [
|
|
'roleAttributePath',
|
|
'roleAttributeStrict',
|
|
'orgMapping',
|
|
'allowAssignGrafanaAdmin',
|
|
'skipOrgRoleSync',
|
|
],
|
|
},
|
|
{
|
|
name: extraSecurityLabel,
|
|
id: 'extra',
|
|
fields: [
|
|
'allowedOrganizations',
|
|
'allowedDomains',
|
|
'teamIds',
|
|
'usePkce',
|
|
'useRefreshToken',
|
|
'tlsSkipVerifyInsecure',
|
|
'tlsClientCert',
|
|
'tlsClientKey',
|
|
'tlsClientCa',
|
|
],
|
|
},
|
|
],
|
|
gitlab: [
|
|
{
|
|
name: generalSettingsLabel,
|
|
id: 'general',
|
|
fields: ['name', 'clientId', 'clientSecret', 'scopes', 'allowSignUp', 'autoLogin', 'signoutRedirectUrl'],
|
|
},
|
|
{
|
|
name: userMappingLabel,
|
|
id: 'user',
|
|
fields: [
|
|
'roleAttributePath',
|
|
'roleAttributeStrict',
|
|
'orgMapping',
|
|
'allowAssignGrafanaAdmin',
|
|
'skipOrgRoleSync',
|
|
],
|
|
},
|
|
{
|
|
name: extraSecurityLabel,
|
|
id: 'extra',
|
|
fields: [
|
|
'allowedDomains',
|
|
'allowedGroups',
|
|
'usePkce',
|
|
'useRefreshToken',
|
|
'tlsSkipVerifyInsecure',
|
|
'tlsClientCert',
|
|
'tlsClientKey',
|
|
'tlsClientCa',
|
|
],
|
|
},
|
|
],
|
|
okta: [
|
|
{
|
|
name: generalSettingsLabel,
|
|
id: 'general',
|
|
fields: [
|
|
'name',
|
|
'clientId',
|
|
'clientSecret',
|
|
'scopes',
|
|
'authUrl',
|
|
'tokenUrl',
|
|
'apiUrl',
|
|
'allowSignUp',
|
|
'autoLogin',
|
|
'signoutRedirectUrl',
|
|
],
|
|
},
|
|
{
|
|
name: userMappingLabel,
|
|
id: 'user',
|
|
fields: [
|
|
'roleAttributePath',
|
|
'roleAttributeStrict',
|
|
'orgMapping',
|
|
'orgAttributePath',
|
|
'allowAssignGrafanaAdmin',
|
|
'skipOrgRoleSync',
|
|
],
|
|
},
|
|
{
|
|
name: extraSecurityLabel,
|
|
id: 'extra',
|
|
fields: [
|
|
'allowedDomains',
|
|
'allowedGroups',
|
|
'usePkce',
|
|
'useRefreshToken',
|
|
'tlsSkipVerifyInsecure',
|
|
'tlsClientCert',
|
|
'tlsClientKey',
|
|
'tlsClientCa',
|
|
],
|
|
},
|
|
],
|
|
};
|
|
};
|
|
|
|
// 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';
|
|
const workloadIdentityLabel = 'Workload identity';
|
|
|
|
/**
|
|
* List all the fields that can be used in the form
|
|
*/
|
|
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 {
|
|
clientAuthentication: {
|
|
label: t('auth-config.fields.client-authentication-label', 'Client authentication'),
|
|
type: 'select',
|
|
description: t(
|
|
'auth-config.fields.client-authentication-description',
|
|
'The client authentication method used to authenticate to the token endpoint.'
|
|
),
|
|
multi: false,
|
|
options: clientAuthenticationOptions(provider),
|
|
defaultValue: { value: 'none', label: t('auth-config.field-map.label.none', 'None') },
|
|
validation: {
|
|
required: true,
|
|
message: t('auth-config.fields.required', 'This field is required'),
|
|
},
|
|
},
|
|
clientId: {
|
|
label: clientIDLabel,
|
|
type: 'text',
|
|
description: t('auth-config.fields.client-id-description', 'The {{ clientIDLabel }} of your OAuth2 app.', {
|
|
clientIDLabel,
|
|
}),
|
|
validation: {
|
|
required: true,
|
|
message: t('auth-config.fields.required', 'This field is required'),
|
|
},
|
|
},
|
|
clientSecret: {
|
|
label: clientSecretLabel,
|
|
type: 'secret',
|
|
description: t(
|
|
'auth-config.fields.client-secret-description',
|
|
'The {{ clientSecretLabel }} of your OAuth2 app.',
|
|
{
|
|
clientSecretLabel,
|
|
}
|
|
),
|
|
},
|
|
managedIdentityClientId: {
|
|
label: t('auth-config.fields.managed-identity-client-id-label', 'FIC managed identity client ID'),
|
|
type: 'text',
|
|
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: {
|
|
label: t('auth-config.fields.federated-credential-audience-label', 'FIC audience'),
|
|
type: 'text',
|
|
description: t(
|
|
'auth-config.fields.federated-credential-audience-description',
|
|
'The audience of the federated identity credential of your OAuth2 app.'
|
|
),
|
|
},
|
|
workloadIdentityTokenFile: {
|
|
label: t('auth-config.fields.workload-identity-token-file-label', '{{ workloadIdentityLabel }} token file', {
|
|
workloadIdentityLabel,
|
|
}),
|
|
type: 'text',
|
|
description: t(
|
|
'auth-config.fields.workload-identity-token-file-description',
|
|
'The file path to the token file used to authenticate to the OAuth2 provider. This is only required when client authentication is set to "workload_identity". Defaults to /var/run/secrets/azure/tokens/azure-identity-token.'
|
|
),
|
|
validation: {
|
|
validate: (value, formValues) => {
|
|
let clientAuth = formValues.clientAuthentication;
|
|
if (isSelectableValue<string>(clientAuth)) {
|
|
clientAuth = clientAuth.value;
|
|
}
|
|
if (clientAuth === 'workload_identity') {
|
|
return !!value;
|
|
}
|
|
return true;
|
|
},
|
|
message: t(
|
|
'auth-config.fields.workload-identity-token-file-required',
|
|
'This field must be set when client authentication is set to "Workload identity".'
|
|
),
|
|
},
|
|
},
|
|
allowedOrganizations: {
|
|
label: t('auth-config.fields.allowed-organizations-label', 'Allowed organizations'),
|
|
type: 'select',
|
|
description: t(
|
|
'auth-config.fields.allowed-organizations-description',
|
|
'List of comma- or space-separated organizations. The user should be a member \nof at least one organization to log in.'
|
|
),
|
|
multi: true,
|
|
allowCustomValue: true,
|
|
options: [],
|
|
placeholder: t(
|
|
'auth-config.fields.allowed-organizations-placeholder',
|
|
'Enter organizations (my-team, myteam...) and press Enter to add'
|
|
),
|
|
},
|
|
allowedDomains: {
|
|
label: allowedDomainsLabel,
|
|
type: 'select',
|
|
description: t(
|
|
'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,
|
|
allowCustomValue: true,
|
|
options: [],
|
|
},
|
|
authUrl: {
|
|
label: authURLLabel,
|
|
type: 'text',
|
|
description: t('auth-config.fields.auth-url-description', 'The authorization endpoint of your OAuth2 provider.'),
|
|
validation: {
|
|
required: true,
|
|
validate: (value) => {
|
|
return isUrlValid(value);
|
|
},
|
|
message: t('auth-config.fields.auth-url-required', 'This field is required and must be a valid URL.'),
|
|
},
|
|
},
|
|
authStyle: {
|
|
label: t('auth-config.fields.auth-style-label', 'Auth style'),
|
|
type: 'select',
|
|
description: t(
|
|
'auth-config.fields.auth-style-description',
|
|
'It determines how "{{ clientIDLabel }}" and "{{ clientSecretLabel }}" are sent to Oauth2 provider. Default is AutoDetect.',
|
|
{ clientIDLabel, clientSecretLabel }
|
|
),
|
|
multi: false,
|
|
options: [
|
|
/* eslint-disable @grafana/i18n/no-untranslated-strings */
|
|
{ value: 'AutoDetect', label: 'AutoDetect' },
|
|
{ value: 'InParams', label: 'InParams' },
|
|
{ value: 'InHeader', label: 'InHeader' },
|
|
],
|
|
defaultValue: { value: 'AutoDetect', label: 'AutoDetect' },
|
|
/* eslint-enable @grafana/i18n/no-untranslated-strings */
|
|
},
|
|
tokenUrl: {
|
|
label: tokenURLLabel,
|
|
type: 'text',
|
|
description: t('auth-config.fields.token-url-description', 'The token endpoint of your OAuth2 provider.'),
|
|
validation: {
|
|
required: true,
|
|
validate: (value) => {
|
|
return isUrlValid(value);
|
|
},
|
|
message: t('auth-config.fields.token-url-required', 'This field is required and must be a valid URL.'),
|
|
},
|
|
},
|
|
scopes: {
|
|
label: scopesLabel,
|
|
type: 'select',
|
|
description: t(
|
|
'auth-config.fields.scopes-description',
|
|
'List of comma- or space-separated OAuth2 {{ scopesLabel }}.',
|
|
{
|
|
scopesLabel,
|
|
}
|
|
),
|
|
multi: true,
|
|
allowCustomValue: true,
|
|
options: [],
|
|
},
|
|
allowedGroups: {
|
|
label: allowedGroupsLabel,
|
|
type: 'select',
|
|
description: (
|
|
<>
|
|
<Trans i18nKey="auth-config.fields.allowed-groups-description">
|
|
List of comma- or space-separated groups. The user should be a member of at least one group to log in.
|
|
</Trans>{' '}
|
|
{provider === 'generic_oauth' &&
|
|
t(
|
|
'auth-config.fields.allowed-groups-description-oauth',
|
|
'If you configure "{{ allowedGroupsLabel }}", you must also configure "{{ groupsAttributePathLabel }}".',
|
|
{ allowedGroupsLabel, groupsAttributePathLabel }
|
|
)}
|
|
</>
|
|
),
|
|
multi: true,
|
|
allowCustomValue: true,
|
|
options: [],
|
|
validation:
|
|
provider === 'azuread'
|
|
? {
|
|
validate: (value) => {
|
|
if (typeof value === 'string') {
|
|
return uuidValidate(value);
|
|
}
|
|
if (isSelectableValueArray(value)) {
|
|
return value.every((v) => v?.value && uuidValidate(v.value));
|
|
}
|
|
return true;
|
|
},
|
|
message: t(
|
|
'auth-config.fields.allowed-groups-object-ids',
|
|
'{{ allowedGroupsLabel }} must be {{ objectIDsField }}.',
|
|
{
|
|
objectIDsField: 'Object IDs',
|
|
}
|
|
),
|
|
}
|
|
: undefined,
|
|
},
|
|
apiUrl: {
|
|
label: apiURLLabel,
|
|
type: 'text',
|
|
description: (
|
|
<Trans i18nKey="auth-config.fields.api-url-description">
|
|
The user information endpoint of your OAuth2 provider. Information returned by this endpoint must be
|
|
compatible with{' '}
|
|
<TextLink href={'https://connect2id.com/products/server/docs/api/userinfo'} external variant={'bodySmall'}>
|
|
OpenID UserInfo
|
|
</TextLink>
|
|
.
|
|
</Trans>
|
|
),
|
|
validation: {
|
|
required: false,
|
|
validate: (value) => {
|
|
if (typeof value !== 'string') {
|
|
return false;
|
|
}
|
|
|
|
if (value.length) {
|
|
return isUrlValid(value);
|
|
}
|
|
|
|
return true;
|
|
},
|
|
message: t('auth-config.fields.api-url-required', 'This field must be a valid URL if set.'),
|
|
},
|
|
},
|
|
roleAttributePath: {
|
|
label: t('auth-config.fields.role-attribute-path-label', 'Role attribute path'),
|
|
description: t(
|
|
'auth-config.fields.role-attribute-path-description',
|
|
'{{ jmesPathLabel }} expression to use for Grafana role lookup.',
|
|
{ jmesPathLabel }
|
|
),
|
|
type: 'text',
|
|
validation: {
|
|
required: false,
|
|
},
|
|
},
|
|
name: {
|
|
label: t('auth-config.fields.display-name-label', 'Display name'),
|
|
description: t(
|
|
'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',
|
|
},
|
|
allowSignUp: {
|
|
label: t('auth-config.fields.allow-sign-up-label', 'Allow sign up'),
|
|
description: t(
|
|
'auth-config.fields.allow-sign-up-description',
|
|
'If not enabled, only existing Grafana users can log in using OAuth.'
|
|
),
|
|
type: 'switch',
|
|
},
|
|
autoLogin: {
|
|
label: t('auth-config.fields.auto-login-label', 'Auto login'),
|
|
description: t('auth-config.fields.auto-login-description', 'Log in automatically, skipping the login screen.'),
|
|
type: 'switch',
|
|
},
|
|
signoutRedirectUrl: {
|
|
label: t('auth-config.fields.signout-redirect-url-label', 'Sign out redirect URL'),
|
|
description: t(
|
|
'auth-config.fields.signout-redirect-url-description',
|
|
'The URL to redirect the user to after signing out from Grafana.'
|
|
),
|
|
type: 'text',
|
|
validation: {
|
|
required: false,
|
|
},
|
|
},
|
|
emailAttributeName: {
|
|
label: t('auth-config.fields.email-attribute-name-label', 'Email attribute name'),
|
|
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',
|
|
},
|
|
emailAttributePath: {
|
|
label: t('auth-config.fields.email-attribute-path-label', 'Email attribute path'),
|
|
description: t(
|
|
'auth-config.fields.email-attribute-path-description',
|
|
'JMESPath expression to use for user email lookup from the user information.'
|
|
),
|
|
type: 'text',
|
|
},
|
|
nameAttributePath: {
|
|
label: t('auth-config.fields.name-attribute-path-label', 'Name attribute path'),
|
|
description: t(
|
|
'auth-config.fields.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."
|
|
),
|
|
type: 'text',
|
|
},
|
|
loginAttributePath: {
|
|
label: t('auth-config.fields.login-attribute-path-label', 'Login attribute path'),
|
|
description: t(
|
|
'auth-config.fields.login-attribute-path-description',
|
|
'JMESPath expression to use for user login lookup from the user ID token.'
|
|
),
|
|
type: 'text',
|
|
},
|
|
idTokenAttributeName: {
|
|
label: t('auth-config.fields.id-token-attribute-name-label', 'ID token attribute name'),
|
|
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',
|
|
},
|
|
roleAttributeStrict: {
|
|
label: t('auth-config.fields.role-attribute-strict-label', 'Role attribute strict mode'),
|
|
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',
|
|
},
|
|
allowAssignGrafanaAdmin: {
|
|
label: t('auth-config.fields.allow-assign-grafana-admin-label', 'Allow assign Grafana admin'),
|
|
description: t(
|
|
'auth-config.fields.allow-assign-grafana-admin-description',
|
|
'If enabled, it will automatically sync the Grafana server administrator role.'
|
|
),
|
|
type: 'switch',
|
|
hidden: !contextSrv.isGrafanaAdmin,
|
|
},
|
|
skipOrgRoleSync: {
|
|
label: t('auth-config.fields.skip-org-role-sync-label', 'Skip organization role sync'),
|
|
description: t(
|
|
'auth-config.fields.skip-org-role-sync-description',
|
|
"Prevent synchronizing users' organization roles from your IdP."
|
|
),
|
|
type: 'switch',
|
|
},
|
|
orgMapping: {
|
|
label: orgMappingLabel,
|
|
description: orgMappingDescription(provider),
|
|
type: 'select',
|
|
hidden: !contextSrv.isGrafanaAdmin,
|
|
multi: true,
|
|
allowCustomValue: true,
|
|
options: [],
|
|
placeholder: t(
|
|
'auth-config.fields.organization-mapping-placeholder',
|
|
'Enter mappings (my-team:1:Viewer...) and press Enter to add'
|
|
),
|
|
},
|
|
orgAttributePath: {
|
|
label: orgAttributePathLabel,
|
|
description: t(
|
|
'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',
|
|
hidden: !(['generic_oauth', 'okta'].includes(provider) && contextSrv.isGrafanaAdmin),
|
|
},
|
|
defineAllowedGroups: {
|
|
label: t('auth-config.fields.define-allowed-groups-label', 'Define allowed groups'),
|
|
type: 'switch',
|
|
},
|
|
defineAllowedTeamsIds: {
|
|
label: t('auth-config.fields.define-allowed-teams-ids-label', 'Define allowed teams IDs'),
|
|
type: 'switch',
|
|
},
|
|
forceUseGraphApi: {
|
|
label: t('auth-config.fields.force-use-graph-api-label', 'Force use 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',
|
|
},
|
|
usePkce: {
|
|
label: t('auth-config.fields.use-pkce-label', 'Use PKCE'),
|
|
description: (
|
|
<Trans i18nKey="auth-config.fields.use-pkce-description">
|
|
If enabled, Grafana will use{' '}
|
|
<TextLink external variant={'bodySmall'} href={'https://datatracker.ietf.org/doc/html/rfc7636'}>
|
|
Proof Key for Code Exchange (PKCE)
|
|
</TextLink>{' '}
|
|
with the OAuth2 Authorization Code Grant.
|
|
</Trans>
|
|
),
|
|
type: 'checkbox',
|
|
},
|
|
useRefreshToken: {
|
|
label: t('auth-config.fields.use-refresh-token-label', 'Use refresh token'),
|
|
description: t(
|
|
'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',
|
|
},
|
|
tlsClientCa: {
|
|
label: t('auth-config.fields.tls-client-ca-label', 'TLS client CA'),
|
|
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',
|
|
hidden: !config.localFileSystemAvailable,
|
|
},
|
|
tlsClientCert: {
|
|
label: t('auth-config.fields.tls-client-cert-label', 'TLS client cert'),
|
|
description: t(
|
|
'auth-config.fields.tls-client-cert-description',
|
|
'The file path to the certificate. Is not applicable on Grafana Cloud.'
|
|
),
|
|
type: 'text',
|
|
hidden: !config.localFileSystemAvailable,
|
|
},
|
|
tlsClientKey: {
|
|
label: t('auth-config.fields.tls-client-key-label', 'TLS client key'),
|
|
description: t(
|
|
'auth-config.fields.tls-client-key-description',
|
|
'The file path to the key. Is not applicable on Grafana Cloud.'
|
|
),
|
|
type: 'text',
|
|
hidden: !config.localFileSystemAvailable,
|
|
},
|
|
tlsSkipVerifyInsecure: {
|
|
label: t('auth-config.fields.tls-skip-verify-label', 'TLS skip verify'),
|
|
description: t(
|
|
'auth-config.fields.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.'
|
|
),
|
|
type: 'switch',
|
|
},
|
|
groupsAttributePath: {
|
|
label: groupsAttributePathLabel,
|
|
description: t(
|
|
'auth-config.fields.groups-attribute-path-description',
|
|
'JMESPath expression to use for user group lookup. If you configure "{{ allowedGroupsLabel }}", \nyou must also configure "{{ groupsAttributePathLabel }}".',
|
|
{ allowedGroupsLabel, groupsAttributePathLabel }
|
|
),
|
|
type: 'text',
|
|
},
|
|
teamsUrl: {
|
|
label: teamsURLLabel,
|
|
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.
|
|
</Trans>{' '}
|
|
{provider === 'generic_oauth' &&
|
|
t(
|
|
'auth-config.fields.teams-url-description-oauth',
|
|
'If you configure "{{ teamsURLLabel }}", you must also configure "{{ teamIDsAttributePathLabel }}".',
|
|
{ teamsURLLabel, teamIDsAttributePathLabel }
|
|
)}
|
|
</>
|
|
),
|
|
type: 'text',
|
|
validation: {
|
|
validate: (value, formValues) => {
|
|
let result = true;
|
|
if (formValues.teamIds.length) {
|
|
result = !!value;
|
|
}
|
|
|
|
if (typeof value === 'string' && value.length) {
|
|
result = isUrlValid(value);
|
|
}
|
|
return result;
|
|
},
|
|
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: {
|
|
label: teamIDsAttributePathLabel,
|
|
description: t(
|
|
'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',
|
|
validation: {
|
|
validate: (value, formValues) => {
|
|
if (formValues.teamIds.length) {
|
|
return !!value;
|
|
}
|
|
return true;
|
|
},
|
|
message: t(
|
|
'auth-config.fields.team-ids-attribute-path-required',
|
|
'This field must be set if "{{ teamIDsLabel }}" are configured.',
|
|
{ teamIDsLabel }
|
|
),
|
|
},
|
|
},
|
|
teamIds: {
|
|
label: teamIDsLabel,
|
|
type: 'select',
|
|
description: (
|
|
<>
|
|
{provider === 'github'
|
|
? t('auth-config.fields.team-ids-github', 'Integer list of Team IDs.')
|
|
: t('auth-config.fields.team-ids-other', 'String list of Team IDs.')}{' '}
|
|
<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.
|
|
</Trans>{' '}
|
|
{provider === 'generic_oauth' &&
|
|
t(
|
|
'auth-config.fields.team-ids-description-oauth',
|
|
'If you configure "{{ teamIDsLabel }}", you must also configure "{{ teamsURLLabel }}" and "{{ teamIDsAttributePathLabel }}".',
|
|
{ teamIDsLabel, teamsURLLabel, teamIDsAttributePathLabel }
|
|
)}
|
|
</>
|
|
),
|
|
multi: true,
|
|
allowCustomValue: true,
|
|
options: [],
|
|
placeholder: t('auth-config.fields.team-ids-placeholder', 'Enter Team IDs and press Enter to add'),
|
|
validation:
|
|
provider === 'github'
|
|
? {
|
|
validate: (value) => {
|
|
if (typeof value === 'string') {
|
|
return isNumeric(value);
|
|
}
|
|
if (isSelectableValueArray(value)) {
|
|
return value.every((v) => v?.value && isNumeric(v.value));
|
|
}
|
|
return true;
|
|
},
|
|
message: t('auth-config.fields.team-ids-numbers', 'Team IDs must be numbers.'),
|
|
}
|
|
: undefined,
|
|
},
|
|
hostedDomain: {
|
|
label: t('auth-config.fields.hosted-domain-label', 'Hosted domain'),
|
|
description: t(
|
|
'auth-config.fields.hosted-domain-description',
|
|
'The domain under which Grafana is hosted and accessible.'
|
|
),
|
|
type: 'text',
|
|
},
|
|
validateHd: {
|
|
label: t('auth-config.fields.validate-hosted-domain-label', 'Validate hosted domain'),
|
|
description: t(
|
|
'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',
|
|
},
|
|
serverDiscoveryUrl: {
|
|
label: openIDConnectDiscoveryLabel,
|
|
description: t(
|
|
'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',
|
|
content: (setValue) => <ServerDiscoveryField setValue={setValue} />,
|
|
},
|
|
};
|
|
}
|
|
|
|
// Check if a string contains only numeric values
|
|
function isNumeric(value: string) {
|
|
return /^-?\d+$/.test(value);
|
|
}
|
|
|
|
function orgMappingDescription(provider: string): string {
|
|
switch (provider) {
|
|
case 'azuread':
|
|
return t(
|
|
'auth-config.fields.org-mapping-description-azuread',
|
|
'List of "<GroupID>:<OrgIdOrName>:<Role>" mappings.'
|
|
);
|
|
case 'github':
|
|
return t(
|
|
'auth-config.fields.org-mapping-description-github',
|
|
'List of "<GitHubTeamName>:<OrgIdOrName>:<Role>" mappings.'
|
|
);
|
|
case 'gitlab':
|
|
return t(
|
|
'auth-config.fields.org-mapping-description-gitlab',
|
|
'List of "<GitlabGroupName>:<OrgIdOrName>:<Role>" mappings.'
|
|
);
|
|
case 'google':
|
|
return t(
|
|
'auth-config.fields.org-mapping-description-google',
|
|
'List of "<GoogleGroupName>:<OrgIdOrName>:<Role>" mappings.'
|
|
);
|
|
default:
|
|
// Generic OAuth, Okta
|
|
return t(
|
|
'auth-config.fields.org-mapping-description-generic',
|
|
'List of "<ExternalName>:<OrgIdOrName>:<Role>" mappings.'
|
|
);
|
|
}
|
|
}
|
|
|
|
function clientAuthenticationOptions(provider: string): Array<SelectableValue<string>> {
|
|
// Other options are purposefully not translated
|
|
/* eslint-disable @grafana/i18n/no-untranslated-strings */
|
|
switch (provider) {
|
|
case 'azuread':
|
|
return [
|
|
{ value: 'none', label: t('auth-config.fields.client-authentication-none', 'None') },
|
|
{ value: 'client_secret_post', label: 'Client secret' },
|
|
{ value: 'managed_identity', label: 'Managed identity' },
|
|
{ value: 'workload_identity', label: 'Workload identity' },
|
|
];
|
|
// Other providers ...
|
|
default:
|
|
return [
|
|
{ value: 'none', label: 'None' },
|
|
{ value: 'client_secret_post', label: 'Client secret' },
|
|
];
|
|
}
|
|
/* eslint-enable @grafana/i18n/no-untranslated-strings */
|
|
}
|
|
|