onReload: () => Promise<void>;
tab: AuthenticationTabs;
excludedField: string[];
+ hasLegacyConfiguration?: boolean;
}
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);
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
if (excludedField.includes(val.key)) {
return null;
}
+
+ const isSet = hasLegacyConfiguration ? false : !val.isNotSet;
return (
<div key={val.key}>
<AuthenticationFormField
definition={val.definition}
mandatory={val.mandatory}
onFieldChange={setNewValue}
- isNotSet={val.isNotSet}
+ isNotSet={!isSet}
error={errors[val.key]?.message}
/>
</div>
* 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';
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[];
setNewGithubProvisioningStatus,
hasGithubProvisioningConfigChange,
resetJitSetting,
+ saveGroup,
+ changeProvisioning,
+ toggleEnable,
+ hasLegacyConfiguration,
} = useGithubConfiguration(definitions, props.onReload);
const hasDifferentProvider = provider !== undefined && provider !== Provider.Github;
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">
</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>
</p>
<Button
className="spacer-top"
- onClick={handleToggleEnable}
+ onClick={toggleEnable}
disabled={githubProvisioningStatus}
>
{enabled
if (newGithubProvisioningStatus !== githubProvisioningStatus) {
setShowConfirmProvisioningModal(true);
} else {
- await handleSaveGroup();
+ await saveGroup();
}
}}
>
)}
{showConfirmProvisioningModal && (
<ConfirmModal
- onConfirm={() => handleConfirmChangeProvisioning()}
+ onConfirm={() => changeProvisioning()}
header={translate(
'settings.authentication.github.confirm',
newGithubProvisioningStatus ? 'auto' : 'jit'
onClose={handleCancelConfiguration}
create={!hasConfiguration}
onReload={reload}
+ hasLegacyConfiguration={hasLegacyConfiguration}
/>
)}
</div>
* 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';
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',
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();
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,
newGithubProvisioningStatus,
setNewGithubProvisioningStatus,
hasGithubProvisioningConfigChange,
+ changeProvisioning,
+ saveGroup,
resetJitSetting,
+ toggleEnable,
+ hasLegacyConfiguration,
};
}
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
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.