return axios.post(GITLAB_CONFIGURATIONS, { | return axios.post(GITLAB_CONFIGURATIONS, { | ||||
...data, | ...data, | ||||
provisioningType: ProvisioningType.jit, | provisioningType: ProvisioningType.jit, | ||||
allowedGroups: [], | |||||
allowUsersToSignUp: false, | allowUsersToSignUp: false, | ||||
enabled: true, | enabled: true, | ||||
}); | }); |
onFieldChange: (key: string, value: string | boolean | string[]) => void; | onFieldChange: (key: string, value: string | boolean | string[]) => void; | ||||
isNotSet: boolean; | isNotSet: boolean; | ||||
error?: string; | error?: string; | ||||
className?: string; | |||||
} | } | ||||
export default function AuthenticationFormField(props: Readonly<Props>) { | export default function AuthenticationFormField(props: Readonly<Props>) { | ||||
const { mandatory = false, definition, settingValue, isNotSet, error } = props; | |||||
const { mandatory = false, definition, settingValue, isNotSet, error, className } = props; | |||||
const intl = useIntl(); | const intl = useIntl(); | ||||
return ( | return ( | ||||
<FormField | <FormField | ||||
className={className} | |||||
htmlFor={definition.key} | htmlFor={definition.key} | ||||
ariaLabel={name} | ariaLabel={name} | ||||
label={name} | label={name} |
provisioningType?: GitLabConfigurationUpdateBody['provisioningType']; | provisioningType?: GitLabConfigurationUpdateBody['provisioningType']; | ||||
allowUsersToSignUp?: GitLabConfigurationUpdateBody['allowUsersToSignUp']; | allowUsersToSignUp?: GitLabConfigurationUpdateBody['allowUsersToSignUp']; | ||||
provisioningToken?: GitLabConfigurationUpdateBody['provisioningToken']; | provisioningToken?: GitLabConfigurationUpdateBody['provisioningToken']; | ||||
allowedGroups?: GitLabConfigurationUpdateBody['allowedGroups']; | |||||
} | } | ||||
const definitions: Record<keyof Omit<ChangesForm, 'provisioningType'>, DefinitionV2> = { | |||||
allowUsersToSignUp: { | |||||
name: translate('settings.authentication.gitlab.form.allowUsersToSignUp.name'), | |||||
secured: false, | |||||
key: 'allowUsersToSignUp', | |||||
description: translate('settings.authentication.gitlab.form.allowUsersToSignUp.description'), | |||||
type: SettingType.BOOLEAN, | |||||
}, | |||||
provisioningToken: { | |||||
name: translate('settings.authentication.gitlab.form.provisioningToken.name'), | |||||
secured: true, | |||||
key: 'provisioningToken', | |||||
description: translate('settings.authentication.gitlab.form.provisioningToken.description'), | |||||
}, | |||||
const getDefinitions = ( | |||||
provisioningType: ProvisioningType, | |||||
): Record<keyof Omit<ChangesForm, 'provisioningType'>, DefinitionV2> => { | |||||
return { | |||||
allowUsersToSignUp: { | |||||
name: translate('settings.authentication.gitlab.form.allowUsersToSignUp.name'), | |||||
secured: false, | |||||
key: 'allowUsersToSignUp', | |||||
description: translate('settings.authentication.gitlab.form.allowUsersToSignUp.description'), | |||||
type: SettingType.BOOLEAN, | |||||
}, | |||||
provisioningToken: { | |||||
name: translate('settings.authentication.gitlab.form.provisioningToken.name'), | |||||
secured: true, | |||||
key: 'provisioningToken', | |||||
description: translate('settings.authentication.gitlab.form.provisioningToken.description'), | |||||
}, | |||||
allowedGroups: { | |||||
name: translate('settings.authentication.gitlab.form.allowedGroups.name'), | |||||
secured: false, | |||||
key: 'allowedGroups', | |||||
description: translate( | |||||
`settings.authentication.gitlab.form.allowedGroups.description.${provisioningType}`, | |||||
), | |||||
multiValues: true, | |||||
}, | |||||
}; | |||||
}; | }; | ||||
export default function GitLabAuthenticationTab() { | export default function GitLabAuthenticationTab() { | ||||
const { mutate: updateConfig, isLoading: isUpdating } = useUpdateGitLabConfigurationMutation(); | const { mutate: updateConfig, isLoading: isUpdating } = useUpdateGitLabConfigurationMutation(); | ||||
const { mutate: deleteConfig, isLoading: isDeleting } = useDeleteGitLabConfigurationMutation(); | const { mutate: deleteConfig, isLoading: isDeleting } = useDeleteGitLabConfigurationMutation(); | ||||
const definitions = getDefinitions( | |||||
changes?.provisioningType ?? configuration?.provisioningType ?? ProvisioningType.jit, | |||||
); | |||||
const toggleEnable = () => { | const toggleEnable = () => { | ||||
if (!configuration) { | if (!configuration) { | ||||
return; | return; | ||||
const setJIT = () => | const setJIT = () => | ||||
setChangesWithCheck({ | setChangesWithCheck({ | ||||
provisioningType: ProvisioningType.jit, | provisioningType: ProvisioningType.jit, | ||||
allowedGroups: changes?.allowedGroups, | |||||
provisioningToken: undefined, | provisioningToken: undefined, | ||||
}); | }); | ||||
const setAuto = () => | const setAuto = () => | ||||
setChangesWithCheck({ | setChangesWithCheck({ | ||||
provisioningType: ProvisioningType.auto, | provisioningType: ProvisioningType.auto, | ||||
allowedGroups: changes?.allowedGroups, | |||||
allowUsersToSignUp: undefined, | allowUsersToSignUp: undefined, | ||||
}); | }); | ||||
const hasDifferentProvider = | const hasDifferentProvider = | ||||
identityProvider?.provider !== undefined && identityProvider.provider !== Provider.Gitlab; | identityProvider?.provider !== undefined && identityProvider.provider !== Provider.Gitlab; | ||||
const allowUsersToSignUpDefinition = definitions.allowUsersToSignUp; | const allowUsersToSignUpDefinition = definitions.allowUsersToSignUp; | ||||
const allowedGroupsDefinition = definitions.allowedGroups; | |||||
const provisioningTokenDefinition = definitions.provisioningToken; | const provisioningTokenDefinition = definitions.provisioningToken; | ||||
const provisioningType = changes?.provisioningType ?? configuration?.provisioningType; | const provisioningType = changes?.provisioningType ?? configuration?.provisioningType; | ||||
const allowUsersToSignUp = changes?.allowUsersToSignUp ?? configuration?.allowUsersToSignUp; | const allowUsersToSignUp = changes?.allowUsersToSignUp ?? configuration?.allowUsersToSignUp; | ||||
const allowedGroups = changes?.allowedGroups ?? configuration?.allowedGroups; | |||||
const provisioningToken = changes?.provisioningToken; | const provisioningToken = changes?.provisioningToken; | ||||
const canSave = () => { | const canSave = () => { | ||||
} | } | ||||
const type = changes.provisioningType ?? configuration.provisioningType; | const type = changes.provisioningType ?? configuration.provisioningType; | ||||
if (type === ProvisioningType.auto) { | if (type === ProvisioningType.auto) { | ||||
return configuration.isProvisioningTokenSet || !!changes.provisioningToken; | |||||
const areGroupsDefined = | |||||
changes.allowedGroups?.some((val) => val !== '') ?? | |||||
configuration.allowedGroups?.some((val) => val !== ''); | |||||
return ( | |||||
(configuration.isProvisioningTokenSet || !!changes.provisioningToken) && areGroupsDefined | |||||
); | |||||
} | } | ||||
return true; | return true; | ||||
}; | }; | ||||
configuration?.allowUsersToSignUp === newChanges.allowUsersToSignUp | configuration?.allowUsersToSignUp === newChanges.allowUsersToSignUp | ||||
? undefined | ? undefined | ||||
: newChanges.allowUsersToSignUp, | : newChanges.allowUsersToSignUp, | ||||
allowedGroups: | |||||
configuration?.allowedGroups === newChanges.allowedGroups | |||||
? undefined | |||||
: newChanges.allowedGroups, | |||||
provisioningToken: newChanges.provisioningToken, | provisioningToken: newChanges.provisioningToken, | ||||
}; | }; | ||||
if (Object.values(newValue).some((v) => v !== undefined)) { | if (Object.values(newValue).some((v) => v !== undefined)) { | ||||
onToggle={toggleEnable} | onToggle={toggleEnable} | ||||
/> | /> | ||||
<ProvisioningSection | <ProvisioningSection | ||||
isLoading={isUpdating} | |||||
provisioningType={provisioningType ?? ProvisioningType.jit} | provisioningType={provisioningType ?? ProvisioningType.jit} | ||||
onChangeProvisioningType={(val: ProvisioningType) => | onChangeProvisioningType={(val: ProvisioningType) => | ||||
val === ProvisioningType.auto ? setAuto() : setJIT() | val === ProvisioningType.auto ? setAuto() : setJIT() | ||||
/> | /> | ||||
} | } | ||||
jitSettings={ | jitSettings={ | ||||
<AuthenticationFormField | |||||
settingValue={allowUsersToSignUp} | |||||
definition={allowUsersToSignUpDefinition} | |||||
mandatory | |||||
onFieldChange={(_, value) => | |||||
setChangesWithCheck({ | |||||
...changes, | |||||
allowUsersToSignUp: value as boolean, | |||||
}) | |||||
} | |||||
isNotSet={configuration.provisioningType !== ProvisioningType.auto} | |||||
/> | |||||
<> | |||||
<AuthenticationFormField | |||||
settingValue={allowUsersToSignUp} | |||||
definition={allowUsersToSignUpDefinition} | |||||
mandatory | |||||
onFieldChange={(_, value) => | |||||
setChangesWithCheck({ | |||||
...changes, | |||||
allowUsersToSignUp: value as boolean, | |||||
}) | |||||
} | |||||
isNotSet={configuration.provisioningType !== ProvisioningType.auto} | |||||
/> | |||||
<AuthenticationFormField | |||||
className="sw-mt-8" | |||||
settingValue={allowedGroups} | |||||
definition={allowedGroupsDefinition} | |||||
onFieldChange={(_, values) => | |||||
setChangesWithCheck({ | |||||
...changes, | |||||
allowedGroups: values as string[], | |||||
}) | |||||
} | |||||
isNotSet={configuration.provisioningType !== ProvisioningType.auto} | |||||
/> | |||||
</> | |||||
} | } | ||||
autoTitle={translate('settings.authentication.gitlab.form.provisioning_with_gitlab')} | autoTitle={translate('settings.authentication.gitlab.form.provisioning_with_gitlab')} | ||||
hasDifferentProvider={hasDifferentProvider} | hasDifferentProvider={hasDifferentProvider} | ||||
canSync={canSyncNow} | canSync={canSyncNow} | ||||
synchronizationDetails={<GitLabSynchronisationWarning />} | synchronizationDetails={<GitLabSynchronisationWarning />} | ||||
autoSettings={ | autoSettings={ | ||||
<AuthenticationFormField | |||||
settingValue={provisioningToken} | |||||
key={tokenKey} | |||||
definition={provisioningTokenDefinition} | |||||
mandatory | |||||
onFieldChange={(_, value) => | |||||
setChangesWithCheck({ | |||||
...changes, | |||||
provisioningToken: value as string, | |||||
}) | |||||
} | |||||
isNotSet={!configuration.isProvisioningTokenSet} | |||||
/> | |||||
<> | |||||
<AuthenticationFormField | |||||
settingValue={provisioningToken} | |||||
key={tokenKey} | |||||
definition={provisioningTokenDefinition} | |||||
mandatory | |||||
onFieldChange={(_, value) => | |||||
setChangesWithCheck({ | |||||
...changes, | |||||
provisioningToken: value as string, | |||||
}) | |||||
} | |||||
isNotSet={!configuration.isProvisioningTokenSet} | |||||
/> | |||||
<AuthenticationFormField | |||||
className="sw-mt-8" | |||||
settingValue={allowedGroups} | |||||
definition={allowedGroupsDefinition} | |||||
mandatory | |||||
onFieldChange={(_, values) => | |||||
setChangesWithCheck({ | |||||
...changes, | |||||
allowedGroups: values as string[], | |||||
}) | |||||
} | |||||
isNotSet={configuration.provisioningType !== ProvisioningType.auto} | |||||
/> | |||||
</> | |||||
} | } | ||||
/> | /> | ||||
</> | </> |
*/ | */ | ||||
import { ButtonPrimary, FlagMessage, Modal, Spinner } from 'design-system'; | import { ButtonPrimary, FlagMessage, Modal, Spinner } from 'design-system'; | ||||
import { isArray, keyBy } from 'lodash'; | |||||
import { keyBy } from 'lodash'; | |||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { FormattedMessage } from 'react-intl'; | import { FormattedMessage } from 'react-intl'; | ||||
import DocumentationLink from '../../../../components/common/DocumentationLink'; | import DocumentationLink from '../../../../components/common/DocumentationLink'; | ||||
type: SettingType.BOOLEAN, | type: SettingType.BOOLEAN, | ||||
}, | }, | ||||
}, | }, | ||||
allowedGroups: { | |||||
value: data?.allowedGroups ?? [], | |||||
required: true, | |||||
definition: { | |||||
name: translate('settings.authentication.gitlab.form.allowedGroups.name'), | |||||
secured: false, | |||||
key: 'allowedGroups', | |||||
description: translate('settings.authentication.gitlab.form.allowedGroups.description'), | |||||
multiValues: true, | |||||
}, | |||||
}, | |||||
}); | }); | ||||
const header = translate('settings.authentication.gitlab.form', isCreate ? 'create' : 'edit'); | const header = translate('settings.authentication.gitlab.form', isCreate ? 'create' : 'edit'); | ||||
const canBeSaved = Object.values(formData).every(({ definition, required, value }) => { | const canBeSaved = Object.values(formData).every(({ definition, required, value }) => { | ||||
return ( | |||||
(!isCreate && definition.secured) || | |||||
!required || | |||||
(isArray(value) ? value.some((val) => val !== '') : value !== '') | |||||
); | |||||
return (!isCreate && definition.secured) || !required || value !== ''; | |||||
}); | }); | ||||
const handleSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => { | const handleSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => { |
ButtonSecondary, | ButtonSecondary, | ||||
FlagMessage, | FlagMessage, | ||||
RadioButton, | RadioButton, | ||||
Spinner, | |||||
SubHeading, | SubHeading, | ||||
} from 'design-system'; | } from 'design-system'; | ||||
import React, { FormEvent, ReactElement } from 'react'; | import React, { FormEvent, ReactElement } from 'react'; | ||||
import { ProvisioningType } from '../../../../types/provisioning'; | import { ProvisioningType } from '../../../../types/provisioning'; | ||||
interface Props { | interface Props { | ||||
isLoading?: boolean; | |||||
provisioningType: ProvisioningType; | provisioningType: ProvisioningType; | ||||
onChangeProvisioningType: (val: ProvisioningType) => void; | onChangeProvisioningType: (val: ProvisioningType) => void; | ||||
disabledConfigText: string; | disabledConfigText: string; | ||||
export default function ProvisioningSection(props: Readonly<Props>) { | export default function ProvisioningSection(props: Readonly<Props>) { | ||||
const { | const { | ||||
isLoading, | |||||
provisioningType, | provisioningType, | ||||
jitTitle, | jitTitle, | ||||
jitDescription, | jitDescription, | ||||
<ButtonSecondary onClick={onCancel} disabled={!hasUnsavedChanges}> | <ButtonSecondary onClick={onCancel} disabled={!hasUnsavedChanges}> | ||||
{translate('cancel')} | {translate('cancel')} | ||||
</ButtonSecondary> | </ButtonSecondary> | ||||
<Spinner loading={!!isLoading} /> | |||||
<FlagMessage variant="warning" className="sw-mb-0"> | <FlagMessage variant="warning" className="sw-mb-0"> | ||||
{hasUnsavedChanges && | {hasUnsavedChanges && | ||||
!isLoading && | |||||
translate('settings.authentication.github.configuration.unsaved_changes')} | translate('settings.authentication.github.configuration.unsaved_changes')} | ||||
</FlagMessage> | </FlagMessage> | ||||
</div> | </div> |
expect(ui.saveConfigButton.get()).toBeDisabled(); | expect(ui.saveConfigButton.get()).toBeDisabled(); | ||||
await user.type(ui.url.get(), 'https://company.ui.com'); | await user.type(ui.url.get(), 'https://company.ui.com'); | ||||
await user.type(ui.secret.get(), '123'); | await user.type(ui.secret.get(), '123'); | ||||
expect(ui.saveConfigButton.get()).toBeDisabled(); | |||||
await user.type(ui.groups.get(), 'NWA'); | |||||
expect(ui.saveConfigButton.get()).toBeEnabled(); | expect(ui.saveConfigButton.get()).toBeEnabled(); | ||||
await user.click(ui.synchronizeGroups.get()); | await user.click(ui.synchronizeGroups.get()); | ||||
await user.click(ui.saveConfigButton.get()); | await user.click(ui.saveConfigButton.get()); | ||||
expect(ui.url.get()).toHaveValue('URL'); | expect(ui.url.get()).toHaveValue('URL'); | ||||
expect(ui.applicationId.get()).toBeInTheDocument(); | expect(ui.applicationId.get()).toBeInTheDocument(); | ||||
expect(ui.secret.query()).not.toBeInTheDocument(); | expect(ui.secret.query()).not.toBeInTheDocument(); | ||||
expect(ui.groups.get()).toHaveValue('Cypress Hill'); | |||||
expect(ui.synchronizeGroups.get()).toBeChecked(); | expect(ui.synchronizeGroups.get()).toBeChecked(); | ||||
expect(ui.applicationId.get()).toBeInTheDocument(); | expect(ui.applicationId.get()).toBeInTheDocument(); | ||||
expect(ui.saveConfigButton.get()).toBeDisabled(); | expect(ui.saveConfigButton.get()).toBeDisabled(); | ||||
await user.type(ui.url.get(), 'www.internet.com'); | await user.type(ui.url.get(), 'www.internet.com'); | ||||
expect(ui.saveConfigButton.get()).toBeEnabled(); | expect(ui.saveConfigButton.get()).toBeEnabled(); | ||||
expect(ui.groups.get()).toHaveValue('Cypress Hill'); | |||||
await user.click(ui.groups.get()); | |||||
await user.click(ui.deleteGroupButton.get()); | |||||
expect(ui.groups.get()).not.toHaveValue('Cypress Hill'); | |||||
expect(ui.saveConfigButton.get()).toBeDisabled(); | |||||
await user.click(ui.groups.get()); | |||||
await user.type(ui.groups.get(), 'Run DMC'); | |||||
expect(ui.saveConfigButton.get()).toBeEnabled(); | |||||
await user.click(ui.saveConfigButton.get()); | await user.click(ui.saveConfigButton.get()); | ||||
expect(glContainer.get()).not.toHaveTextContent('URL'); | expect(glContainer.get()).not.toHaveTextContent('URL'); | ||||
expect(ui.editConfigButton.query()).not.toBeInTheDocument(); | expect(ui.editConfigButton.query()).not.toBeInTheDocument(); | ||||
}); | }); | ||||
it('should change from just-in-time to Auto Provisioning if auto was never set', async () => { | |||||
it('should be able to save just-in-time with no organizations', async () => { | |||||
const user = userEvent.setup(); | |||||
renderAuthentication([Feature.GitlabProvisioning]); | |||||
expect(await ui.jitProvisioningRadioButton.find()).toBeChecked(); | |||||
expect(ui.groups.get()).toHaveValue('Cypress Hill'); | |||||
expect(await ui.saveProvisioning.find()).toBeDisabled(); | |||||
await user.click(ui.deleteGroupButton.get()); | |||||
expect(await ui.saveProvisioning.find()).toBeEnabled(); | |||||
}); | |||||
it('should not be able to save Auto provisioning with no organizations', async () => { | |||||
const user = userEvent.setup(); | |||||
handler.setGitlabConfigurations([ | |||||
mockGitlabConfiguration({ | |||||
allowUsersToSignUp: false, | |||||
enabled: true, | |||||
provisioningType: ProvisioningType.auto, | |||||
allowedGroups: ['D12'], | |||||
isProvisioningTokenSet: true, | |||||
}), | |||||
]); | |||||
renderAuthentication([Feature.GitlabProvisioning]); | |||||
expect(await ui.autoProvisioningRadioButton.find()).toBeChecked(); | |||||
expect(ui.groups.get()).toHaveValue('D12'); | |||||
expect(ui.saveProvisioning.get()).toBeDisabled(); | |||||
await user.click(ui.deleteGroupButton.get()); | |||||
expect(await ui.saveProvisioning.find()).toBeDisabled(); | |||||
}); | |||||
it('should change from just-in-time to Auto Provisioning if auto was never set before', async () => { | |||||
const user = userEvent.setup(); | const user = userEvent.setup(); | ||||
handler.setGitlabConfigurations([ | |||||
mockGitlabConfiguration({ | |||||
allowUsersToSignUp: false, | |||||
enabled: true, | |||||
provisioningType: ProvisioningType.jit, | |||||
allowedGroups: [], | |||||
isProvisioningTokenSet: false, | |||||
}), | |||||
]); | |||||
renderAuthentication([Feature.GitlabProvisioning]); | renderAuthentication([Feature.GitlabProvisioning]); | ||||
expect(await ui.editConfigButton.find()).toBeInTheDocument(); | expect(await ui.editConfigButton.find()).toBeInTheDocument(); | ||||
expect(ui.jitProvisioningRadioButton.get()).toBeChecked(); | expect(ui.jitProvisioningRadioButton.get()).toBeChecked(); | ||||
user.click(ui.autoProvisioningRadioButton.get()); | |||||
await user.click(ui.autoProvisioningRadioButton.get()); | |||||
expect(await ui.autoProvisioningRadioButton.find()).toBeEnabled(); | expect(await ui.autoProvisioningRadioButton.find()).toBeEnabled(); | ||||
expect(ui.saveProvisioning.get()).toBeDisabled(); | expect(ui.saveProvisioning.get()).toBeDisabled(); | ||||
await user.type(ui.autoProvisioningToken.get(), 'JRR Tolkien'); | await user.type(ui.autoProvisioningToken.get(), 'JRR Tolkien'); | ||||
expect(await ui.saveProvisioning.find()).toBeDisabled(); | |||||
await user.type(ui.groups.get(), 'Run DMC'); | |||||
expect(await ui.saveProvisioning.find()).toBeEnabled(); | |||||
await user.click(ui.deleteGroupButton.get()); | |||||
expect(await ui.saveProvisioning.find()).toBeDisabled(); | |||||
await user.type(ui.groups.get(), 'Public Enemy'); | |||||
expect(await ui.saveProvisioning.find()).toBeEnabled(); | expect(await ui.saveProvisioning.find()).toBeEnabled(); | ||||
}); | }); | ||||
user.click(ui.autoProvisioningRadioButton.get()); | user.click(ui.autoProvisioningRadioButton.get()); | ||||
expect(await ui.autoProvisioningRadioButton.find()).toBeEnabled(); | expect(await ui.autoProvisioningRadioButton.find()).toBeEnabled(); | ||||
expect(await ui.saveProvisioning.find()).toBeEnabled(); | |||||
expect(ui.groups.get()).toHaveValue('D12'); | |||||
await user.click(ui.deleteGroupButton.get()); | |||||
expect(await ui.saveProvisioning.find()).toBeDisabled(); | |||||
await user.type(ui.groups.get(), 'Wu Tang Clan'); | |||||
expect(ui.saveProvisioning.get()).toBeEnabled(); | expect(ui.saveProvisioning.get()).toBeEnabled(); | ||||
}); | }); | ||||
url: string; | url: string; | ||||
secret: string; | secret: string; | ||||
synchronizeGroups: boolean; | synchronizeGroups: boolean; | ||||
allowedGroups: string[]; | |||||
} | } | ||||
export type GitLabConfigurationUpdateBody = { | export type GitLabConfigurationUpdateBody = { |
settings.authentication.gitlab.form.synchronizeGroups.name=Synchronize user groups | settings.authentication.gitlab.form.synchronizeGroups.name=Synchronize user groups | ||||
settings.authentication.gitlab.form.synchronizeGroups.description=For each GitLab group they belong to, the user will be associated to a group with the same name (if it exists) in SonarQube. If enabled, the GitLab OAuth 2 application will need to provide the api scope. | settings.authentication.gitlab.form.synchronizeGroups.description=For each GitLab group they belong to, the user will be associated to a group with the same name (if it exists) in SonarQube. If enabled, the GitLab OAuth 2 application will need to provide the api scope. | ||||
settings.authentication.gitlab.form.allowedGroups.name=Allowed groups | settings.authentication.gitlab.form.allowedGroups.name=Allowed groups | ||||
settings.authentication.gitlab.form.allowedGroups.description=Only members of these groups (and sub-groups) will be allowed to authenticate. Please enter the group slug as it appears in the GitLab URL, for instance `my-gitlab-group`. If you use Auto-provisioning, only members of these groups (and sub-groups) will be provisioned. | |||||
settings.authentication.gitlab.form.allowedGroups.description.JIT=Only members of these groups (and sub-groups) will be allowed to authenticate. Please enter the group slug as it appears in the GitLab URL, for instance `my-gitlab-group`. ⚠︎ if not set and `Allow users to sign up` is enabled, any user from GitLab will be able to login to this SonarQube instance. | |||||
settings.authentication.gitlab.form.allowedGroups.description.AUTO_PROVISIONING=Only members of these groups (and sub-groups) will be provisioned. Please enter the group slug as it appears in the GitLab URL, for instance `my-gitlab-group`. | |||||
settings.authentication.gitlab.form.allowUsersToSignUp.name=Allow users to sign up | settings.authentication.gitlab.form.allowUsersToSignUp.name=Allow users to sign up | ||||
settings.authentication.gitlab.form.allowUsersToSignUp.description=Allow new users to authenticate. When set to disabled, only existing users will be able to authenticate to the server. | settings.authentication.gitlab.form.allowUsersToSignUp.description=Allow new users to authenticate. When set to disabled, only existing users will be able to authenticate to the server. | ||||
settings.authentication.gitlab.form.provisioningToken.name=Provisioning token | settings.authentication.gitlab.form.provisioningToken.name=Provisioning token |