/* * SonarQube * Copyright (C) 2009-2023 SonarSource SA * mailto:info AT sonarsource DOT com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import React from 'react'; import { FormattedMessage } from 'react-intl'; import DocLink from '../../../../components/common/DocLink'; import Link from '../../../../components/common/Link'; import ConfirmModal from '../../../../components/controls/ConfirmModal'; import RadioCard from '../../../../components/controls/RadioCard'; import { Button, ResetButtonLink, SubmitButton } from '../../../../components/controls/buttons'; import { Provider } from '../../../../components/hooks/useManageProvider'; import CheckIcon from '../../../../components/icons/CheckIcon'; import DeleteIcon from '../../../../components/icons/DeleteIcon'; import EditIcon from '../../../../components/icons/EditIcon'; import { Alert } from '../../../../components/ui/Alert'; import { translate } from '../../../../helpers/l10n'; import { ExtendedSettingDefinition } from '../../../../types/settings'; import { useSaveValueMutation } from '../../queries/settings'; import { getPropertyName } from '../../utils'; import DefinitionDescription from '../DefinitionDescription'; import ConfigurationForm from './ConfigurationForm'; import useSamlConfiguration, { SAML_ENABLED_FIELD, SAML_GROUP_NAME, SAML_SCIM_DEPRECATED, } from './hook/useSamlConfiguration'; import { useIdentityProvierQuery, useToggleScimMutation } from './queries/identity-provider'; interface SamlAuthenticationProps { definitions: ExtendedSettingDefinition[]; } export const SAML = 'saml'; const CONFIG_TEST_PATH = '/saml/validation_init'; const SAML_EXCLUDED_FIELD = [SAML_ENABLED_FIELD, SAML_GROUP_NAME, SAML_SCIM_DEPRECATED]; export default function SamlAuthenticationTab(props: SamlAuthenticationProps) { const { definitions } = props; const [showEditModal, setShowEditModal] = React.useState(false); const [showConfirmProvisioningModal, setShowConfirmProvisioningModal] = React.useState(false); const { hasScim, scimStatus, isLoading, samlEnabled, name, groupValue, url, hasConfiguration, values, setNewValue, canBeSave, hasScimTypeChange, hasScimConfigChange, newScimStatus, setNewScimStatus, setNewGroupSetting, deleteMutation: { isLoading: isDeleting, mutate: deleteConfiguration }, } = useSamlConfiguration(definitions); const toggleScim = useToggleScimMutation(); const { data } = useIdentityProvierQuery(); const { mutate: saveSetting } = useSaveValueMutation(); const hasDifferentProvider = data?.provider !== undefined && data.provider !== Provider.Scim; const handleCreateConfiguration = () => { setShowEditModal(true); }; const handleCancelConfiguration = () => { setShowEditModal(false); }; const handleToggleEnable = () => { const value = values[SAML_ENABLED_FIELD]; saveSetting({ newValue: !samlEnabled, definition: value.definition }); }; const handleSaveGroup = () => { if (groupValue.newValue !== undefined) { saveSetting({ newValue: groupValue.newValue, definition: groupValue.definition }); } }; const handleConfirmChangeProvisioning = async () => { await toggleScim.mutateAsync(!!newScimStatus); if (!newScimStatus) { handleSaveGroup(); } }; return (

{translate('settings.authentication.saml.configuration')}

{!hasConfiguration && (
)}
{!hasConfiguration && (
{translate('settings.authentication.saml.form.not_configured')}
)} {hasConfiguration && ( <>
{name}

{url}

{samlEnabled ? ( {translate('settings.authentication.form.enabled')} ) : ( translate('settings.authentication.form.not_enabled') )}

{translate('settings.authentication.saml.form.test')}
{ e.preventDefault(); if (hasScimTypeChange) { setShowConfirmProvisioningModal(true); } else { handleSaveGroup(); } }} >
{samlEnabled ? (
setNewScimStatus(true)} disabled={!hasScim || hasDifferentProvider} > {!hasScim ? (

{translate('documentation')} ), }} />

) : ( <> {hasDifferentProvider && (

{translate('settings.authentication.form.other_provisioning_enabled')}

)}

{translate( 'settings.authentication.saml.form.provisioning_with_scim.sub' )}

{translate( 'settings.authentication.saml.form.provisioning_with_scim.description' )}

{translate('documentation')} ), }} />

)}
setNewScimStatus(false)} >

{translate('settings.authentication.saml.form.provisioning_at_login.sub')}

{groupValue && (
setNewGroupSetting(e.currentTarget.value)} type="text" value={String(groupValue.newValue ?? groupValue.value ?? '')} aria-label={getPropertyName(groupValue.definition)} />
)}
) : ( {translate('settings.authentication.saml.enable_first')} )}
{samlEnabled && ( <> {translate('save')} { setNewScimStatus(undefined); setNewGroupSetting(); }} disabled={!hasScimConfigChange} > {translate('cancel')} )} {showConfirmProvisioningModal && ( handleConfirmChangeProvisioning()} header={translate( 'settings.authentication.saml.confirm', newScimStatus ? 'scim' : 'jit' )} onClose={() => setShowConfirmProvisioningModal(false)} isDestructive={!newScimStatus} confirmButtonText={translate('yes')} > {translate( 'settings.authentication.saml.confirm', newScimStatus ? 'scim' : 'jit', 'description' )} )}
)} {showEditModal && ( )}
); }