Web: Studio: SSO: Added missing fields, refactoring

This commit is contained in:
Dmitry Kulak 2022-02-17 18:35:06 +03:00
parent 32576b74cd
commit 90c5de609e
13 changed files with 462 additions and 180 deletions

View File

@ -9,23 +9,23 @@
"CustomEntryButton": "Пользовательская надпись для кнопки входа:",
"CustomEntryButtonPlaceholder": "Single Sign-on",
"CustomEntryTooltip": "Надпись для кнопки, которая используется для входа на портал с помощью сервиса Single Sign-on",
"DecryptStatements": "Расшифровывать утверждения",
"DownloadMetadataXML": "Скачать XML-файл метаданных поставщика сервиса",
"EmptyFieldErrorMessage": "Поле не заполнено",
"EndpointURL": "URL-адрес конечной точки единого входа IdP:",
"EndpointURLTooltip": "URL-адрес, используемый для единого входа на стороне поставщика учетных записей",
"Encryption": "шифрование",
"FirstName": "Имя",
"GenerateCertificate": "Сгенерировать новый самоподписанный сертификат ",
"Hide": "Скрыть",
"HideAdditionalParameters": "Скрыть дополнительные параметры",
"HideAuthPage": "Скрыть страницу аутентификации",
"LastName": "Фамилия",
"Location": "Местоположение",
"LogoutEndpointUrl": "URL-адрес конечной точки единого выхода IdP:",
"LogoutEndpointUrlTooltip": "URL-адрес, используемый для единого выхода на стороне поставщика сервиса",
"NameIDFormat": "Формат NameID:",
"NewCertificate": "Новый сертификат",
"OpenCertificate": "Открытый сертификат:",
"OpenCertificates": "Открытые сертификаты поставщика учетных записей: ",
"OpenCertificatesTooltip": "Открытые сертификаты поставщика учетных записей, используемые или для проверки, или для расшифровки (или для того и другого) запросов и ответов от поставщика учетных записей",
"Or": "или",
"PrivateKey": "Закрытый ключ:",
"ProviderCertificates": "Сертификаты поставщика сервиса",
"ProviderURL": "Идентификатор сущности поставщика учетных записей:",
"ProviderURLTooltip": "Идентификатор сущности поставщика учетных записей (URL-адрес поставщика)",
@ -40,10 +40,10 @@
"ServiceProviderSettings": "Настройки поставщика сервиса",
"Show": "Показать",
"ShowAdditionalParameters": "Показать дополнительные параметры",
"SignAuthRequest": "Подписывать запросы аутентификации",
"SignExitRequest": "Подписывать запросы выхода",
"SignResponseRequest": "Подписывать ответы выхода",
"SigningAlgorithm": "Алгоритм подписи:",
"SignOnEndpointUrl": "URL-адрес конечной точки единого входа IdP:",
"SignOnEndpointUrlTooltip": "URL-адрес, используемый для единого входа на стороне поставщика учетных записей",
"Signing": "подпись",
"SigningAndEncryption": "подпись и шифрование",
"StandardDecryptionAlgorithm": "Стандартный алгоритм расшифровки:",
"Title": "Должность",
"TurnOnSSO": "Включить аутентификацию с помощью технологии единого входа",
@ -51,7 +51,21 @@
"TurnOnSSOTooltip": "Включите эту опцию, если вы хотите автоматически добавить на портал пользователей из сервиса SSO",
"UploadXML": "Для автоматического заполнения необходимых полей загрузите метаданные из XML-файла",
"UploadXMLPlaceholder": "URL адрес XML-файла метаданных",
"UsedFor": "Использовать для",
"emailErrorMessage": "Неверный формат электронной почты",
"idpAuthRequest": "Проверять подпись ответов аутентификации",
"idpCertificates": "Открытые сертификаты поставщика учетных записей: ",
"idpCertificatesTooltip": "Открытые сертификаты поставщика учетных записей, используемые или для проверки, или для расшифровки (или для того и другого) запросов и ответов от поставщика учетных записей",
"idpSignExitRequest": "Проверять подпись запросов выхода",
"idpSignResponseRequest": "Проверять подпись ответов выхода",
"idpSigningAlgorithm": "Стандартный алгоритм проверки подписи:",
"phoneErrorMessage": "Неверный формат номера телефона",
"spAuthRequest": "Подписывать запросы аутентификации",
"spCertificates": "Сертификаты поставщика сервиса",
"spCertificatesTooltip": "Сертификаты поставщика сервиса, используемые для подписи и шифрования запросов и ответов от поставщика сервиса",
"spDecryptStatements": "Расшифровывать утверждения",
"spSignExitRequest": "Подписывать запросы выхода",
"spSignResponseRequest": "Подписывать ответы выхода",
"spSigningAlgorithm": "Алгоритм подписи:",
"urlErrorMessage": "Недопустимый URL-адрес"
}

View File

@ -0,0 +1,123 @@
import React from "react";
import { observer } from "mobx-react";
import Box from "@appserver/components/box";
import Button from "@appserver/components/button";
import HelpButton from "@appserver/components/help-button";
import Text from "@appserver/components/text";
import AddIdpCertificateModal from "./sub-components/AddIdpCertificateModal";
import AddSpCertificateModal from "./sub-components/AddSpCertificateModal";
import CheckboxSet from "./sub-components/CheckboxSet";
import HideButton from "./sub-components/HideButton";
import PropTypes from "prop-types";
import SimpleComboBox from "./sub-components/SimpleComboBox";
import {
decryptAlgorithmsOptions,
verifyAlgorithmsOptions,
} from "./sub-components/constants";
const Certificates = ({ FormStore, t, provider }) => {
let prefix = "";
switch (provider) {
case "IdentityProvider":
prefix = "idp";
break;
case "ServiceProvider":
prefix = "sp";
}
return (
<Box>
<Box
alignItems="center"
displayProp="flex"
flexDirection="row"
marginProp="24px 0"
>
<Text as="h2" fontSize="14px" fontWeight={600}>
{t(`${prefix}Certificates`)}
</Text>
<HelpButton
offsetRight={0}
tooltipContent={t(`${prefix}CertificatesTooltip`)}
/>
</Box>
<Box alignItems="center" displayProp="flex" flexDirection="row">
{prefix === "idp" && (
<>
<Button
onClick={FormStore.onOpenIdpModal}
label={t("AddCertificate")}
size="medium"
tabIndex={9}
/>
<AddIdpCertificateModal FormStore={FormStore} t={t} />
</>
)}
{prefix === "sp" && (
<>
<Button
onClick={FormStore.onOpenSpModal}
label={t("AddCertificate")}
size="medium"
tabIndex={9}
/>
<AddSpCertificateModal FormStore={FormStore} t={t} />
</>
)}
<HideButton
FormStore={FormStore}
label="ShowAdditionalParameters"
isAdditionalParameters
t={t}
/>
</Box>
<CheckboxSet FormStore={FormStore} id={prefix} prefix={prefix} t={t} />
{provider === "IdentityProvider" && (
<>
<SimpleComboBox
FormStore={FormStore}
labelText={t(`${prefix}SigningAlgorithm`)}
name={"idp_verifyAlgorithm"}
options={verifyAlgorithmsOptions}
tabIndex={14}
/>
</>
)}
{provider === "ServiceProvider" && (
<>
<SimpleComboBox
FormStore={FormStore}
labelText={t(`${prefix}SigningAlgorithm`)}
name={"sp_signingAlgorithm"}
options={verifyAlgorithmsOptions}
tabIndex={14}
/>
<SimpleComboBox
FormStore={FormStore}
labelText={t("StandardDecryptionAlgorithm")}
name={"sp_encryptAlgorithm"}
options={decryptAlgorithmsOptions}
tabIndex={15}
/>
</>
)}
</Box>
);
};
export default observer(Certificates);
Certificates.PropTypes = {
provider: PropTypes.oneOf(["IdentityProvider", "ServiceProvider"]),
};

View File

@ -1,101 +0,0 @@
import React from "react";
import { observer } from "mobx-react";
import Box from "@appserver/components/box";
import Button from "@appserver/components/button";
import HelpButton from "@appserver/components/help-button";
import Text from "@appserver/components/text";
import AddCertificateModal from "./sub-components/AddCertificateModal";
import HideButton from "./sub-components/HideButton";
import SimpleCheckbox from "./sub-components/SimpleCheckbox";
import SimpleComboBox from "./sub-components/SimpleComboBox";
import {
decryptAlgorithmsOptions,
verifyAlgorithmsOptions,
} from "./sub-components/constants";
const IdpCertificates = ({ FormStore, t }) => {
return (
<Box>
<Box
alignItems="center"
displayProp="flex"
flexDirection="row"
marginProp="24px 0"
>
<Text as="h2" fontSize="14px" fontWeight={600}>
{t("OpenCertificates")}
</Text>
<HelpButton
offsetRight={0}
tooltipContent={t("OpenCertificatesTooltip")}
/>
</Box>
<Box alignItems="center" displayProp="flex" flexDirection="row">
<Button
onClick={FormStore.onOpenModal}
label={t("AddCertificate")}
size="medium"
tabIndex={9}
/>
<AddCertificateModal FormStore={FormStore} t={t} />
<HideButton
FormStore={FormStore}
label="ShowAdditionalParameters"
isAdditionalParameters
t={t}
/>
</Box>
<Box marginProp="12px 0">
<SimpleCheckbox
FormStore={FormStore}
label={t("SignAuthRequest")}
name="idp_verifyAuthResponsesSign"
tabIndex={10}
/>
<SimpleCheckbox
FormStore={FormStore}
label={t("SignExitRequest")}
name="idp_verifyLogoutRequestsSign"
tabIndex={11}
/>
<SimpleCheckbox
FormStore={FormStore}
label={t("SignResponseRequest")}
name="idp_verifyLogoutResponsesSign"
tabIndex={12}
/>
<SimpleCheckbox
FormStore={FormStore}
label={t("DecryptStatements")}
name="ipd_decryptAssertions"
tabIndex={13}
/>
</Box>
<SimpleComboBox
FormStore={FormStore}
labelText={t("SigningAlgorithm")}
name="idp_verifyAlgorithm"
options={verifyAlgorithmsOptions}
tabIndex={14}
/>
<SimpleComboBox
FormStore={FormStore}
labelText={t("StandardDecryptionAlgorithm")}
name="idp_decryptAlgorithm"
options={decryptAlgorithmsOptions}
tabIndex={15}
/>
</Box>
);
};
export default observer(IdpCertificates);

View File

@ -40,19 +40,19 @@ const IdpSettings = ({ FormStore, t }) => {
<SimpleFormField
FormStore={FormStore}
labelText={t("EndpointURL")}
labelText={t("SignOnEndpointUrl")}
name="ssoUrl"
placeholder="https://www.test.com/saml/login"
t={t}
tabIndex={7}
tooltipContent={t("EndpointURLTooltip")}
tooltipContent={t("SignOnEndpointUrlTooltip")}
>
<Box displayProp="flex" flexDirection="row" marginProp="0 0 4px 0">
<Text>{t("Binding")}</Text>
<RadioButtonGroup
className="radio-button-group"
name="binding"
name="ssoBinding"
onClick={FormStore.onBindingChange}
options={bindingOptions}
selected={FormStore.ssoBinding}
@ -62,6 +62,30 @@ const IdpSettings = ({ FormStore, t }) => {
</Box>
</SimpleFormField>
<SimpleFormField
FormStore={FormStore}
labelText={t("LogoutEndpointUrl")}
name="sloUrl"
placeholder="https://www.test.com/saml/logout"
t={t}
tabIndex={9}
tooltipContent={t("LogoutEndpointUrlTooltip")}
>
<Box displayProp="flex" flexDirection="row" marginProp="0 0 4px 0">
<Text>{t("Binding")}</Text>
<RadioButtonGroup
className="radio-button-group"
name="sloBinding"
onClick={FormStore.onBindingChange}
options={bindingOptions}
selected={FormStore.sloBinding}
spacing="21px"
tabIndex={8}
/>
</Box>
</SimpleFormField>
<SimpleComboBox
FormStore={FormStore}
labelText={t("NameIDFormat")}

View File

@ -5,7 +5,7 @@ import { useTranslation } from "react-i18next";
import FormStore from "@appserver/studio/src/store/SsoFormStore";
import FieldMapping from "./FieldMapping";
import IdpCertificates from "./IdpCertificates";
import Certificates from "./Certificates";
import IdpSettings from "./IdpSettings";
import ProviderMetadata from "./ProviderMetadata";
import StyledSsoPage from "./styled-containers/StyledSsoPageContainer";
@ -20,7 +20,9 @@ const SingleSignOn = () => {
<IdpSettings FormStore={FormStore} t={t} />
<IdpCertificates FormStore={FormStore} t={t} />
<Certificates FormStore={FormStore} t={t} provider="IdentityProvider" />
<Certificates FormStore={FormStore} t={t} provider="ServiceProvider" />
<FieldMapping FormStore={FormStore} t={t} />

View File

@ -0,0 +1,30 @@
import styled from "styled-components";
import ModalDialog from "@appserver/components/modal-dialog";
const StyledModalDialog = styled(ModalDialog)`
.generate {
font-weight: 600;
}
.text-area {
margin-top: 4px;
margin-bottom: 16px;
&-label {
font-weight: 600;
margin-bottom: 5px;
}
}
.field-label-icon {
margin-bottom: 5px;
}
.ok-button {
padding: 8px 26px;
margin-right: 10px;
}
`;
export default StyledModalDialog;

View File

@ -80,6 +80,16 @@ const StyledSsoPage = styled.div`
max-width: 404px;
width: 100%;
}
.xml-upload-file {
.text-input {
display: none;
}
.icon {
position: static;
}
}
`;
export default StyledSsoPage;

View File

@ -1,41 +1,33 @@
import React from "react";
import styled from "styled-components";
import { observer } from "mobx-react";
import Box from "@appserver/components/box";
import Button from "@appserver/components/button";
import ModalDialog from "@appserver/components/modal-dialog";
import StyledModalDialog from "../styled-containers/StyledModalDialog";
import Text from "@appserver/components/text";
import TextArea from "@appserver/components/textarea";
import { addArgument } from "../../../../utils";
const StyledModalDialog = styled(ModalDialog)`
.text-area {
margin-top: 12px;
}
.ok-button {
margin-right: 10px;
}
.text-area-label {
margin-top: 5px;
}
`;
const AddCertificateModal = ({ FormStore, t }) => {
const AddIdpCertificateModal = ({ FormStore, t }) => {
const headerContent = t("NewCertificate");
const onClose = addArgument(FormStore.onCloseModal, "isIdpModalVisible");
return (
<StyledModalDialog
contentHeight="100%"
displayType="modal"
onClose={FormStore.onCloseModal}
visible={FormStore.isModalVisible}
onClose={onClose}
visible={FormStore.isIdpModalVisible}
>
<ModalDialog.Header>{headerContent}</ModalDialog.Header>
<ModalDialog.Body>
<Text className="text-area-label">{t("OpenCertificate")}</Text>
<Text isBold className="text-area-label">
{t("OpenCertificate")}
</Text>
<TextArea
className="text-area"
name="newIdpCertificate"
@ -51,12 +43,12 @@ const AddCertificateModal = ({ FormStore, t }) => {
label={t("Common:OKButton")}
onClick={FormStore.onAddCertificate}
primary
size="medium"
size="big"
/>
<Button
label={t("Common:CancelButton")}
onClick={FormStore.onCloseModal}
size="medium"
onClick={onClose}
size="big"
/>
</Box>
</ModalDialog.Footer>
@ -64,4 +56,4 @@ const AddCertificateModal = ({ FormStore, t }) => {
);
};
export default observer(AddCertificateModal);
export default observer(AddIdpCertificateModal);

View File

@ -0,0 +1,88 @@
import React from "react";
import { observer } from "mobx-react";
import Box from "@appserver/components/box";
import Button from "@appserver/components/button";
import Link from "@appserver/components/link";
import ModalDialog from "@appserver/components/modal-dialog";
import Text from "@appserver/components/text";
import TextArea from "@appserver/components/textarea";
import ModalComboBox from "./ModalComboBox";
import StyledModalDialog from "../styled-containers/StyledModalDialog";
import { addArgument } from "../../../../utils";
const AddSpCertificateModal = ({ FormStore, t }) => {
const onClose = addArgument(FormStore.onCloseModal, "isSpModalVisible");
const onOkClick = (e) => {
FormStore.onAddCertificate();
onClose(e);
};
return (
<StyledModalDialog
contentHeight="100%"
displayType="modal"
onClose={onClose}
visible={FormStore.isSpModalVisible}
>
<ModalDialog.Header>{t("NewCertificate")}</ModalDialog.Header>
<ModalDialog.Body>
<Box marginProp="4px 0 15px 0">
<Link
className="generate"
isHovered
onClick={FormStore.generateCertificate}
type="action"
>
{t("GenerateCertificate")}
</Link>
</Box>
<Text isBold className="text-area-label">
{t("OpenCertificate")}
</Text>
<TextArea
className="text-area"
name="newSpCertificate"
onChange={FormStore.onTextInputChange}
value={FormStore.newSpCertificate}
/>
<Text isBold className="text-area-label">
{t("PrivateKey")}
</Text>
<TextArea
className="text-area"
name="newSpPrivateKey"
onChange={FormStore.onTextInputChange}
value={FormStore.newSpPrivateKey}
/>
<ModalComboBox FormStore={FormStore} t={t} />
</ModalDialog.Body>
<ModalDialog.Footer>
<Box displayProp="flex">
<Button
className="ok-button"
label={t("Common:OKButton")}
onClick={onOkClick}
primary
size="big"
/>
<Button
label={t("Common:CancelButton")}
onClick={onClose}
size="big"
/>
</Box>
</ModalDialog.Footer>
</StyledModalDialog>
);
};
export default observer(AddSpCertificateModal);

View File

@ -0,0 +1,55 @@
import React from "react";
import Box from "@appserver/components/box";
import SimpleCheckbox from "./SimpleCheckbox";
import { observer } from "mobx-react";
const checkboxesNames = {
idp: [
"idp_verifyAuthResponsesSign",
"idp_verifyLogoutRequestsSign",
"idp_verifyLogoutResponsesSign",
],
sp: [
"sp_signAuthRequests",
"sp_signLogoutRequests",
"sp_signLogoutResponses",
"sp_encryptAssertions",
],
};
const CheckboxSet = ({ FormStore, prefix, t }) => {
return (
<Box marginProp="12px 0">
<SimpleCheckbox
FormStore={FormStore}
label={t(`${prefix}AuthRequest`)}
name={checkboxesNames[prefix][0]}
tabIndex={10}
/>
<SimpleCheckbox
FormStore={FormStore}
label={t(`${prefix}SignExitRequest`)}
name={checkboxesNames[prefix][1]}
tabIndex={11}
/>
<SimpleCheckbox
FormStore={FormStore}
label={t(`${prefix}SignResponseRequest`)}
name={checkboxesNames[prefix][2]}
tabIndex={12}
/>
{prefix === "sp" && (
<SimpleCheckbox
FormStore={FormStore}
label={t(`${prefix}DecryptStatements`)}
name={checkboxesNames[prefix][3]}
tabIndex={13}
/>
)}
</Box>
);
};
export default observer(CheckboxSet);

View File

@ -0,0 +1,36 @@
import React from "react";
import { observer } from "mobx-react";
import ComboBox from "@appserver/components/combobox";
import FieldContainer from "@appserver/components/field-container";
import StyledInputWrapper from "../styled-containers/StyledInputWrapper";
const ModalComboBox = ({ FormStore, t }) => {
const certificateOptions = [
{ key: "signing", label: t("Signing") },
{ key: "encryption", label: t("Encryption") },
{ key: "signingAndEncryption", label: t("SigningAndEncryption") },
];
const currentOption = certificateOptions.find(
(option) => option.key === FormStore.newSpCertificateUsedFor
);
return (
<FieldContainer isVertical labelText={t("UsedFor")}>
<StyledInputWrapper>
<ComboBox
onSelect={FormStore.onModalComboBoxChange}
options={certificateOptions}
scaled
scaledOptions
selectedOption={currentOption}
showDisabledItems
/>
</StyledInputWrapper>
</FieldContainer>
);
};
export default observer(ModalComboBox);

View File

@ -8,6 +8,9 @@ import FieldContainer from "@appserver/components/field-container";
import Text from "@appserver/components/text";
import SimpleTextInput from "./SimpleTextInput";
import { FileInput } from "@appserver/components";
const uploadIcon = <ReactSVG src="images/actions.upload.react.svg" />;
const UploadXML = ({ FormStore, t }) => {
return (
@ -28,12 +31,21 @@ const UploadXML = ({ FormStore, t }) => {
<Button
className="upload-button"
icon={<ReactSVG src="images/actions.upload.react.svg" />}
icon={uploadIcon}
size="medium"
onClick={FormStore.onUploadXmlMetadata}
tabIndex={2}
/>
<Text className="or-text">{t("Or")}</Text>
<Button label={t("ChooseFile")} size="medium" tabIndex={3} />
<FileInput
accept=".xml"
buttonLabel={t("ChooseFile")}
className="xml-upload-file"
size="middle"
tabIndex={3}
/>
</Box>
</FieldContainer>
);

View File

@ -27,32 +27,38 @@ class SsoFormStore {
// idpSettings
entityId = "";
ssoUrl = "";
ssoBinding = "Redirect";
ssoBinding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST";
sloUrl = "";
sloBinding = "Redirect";
nameIdFormat = "transient";
sloBinding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST";
nameIdFormat = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient";
newIdpCertificate = "";
idpCertificates = [];
// idpCertificateAdvanced
idp_verifyAlgorithm = "rsa-sha1";
idp_verifyAuthResponsesSign = true;
idp_verifyLogoutRequestsSign = true;
idp_verifyLogoutResponsesSign = true;
idp_decryptAlgorithm = "aes128-cbc";
idp_decryptAlgorithm = "http://www.w3.org/2001/04/xmlenc#aes128-cbc";
// no checkbox for that
ipd_decryptAssertions = false;
idp_verifyAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
idp_verifyAuthResponsesSign = false;
idp_verifyLogoutRequestsSign = false;
idp_verifyLogoutResponsesSign = false;
newSpCertificate = "";
newSpPrivateKey = "";
newSpCertificateUsedFor = "signing";
spCertificates = [];
// spCertificateAdvanced
// null for some reason and no checkbox
sp_decryptAlgorithm = null;
sp_signingAlgorithm = "rsa-sha1";
sp_signAuthRequests = true;
sp_signLogoutRequests = true;
sp_signLogoutResponses = true;
sp_encryptAlgorithm = "aes128-cbc";
sp_encryptAlgorithm = "http://www.w3.org/2001/04/xmlenc#aes128-cbc";
sp_encryptAssertions = false;
sp_signAuthRequests = false;
sp_signLogoutRequests = false;
sp_signLogoutResponses = false;
sp_signingAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
// sp_verifyAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
firstName = "";
lastName = "";
@ -70,28 +76,11 @@ class SsoFormStore {
// hide parts of form
ServiceProviderSettings = true;
ShowAdditionalParameters = true;
ShowAdditionalParametersIdp = true;
ShowAdditionalParametersSp = true;
SPMetadata = true;
isModalVisible = false;
// touched fields
uploadXmlUrlTouched = false;
spLoginLabelTouched = false;
entityIdTouched = false;
ssoUrlTouched = false;
sloUrlTouched = false;
firstNameTouched = false;
lastNameTouched = false;
emailTouched = false;
locationTouched = false;
titleTouched = false;
phoneTouched = false;
sp_entityIdTouched = false;
sp_assertionConsumerUrlTouched = false;
sp_singleLogoutUrlTouched = false;
isIdpModalVisible = false;
isSpModalVisible = false;
// errors
uploadXmlUrlHasError = false;
@ -144,7 +133,7 @@ class SsoFormStore {
};
onBindingChange = (e) => {
this.ssoBinding = e.target.value;
this[e.target.name] = e.target.value;
};
onComboBoxChange = (option, field) => {
@ -159,12 +148,20 @@ class SsoFormStore {
this[e.target.name] = e.target.checked;
};
onOpenModal = () => {
this.isModalVisible = true;
onOpenIdpModal = () => {
this.isIdpModalVisible = true;
};
onCloseModal = () => {
this.isModalVisible = false;
onOpenSpModal = () => {
this.isSpModalVisible = true;
};
onCloseModal = (e, modalVisible) => {
this[modalVisible] = false;
};
onModalComboBoxChange = (option) => {
this.spCertificateUsedFor = option.key;
};
onAddCertificate = () => {