]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-19055 SAML Group config is no longer available for Community and Developer...
authorguillaume-peoch-sonarsource <guillaume.peoch@sonarsource.com>
Thu, 20 Apr 2023 10:00:37 +0000 (12:00 +0200)
committersonartech <sonartech@sonarsource.com>
Wed, 26 Apr 2023 20:02:45 +0000 (20:02 +0000)
server/sonar-web/src/main/js/apps/settings/components/authentication/SamlAuthentication.tsx
server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-it.tsx
server/sonar-web/src/main/js/components/controls/RadioCard.css
server/sonar-web/src/main/js/components/controls/RadioCard.tsx
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 9492328cbd4f1efc36a7fb1b0f3100b66735f6b0..e6e123b5f393ee41233cf173c733fa695e5a2cde 100644 (file)
@@ -28,9 +28,9 @@ import {
 } from '../../../../api/settings';
 import DocLink from '../../../../components/common/DocLink';
 import Link from '../../../../components/common/Link';
-import { Button, ResetButtonLink, SubmitButton } from '../../../../components/controls/buttons';
 import ConfirmModal from '../../../../components/controls/ConfirmModal';
 import RadioCard from '../../../../components/controls/RadioCard';
+import { Button, ResetButtonLink, SubmitButton } from '../../../../components/controls/buttons';
 import CheckIcon from '../../../../components/icons/CheckIcon';
 import DeleteIcon from '../../../../components/icons/DeleteIcon';
 import EditIcon from '../../../../components/icons/EditIcon';
@@ -40,8 +40,8 @@ import { getBaseUrl } from '../../../../helpers/system';
 import { ExtendedSettingDefinition } from '../../../../types/settings';
 import { getPropertyName } from '../../utils';
 import DefinitionDescription from '../DefinitionDescription';
-import useSamlConfiguration, { SAML_ENABLED_FIELD } from './hook/useLoadSamlSettings';
 import SamlConfigurationForm from './SamlConfigurationForm';
+import useSamlConfiguration, { SAML_ENABLED_FIELD } from './hook/useLoadSamlSettings';
 
 interface SamlAuthenticationProps {
   definitions: ExtendedSettingDefinition[];
@@ -177,49 +177,36 @@ export default function SamlAuthentication(props: SamlAuthenticationProps) {
               </Button>
             </div>
           </div>
-          {hasScim && (
-            <div className="spacer-bottom big-padded bordered display-flex-space-between">
-              <form
-                onSubmit={(e) => {
-                  e.preventDefault();
-                  if (newScimStatus !== scimStatus) {
-                    setShowConfirmProvisioningModal(true);
-                  } else {
-                    handleSaveGroup();
-                  }
-                }}
-              >
-                <fieldset className="display-flex-column big-spacer-bottom">
-                  <label className="h5">
-                    {translate('settings.authentication.saml.form.provisioning')}
-                  </label>
-                  {samlEnabled ? (
-                    <div className="display-flex-row spacer-top">
-                      <RadioCard
-                        label={translate(
-                          'settings.authentication.saml.form.provisioning_with_scim'
-                        )}
-                        title={translate(
-                          'settings.authentication.saml.form.provisioning_with_scim'
-                        )}
-                        selected={newScimStatus ?? scimStatus}
-                        onClick={() => setNewScimStatus(true)}
-                      >
-                        <p className="spacer-bottom">
-                          {translate(
-                            'settings.authentication.saml.form.provisioning_with_scim.sub'
-                          )}
-                        </p>
-                        <p className="spacer-bottom">
-                          {translate(
-                            'settings.authentication.saml.form.provisioning_with_scim.description'
-                          )}
-                        </p>
+          <div className="spacer-bottom big-padded bordered display-flex-space-between">
+            <form
+              onSubmit={(e) => {
+                e.preventDefault();
+                if (newScimStatus !== scimStatus) {
+                  setShowConfirmProvisioningModal(true);
+                } else {
+                  handleSaveGroup();
+                }
+              }}
+            >
+              <fieldset className="display-flex-column big-spacer-bottom">
+                <label className="h5">
+                  {translate('settings.authentication.saml.form.provisioning')}
+                </label>
+                {samlEnabled ? (
+                  <div className="display-flex-row spacer-top">
+                    <RadioCard
+                      label={translate('settings.authentication.saml.form.provisioning_with_scim')}
+                      title={translate('settings.authentication.saml.form.provisioning_with_scim')}
+                      selected={newScimStatus ?? scimStatus}
+                      onClick={() => setNewScimStatus(true)}
+                      disabled={!hasScim}
+                    >
+                      {!hasScim ? (
                         <p>
                           <FormattedMessage
-                            id="settings.authentication.saml.form.provisioning_with_scim.description.doc"
+                            id="settings.authentication.saml.form.provisioning.disabled"
                             defaultMessage={translate(
-                              'settings.authentication.saml.form.provisioning_with_scim.description.doc'
+                              'settings.authentication.saml.form.provisioning.disabled'
                             )}
                             values={{
                               documentation: (
@@ -230,76 +217,104 @@ export default function SamlAuthentication(props: SamlAuthenticationProps) {
                             }}
                           />
                         </p>
-                      </RadioCard>
-                      <RadioCard
-                        label={translate('settings.authentication.saml.form.provisioning_at_login')}
-                        title={translate('settings.authentication.saml.form.provisioning_at_login')}
-                        selected={!(newScimStatus ?? scimStatus)}
-                        onClick={() => setNewScimStatus(false)}
-                      >
-                        <p>
-                          {translate('settings.authentication.saml.form.provisioning_at_login.sub')}
-                        </p>
-                        {groupValue && (
-                          <div className="settings-definition">
-                            <DefinitionDescription definition={groupValue.definition} />
-                            <div className="settings-definition-right">
-                              <input
-                                id={groupValue.definition.key}
-                                maxLength={4000}
-                                name={groupValue.definition.key}
-                                onChange={(e) => setNewGroupSetting(e.currentTarget.value)}
-                                type="text"
-                                value={String(groupValue.newValue ?? groupValue.value ?? '')}
-                                aria-label={getPropertyName(groupValue.definition)}
-                              />
-                            </div>
-                          </div>
-                        )}
-                      </RadioCard>
-                    </div>
-                  ) : (
-                    <Alert className="big-spacer-top" variant="info">
-                      {translate('settings.authentication.saml.enable_first')}
-                    </Alert>
-                  )}
-                </fieldset>
-                {samlEnabled && (
-                  <>
-                    <SubmitButton disabled={!hasScimConfigChange}>{translate('save')}</SubmitButton>
-                    <ResetButtonLink
-                      className="spacer-left"
-                      onClick={() => {
-                        setNewScimStatus(undefined);
-                        setNewGroupSetting();
-                      }}
-                      disabled={!hasScimConfigChange}
+                      ) : (
+                        <>
+                          <p className="spacer-bottom">
+                            {translate(
+                              'settings.authentication.saml.form.provisioning_with_scim.sub'
+                            )}
+                          </p>
+                          <p className="spacer-bottom">
+                            {translate(
+                              'settings.authentication.saml.form.provisioning_with_scim.description'
+                            )}
+                          </p>
+                          <p>
+                            <FormattedMessage
+                              id="settings.authentication.saml.form.provisioning_with_scim.description.doc"
+                              defaultMessage={translate(
+                                'settings.authentication.saml.form.provisioning_with_scim.description.doc'
+                              )}
+                              values={{
+                                documentation: (
+                                  <DocLink to="/instance-administration/authentication/saml/scim/overview">
+                                    {translate('documentation')}
+                                  </DocLink>
+                                ),
+                              }}
+                            />
+                          </p>
+                        </>
+                      )}
+                    </RadioCard>
+                    <RadioCard
+                      label={translate('settings.authentication.saml.form.provisioning_at_login')}
+                      title={translate('settings.authentication.saml.form.provisioning_at_login')}
+                      selected={!(newScimStatus ?? scimStatus)}
+                      onClick={() => setNewScimStatus(false)}
                     >
-                      {translate('cancel')}
-                    </ResetButtonLink>
-                  </>
+                      <p>
+                        {translate('settings.authentication.saml.form.provisioning_at_login.sub')}
+                      </p>
+                      {groupValue && (
+                        <div className="settings-definition">
+                          <DefinitionDescription definition={groupValue.definition} />
+                          <div className="settings-definition-right">
+                            <input
+                              id={groupValue.definition.key}
+                              maxLength={4000}
+                              name={groupValue.definition.key}
+                              onChange={(e) => setNewGroupSetting(e.currentTarget.value)}
+                              type="text"
+                              value={String(groupValue.newValue ?? groupValue.value ?? '')}
+                              aria-label={getPropertyName(groupValue.definition)}
+                            />
+                          </div>
+                        </div>
+                      )}
+                    </RadioCard>
+                  </div>
+                ) : (
+                  <Alert className="big-spacer-top" variant="info">
+                    {translate('settings.authentication.saml.enable_first')}
+                  </Alert>
                 )}
-                {showConfirmProvisioningModal && (
-                  <ConfirmModal
-                    onConfirm={() => handleConfirmChangeProvisioning()}
-                    header={translate(
-                      'settings.authentication.saml.confirm',
-                      newScimStatus ? 'scim' : 'jit'
-                    )}
-                    onClose={() => setShowConfirmProvisioningModal(false)}
-                    isDestructive={!newScimStatus}
-                    confirmButtonText={translate('yes')}
+              </fieldset>
+              {samlEnabled && (
+                <>
+                  <SubmitButton disabled={!hasScimConfigChange}>{translate('save')}</SubmitButton>
+                  <ResetButtonLink
+                    className="spacer-left"
+                    onClick={() => {
+                      setNewScimStatus(undefined);
+                      setNewGroupSetting();
+                    }}
+                    disabled={!hasScimConfigChange}
                   >
-                    {translate(
-                      'settings.authentication.saml.confirm',
-                      newScimStatus ? 'scim' : 'jit',
-                      'description'
-                    )}
-                  </ConfirmModal>
-                )}
-              </form>
-            </div>
-          )}
+                    {translate('cancel')}
+                  </ResetButtonLink>
+                </>
+              )}
+              {showConfirmProvisioningModal && (
+                <ConfirmModal
+                  onConfirm={() => 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'
+                  )}
+                </ConfirmModal>
+              )}
+            </form>
+          </div>
         </>
       )}
       {showEditModal && (
index 0e597dc7bb348d26df47c1323488c7a910ff1fdd..b8136d361e4da7d740824a7e96a7d97d00855bc2 100644 (file)
@@ -189,6 +189,19 @@ describe('SAML tab', () => {
     expect(await saml.scimProvisioningButton.find()).toBeChecked();
     expect(await saml.saveScim.find()).toBeDisabled();
   });
+
+  it('should not allow edtion below Enterprise to select SCIM provisioning', async () => {
+    const { saml } = ui;
+    const user = userEvent.setup();
+
+    renderAuthentication();
+
+    await saml.createConfiguration(user);
+    await user.click(await saml.enableConfigButton.find());
+
+    expect(await saml.jitProvisioningButton.find()).toBeChecked();
+    expect(saml.scimProvisioningButton.get()).toHaveAttribute('aria-disabled', 'true');
+  });
 });
 
 function renderAuthentication(features: Feature[] = []) {
index 80bba7941147095768cfec1f8e21b188ce504f31..4f583626f53c23f50c175702d92f50d7e8611ce4 100644 (file)
   margin-right: 0;
 }
 
-.radio-card:focus {
-  outline: none;
-}
-
 .radio-card-vertical {
   width: 100%;
   min-height: auto;
index 1e0a7ee30ba7c9d1f755f829f655d33263de71e6..c7241217014e596839b129c02e07b22ed52086fb 100644 (file)
@@ -71,7 +71,8 @@ export default function RadioCard(props: Props) {
       onClick={isActionable && !disabled ? onClick : undefined}
       role="radio"
       aria-label={label}
-      tabIndex={0}
+      aria-disabled={disabled}
+      tabIndex={disabled ? -1 : 0}
     >
       <h2 className="radio-card-header big-spacer-bottom">
         <span className="display-flex-center link-radio">
index aae9c18cab76d46e35865b0228615845637ebf4a..87e48c71bf929e099d79ebae09aa51d309f6a20b 100644 (file)
@@ -1369,6 +1369,7 @@ settings.authentication.saml.form.provisioning_with_scim=Automatic user and grou
 settings.authentication.saml.form.provisioning_with_scim.sub=Preferred option when using a supported identity provider.
 settings.authentication.saml.form.provisioning_with_scim.description=Users and groups are automatically provisioned from your identity provider using the SCIM protocol. Once activated, managed users and groups can only be modified from your identity provider. Existing local users and groups will be kept.
 settings.authentication.saml.form.provisioning_with_scim.description.doc=For a list of supported providers and more details on automatic provisioning, see {documentation}.
+settings.authentication.saml.form.provisioning.disabled=Your current edition does not support provisioning with SCIM. See the {documentation} for more information. 
 settings.authentication.saml.enable_first=Enable your SAML configuration to benefit from automatic user provisioning options.
 settings.pr_decoration.binding.category=DevOps Platform Integration
 settings.pr_decoration.binding.no_bindings=A system administrator needs to enable this feature in the global settings.