diff options
author | Mathieu Suen <mathieu.suen@sonarsource.com> | 2023-05-08 16:56:30 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2023-05-11 20:03:14 +0000 |
commit | 183d279e41b9ad09de10712a0d81ebbeccc040eb (patch) | |
tree | 3949b8edbe09f85ac6cd1a81dbd260298a44c10b | |
parent | 15727e6c67bb83b5230df53b72055daad1e78d86 (diff) | |
download | sonarqube-183d279e41b9ad09de10712a0d81ebbeccc040eb.tar.gz sonarqube-183d279e41b9ad09de10712a0d81ebbeccc040eb.zip |
SONAR-19084 Warn when github authentication configuration has missing properties
4 files changed, 101 insertions, 57 deletions
diff --git a/server/sonar-web/src/main/js/apps/settings/components/authentication/ConfigurationForm.tsx b/server/sonar-web/src/main/js/apps/settings/components/authentication/ConfigurationForm.tsx index 8f6406b8672..e07e859adc6 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/authentication/ConfigurationForm.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/authentication/ConfigurationForm.tsx @@ -42,6 +42,7 @@ interface Props { onReload: () => Promise<void>; tab: AuthenticationTabs; excludedField: string[]; + hasLegacyConfiguration?: boolean; } interface ErrorValue { @@ -50,7 +51,16 @@ interface ErrorValue { } export default function ConfigurationForm(props: Props) { - const { create, loading, values, setNewValue, canBeSave, tab, excludedField } = props; + const { + create, + loading, + values, + setNewValue, + canBeSave, + tab, + excludedField, + hasLegacyConfiguration, + } = props; const [errors, setErrors] = React.useState<Dict<ErrorValue>>({}); const headerLabel = translate('settings.authentication.form', create ? 'create' : 'edit', tab); @@ -104,10 +114,13 @@ export default function ConfigurationForm(props: Props) { loading={loading} ariaLabel={translate('settings.authentication.form.loading')} > - <Alert variant="info"> + <Alert variant={hasLegacyConfiguration ? 'warning' : 'info'}> <FormattedMessage - id="settings.authentication.help" - defaultMessage={translate('settings.authentication.help')} + id={`settings.authentication.${hasLegacyConfiguration ? 'legacy_help' : 'help'}`} + defaultMessage={translate( + `settings.authentication.${hasLegacyConfiguration ? 'legacy_help' : 'help'}`, + tab + )} values={{ link: ( <DocLink @@ -123,6 +136,8 @@ export default function ConfigurationForm(props: Props) { if (excludedField.includes(val.key)) { return null; } + + const isSet = hasLegacyConfiguration ? false : !val.isNotSet; return ( <div key={val.key}> <AuthenticationFormField @@ -130,7 +145,7 @@ export default function ConfigurationForm(props: Props) { definition={val.definition} mandatory={val.mandatory} onFieldChange={setNewValue} - isNotSet={val.isNotSet} + isNotSet={!isSet} error={errors[val.key]?.message} /> </div> 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 88055fb19d1..ca32c00991b 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 @@ -17,15 +17,8 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { isEmpty } from 'lodash'; import React, { useState } from 'react'; import { FormattedMessage } from 'react-intl'; -import { - activateGithubProvisioning, - deactivateGithubProvisioning, - resetSettingValue, - setSettingValue, -} from '../../../../api/settings'; import GitHubSynchronisationWarning from '../../../../app/components/GitHubSynchronisationWarning'; import DocLink from '../../../../components/common/DocLink'; import ConfirmModal from '../../../../components/controls/ConfirmModal'; @@ -42,10 +35,7 @@ import { ExtendedSettingDefinition } from '../../../../types/settings'; import { DOCUMENTATION_LINK_SUFFIXES } from './Authentication'; import AuthenticationFormField from './AuthenticationFormField'; import ConfigurationForm from './ConfigurationForm'; -import useGithubConfiguration, { - GITHUB_ENABLED_FIELD, - GITHUB_JIT_FIELDS, -} from './hook/useGithubConfiguration'; +import useGithubConfiguration, { GITHUB_JIT_FIELDS } from './hook/useGithubConfiguration'; interface GithubAuthenticationProps { definitions: ExtendedSettingDefinition[]; @@ -82,6 +72,10 @@ export default function GithubAuthenticationTab(props: GithubAuthenticationProps setNewGithubProvisioningStatus, hasGithubProvisioningConfigChange, resetJitSetting, + saveGroup, + changeProvisioning, + toggleEnable, + hasLegacyConfiguration, } = useGithubConfiguration(definitions, props.onReload); const hasDifferentProvider = provider !== undefined && provider !== Provider.Github; @@ -94,40 +88,6 @@ export default function GithubAuthenticationTab(props: GithubAuthenticationProps setShowEditModal(false); }; - const handleConfirmChangeProvisioning = async () => { - if (newGithubProvisioningStatus && newGithubProvisioningStatus !== githubProvisioningStatus) { - await activateGithubProvisioning(); - await reload(); - } else { - if (newGithubProvisioningStatus !== githubProvisioningStatus) { - await deactivateGithubProvisioning(); - } - await handleSaveGroup(); - } - }; - - const handleSaveGroup = async () => { - await Promise.all( - GITHUB_JIT_FIELDS.map(async (settingKey) => { - const value = values[settingKey]; - if (value.newValue !== undefined) { - if (isEmpty(value.newValue) && typeof value.newValue !== 'boolean') { - await resetSettingValue({ keys: value.definition.key }); - } else { - await setSettingValue(value.definition, value.newValue); - } - } - }) - ); - await reload(); - }; - - const handleToggleEnable = async () => { - const value = values[GITHUB_ENABLED_FIELD]; - await setSettingValue(value.definition, !enabled); - await reload(); - }; - return ( <div className="authentication-configuration"> <div className="spacer-bottom display-flex-space-between display-flex-center"> @@ -141,11 +101,29 @@ export default function GithubAuthenticationTab(props: GithubAuthenticationProps </div> )} </div> - {!hasConfiguration ? ( + {!hasConfiguration && !hasLegacyConfiguration && ( <div className="big-padded text-center huge-spacer-bottom authentication-no-config"> {translate('settings.authentication.github.form.not_configured')} </div> - ) : ( + )} + {!hasConfiguration && hasLegacyConfiguration && ( + <div className="big-padded"> + <Alert variant="warning"> + <FormattedMessage + id="settings.authentication.github.form.legacy_configured" + defaultMessage={translate('settings.authentication.github.form.legacy_configured')} + values={{ + documentation: ( + <DocLink to="/instance-administration/authentication/github"> + {translate('documentation')} + </DocLink> + ), + }} + /> + </Alert> + </div> + )} + {hasConfiguration && ( <> <div className="spacer-bottom big-padded bordered display-flex-space-between"> <div> @@ -163,7 +141,7 @@ export default function GithubAuthenticationTab(props: GithubAuthenticationProps </p> <Button className="spacer-top" - onClick={handleToggleEnable} + onClick={toggleEnable} disabled={githubProvisioningStatus} > {enabled @@ -189,7 +167,7 @@ export default function GithubAuthenticationTab(props: GithubAuthenticationProps if (newGithubProvisioningStatus !== githubProvisioningStatus) { setShowConfirmProvisioningModal(true); } else { - await handleSaveGroup(); + await saveGroup(); } }} > @@ -312,7 +290,7 @@ export default function GithubAuthenticationTab(props: GithubAuthenticationProps )} {showConfirmProvisioningModal && ( <ConfirmModal - onConfirm={() => handleConfirmChangeProvisioning()} + onConfirm={() => changeProvisioning()} header={translate( 'settings.authentication.github.confirm', newGithubProvisioningStatus ? 'auto' : 'jit' @@ -344,6 +322,7 @@ export default function GithubAuthenticationTab(props: GithubAuthenticationProps onClose={handleCancelConfiguration} create={!hasConfiguration} onReload={reload} + hasLegacyConfiguration={hasLegacyConfiguration} /> )} </div> diff --git a/server/sonar-web/src/main/js/apps/settings/components/authentication/hook/useGithubConfiguration.ts b/server/sonar-web/src/main/js/apps/settings/components/authentication/hook/useGithubConfiguration.ts index 168325e60b2..dea619fd54a 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/authentication/hook/useGithubConfiguration.ts +++ b/server/sonar-web/src/main/js/apps/settings/components/authentication/hook/useGithubConfiguration.ts @@ -17,9 +17,15 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { some } from 'lodash'; +import { isEmpty, some } from 'lodash'; import { useCallback, useContext, useEffect, useState } from 'react'; -import { fetchIsGithubProvisioningEnabled } from '../../../../../api/settings'; +import { + activateGithubProvisioning, + deactivateGithubProvisioning, + fetchIsGithubProvisioningEnabled, + resetSettingValue, + setSettingValue, +} from '../../../../../api/settings'; import { AvailableFeaturesContext } from '../../../../../app/components/available-features/AvailableFeaturesContext'; import { Feature } from '../../../../../types/features'; import { ExtendedSettingDefinition } from '../../../../../types/settings'; @@ -28,6 +34,7 @@ import useConfiguration from './useConfiguration'; export const GITHUB_ENABLED_FIELD = 'sonar.auth.github.enabled'; export const GITHUB_APP_ID_FIELD = 'sonar.auth.github.appId'; export const GITHUB_API_URL_FIELD = 'sonar.auth.github.apiUrl'; +export const GITHUB_CLIENT_ID_FIELD = 'sonar.auth.github.clientId.secured'; export const GITHUB_JIT_FIELDS = [ 'sonar.auth.github.organizations', 'sonar.auth.github.allowUsersToSignUp', @@ -76,6 +83,7 @@ export default function useGithubConfiguration( const enabled = values[GITHUB_ENABLED_FIELD]?.value === 'true'; const appId = values[GITHUB_APP_ID_FIELD]?.value as string; const url = values[GITHUB_API_URL_FIELD]?.value; + const clientIdIsNotSet = values[GITHUB_CLIENT_ID_FIELD]?.isNotSet; const reload = useCallback(async () => { await reloadConfig(); @@ -83,6 +91,42 @@ export default function useGithubConfiguration( onReload(); }, [reloadConfig, onReload]); + const changeProvisioning = async () => { + if (newGithubProvisioningStatus && newGithubProvisioningStatus !== githubProvisioningStatus) { + await activateGithubProvisioning(); + await reload(); + } else { + if (newGithubProvisioningStatus !== githubProvisioningStatus) { + await deactivateGithubProvisioning(); + } + await saveGroup(); + } + }; + + const saveGroup = async () => { + await Promise.all( + GITHUB_JIT_FIELDS.map(async (settingKey) => { + const value = values[settingKey]; + if (value.newValue !== undefined) { + if (isEmpty(value.newValue) && typeof value.newValue !== 'boolean') { + await resetSettingValue({ keys: value.definition.key }); + } else { + await setSettingValue(value.definition, value.newValue); + } + } + }) + ); + await reload(); + }; + + const toggleEnable = async () => { + const value = values[GITHUB_ENABLED_FIELD]; + await setSettingValue(value.definition, !enabled); + await reload(); + }; + + const hasLegacyConfiguration = appId === undefined && !clientIdIsNotSet; + return { ...config, reload, @@ -95,6 +139,10 @@ export default function useGithubConfiguration( newGithubProvisioningStatus, setNewGithubProvisioningStatus, hasGithubProvisioningConfigChange, + changeProvisioning, + saveGroup, resetJitSetting, + toggleEnable, + hasLegacyConfiguration, }; } 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 58f7a67c6dc..853047d3aca 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -1320,6 +1320,7 @@ settings.authentication.custom_message_information=You can define a custom log-i settings.authentication.custom_message_information.link=General settings.authentication.description=The following settings allow you to delegate authentication via SAML, or any of the following DevOps Platforms: GitHub, GitLab, and Bitbucket. settings.authentication.help=If you need help setting up authentication, read our dedicated {link}. +settings.authentication.legacy_help.github=Your configuration is no longer supported, please checkout the {link} on how to change your configuration. settings.authentication.help.link=documentation settings.authentication.form.create=Create configuration settings.authentication.form.edit=Edit @@ -1343,6 +1344,7 @@ settings.authentication.github.confirm.auto.description=After you switch to auto settings.authentication.github.confirm.jit.description=Switching to Just-in-Time provisioning removes all information provided while automatic provisioning through SCIM was active. These changes cannot be reverted. Are you sure? settings.authentication.github.configuration=GitHub Configuration settings.authentication.github.form.not_configured=GitHub App is not configured +settings.authentication.github.form.legacy_configured=You current configuration is no longer supported. It will continue working but with limitted support.See the {documentation} for more information. settings.authentication.github.enable_first=Enable your GitHub configuration for more provisioning options. settings.authentication.github.form.provisioning_with_github=Automatic user and group provisioning settings.authentication.github.form.provisioning_with_github.description=Users and groups are automatically provisioned from your GitHub organizations. Once activated, managed users and groups can only be modified from your GitHub organizations/teams. Existing local users and groups will be kept. |