From ba213d1635965f61a599157e8fa95a4d9c42ffe9 Mon Sep 17 00:00:00 2001 From: guillaume-peoch-sonarsource Date: Tue, 23 Jul 2024 16:57:02 +0200 Subject: [PATCH] SONAR-22596 Inform Admins about GitLab auto-provisioning --- .../main/js/api/mocks/SettingsServiceMock.ts | 4 + .../AutoProvisionningConsent.tsx | 94 +++++++++++++------ .../GitHubAuthenticationTab.tsx | 2 +- .../GitLabAuthenticationTab.tsx | 2 + .../__tests__/Authentication-Github-it.tsx | 6 +- .../__tests__/Authentication-Gitlab-it.tsx | 53 +++++++++++ .../resources/org/sonar/l10n/core.properties | 12 +-- 7 files changed, 133 insertions(+), 40 deletions(-) diff --git a/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts index a281f8b2501..cd33aaa83e1 100644 --- a/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts +++ b/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts @@ -224,6 +224,10 @@ export default class SettingsServiceMock { this.#settingValues = this.#settingValues.filter( (s) => s.key !== 'sonar.auth.github.userConsentForPermissionProvisioningRequired', ); + } else if (data.keys === 'sonar.auth.gitlab.userConsentForPermissionProvisioningRequired') { + this.#settingValues = this.#settingValues.filter( + (s) => s.key !== 'sonar.auth.gitlab.userConsentForPermissionProvisioningRequired', + ); } else if (definition.type === SettingType.PROPERTY_SET) { const fieldValues: Dict[] = []; if (setting) { diff --git a/server/sonar-web/src/main/js/apps/settings/components/authentication/AutoProvisionningConsent.tsx b/server/sonar-web/src/main/js/apps/settings/components/authentication/AutoProvisionningConsent.tsx index 1f78fefae0e..0e18dea9b7b 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/authentication/AutoProvisionningConsent.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/authentication/AutoProvisionningConsent.tsx @@ -25,44 +25,73 @@ import * as React from 'react'; import { FormattedMessage, useIntl } from 'react-intl'; import DocumentationLink from '../../../../components/common/DocumentationLink'; import { DocLink } from '../../../../helpers/doc-links'; -import { - useSearchGitHubConfigurationsQuery, - useUpdateGitHubConfigurationMutation, -} from '../../../../queries/dop-translation'; -import { ProvisioningType } from '../../../../types/provisioning'; +import { useUpdateGitHubConfigurationMutation } from '../../../../queries/dop-translation'; +import { useUpdateGitLabConfigurationMutation } from '../../../../queries/identity-provider/gitlab'; +import { useGetValueQuery, useResetSettingsMutation } from '../../../../queries/settings'; +import { GitHubConfigurationResponse } from '../../../../types/dop-translation'; +import { GitlabConfiguration, ProvisioningType } from '../../../../types/provisioning'; -export default function AutoProvisioningConsent() { +const CONSENT_SETTING_KEY = 'sonar.auth.gitlab.userConsentForPermissionProvisioningRequired'; + +interface Props { + githubConfiguration?: GitHubConfigurationResponse; + gitlabConfiguration?: GitlabConfiguration; +} + +export default function AutoProvisioningConsent(props: Readonly) { const { formatMessage } = useIntl(); - const { data: list } = useSearchGitHubConfigurationsQuery(); - const gitHubConfiguration = list?.githubConfigurations[0]; + const { githubConfiguration, gitlabConfiguration } = props; - const { mutate: updateConfig } = useUpdateGitHubConfigurationMutation(); + const { mutate: updateGithubConfig } = useUpdateGitHubConfigurationMutation(); + const { mutate: updateGitlabConfig } = useUpdateGitLabConfigurationMutation(); + const { data: userConsent } = useGetValueQuery(CONSENT_SETTING_KEY); + const { mutateAsync: resetSettingValue } = useResetSettingsMutation(); - if (gitHubConfiguration?.userConsentRequiredAfterUpgrade !== true) { + if ( + (githubConfiguration?.userConsentRequiredAfterUpgrade !== true && + gitlabConfiguration === undefined) || + (!userConsent && githubConfiguration === undefined) + ) { return null; } const header = formatMessage({ - id: 'settings.authentication.github.confirm_auto_provisioning.header', + id: 'settings.authentication.confirm_auto_provisioning.header', }); const onClickAutoProvisioning = () => { - updateConfig({ - id: gitHubConfiguration.id, - gitHubConfiguration: { - userConsentRequiredAfterUpgrade: false, - }, - }); + if (githubConfiguration) { + updateGithubConfig({ + id: githubConfiguration.id, + gitHubConfiguration: { + userConsentRequiredAfterUpgrade: false, + }, + }); + } + if (gitlabConfiguration) { + resetSettingValue({ keys: [CONSENT_SETTING_KEY] }); + } }; const onClickJitProvisioning = () => { - updateConfig({ - id: gitHubConfiguration.id, - gitHubConfiguration: { - provisioningType: ProvisioningType.jit, - userConsentRequiredAfterUpgrade: false, - }, - }); + if (githubConfiguration) { + updateGithubConfig({ + id: githubConfiguration.id, + gitHubConfiguration: { + provisioningType: ProvisioningType.jit, + userConsentRequiredAfterUpgrade: false, + }, + }); + } + if (gitlabConfiguration) { + updateGitlabConfig({ + id: gitlabConfiguration.id, + data: { + provisioningType: ProvisioningType.jit, + }, + }); + resetSettingValue({ keys: [CONSENT_SETTING_KEY] }); + } }; return ( @@ -71,14 +100,19 @@ export default function AutoProvisioningConsent() { + ), @@ -86,18 +120,18 @@ export default function AutoProvisioningConsent() { /> - + } secondaryButton={ } /> diff --git a/server/sonar-web/src/main/js/apps/settings/components/authentication/GitHubAuthenticationTab.tsx b/server/sonar-web/src/main/js/apps/settings/components/authentication/GitHubAuthenticationTab.tsx index 171836a2911..90b6bbcad3f 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/authentication/GitHubAuthenticationTab.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/authentication/GitHubAuthenticationTab.tsx @@ -376,7 +376,7 @@ export default function GitHubAuthenticationTab() { /> )} - + ); diff --git a/server/sonar-web/src/main/js/apps/settings/components/authentication/GitLabAuthenticationTab.tsx b/server/sonar-web/src/main/js/apps/settings/components/authentication/GitLabAuthenticationTab.tsx index 51b955320a8..59562f8facd 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/authentication/GitLabAuthenticationTab.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/authentication/GitLabAuthenticationTab.tsx @@ -39,6 +39,7 @@ import { GitLabConfigurationUpdateBody, ProvisioningType } from '../../../../typ import { DefinitionV2, SettingType } from '../../../../types/settings'; import { Provider } from '../../../../types/types'; import AuthenticationFormField from './AuthenticationFormField'; +import AutoProvisioningConsent from './AutoProvisionningConsent'; import ConfigurationDetails from './ConfigurationDetails'; import ConfirmProvisioningModal from './ConfirmProvisioningModal'; import GitLabConfigurationForm from './GitLabConfigurationForm'; @@ -392,6 +393,7 @@ export default function GitLabAuthenticationTab() { onClose={() => setOpenForm(false)} /> )} + ); } diff --git a/server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-Github-it.tsx b/server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-Github-it.tsx index 7b69d09c709..5e75ebb38af 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-Github-it.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-Github-it.tsx @@ -196,13 +196,13 @@ const ui = { name: 'settings.authentication.github.configuration.validation.details.title', }), continueAutoButton: byRole('button', { - name: 'settings.authentication.github.confirm_auto_provisioning.continue', + name: 'settings.authentication.confirm_auto_provisioning.continue', }), switchJitButton: byRole('button', { - name: 'settings.authentication.github.confirm_auto_provisioning.switch_jit', + name: 'settings.authentication.confirm_auto_provisioning.switch_jit', }), consentDialog: byRole('dialog', { - name: 'settings.authentication.github.confirm_auto_provisioning.header', + name: 'settings.authentication.confirm_auto_provisioning.header', }), getConfigDetailsTitle: () => ui.configDetailsDialog.byRole('heading').get(), getOrgs: () => ui.configDetailsDialog.byRole('listitem').getAll(), diff --git a/server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-Gitlab-it.tsx b/server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-Gitlab-it.tsx index da293414c1c..186bbc3ab96 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-Gitlab-it.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-Gitlab-it.tsx @@ -144,6 +144,15 @@ const ui = { testConfiguration: glContainer.byRole('button', { name: 'settings.authentication.configuration.test', }), + continueAutoButton: byRole('button', { + name: 'settings.authentication.confirm_auto_provisioning.continue', + }), + switchJitButton: byRole('button', { + name: 'settings.authentication.confirm_auto_provisioning.switch_jit', + }), + consentDialog: byRole('dialog', { + name: 'settings.authentication.confirm_auto_provisioning.header', + }), }; it('should create a Gitlab configuration and disable it with proper validation', async () => { @@ -581,6 +590,50 @@ describe('Gitlab Provisioning', () => { await user.click(ui.disableConfigButton.get()); expect(ui.gitlabConfigurationStatus.query()).not.toBeInTheDocument(); }); + + it('should display a modal if user was already using auto and continue using auto provisioning', async () => { + const user = userEvent.setup(); + + settingsHandler.set('sonar.auth.gitlab.userConsentForPermissionProvisioningRequired', ''); + handler.setGitlabConfigurations([ + mockGitlabConfiguration({ + allowUsersToSignUp: false, + enabled: true, + provisioningType: ProvisioningType.auto, + allowedGroups: ['D12'], + isProvisioningTokenSet: true, + }), + ]); + renderAuthentication([Feature.GitlabProvisioning]); + + expect(await ui.consentDialog.find()).toBeInTheDocument(); + await user.click(ui.continueAutoButton.get()); + + expect(await ui.autoProvisioningRadioButton.find()).toBeChecked(); + expect(ui.consentDialog.query()).not.toBeInTheDocument(); + }); + + it('should display a modal if user was already using auto and switch to JIT', async () => { + const user = userEvent.setup(); + + settingsHandler.set('sonar.auth.gitlab.userConsentForPermissionProvisioningRequired', ''); + handler.setGitlabConfigurations([ + mockGitlabConfiguration({ + allowUsersToSignUp: false, + enabled: true, + provisioningType: ProvisioningType.auto, + allowedGroups: ['D12'], + isProvisioningTokenSet: true, + }), + ]); + renderAuthentication([Feature.GitlabProvisioning]); + + expect(await ui.consentDialog.find()).toBeInTheDocument(); + await user.click(ui.switchJitButton.get()); + + expect(await ui.jitProvisioningRadioButton.find()).toBeChecked(); + expect(ui.consentDialog.query()).not.toBeInTheDocument(); + }); }); function renderAuthentication(features: Feature[] = []) { diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 05b973f80b9..044cee3790f 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -1538,6 +1538,12 @@ settings.authentication.form.provisioning=Provisioning settings.authentication.form.provisioning_at_login=Just-in-Time user and group provisioning (default) settings.authentication.form.other_provisioning_enabled=Already enabled for another provider. Only one identity provider can have automatic users and groups provisioning enabled. settings.authentication.form.settings.save_success=Settings saved successfully. +settings.authentication.confirm_auto_provisioning.header=Confirm the provisioning method +settings.authentication.confirm_auto_provisioning.description1=Automatic user and group provisioning is currently suspended. +settings.authentication.confirm_auto_provisioning.description2=This provisioning method has been enhanced. It now includes the synchronization of user permissions and project visibility from {alm}. For more details, please refer to the {documentation}. +settings.authentication.confirm_auto_provisioning.question=Which provisioning method would you like to use? +settings.authentication.confirm_auto_provisioning.continue=Automatic user, group, and permission provisioning +settings.authentication.confirm_auto_provisioning.switch_jit=Just-in-Time user and group provisioning # GITHUB settings.authentication.github.form.create=New GitHub Configuration @@ -1548,12 +1554,6 @@ settings.authentication.github.confirm.JIT=Switch to Just-in-Time provisioning settings.authentication.github.confirm.insecure=Potentially insecure configuration settings.authentication.github.confirm.AUTO_PROVISIONING.description=Once you transition to automatic provisioning, groups, users, group memberships, and permissions on GitHub projects will be inherited from GitHub. You will no longer have the ability to edit them within SonarQube. Do you want to proceed with this change? settings.authentication.github.confirm.JIT.description=Switching to Just-in-Time provisioning removes the automatic synchronization of users, groups, and group memberships. Users are provisioned and group memberships are updated only at user login. Are you sure? -settings.authentication.github.confirm_auto_provisioning.header=Confirm the provisioning method -settings.authentication.github.confirm_auto_provisioning.description1=Automatic user and group provisioning is currently suspended. -settings.authentication.github.confirm_auto_provisioning.description2=This provisioning method has been enhanced. It now includes the synchronization of user permissions and project visibility from GitHub. For more details, please refer to the {documentation}. -settings.authentication.github.confirm_auto_provisioning.question=Which provisioning method would you like to use? -settings.authentication.github.confirm_auto_provisioning.continue=Automatic user, group, and permission provisioning -settings.authentication.github.confirm_auto_provisioning.switch_jit=Just-in-Time user and group provisioning settings.authentication.github.provisioning_change.confirm_changes=Confirm changes settings.authentication.github.provisioning_change.insecure_config=Please be aware that your configuration is potentially insecure because you didn't add any organization to the allowlist. If your GitHub App is public, anyone can install it and gain access to your instance. settings.authentication.github.configuration=GitHub Configuration -- 2.39.5